Merge remote-tracking branch 'origin/master'
diff --git a/core/api/src/main/java/org/onlab/onos/mastership/MastershipTerm.java b/core/api/src/main/java/org/onlab/onos/mastership/MastershipTerm.java
index 91e3868..e1731ef 100644
--- a/core/api/src/main/java/org/onlab/onos/mastership/MastershipTerm.java
+++ b/core/api/src/main/java/org/onlab/onos/mastership/MastershipTerm.java
@@ -55,13 +55,8 @@
         }
         if (other instanceof MastershipTerm) {
             MastershipTerm that = (MastershipTerm) other;
-            if (!this.master.equals(that.master)) {
-                return false;
-            }
-            if (this.termNumber != that.termNumber) {
-                return false;
-            }
-            return true;
+            return Objects.equals(this.master, that.master) &&
+                    Objects.equals(this.termNumber, that.termNumber);
         }
         return false;
     }
diff --git a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
index d1dab70..af59abd 100644
--- a/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/device/impl/DeviceManager.java
@@ -257,7 +257,8 @@
             MastershipTerm term = mastershipService.requestTermService()
                     .getMastershipTerm(deviceId);
 
-            if (!term.master().equals(clusterService.getLocalNode().id())) {
+            final NodeId myNodeId = clusterService.getLocalNode().id();
+            if (!myNodeId.equals(term.master())) {
                 // lost mastership after requestRole told this instance was MASTER.
                 log.info("lost mastership before getting term info.");
                 return;
@@ -451,6 +452,35 @@
                     return;
                 }
                 applyRole(did, MastershipRole.STANDBY);
+            } else {
+                // Event suggests that this Node has no connection to this Device
+                // confirm.
+                final Device device = getDevice(did);
+                if (!isReachable(device)) {
+                    // not connection to device, as expected
+                    return;
+                }
+                // connection seems to exist
+                log.info("Detected mastership info mismatch, requesting Role");
+                mastershipService.requestRoleFor(did);
+                final MastershipTerm term = termService.getMastershipTerm(did);
+                if (myNodeId.equals(term.master())) {
+                    // became MASTER
+                    // TODO: consider slicing out method for applying MASTER role
+                    deviceClockProviderService.setMastershipTerm(did, term);
+
+                    //flag the device as online. Is there a better way to do this?
+                    DeviceEvent devEvent =
+                            store.createOrUpdateDevice(device.providerId(), did,
+                                                       new DefaultDeviceDescription(
+                                                               did.uri(), device.type(), device.manufacturer(),
+                                                               device.hwVersion(), device.swVersion(),
+                                                               device.serialNumber(), device.chassisId()));
+                    applyRole(did, MastershipRole.MASTER);
+                    post(devEvent);
+                } else {
+                    applyRole(did, MastershipRole.STANDBY);
+                }
             }
         }
 
diff --git a/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
index 1572408..ddd805f 100644
--- a/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/cluster/impl/MastershipManagerTest.java
@@ -139,14 +139,14 @@
     public void termService() {
         MastershipTermService ts = mgr.requestTermService();
 
-        //term = 0 for both
+        //term = 1 for both
         mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
-        assertEquals("inconsistent term: ", 0, ts.getMastershipTerm(DEV_MASTER).termNumber());
+        assertEquals("inconsistent term: ", 1, ts.getMastershipTerm(DEV_MASTER).termNumber());
 
-        //hand devices to NID_LOCAL and back: term = 2
+        //hand devices to NID_LOCAL and back: term = 1 + 2
         mgr.setRole(NID_OTHER, DEV_MASTER, MASTER);
         mgr.setRole(NID_LOCAL, DEV_MASTER, MASTER);
-        assertEquals("inconsistent terms: ", 2, ts.getMastershipTerm(DEV_MASTER).termNumber());
+        assertEquals("inconsistent terms: ", 3, ts.getMastershipTerm(DEV_MASTER).termNumber());
     }
 
     private final class TestClusterService implements ClusterService {
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
index 0e0b240..fc89e3a 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStore.java
@@ -60,8 +60,10 @@
 extends AbstractHazelcastStore<MastershipEvent, MastershipStoreDelegate>
 implements MastershipStore {
 
+    //term number representing that master has never been chosen yet
+    private static final Integer NOTHING = 0;
     //initial term/TTL value
-    private static final Integer INIT = 0;
+    private static final Integer INIT = 1;
 
     //device to node roles
     protected SMap<DeviceId, RoleValue> roleMap;
@@ -256,8 +258,8 @@
             RoleValue rv = getRoleValue(deviceId);
             final Integer term = terms.get(deviceId);
             final NodeId master = rv.get(MASTER);
-            if ((master == null) || (term == null)) {
-                return null;
+            if (term == null) {
+                return MastershipTerm.of(null, NOTHING);
             }
             return MastershipTerm.of(master, term);
         } finally {
diff --git a/core/store/dist/src/test/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStoreTest.java b/core/store/dist/src/test/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStoreTest.java
index d03ffe6..f598374 100644
--- a/core/store/dist/src/test/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStoreTest.java
+++ b/core/store/dist/src/test/java/org/onlab/onos/store/mastership/impl/DistributedMastershipStoreTest.java
@@ -149,7 +149,7 @@
         assertEquals("wrong role for NONE:", MASTER, dms.requestRole(DID1));
         assertTrue("wrong state for store:", !dms.terms.isEmpty());
         assertEquals("wrong term",
-                MastershipTerm.of(N1, 0), dms.getTermFor(DID1));
+                MastershipTerm.of(N1, 1), dms.getTermFor(DID1));
 
         //CN2 now local. DID2 has N1 as MASTER so N2 is STANDBY
         testStore.setCurrent(CN2);
@@ -172,15 +172,15 @@
         //switch over to N2
         assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID1).type());
         System.out.println(dms.getTermFor(DID1).master() + ":" + dms.getTermFor(DID1).termNumber());
-        assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID1));
+        assertEquals("wrong term", MastershipTerm.of(N2, 2), dms.getTermFor(DID1));
 
         //orphan switch - should be rare case
         assertEquals("wrong event:", Type.MASTER_CHANGED, dms.setMaster(N2, DID2).type());
-        assertEquals("wrong term", MastershipTerm.of(N2, 0), dms.getTermFor(DID2));
+        assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
         //disconnect and reconnect - sign of failing re-election or single-instance channel
         dms.roleMap.clear();
         dms.setMaster(N2, DID2);
-        assertEquals("wrong term", MastershipTerm.of(N2, 1), dms.getTermFor(DID2));
+        assertEquals("wrong term", MastershipTerm.of(N2, 2), dms.getTermFor(DID2));
     }
 
     @Test
diff --git a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java
index 2d665cd..768fb85 100644
--- a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java
+++ b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/MastershipTermSerializer.java
@@ -38,15 +38,14 @@
 
     @Override
     public MastershipTerm read(Kryo kryo, Input input, Class<MastershipTerm> type) {
-        final NodeId node = new NodeId(input.readString());
+        final NodeId node = (NodeId) kryo.readClassAndObject(input);
         final int term = input.readInt();
         return MastershipTerm.of(node, term);
     }
 
     @Override
     public void write(Kryo kryo, Output output, MastershipTerm object) {
-        output.writeString(object.master().toString());
+        kryo.writeClassAndObject(output, object.master());
         output.writeInt(object.termNumber());
     }
-
 }
diff --git a/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java b/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
index a4f098a..654ab11 100644
--- a/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
+++ b/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
@@ -201,6 +201,7 @@
     @Test
     public void testMastershipTerm() {
         testSerialized(MastershipTerm.of(new NodeId("foo"), 2));
+        testSerialized(MastershipTerm.of(null, 0));
     }
 
     @Test
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
index 33da987..0f36393 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleMastershipStore.java
@@ -62,6 +62,9 @@
 
     public static final IpAddress LOCALHOST = IpAddress.valueOf("127.0.0.1");
 
+    private static final int NOTHING = 0;
+    private static final int INIT = 1;
+
     private ControllerNode instance =
             new DefaultControllerNode(new NodeId("local"), LOCALHOST);
 
@@ -97,7 +100,7 @@
                     break;
                 case NONE:
                     masterMap.put(deviceId, nodeId);
-                    termMap.put(deviceId, new AtomicInteger());
+                    termMap.put(deviceId, new AtomicInteger(INIT));
                     backups.add(nodeId);
                     break;
                 default:
@@ -149,7 +152,7 @@
                     NodeId rel = reelect(node);
                     if (rel == null) {
                         masterMap.put(deviceId, node);
-                        termMap.put(deviceId, new AtomicInteger());
+                        termMap.put(deviceId, new AtomicInteger(INIT));
                         role = MastershipRole.MASTER;
                     }
                     backups.add(node);
@@ -159,7 +162,7 @@
                 //first to get to it, say we are master
                 synchronized (this) {
                     masterMap.put(deviceId, node);
-                    termMap.put(deviceId, new AtomicInteger());
+                    termMap.put(deviceId, new AtomicInteger(INIT));
                     backups.add(node);
                     role = MastershipRole.MASTER;
                 }
@@ -194,9 +197,8 @@
 
     @Override
     public MastershipTerm getTermFor(DeviceId deviceId) {
-        if ((masterMap.get(deviceId) == null) ||
-                (termMap.get(deviceId) == null)) {
-            return null;
+        if ((termMap.get(deviceId) == null)) {
+            return MastershipTerm.of(masterMap.get(deviceId), NOTHING);
         }
         return MastershipTerm.of(
                 masterMap.get(deviceId), termMap.get(deviceId).get());
@@ -220,7 +222,7 @@
                 case STANDBY:
                 case NONE:
                     if (!termMap.containsKey(deviceId)) {
-                        termMap.put(deviceId, new AtomicInteger());
+                        termMap.put(deviceId, new AtomicInteger(INIT));
                     }
                     backups.add(nodeId);
                     break;
diff --git a/core/store/trivial/src/test/java/org/onlab/onos/store/trivial/impl/SimpleLinkResourceStoreTest.java b/core/store/trivial/src/test/java/org/onlab/onos/store/trivial/impl/SimpleLinkResourceStoreTest.java
new file mode 100644
index 0000000..1daad2f
--- /dev/null
+++ b/core/store/trivial/src/test/java/org/onlab/onos/store/trivial/impl/SimpleLinkResourceStoreTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2014 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onlab.onos.store.trivial.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.Link.Type.DIRECT;
+import static org.onlab.onos.net.PortNumber.portNumber;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DefaultLink;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.resource.Bandwidth;
+import org.onlab.onos.net.resource.BandwidthResourceAllocation;
+import org.onlab.onos.net.resource.LambdaResourceAllocation;
+import org.onlab.onos.net.resource.LinkResourceAllocations;
+import org.onlab.onos.net.resource.LinkResourceStore;
+import org.onlab.onos.net.resource.ResourceAllocation;
+import org.onlab.onos.net.resource.ResourceType;
+
+/**
+ * Test of the simple LinkResourceStore implementation.
+ */
+public class SimpleLinkResourceStoreTest {
+
+    private LinkResourceStore store;
+    private SimpleLinkResourceStore simpleStore;
+    private Link link1;
+    private Link link2;
+    private Link link3;
+
+    /**
+     * Returns {@link Link} object.
+     *
+     * @param dev1 source device
+     * @param port1 source port
+     * @param dev2 destination device
+     * @param port2 destination port
+     * @return created {@link Link} object
+     */
+    private Link newLink(String dev1, int port1, String dev2, int port2) {
+        return new DefaultLink(
+                new ProviderId("of", "foo"),
+                new ConnectPoint(deviceId(dev1), portNumber(port1)),
+                new ConnectPoint(deviceId(dev2), portNumber(port2)),
+                DIRECT);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        simpleStore = new SimpleLinkResourceStore();
+        simpleStore.activate();
+        store = simpleStore;
+
+        link1 = newLink("of:1", 1, "of:2", 2);
+        link2 = newLink("of:2", 1, "of:3", 2);
+        link3 = newLink("of:3", 1, "of:4", 2);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        simpleStore.deactivate();
+    }
+
+    /**
+     * Tests constructor and activate method.
+     */
+    @Test
+    public void testConstructorAndActivate() {
+        final Iterable<LinkResourceAllocations> allAllocations = store.getAllocations();
+        assertNotNull(allAllocations);
+        assertFalse(allAllocations.iterator().hasNext());
+
+        final Iterable<LinkResourceAllocations> linkAllocations =
+                store.getAllocations(link1);
+        assertNotNull(linkAllocations);
+        assertFalse(linkAllocations.iterator().hasNext());
+
+        final Set<ResourceAllocation> res = store.getFreeResources(link2);
+        assertNotNull(res);
+    }
+
+    /**
+     * Picks up and returns one of bandwidth allocations from a given set.
+     *
+     * @param resources the set of {@link ResourceAllocation}s
+     * @return {@link BandwidthResourceAllocation} object if found, null
+     *         otherwise
+     */
+    private BandwidthResourceAllocation getBandwidthObj(Set<ResourceAllocation> resources) {
+        for (ResourceAllocation res : resources) {
+            if (res.type() == ResourceType.BANDWIDTH) {
+                return ((BandwidthResourceAllocation) res);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns all lambda allocations from a given set.
+     *
+     * @param resources the set of {@link ResourceAllocation}s
+     * @return a set of {@link LambdaResourceAllocation} objects
+     */
+    private Set<LambdaResourceAllocation> getLambdaObjs(Set<ResourceAllocation> resources) {
+        Set<LambdaResourceAllocation> lambdaResources = new HashSet<>();
+        for (ResourceAllocation res : resources) {
+            if (res.type() == ResourceType.LAMBDA) {
+                lambdaResources.add((LambdaResourceAllocation) res);
+            }
+        }
+        return lambdaResources;
+    }
+
+    /**
+     * Tests initial free bandwidth for a link.
+     */
+    @Test
+    public void testInitialBandwidth() {
+        final Set<ResourceAllocation> freeRes = store.getFreeResources(link1);
+        assertNotNull(freeRes);
+
+        final BandwidthResourceAllocation alloc = getBandwidthObj(freeRes);
+        assertNotNull(alloc);
+
+        assertEquals(Bandwidth.valueOf(1000000.0), alloc.bandwidth());
+    }
+
+    /**
+     * Tests initial free lambda for a link.
+     */
+    @Test
+    public void testInitialLambdas() {
+        final Set<ResourceAllocation> freeRes = store.getFreeResources(link3);
+        assertNotNull(freeRes);
+
+        final Set<LambdaResourceAllocation> res = getLambdaObjs(freeRes);
+        assertNotNull(res);
+        assertEquals(100, res.size());
+    }
+}
diff --git a/tools/dev/onos.cshrc b/tools/dev/onos.cshrc
index 8dba4b2..feff165 100644
--- a/tools/dev/onos.cshrc
+++ b/tools/dev/onos.cshrc
@@ -29,7 +29,7 @@
 endif
 setenv KARAF_LOG $KARAF/data/log/karaf.log
 
-alias onos-setup-cell ' ( $ONOS_ROOT/tools/test/bin/onos-show-cell \!^ ) && setenv ONOS_CELL \!^'
+alias onos-setup-cell ' ( env ONOS_CELL=\!^ $ONOS_ROOT/tools/test/bin/onos-show-cell \!^ ) && setenv ONOS_CELL \!^'
 
 set path=( $path $ONOS_ROOT/tools/dev/bin $ONOS_ROOT/tools/test/bin )
 set path=( $path $ONOS_ROOT/tools/build )
diff --git a/tools/test/bin/onos-show-cell b/tools/test/bin/onos-show-cell
index 5aee338..eedea9e 100755
--- a/tools/test/bin/onos-show-cell
+++ b/tools/test/bin/onos-show-cell
@@ -40,7 +40,6 @@
 # Load the cell setup
 . $ONOS_ROOT/tools/test/cells/${cell}
 
-echo "ONOS_CELL=${ONOS_CELL}"
 echo "ONOS_NIC=${ONOS_NIC}"
 for n in {0..9}; do
     ocn="OC${n}"