Package com.sun.sgs.test.impl.service.nodemap

Source Code of com.sun.sgs.test.impl.service.nodemap.TestNodeMappingServiceImpl

/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* --
*/

package com.sun.sgs.test.impl.service.nodemap;

import com.sun.sgs.auth.Identity;
import com.sun.sgs.impl.auth.IdentityImpl;
import com.sun.sgs.impl.kernel.StandardProperties;
import com.sun.sgs.impl.service.nodemap.policy.LocalNodePolicy;
import com.sun.sgs.impl.service.nodemap.NodeMappingServerImpl;
import com.sun.sgs.impl.service.nodemap.NodeMappingServiceImpl;
import com.sun.sgs.impl.util.AbstractService.Version;
import com.sun.sgs.kernel.ComponentRegistry;
import com.sun.sgs.kernel.TransactionScheduler;
import com.sun.sgs.service.DataService;
import com.sun.sgs.service.IdentityRelocationListener;
import com.sun.sgs.service.Node;
import com.sun.sgs.service.Node.Health;
import com.sun.sgs.service.NodeMappingListener;
import com.sun.sgs.service.NodeMappingService;
import com.sun.sgs.service.SimpleCompletionHandler;
import com.sun.sgs.service.TransactionProxy;
import com.sun.sgs.service.UnknownIdentityException;
import com.sun.sgs.service.UnknownNodeException;
import com.sun.sgs.service.WatchdogService;
import com.sun.sgs.test.util.SgsTestNode;
import com.sun.sgs.test.util.TestAbstractKernelRunnable;
import com.sun.sgs.test.util.UtilReflection;
import com.sun.sgs.tools.test.FilteredNameRunner;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

@RunWith(FilteredNameRunner.class)
public class TestNodeMappingServiceImpl {

    /** Number of additional nodes to create for selected tests */
    private static final int NUM_NODES = 3;
   
    /** Reflective stuff */
    private static Method assertValidMethod;
    private static Method moveMethod;
    private static Field serverImplField;
    private static String VERSION_KEY;
    private static int MAJOR_VERSION;
    private static int MINOR_VERSION;
    static {
        try {
            Class nmsImpl = NodeMappingServiceImpl.class;
            moveMethod = UtilReflection.getMethod(NodeMappingServerImpl.class,
                    "mapToNewNode", Identity.class, String.class,
                     Node.class, long.class);
            assertValidMethod =
                UtilReflection.getMethod(nmsImpl,
                                         "assertValid", Identity.class);
            serverImplField = UtilReflection.getField(nmsImpl, "serverImpl");
           
            Class nodeMapUtilClass =
                Class.forName("com.sun.sgs.impl.service.nodemap.NodeMapUtil");
           
            VERSION_KEY = (String)
                    getField(nodeMapUtilClass, "VERSION_KEY").get(null);
            MAJOR_VERSION =
                    getField(nodeMapUtilClass, "MAJOR_VERSION").getInt(null);
            MINOR_VERSION =
                    getField(nodeMapUtilClass, "MINOR_VERSION").getInt(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    /** The node that creates the servers */
    private SgsTestNode serverNode;
    /** Any additional nodes, for tests needing more than one node */
    private SgsTestNode additionalNodes[];
   
    private TransactionProxy txnProxy;
    private ComponentRegistry systemRegistry;
    private Properties serviceProps;
   
    /** A specific property we started with, for remove tests */
    private int removeTime;

    /** The renew interval for the watchdog service */
    private int renewTime;
   
    /** The transaction scheduler. */
    private TransactionScheduler txnScheduler;
   
    /** The owner for tasks I initiate. */
    private Identity taskOwner;
   
    private NodeMappingService nodeMappingService;
   
    /** A mapping of node id ->NodeMappingListener, for listener checks */
    private Map<Long, TestListener> nodeListenerMap;
    private static Field getField(Class cl, String name) throws Exception {
        return UtilReflection.getField(cl, name);
    }

    @Before
    public void setUp() throws Exception {
        setUp(null);
    }

    protected void setUp(Properties props) throws Exception {
        nodeListenerMap = new HashMap<Long, TestListener>();
       
        serverNode = new SgsTestNode("TestNodeMappingServiceImpl", null, props);
        txnProxy = serverNode.getProxy();
        systemRegistry = serverNode.getSystemRegistry();
        serviceProps = serverNode.getServiceProperties();
        removeTime = Integer.valueOf(
            serviceProps.getProperty(
                "com.sun.sgs.impl.service.nodemap.remove.expire.time"));
  renewTime = Integer.valueOf(
      serviceProps.getProperty(
    "com.sun.sgs.impl.service.watchdog.server.renew.interval"));
       
        txnScheduler = systemRegistry.getComponent(TransactionScheduler.class);
        taskOwner = txnProxy.getCurrentOwner();
       
        nodeMappingService = serverNode.getNodeMappingService();
       
        // Add to our test data structures, so we can find these nodes
        // and listeners.
        TestListener listener = new TestListener();       
        nodeMappingService.addNodeMappingListener(listener);
        nodeListenerMap.put(serverNode.getNodeId(), listener);
    }
   
  
    /**
     * Add additional nodes.  We only do this as required by the tests.
     *
     * @param props properties for node creation, or {@code null} if default
     *     properties should be used
     */
    private void addNodes(Properties props) throws Exception {
        // Create the other nodes
        additionalNodes = new SgsTestNode[NUM_NODES];
       
        for (int i = 0; i < NUM_NODES; i++) {
            SgsTestNode node =  new SgsTestNode(serverNode, null, props);
            additionalNodes[i] = node;
       
            NodeMappingService nmap = node.getNodeMappingService();

            // Add to our test data structures, so we can find these nodes
            // and listeners.
            TestListener listener = new TestListener();       
            nmap.addNodeMappingListener(listener);
            nodeListenerMap.put(node.getNodeId(), listener);
        }
    }
       
    /** Shut down the nodes. */
    @After
    public void tearDown() throws Exception {
        if (additionalNodes != null) {
            for (SgsTestNode node : additionalNodes) {
                node.shutdown(false);
            }
            additionalNodes = null;
        }
        serverNode.shutdown(true);
    }

   
        ////////     The tests     /////////
    @Test
    public void testConstructor() {
        NodeMappingService nodemap = null;
        try {
            nodemap =
                new NodeMappingServiceImpl(
                            serviceProps, systemRegistry, txnProxy);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (nodemap != null) { nodemap.shutdown(); }
        }
    }

    @Test(expected = NullPointerException.class)
    public void testConstructorNullProperties() throws Exception {
        NodeMappingService nodemap = null;
        try {
            nodemap =
                new NodeMappingServiceImpl(null, systemRegistry, txnProxy);
        } finally {
            if (nodemap != null) { nodemap.shutdown(); }
        }
    }
   
    @Test(expected = NullPointerException.class)
    public void testConstructorNullProxy() throws Exception {
        NodeMappingService nodemap = null;
        try {
            nodemap =
              new NodeMappingServiceImpl(serviceProps, systemRegistry, null);
        } finally {
            if (nodemap != null) { nodemap.shutdown(); }
        }
    }
   
    @Test(expected = IllegalArgumentException.class)
    public void testConstructorAppButNoServerHost() throws Exception {
        // Server start is false but we didn't specify a server host
        Properties props =
                SgsTestNode.getDefaultProperties(
                    "TestNodeMappingServiceImpl",
                    serverNode,
                    SgsTestNode.DummyAppListener.class);
        props.remove(StandardProperties.SERVER_HOST);
 
        NodeMappingService nmap =
            new NodeMappingServiceImpl(props, systemRegistry, txnProxy);
    }
   
    @Test
    public void testConstructedVersion() throws Exception {
  txnScheduler.runTask(new TestAbstractKernelRunnable() {
    public void run() {
        Version version = (Version)
      serverNode.getDataService()
                        .getServiceBinding(VERSION_KEY);
        if (version.getMajorVersion() != MAJOR_VERSION ||
      version.getMinorVersion() != MINOR_VERSION)
        {
      fail("Expected service version (major=" +
           MAJOR_VERSION + ", minor=" + MINOR_VERSION +
           "), got:" + version);
        }
    }}, taskOwner);
    }
   
    @Test
    public void testConstructorWithCurrentVersion() throws Exception {
  txnScheduler.runTask(new TestAbstractKernelRunnable() {
    public void run() {
        Version version = new Version(MAJOR_VERSION, MINOR_VERSION);
        serverNode.getDataService()
                              .setServiceBinding(VERSION_KEY, version);
    }}, taskOwner);

  new NodeMappingServiceImpl(
      SgsTestNode.getDefaultProperties(
    "TestNodeMappingServiceImpl", serverNode, null),
      systemRegistry, txnProxy)
    }

    @Test(expected = IllegalStateException.class)
    public void testConstructorWithMajorVersionMismatch() throws Exception {
  txnScheduler.runTask(new TestAbstractKernelRunnable() {
    public void run() {
        Version version =
      new Version(MAJOR_VERSION + 1, MINOR_VERSION);
        serverNode.getDataService()
                              .setServiceBinding(VERSION_KEY, version);
    }}, taskOwner);

        new NodeMappingServiceImpl(serviceProps, systemRegistry, txnProxy)
    }

    @Test(expected = IllegalStateException.class)
    public void testConstructorWithMinorVersionMismatch() throws Exception {
  txnScheduler.runTask(new TestAbstractKernelRunnable() {
    public void run() {
        Version version =
      new Version(MAJOR_VERSION, MINOR_VERSION + 1);
        serverNode.getDataService()
                              .setServiceBinding(VERSION_KEY, version);
    }}, taskOwner);

        new NodeMappingServiceImpl(serviceProps, systemRegistry, txnProxy)
    }
   
    @Test
    public void testReady() throws Exception {
        NodeMappingService nodemap = null;
        try {
            nodemap =
                new NodeMappingServiceImpl(
        SgsTestNode.getDefaultProperties(
      "TestNodeMappingServiceImpl", serverNode, null),
        systemRegistry, txnProxy);
            TestListener listener = new TestListener();       
            nodemap.addNodeMappingListener(listener);
           
            // We have NOT called ready yet.
            final Identity id = new IdentityImpl("first");
            nodemap.assignNode(NodeMappingService.class, id);
           
            txnScheduler.runTask(
                new TestAbstractKernelRunnable() {
                    public void run() throws Exception {
                        nodeMappingService.getNode(id);
                    }
                }, taskOwner);
           
            // Ensure the listener has not been called yet.
            assertTrue(listener.isClear());

            nodemap.ready();
            // Listener should be notified
            listener.waitForNotification();
           
            // no old node
            checkIdAdded(listener, id, null);
        } finally {
            if (nodemap != null) { nodemap.shutdown(); }
        }
    }
   
    /* -- Test Service -- */
    @Test
    public void testGetName() {
        System.out.println(nodeMappingService.getName());
    }
   
    /* -- Test assignNode -- */
    @Test
    public void testAssignNode() throws Exception {  
        // Assign outside a transaction
        final Identity id = new IdentityImpl("first");
        long nodeId =
                nodeMappingService.assignNode(NodeMappingService.class, id);

        if (nodeId < 0) {
            fail("Unexpected assignNode failure");
        }
        verifyMapCorrect(id);
  TestListener l = nodeListenerMap.get(serverNode.getNodeId());
        l.waitForNotification();
      
        // Now expect to be able to find the identity
        txnScheduler.runTask(
            new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    Node node = nodeMappingService.getNode(id);
                    // Make sure we got a notification, no old node
                    TestListener listener = nodeListenerMap.get(node.getId());
                    checkIdAdded(listener, id, null);
                }
        }, taskOwner);
    }
   
    @Test(expected = NullPointerException.class)
    public void testAssignNodeNullServer() throws Exception {
        nodeMappingService.assignNode(null, new IdentityImpl("first"));
    }
   
    @Test(expected = NullPointerException.class)
    public void testAssignNodeNullIdentity() throws Exception {
        nodeMappingService.assignNode(NodeMappingService.class, null);
    }
   
    @Test
    public void testAssignNodeTwice() throws Exception {
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
       
        // Now expect to be able to find the identity
        GetNodeTask task1 = new GetNodeTask(id);
        txnScheduler.runTask(task1, taskOwner);
        Node node1 = task1.getNode();
       
        // There shouldn't be a problem if we assign it twice;  as an
        // optimization we shouldn't call out to the server
        nodeMappingService.assignNode(NodeMappingService.class, id);
        verifyMapCorrect(id);
       
        // Now expect to be able to find the identity
        GetNodeTask task2 = new GetNodeTask(id);
        txnScheduler.runTask(task2, taskOwner);
        Node node2 = task2.getNode();
        assertEquals(node1, node2);
    }
   
    @Test
    public void testAssignMultNodes() throws Exception {
        // This test is partly so I can compare the time it takes to
        // assign one node, or the same node twice
        addNodes(null);
       
        final int MAX = 25;
        Identity ids[] = new Identity[MAX];
        for (int i = 0; i < MAX; i++) {
            ids[i] = new IdentityImpl("identity" + i);        
            nodeMappingService.assignNode(NodeMappingService.class, ids[i]);
               
            verifyMapCorrect(ids[i]);
        }

        for (int j = 0; j < MAX; j++) {
            final Identity id = ids[j];
            txnScheduler.runTask(
                new TestAbstractKernelRunnable() {
                    public void run() throws Exception {
                        nodeMappingService.getNode(id);
                    }
            }, taskOwner);
        }
    }

    @Test
    public void testAssignNodeNoNodes() throws Exception {
        WatchdogService watchdogService =
                    (WatchdogService)serverNode.getWatchdogService();

        // By reporting health as YELLOW there should not be any nodes available
        // for assignment
        watchdogService.reportHealth(
                                serverNode.getDataService().getLocalNodeId(),
                                Health.YELLOW, "A");

        long nodeId = nodeMappingService.assignNode(NodeMappingService.class,
                                                    new IdentityImpl("first"));

        if (nodeId >= 0) {
            fail("Expected assignNode to fail (-1), got: " + nodeId);
        }
    }

    @Test
    public void testLocalNodePolicy() throws Exception {
        // Remove what happened at setup().  I know, I know...
        tearDown();
  serviceProps = SgsTestNode.getDefaultProperties(
      "TestNodeMappingServiceImpl", null, null);

        // Create a new nodeMappingServer which will move an identity
        // automatically every so often. 
        serviceProps.setProperty(
                "com.sun.sgs.impl.service.nodemap.policy.class",
                LocalNodePolicy.class.getName());

        setUp(serviceProps);
        addNodes(null);

        Map<Identity, Long> idMap = new HashMap<Identity, Long>();
        // Assign an identity on each of our nodes
        for (int i = 0; i < NUM_NODES; i++) {
            Identity id = new IdentityImpl("Identity" + i);
            additionalNodes[i].getNodeMappingService().
                                        assignNode(DataService.class, id);
            idMap.put(id, additionalNodes[i].getNodeId());
        }
       
        // Now test each identity to see where it was actually assigned
        for (Identity id : idMap.keySet()) {
            GetNodeTask task = new GetNodeTask(id);
            txnScheduler.runTask(task, taskOwner);
            long expectedNodeId = (long) idMap.get(id);
            assertEquals(expectedNodeId, task.getNodeId());
        }

     }
   
    @Test (expected = IllegalStateException.class)
    public void testAssignNodeInTransaction() throws Exception {
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
            public void run() {
                nodeMappingService.assignNode(NodeMappingService.class,
                                              new IdentityImpl("first"));
            }
        }, taskOwner);
    }
   
    /* -- Test getNode -- */
    @Test(expected = NullPointerException.class)
    public void testGetNodeNullIdentity() throws Exception {
        txnScheduler.runTask(
                new TestAbstractKernelRunnable() {
                    public void run() throws Exception {
                        nodeMappingService.getNode(null);
                    }
            }, taskOwner);
    }
   
    @Test(expected = UnknownIdentityException.class)
    public void testGetNodeBadIdentity() throws Exception {
        txnScheduler.runTask(
                new TestAbstractKernelRunnable() {
                    public void run() throws Exception {
                        nodeMappingService.getNode(new IdentityImpl("first"));
                    }
            }, taskOwner);
    }
  
    @Test
    public void testGetNode() {
        final Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
        try {
            txnScheduler.runTask(
                    new TestAbstractKernelRunnable() {
                        public void run() throws Exception {
                            nodeMappingService.getNode(id);
                        }
                }, taskOwner);
        } catch (Exception e) {
            e.printStackTrace();
            fail("Unexpected exception");
        }
    }
   

    // Check to see if identities are changing in a transaction
    // and that any caching of identities in transaction works.
    @Test
    public void testGetNodeMultiple() throws Exception {
        // A better test would have another thread racing to change
        // the identity.
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
       
        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node node1 = task.getNode();
        txnScheduler.runTask(task, taskOwner);
        Node node2 = task.getNode();
        txnScheduler.runTask(task, taskOwner);
        Node node3 = task.getNode();
        assertEquals(node1, node2);
        assertEquals(node1, node3);
        assertEquals(node2, node3);
    }
   
    /*-- Test getIdentities --*/
    @Test(expected = UnknownNodeException.class)
    public void testGetIdentitiesBadNode() throws Exception {
        txnScheduler.runTask(
                new TestAbstractKernelRunnable() {
                    public void run() throws Exception {
                        nodeMappingService.getIdentities(999L);
                    }
            }, taskOwner);
    }
  
    @Test
    public void testGetIdentities() throws Exception {
        final Identity id1 = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id1);

        txnScheduler.runTask(
            new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    Node node = nodeMappingService.getNode(id1);
        Set<Identity> foundSet = new HashSet<Identity>();
                    Iterator<Identity> ids =
                        nodeMappingService.getIdentities(node.getId());
                    while (ids.hasNext()) {
                        foundSet.add(ids.next());
        }
        assertTrue(foundSet.contains(id1));
                }
        }, taskOwner);
    }
   
    @Test
    public void testGetIdentitiesNoIds() throws Exception {
        addNodes(null);
        // This test assumes that we can create a node that has no
        // assignments.  That's currently true (Dec 11 2007).
        final long nodeId = additionalNodes[NUM_NODES - 1].getNodeId();

        txnScheduler.runTask(
            new TestAbstractKernelRunnable() {
                public void run() throws Exception {
                    Iterator<Identity> ids =
                        nodeMappingService.getIdentities(nodeId);
                    while (ids.hasNext()) {
                        fail("expected no identities on this node " +
                             ids.next());
                    }
                }
        }, taskOwner);
    }
   
    @Test
    public void testGetIdentitiesMultiple() throws Exception {
        addNodes(null);
       
        final int MAX = 8;
        Identity ids[] = new Identity[MAX];
        for (int i = 0; i < MAX; i++ ) {
            ids[i] = new IdentityImpl("dummy" + i);
            nodeMappingService.assignNode(NodeMappingService.class, ids[i]);
        }
           
        Set<Node> nodeset = new HashSet<Node>();
        Node nodes[] = new Node[MAX];
         
        for (int j = 0; j < MAX; j++) {
            GetNodeTask task = new GetNodeTask(ids[j]);
            txnScheduler.runTask(task, taskOwner);
            Node n = task.getNode();
            nodes[j] = n;
            nodeset.add(n);
        }
       
        // Set up our own internal node map based on the info above
        Map<Node, Set<Identity>> nodemap = new HashMap<Node, Set<Identity>>();
        for (Node n : nodeset) {
            nodemap.put(n, new HashSet<Identity>());
        }
        for (int k = 0; k < MAX; k++) {
            Set<Identity> s = nodemap.get(nodes[k]);
            s.add(ids[k]);
        }
       
        for (final Node node : nodeset) {
            final Set s = nodemap.get(node);
           
            txnScheduler.runTask(new TestAbstractKernelRunnable(){
                public void run() throws Exception {
        Set<Identity> foundSet = new HashSet<Identity>();
                    Iterator<Identity> idIter =
                        nodeMappingService.getIdentities(node.getId());
                    while (idIter.hasNext()) {
                        foundSet.add(idIter.next());
        }
        assertTrue(foundSet.containsAll(s));
                }
            }, taskOwner);
        }
       
    }
   
    /* -- Test setStatus -- */
    @Test(expected = NullPointerException.class)
    public void testSetStatusNullService() throws Exception {
        nodeMappingService.setStatus(null, new IdentityImpl("first"), true);
    }
   
    @Test(expected = NullPointerException.class)
    public void testSetStatusNullIdentity() throws Exception {
        nodeMappingService.setStatus(NodeMappingService.class, null, true);
    }
    @Test (expected = IllegalStateException.class)
    public void testSetStatusInTransaction() throws Exception {
        txnScheduler.runTask(new TestAbstractKernelRunnable() {
            public void run() throws Exception {
                nodeMappingService.setStatus(NodeMappingService.class,
                                              new IdentityImpl("first"), true);
            }
        }, taskOwner);
    }
   
    @Test
    public void testSetStatusRemove() throws Exception {
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node node = task.getNode();
       
        // clear out the listener
        TestListener listener = nodeListenerMap.get(node.getId());
  listener.waitForNotification();
        listener.clear();
        nodeMappingService.setStatus(NodeMappingService.class, id, false);
        listener.waitForNotification(removeTime * 4);
       
        try {
            txnScheduler.runTask(task, taskOwner);
            fail("Expected UnknownIdentityException");
        } catch (UnknownIdentityException e) {
            // Make sure we got a notification
            checkIdRemoved(listener, id, null);
        }
    }
   
    @Test
    public void testSetStatusMultRemove() throws Exception {
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node node = task.getNode();
       
        // clear out the listener
        TestListener listener = nodeListenerMap.get(node.getId());
  listener.waitForNotification();
        listener.clear();
        // SetStatus is idempotent:  it doesn't matter how often a particular
        // service says an id is active.
        nodeMappingService.setStatus(NodeMappingService.class, id, true);
        nodeMappingService.setStatus(NodeMappingService.class, id, true);
        // Likewise, it should be OK to make multiple "false" calls.
        nodeMappingService.setStatus(NodeMappingService.class, id, false);
        nodeMappingService.setStatus(NodeMappingService.class, id, false);

        listener.waitForNotification(removeTime * 4);
       
        try {
            txnScheduler.runTask(task, taskOwner);
            fail("Expected UnknownIdentityException");
        } catch (UnknownIdentityException e) {
            // Make sure we got a notification
            checkIdRemoved(listener, id, null);
        }
    }
   
    /**
     * Regression test for sgs-server issue #140, node mapping server
     * is logging at too high a level in a particular scenario.
     */
    @Test
    public void testSetStatusQuickMultRemove() throws Exception
        Identity id = new IdentityImpl("something");
        nodeMappingService.assignNode(NodeMappingService.class, id);
        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node node = task.getNode();
       
        // clear out the listener
        TestListener listener = nodeListenerMap.get(node.getId());
  listener.waitForNotification();
        listener.clear();

        // We arrange for the test to fail if there is a WARNING log message
        // in the time period we're interested in.  The threads use an
        // Exchanger to synchronize and get results from the logger.
        final Exchanger<Boolean> errorExchanger = new Exchanger<Boolean>();
       
        Logger logger =
            Logger.getLogger("com.sun.sgs.impl.service.nodemap.server");
        Level oldLevel = logger.getLevel();
        logger.setLevel(Level.INFO);
        logger.setFilter(new Filter() {
            public boolean isLoggable(LogRecord record) {
                if (record.getLevel() == Level.WARNING) {
                    // Tell the parent thread we've seen a WARNING message.
                    try {
                        errorExchanger.exchange(Boolean.TRUE);
                    } catch (InterruptedException ignored) {
                        // do nothing
                    }
                }
                return true;
            }
        });
       
        // Much like testSetStatusMultRemove, but need to check logging
        // output for inappropriate warning message.
        // We're simulating an identity that is logged in, logged out...
        nodeMappingService.setStatus(NodeMappingService.class, id, true);
        nodeMappingService.setStatus(NodeMappingService.class, id, false);
        // ... and then immediately logged in and out again.
        nodeMappingService.setStatus(NodeMappingService.class, id, true);
        nodeMappingService.setStatus(NodeMappingService.class, id, false);
       
        // Wait up to removeTime * 4, and see if we got a WARNING log message
        try {
            Boolean error = errorExchanger.exchange(null,
                                                    removeTime * 4,
                                                    TimeUnit.MILLISECONDS);
            if (error) {
                fail(" Got a log record at level WARNING");
            }
        } catch (TimeoutException e) {
            // There might be multiple messages at different levels, or none
            // at all:  we are only looking for confusing WARNING messages
            // when there is actually no error to warn about.
            System.out.println("OK: Time out without a WARNING log message");
        }
       
        // Remove our test filter and reset the logging level.
        logger.setFilter(null);
        logger.setLevel(oldLevel);
       
        // Sanity check, be sure our listener still gets a single notification
        // in this log in, out, in, out scenario.
  listener.waitForNotification();
        try {
            txnScheduler.runTask(task, taskOwner);
            fail("Expected UnknownIdentityException");
        } catch (UnknownIdentityException e) {
            // Make sure we got a notification
            checkIdRemoved(listener, id, null);
        }
    }
       
    @Test
    public void testSetStatusNoRemove() throws Exception {
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
        GetNodeTask task = new GetNodeTask(id);
        try {
            txnScheduler.runTask(task, taskOwner);
        } catch (UnknownIdentityException e) {
            fail("Expected UnknownIdentityException");
        }
       
        nodeMappingService.setStatus(NodeMappingService.class, id, false);
        nodeMappingService.setStatus(NodeMappingService.class, id, true);
        Thread.sleep(removeTime * 4);
        // Error if we cannot find the identity!
        try {
            txnScheduler.runTask(task, taskOwner);
        } catch (UnknownIdentityException e) {
            fail("Unexpected UnknownIdentityException");
        }
    }
   
    /* -- Test private mapToNewNode -- */
    @Test
    public void testListenersOnMove() throws Exception {  
        // We need some additional nodes for this test to work correctly.
        addNodes(null);
       
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node firstNode = task.getNode();
        long firstNodeId = task.getNodeId();
        TestListener firstNodeListener = nodeListenerMap.get(firstNodeId);
  firstNodeListener.waitForNotification();

        NodeMappingServerImpl server =
            (NodeMappingServerImpl)serverImplField.get(nodeMappingService);
       
        // clear out the listeners
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        // ... and invoke the method
        moveMethod.invoke(server, id, null, firstNode, firstNodeId);

  firstNodeListener.waitForNotification();
 
  txnScheduler.runTask(task, taskOwner);
  Node secondNode = task.getNode();
        TestListener secondNodeListener =
      nodeListenerMap.get(secondNode.getId());

  secondNodeListener.waitForNotification();

        checkIdMoved(firstNodeListener, firstNode,
                     secondNodeListener, secondNode, id);
    }


    /* -- Test identity relocation listeners -- */
    @Test(expected = NullPointerException.class)
    public void testAddNullIdentityRelocationListener() throws Exception {
        nodeMappingService.addIdentityRelocationListener(null);
    }

    @Test
    public void testIdRelocationListenerNotification() throws Exception {
        addNodes(null);

        // Add id relocation listeners to each node, and keep a map of them.
        Map<Long, TestRelocationListener> moveMap =
                new HashMap<Long, TestRelocationListener>();
        addRelocationListeners(false, moveMap);

        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);
        Node firstNode = task.getNode();
        long firstNodeId = task.getNodeId();
        TestListener firstNodeListener = nodeListenerMap.get(firstNodeId);
        TestRelocationListener idListener = moveMap.get(firstNodeId);

  firstNodeListener.waitForNotification();

        NodeMappingServerImpl server =
            (NodeMappingServerImpl)serverImplField.get(nodeMappingService);

        // clear out the listeners
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        for (TestRelocationListener lis : moveMap.values()) {
            lis.clear();
        }
        // ... and invoke the method
        moveMethod.invoke(server, id, null, firstNode, firstNodeId);

        // Give the id relocation listener a chance to finish, and the
        // actual node assignment to complete.
        idListener.waitForNotification();

        txnScheduler.runTask(task, taskOwner);
        Node secondNode = task.getNode();
        long secondNodeId = task.getNodeId();
        TestListener secondNodeListener =
                nodeListenerMap.get(secondNodeId);

  secondNodeListener.waitForNotification();

        checkRelocationNotification(idListener, id, secondNodeId);

        // Make sure no other listeners were affected
        for (TestRelocationListener listener : moveMap.values()) {
            if (listener != idListener) {
                assertTrue(listener.isClear());
            }
        }

        // Make sure the node mapping listeners were correctly updated
        checkIdMoved(firstNodeListener, firstNode,
                     secondNodeListener, secondNode, id);
    }

    @Test
    public void testIdRelocNotificationOldNodeFailed() throws Exception {
        addNodes(null);

        // Add id relocation listeners to each node, and keep a map of them.
        Map<Long, TestRelocationListener> moveMap =
                new HashMap<Long, TestRelocationListener>();
        addRelocationListeners(true, moveMap);

        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);;
        long firstNodeId = task.getNodeId();
        Node firstNode = task.getNode();
        TestListener firstNodeListener = nodeListenerMap.get(firstNodeId);
        TestRelocationListener idListener = moveMap.get(firstNodeId);

  firstNodeListener.waitForNotification();

        NodeMappingServerImpl server =
            (NodeMappingServerImpl)serverImplField.get(nodeMappingService);

        // clear out the listeners
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        for (TestRelocationListener lis : moveMap.values()) {
            lis.clear();
        }
        // ... and invoke the method
        Long newNode =
            (Long) moveMethod.invoke(server, id, null,
                                     task.getNode(), firstNodeId);

        // Give the id relocation listener a chance to finish.
        idListener.waitForNotification();

        txnScheduler.runTask(task, taskOwner);
        long secondNodeId = task.getNodeId();

        // Make sure the node hasn't actually moved yet.
        assertEquals(firstNodeId, secondNodeId);

        // Check the id relocation listener
        checkRelocationNotification(idListener, id, newNode);

        // Make sure no other listeners were affected
        for (TestRelocationListener listener : moveMap.values()) {
            if (listener != idListener) {
                assertTrue(listener.isClear());
            }
        }

        // Ensure that the node mapping listeners haven't been called yet
        for (TestListener listener : nodeListenerMap.values()) {
            assertTrue(listener.isClear());
        }

        // Now, cause the old node to fail.  First we have to find the
        // correct test node.
        for (SgsTestNode sgs : additionalNodes) {
            if (sgs.getNodeId() == firstNodeId) {
                System.out.println("Shutting down node " + firstNodeId);
                sgs.shutdown(false);
                break;
            }
        }

        // Wait for notification.  We expect to be notified on the
        // newNode assigned above.
        TestListener secondNodeListener = nodeListenerMap.get(newNode);
        secondNodeListener.waitForNotification(renewTime * 2);

        txnScheduler.runTask(task, taskOwner);
        assertEquals((long) newNode, task.getNodeId());

        checkIdAdded(secondNodeListener, id, firstNode);
    }

    @Test
    public void testIdRelocNotificationTwice() throws Exception {
        addNodes(null);

        // Add id relocation listeners to each node, and keep a map of them.
        Map<Long, TestRelocationListener> moveMap =
                new HashMap<Long, TestRelocationListener>();
        addRelocationListeners(true, moveMap);

        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);;
        long firstNodeId = task.getNodeId();
        Node firstNode = task.getNode();
        TestListener firstNodeListener = nodeListenerMap.get(firstNodeId);
        TestRelocationListener idListener = moveMap.get(firstNodeId);

  firstNodeListener.waitForNotification();

        NodeMappingServerImpl server =
            (NodeMappingServerImpl)serverImplField.get(nodeMappingService);

        // clear out the listeners
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        for (TestRelocationListener lis : moveMap.values()) {
            lis.clear();
        }
        // ... and invoke the method twice
        Long newNode =
            (Long) moveMethod.invoke(server, id, null,
                                     task.getNode(), firstNodeId);
        Long secondTryNode =
            (Long) moveMethod.invoke(server, id, null,
                                     task.getNode(), newNode);

        assertEquals(newNode, secondTryNode);

        // Give the id relocation listener a chance to finish.
        idListener.waitForNotification();

        txnScheduler.runTask(task, taskOwner);
        long secondNodeId = task.getNodeId();

        // Make sure the node hasn't actually moved yet.
        assertEquals(firstNodeId, secondNodeId);

        // Check the id relocation listener
        checkRelocationNotification(idListener, id, newNode);

        // Make sure no other listeners were affected
        for (TestRelocationListener listener : moveMap.values()) {
            if (listener != idListener) {
                assertTrue(listener.isClear());
            }
        }

        // Ensure that the node mapping listeners haven't been called yet
        for (TestListener listener : nodeListenerMap.values()) {
            assertTrue(listener.isClear());
        }

        // Now, allow the movement to complete.
        idListener.handler.completed();

        // Wait for notification.  We expect to be notified on the
        // newNode assigned above.
        TestListener secondNodeListener = nodeListenerMap.get(newNode);
        secondNodeListener.waitForNotification();
        txnScheduler.runTask(task, taskOwner);
        assertEquals((long) newNode, task.getNodeId());

        checkIdAdded(secondNodeListener, id, firstNode);
    }

    @Test
    public void testIdRelocNotificationNoResponse() throws Exception {
        // Set up using our properties
        tearDown();
  serviceProps = SgsTestNode.getDefaultProperties(
      "TestNodeMappingServiceImpl", null, null);

        final int RELOCATION_TIME = 20;
        // Create a new nodeMappingServer with a very short timeout for
        // relocation expiration.
        serviceProps.setProperty(
                "com.sun.sgs.impl.service.nodemap.relocation.expire.time",
                String.valueOf(RELOCATION_TIME));

        setUp(serviceProps);
        addNodes(null);

        // Add id relocation listeners to each node, and keep a map of them.
        Map<Long, TestRelocationListener> moveMap =
                new HashMap<Long, TestRelocationListener>();
        addRelocationListeners(true, moveMap);

        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        GetNodeTask task = new GetNodeTask(id);
        txnScheduler.runTask(task, taskOwner);;
        long firstNodeId = task.getNodeId();
        Node firstNode = task.getNode();
        TestRelocationListener idListener = moveMap.get(firstNodeId);

        NodeMappingServerImpl server =
            (NodeMappingServerImpl)serverImplField.get(nodeMappingService);

        // clear out the listeners
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        for (TestRelocationListener lis : moveMap.values()) {
            lis.clear();
        }
        // ... and invoke the method
        moveMethod.invoke(server, id, null, firstNode, firstNodeId);

        // Ensure that the idListener has been notified.
        idListener.waitForNotification();

        // ... and wait for the id relocation to expire.
        Thread.sleep(RELOCATION_TIME);

        // The identity should not have moved.
        txnScheduler.runTask(task, taskOwner);
        assertEquals(firstNodeId, task.getNodeId());

        // Try another move
        for (TestListener lis : nodeListenerMap.values()) {
            lis.clear();
        }
        for (TestRelocationListener lis : moveMap.values()) {
            lis.clear();
        }
        Long secondTryNode =
            (Long) moveMethod.invoke(server, id, null,
                                     firstNode, firstNodeId);

        // Give the id relocation listener a chance to finish.
        idListener.waitForNotification();
        // This time, allow the movement to complete.
        idListener.handler.completed();

        // Wait for notification.  We expect to be notified on the
        // secondTryNode assigned above.
        TestListener secondNodeListener = nodeListenerMap.get(secondTryNode);
        secondNodeListener.waitForNotification();

        txnScheduler.runTask(task, taskOwner);
        assertEquals((long) secondTryNode, task.getNodeId());

        checkIdAdded(secondNodeListener, id, firstNode);
    }

    /* -- Tests to see what happens if the server isn't available --*/
    @Test
    public void testEvilServerAssignNode() throws Exception {
        // replace the serverimpl with our evil proxy
        Object oldServer = swapToEvilServer(nodeMappingService);
       
        Identity id = new IdentityImpl("first");
       
        try {
            nodeMappingService.assignNode(NodeMappingService.class, id);
        } catch (IllegalStateException e) {
            // All OK, the server is probably shutting down
        }
        swapToNormalServer(nodeMappingService, oldServer);
    }
   
    @Test
    public void testEvilServerGetNode() throws Exception {
        // replace the serverimpl with our evil proxy
        Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);
       
        Object oldServer = swapToEvilServer(nodeMappingService);
       
        GetNodeTask task = new GetNodeTask(id);
        // Reads should cause no trouble
        txnScheduler.runTask(task, taskOwner);
        swapToNormalServer(nodeMappingService, oldServer);
    }
   
    @Test
    public void testEvilServerGetIdentities() throws Exception {
        // put an identity in with a node
        // try to getNode that identity.
        final Identity id1 = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id1);
       
        Object oldServer = swapToEvilServer(nodeMappingService);
       
        txnScheduler.runTask(new TestAbstractKernelRunnable(){
                public void run() throws Exception {
                    Node node = nodeMappingService.getNode(id1);
        Set<Identity> foundSet = new HashSet<Identity>();
                    Iterator<Identity> idIter =
                        nodeMappingService.getIdentities(node.getId());  
                    while (idIter.hasNext()) {
                        foundSet.add(idIter.next());
        }
        assertTrue(foundSet.contains(id1));
                }
            }, taskOwner);
        swapToNormalServer(nodeMappingService, oldServer);
    }
   
    @Test
    public void testEvilServerSetStatus() throws Exception {
        final Identity id = new IdentityImpl("first");
        nodeMappingService.assignNode(NodeMappingService.class, id);

        Object oldServer = swapToEvilServer(nodeMappingService);
       
        try {
            nodeMappingService.setStatus(NodeMappingService.class, id, false);
        } catch (IllegalStateException e) {
            // All OK, the server is probably shutting down
        }
        swapToNormalServer(nodeMappingService, oldServer);
    }
   
    private Object swapToEvilServer(NodeMappingService service) throws Exception {
        Field serverField =
            NodeMappingServiceImpl.class.getDeclaredField("server");
        serverField.setAccessible(true);
       
        Object server = serverField.get(service);
        Object proxy = EvilProxy.proxyFor(server);
        serverField.set(service,proxy);
        return server;
    }
   
    private void swapToNormalServer(NodeMappingService service, Object old)
        throws Exception
    {
        Field serverField =
            NodeMappingServiceImpl.class.getDeclaredField("server");
        serverField.setAccessible(true);
        serverField.set(service, old);
    }
       
//    public void testShutdown() {
//        // queue up a bunch of removes with very long timeouts
//        // make sure we terminate them early
//    }
   
    /** Utilties */
   
    /** Use the invariant checking method */
    private void verifyMapCorrect(final Identity id) throws Exception
        txnScheduler.runTask( new TestAbstractKernelRunnable() {
            public void run() throws Exception {
                boolean valid =
                    (Boolean) assertValidMethod.invoke(nodeMappingService, id);
                assertTrue(valid);
            }
        },taskOwner);
   
   
    /**
     * Simple task to call getNode and return an id
     */
    private class GetNodeTask extends TestAbstractKernelRunnable {
        /** The identity */
        private final Identity id;
        /** The node the identity is assigned to */
        private volatile Node node;
        private volatile long nodeId;
        GetNodeTask(Identity id) {
            this.id = id;
        }
        public void run() throws Exception {
            node = nodeMappingService.getNode(id);
            nodeId = node.getId();
        }
        public Node getNode() { return node; }
        public long getNodeId() { return nodeId; }
    }
   
    /** A test node mapping listener */
    private class TestListener implements NodeMappingListener {
        private final List<Identity> addedIds = new ArrayList<Identity>();
        private final List<Node> addedNodes = new ArrayList<Node>();
        private final List<Identity> removedIds = new ArrayList<Identity>();
        private final List<Node> removedNodes = new ArrayList<Node>();

        // A notificationLock to let us know when the listener has been called.
        private final Object notificationLock = new Object();
        private boolean notified;

        public void mappingAdded(Identity identity, Node node) {
            addedIds.add(identity);
            addedNodes.add(node);
            synchronized (notificationLock) {
                notified = true;
                notificationLock.notifyAll();
            }
        }

        public void mappingRemoved(Identity identity, Node node) {
            removedIds.add(identity);
            removedNodes.add(node);
            synchronized (notificationLock) {
                notified = true;
                notificationLock.notifyAll();
            }
        }
       
        public void clear() {
            addedIds.clear();
            addedNodes.clear();
            removedIds.clear();
            removedNodes.clear();
            notified = false;
        }

        public boolean isClear() {
            return (addedIds.size() == 0) && (addedNodes.size() == 0) &&
                   (removedIds.size() == 0) && (removedNodes.size() == 0);
        }

        public void waitForNotification(long stop) throws InterruptedException {
            long stopTime = System.currentTimeMillis() + stop;
            synchronized (notificationLock) {
                while (!notified &&
                       System.currentTimeMillis() < stopTime)
                {
                    notificationLock.wait(100);
                }
    assertTrue(notified);
            }
        }
        public void waitForNotification() throws InterruptedException {
            waitForNotification(1000);
        }

        public List<Identity> getAddedIds()   { return addedIds; }
        public List<Node> getAddedNodes()     { return addedNodes; }
        public List<Identity> getRemovedIds() { return removedIds; }
        public List<Node> getRemovedNodes()   { return removedNodes; }

       
        public String toString() {
            return "TestListener: AddedIds size: " + addedIds.size() +
                   " AddedNodes size: " + addedNodes.size() +
                   " removedIds size: " + removedIds.size() +
                   " removedNodes size: " + removedNodes.size();
        }
    }

    /* Check that the listener was notified of id moving from this node,
     * to node "to".
     */
    private void checkIdRemoved(TestListener listener, Identity id, Node to) {
        // Make sure we got a notification
        assertEquals(0, listener.getAddedIds().size());
        assertEquals(0, listener.getAddedNodes().size());

        List<Identity> removedIds = listener.getRemovedIds();
        List<Node> removedNodes = listener.getRemovedNodes();
        assertEquals(1, removedIds.size());
        assertEquals(1, removedNodes.size());
        assertTrue(removedIds.contains(id));
        // no new node
        assertTrue(removedNodes.contains(to));
    }

    /* Check that the listener was notified of id moving to this node,
     * from node "from"
     */
    private void checkIdAdded(TestListener listener, Identity id, Node from) {
        // Make sure we got a notification
        assertEquals(0, listener.getRemovedIds().size());
        assertEquals(0, listener.getRemovedNodes().size());

        List<Identity> addedIds = listener.getAddedIds();
        List<Node> addedNodes = listener.getAddedNodes();
        assertEquals(1, addedIds.size());
        assertEquals(1, addedNodes.size());
        assertTrue(addedIds.contains(id));
        // no new node
        assertTrue(addedNodes.contains(from));
    }

    /* Check that the listeners on each node were correctly notified. */
    private void checkIdMoved(TestListener firstNodeListener, Node firstNode,
                              TestListener secondNodeListener, Node secondNode,
                              Identity id)
    {
        // The id was removed from the first node
        checkIdRemoved(firstNodeListener, id, secondNode);

        // The id was added to the second node
        checkIdAdded(secondNodeListener, id, firstNode);

        // Make sure no other listeners were affected
        for (TestListener listener : nodeListenerMap.values()) {
            if (listener != firstNodeListener &&
                listener != secondNodeListener)
            {
                assertTrue(listener.isClear());
            }
        }
    }

    /** A test identity relocation listener. */
    private class TestRelocationListener implements IdentityRelocationListener {
        private final List<Identity> movingIds = new ArrayList<Identity>();
        private final List<Long> movingNodes = new ArrayList<Long>();

        // The corresponding node mapping listener for this node.
        private final TestListener nodeMapListener;

        // If true, this listener won't call completed right away.
        private final boolean asynch;

        // Set to false if a problem is encountered
        private boolean ok = true;

        // The pending handler, which allows us to control when the
        // complete method is called.
        SimpleCompletionHandler handler;
        // A notificationLock to let us know when the listener has been called.
        private final Object notificationLock = new Object();
        private boolean notified;

        TestRelocationListener(TestListener lis, boolean asynch) {
            nodeMapListener = lis;
            this.asynch = asynch;
        }
        public void prepareToRelocate(Identity id, long newNodeId,
                                      SimpleCompletionHandler handler)
        {
            movingIds.add(id);
            movingNodes.add(newNodeId);

            // Ensure that the nm listener has not been notified yet.
            // This assumes the nm listener was cleared before the move.
            ok = nodeMapListener.isClear();

            if (asynch) {
                this.handler = handler;
            } else {
                handler.completed();
            }
            synchronized (notificationLock) {
                notified = true;
                notificationLock.notifyAll();
            }
        }

        public void clear() {
            movingIds.clear();
            movingNodes.clear();
            handler = null;
            notified = false;
        }

        public boolean isClear() {
            return (movingIds.size() == 0) && (movingNodes.size() == 0) &&
                   (handler == null);
        }

        public void waitForNotification() throws InterruptedException {
            long stopTime = System.currentTimeMillis() + 1000;
            synchronized (notificationLock) {
                while (!notified &&
                       System.currentTimeMillis() < stopTime)
                {
                    notificationLock.wait(100);
                }
            }
        }

        public List<Identity> getIds()  { return movingIds; }
        public List<Long> getNodes()    { return movingNodes; }
        public boolean isOK()           { return ok; }
    }

    /* Add id relocation listeners for each node, putting them in the given
     * map.  If "asynch" is true, construct a listener which won't call
     * the completed method.
     */
    private void addRelocationListeners(boolean asynch,
                                    Map<Long, TestRelocationListener> moveMap)
    {
        long nodeId = serverNode.getNodeId();
        TestRelocationListener idListener =
                new TestRelocationListener(nodeListenerMap.get(nodeId), asynch);
        nodeMappingService.addIdentityRelocationListener(idListener);
        moveMap.put(nodeId, idListener);
        for (SgsTestNode node : additionalNodes) {
            nodeId = node.getNodeId();
            idListener =
                new TestRelocationListener(nodeListenerMap.get(nodeId), asynch);
            node.getNodeMappingService().
                    addIdentityRelocationListener(idListener);
            moveMap.put(nodeId, idListener);
        }
    }
    private void checkRelocationNotification(TestRelocationListener listener,
            Identity id, long toNode)
    {
        // The id is moving from the first node to the second
        assertEquals(1, listener.getIds().size());
        assertTrue(listener.getIds().contains(id));
        assertEquals(1, listener.getNodes().size());
        assertTrue(listener.getNodes().contains(toNode));
        // Make sure the node mapping listener hadn't been notified yet.
        assertTrue(listener.isOK());
    }
}
TOP

Related Classes of com.sun.sgs.test.impl.service.nodemap.TestNodeMappingServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.