Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
index 66366c1..19dc3e3 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
@@ -32,6 +32,8 @@
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.NodeId;
 import org.onlab.onos.mastership.MastershipService;
+import org.onlab.onos.mastership.MastershipTerm;
+import org.onlab.onos.mastership.MastershipTermService;
 import org.onlab.onos.net.AnnotationsUtil;
 import org.onlab.onos.net.DefaultAnnotations;
 import org.onlab.onos.net.DefaultDevice;
@@ -39,6 +41,7 @@
 import org.onlab.onos.net.Device;
 import org.onlab.onos.net.Device.Type;
 import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.MastershipRole;
 import org.onlab.onos.net.Port;
 import org.onlab.onos.net.PortNumber;
 import org.onlab.onos.net.device.DeviceClockService;
@@ -89,6 +92,7 @@
 import static org.onlab.util.Tools.namedThreads;
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static org.onlab.onos.store.device.impl.GossipDeviceStoreMessageSubjects.DEVICE_ADVERTISE;
+import static org.onlab.onos.store.device.impl.GossipDeviceStoreMessageSubjects.DEVICE_REMOVE_REQ;
 
 // TODO: give me a better name
 /**
@@ -160,6 +164,7 @@
                 GossipDeviceStoreMessageSubjects.DEVICE_UPDATE, new InternalDeviceEventListener());
         clusterCommunicator.addSubscriber(
                 GossipDeviceStoreMessageSubjects.DEVICE_OFFLINE, new InternalDeviceOfflineEventListener());
+        clusterCommunicator.addSubscriber(DEVICE_REMOVE_REQ, new InternalRemoveRequestListener());
         clusterCommunicator.addSubscriber(
                 GossipDeviceStoreMessageSubjects.DEVICE_REMOVED, new InternalDeviceRemovedEventListener());
         clusterCommunicator.addSubscriber(
@@ -715,14 +720,48 @@
 
     @Override
     public synchronized DeviceEvent removeDevice(DeviceId deviceId) {
-        final NodeId master = mastershipService.getMasterFor(deviceId);
-        if (!clusterService.getLocalNode().id().equals(master)) {
-            log.info("Removal of device {} requested on non master node", deviceId);
-            // FIXME silently ignoring. Should be forwarding or broadcasting to
-            // master.
-            return null;
+        final NodeId myId = clusterService.getLocalNode().id();
+        NodeId master = mastershipService.getMasterFor(deviceId);
+
+        // if there exist a master, forward
+        // if there is no master, try to become one and process
+
+        boolean relinquishAtEnd = false;
+        if (master == null) {
+            final MastershipRole myRole = mastershipService.getLocalRole(deviceId);
+            if (myRole != MastershipRole.NONE) {
+                relinquishAtEnd = true;
+            }
+            log.info("Temporarlily requesting role for {} to remove", deviceId);
+            mastershipService.requestRoleFor(deviceId);
+            MastershipTermService termService = mastershipService.requestTermService();
+            MastershipTerm term = termService.getMastershipTerm(deviceId);
+            if (myId.equals(term.master())) {
+                master = myId;
+            }
         }
 
+        if (!myId.equals(master)) {
+            log.info("{} has control of {}, forwarding remove request",
+                     master, deviceId);
+
+             ClusterMessage message = new ClusterMessage(
+                     myId,
+                     DEVICE_REMOVE_REQ,
+                     SERIALIZER.encode(deviceId));
+
+             try {
+                 clusterCommunicator.unicast(message, master);
+             } catch (IOException e) {
+                 log.error("Failed to forward {} remove request to {}", deviceId, master, e);
+             }
+
+             // event will be triggered after master processes it.
+             return null;
+        }
+
+        // I have control..
+
         Timestamp timestamp = deviceClockService.getTimestamp(deviceId);
         DeviceEvent event = removeDeviceInternal(deviceId, timestamp);
         if (event != null) {
@@ -735,6 +774,10 @@
                      deviceId);
             }
         }
+        if (relinquishAtEnd) {
+            log.info("Relinquishing temporary role acquired for {}", deviceId);
+            mastershipService.relinquishMastership(deviceId);
+        }
         return event;
     }
 
@@ -1241,6 +1284,16 @@
         }
     }
 
+    private final class InternalRemoveRequestListener
+            implements ClusterMessageHandler {
+        @Override
+        public void handle(ClusterMessage message) {
+            log.debug("Received device remove request from peer: {}", message.sender());
+            DeviceId did = SERIALIZER.decode(message.payload());
+            removeDevice(did);
+        }
+    }
+
     private class InternalDeviceRemovedEventListener implements ClusterMessageHandler {
         @Override
         public void handle(ClusterMessage message) {
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStoreMessageSubjects.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStoreMessageSubjects.java
index 89577a8..4c9e48c 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStoreMessageSubjects.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStoreMessageSubjects.java
@@ -27,6 +27,7 @@
 
     public static final MessageSubject DEVICE_UPDATE = new MessageSubject("peer-device-update");
     public static final MessageSubject DEVICE_OFFLINE = new MessageSubject("peer-device-offline");
+    public static final MessageSubject DEVICE_REMOVE_REQ = new MessageSubject("peer-device-remove-request");
     public static final MessageSubject DEVICE_REMOVED = new MessageSubject("peer-device-removed");
     public static final MessageSubject PORT_UPDATE = new MessageSubject("peer-port-update");
     public static final MessageSubject PORT_STATUS_UPDATE = new MessageSubject("peer-port-status-update");
diff --git a/pom.xml b/pom.xml
index 5c24516..5583f30 100644
--- a/pom.xml
+++ b/pom.xml
@@ -361,8 +361,8 @@
                     <!-- https://jira.codehaus.org/browse/MCOMPILER-205 -->
                     <version>2.5.1</version>
                     <configuration>
-                        <source>1.7</source>
-                        <target>1.7</target>
+                        <source>1.8</source>
+                        <target>1.8</target>
                     </configuration>
                 </plugin>
 
@@ -407,7 +407,7 @@
                 <plugin>
                     <groupId>org.apache.felix</groupId>
                     <artifactId>maven-scr-plugin</artifactId>
-                    <version>1.15.0</version>
+                    <version>1.20.0</version>
                     <executions>
                         <execution>
                             <id>generate-scr-srcdescriptor</id>
diff --git a/tools/package/bin/onos-service b/tools/package/bin/onos-service
index 9250d5b..ae6d970 100755
--- a/tools/package/bin/onos-service
+++ b/tools/package/bin/onos-service
@@ -3,7 +3,7 @@
 # Starts ONOS Apache Karaf container
 # -----------------------------------------------------------------------------
 
-export JAVA_HOME=${JAVA_HOME:-/usr/lib/jvm/java-7-openjdk-amd64/}
+#export JAVA_HOME=${JAVA_HOME:-/usr/lib/jvm/java-7-openjdk-amd64/}
 export JAVA_OPTS="${JAVA_OPTS:--Xms256M -Xmx2048M}"
 
 cd /opt/onos
diff --git a/tools/package/debian/onos.conf b/tools/package/debian/onos.conf
index 1d8f10a..888c02b 100644
--- a/tools/package/debian/onos.conf
+++ b/tools/package/debian/onos.conf
@@ -11,8 +11,8 @@
 respawn
 
 env LANG=en_US.UTF-8
-env JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
-env NEW_JAVA_HOME=/usr/lib/jvm/java-8-oracle/
+#env JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
+#env NEW_JAVA_HOME=/usr/lib/jvm/java-8-oracle/
 
 pre-stop script
     /opt/onos/bin/onos halt 2>/opt/onos/var/stderr.log
diff --git a/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java b/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java
index 39712ba..68e407f 100644
--- a/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java
+++ b/utils/junit/src/test/java/org/onlab/junit/TestUtilsTest.java
@@ -101,9 +101,9 @@
     @Test
     public void testSetGetPrivateField() throws TestUtilsException {
 
-        assertEquals(42, TestUtils.getField(test, "privateField"));
+        assertEquals(42, (int) TestUtils.getField(test, "privateField"));
         TestUtils.setField(test, "privateField", 0xDEAD);
-        assertEquals(0xDEAD, TestUtils.getField(test, "privateField"));
+        assertEquals(0xDEAD, (int) TestUtils.getField(test, "privateField"));
     }
 
     /**
@@ -114,9 +114,9 @@
     @Test
     public void testSetGetProtectedField() throws TestUtilsException {
 
-        assertEquals(2501, TestUtils.getField(test, "protectedField"));
+        assertEquals(2501, (int) TestUtils.getField(test, "protectedField"));
         TestUtils.setField(test, "protectedField", 0xBEEF);
-        assertEquals(0xBEEF, TestUtils.getField(test, "protectedField"));
+        assertEquals(0xBEEF, (int) TestUtils.getField(test, "protectedField"));
     }
 
     /**