Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next

Conflicts:
	core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java

Change-Id: I23a7b1bff399c95499a39f7a00563650f58b7210
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
index 7a6e6bb..c609b95 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/HostToInterfaceAdaptor.java
@@ -4,19 +4,17 @@
 
 import java.util.Set;
 
-import org.apache.commons.lang.NotImplementedException;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.host.PortAddresses;
 import org.onlab.onos.sdnip.config.Interface;
 import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 
 import com.google.common.collect.Sets;
 
-
-
 /**
- * Provides IntefaceService using PortAddresses data from the HostService.
+ * Provides InterfaceService using PortAddresses data from the HostService.
  */
 public class HostToInterfaceAdaptor implements InterfaceService {
 
@@ -52,8 +50,17 @@
 
     @Override
     public Interface getMatchingInterface(IpAddress ipAddress) {
-        // TODO implement
-        throw new NotImplementedException("getMatchingInteface is not yet implemented");
+        checkNotNull(ipAddress);
+
+        for (PortAddresses portAddresses : hostService.getAddressBindings()) {
+            for (IpPrefix p : portAddresses.ips()) {
+                if (p.contains(ipAddress)) {
+                    return new Interface(portAddresses);
+                }
+            }
+        }
+
+        return null;
     }
 
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
index 54aa9e5..d66ec9c 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/SdnIp.java
@@ -64,6 +64,7 @@
         bgpSessionManager.startUp(2000); // TODO
 
         // TODO need to disable link discovery on external ports
+
     }
 
     @Deactivate
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java
new file mode 100644
index 0000000..5a3dc51
--- /dev/null
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/HostToInterfaceAdaptorTest.java
@@ -0,0 +1,177 @@
+package org.onlab.onos.sdnip;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.reset;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.DeviceId;
+import org.onlab.onos.net.PortNumber;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.host.PortAddresses;
+import org.onlab.onos.sdnip.config.Interface;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+/**
+ * Unit tests for the HostToInterfaceAdaptor class.
+ */
+public class HostToInterfaceAdaptorTest {
+
+    private HostService hostService;
+    private HostToInterfaceAdaptor adaptor;
+
+    private Set<PortAddresses> portAddresses;
+    private Map<ConnectPoint, Interface> interfaces;
+
+    private static final ConnectPoint CP1 = new ConnectPoint(
+            DeviceId.deviceId("of:1"), PortNumber.portNumber(1));
+    private static final ConnectPoint CP2 = new ConnectPoint(
+            DeviceId.deviceId("of:1"), PortNumber.portNumber(2));
+    private static final ConnectPoint CP3 = new ConnectPoint(
+            DeviceId.deviceId("of:2"), PortNumber.portNumber(1));
+
+    private static final ConnectPoint NON_EXISTENT_CP = new ConnectPoint(
+            DeviceId.deviceId("doesnotexist"), PortNumber.portNumber(1));
+
+    private static final PortAddresses DEFAULT_PA = new PortAddresses(
+            NON_EXISTENT_CP, null, null);
+
+
+    @Before
+    public void setUp() throws Exception {
+        hostService = createMock(HostService.class);
+
+        portAddresses = Sets.newHashSet();
+        interfaces = Maps.newHashMap();
+
+        createPortAddressesAndInterface(CP1,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.1.1/24")),
+                MacAddress.valueOf("00:00:00:00:00:01"));
+
+        // Two addresses in the same subnet
+        createPortAddressesAndInterface(CP2,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.2.1/24"),
+                        IpPrefix.valueOf("192.168.2.2/24")),
+                MacAddress.valueOf("00:00:00:00:00:02"));
+
+        // Two addresses in different subnets
+        createPortAddressesAndInterface(CP3,
+                Sets.newHashSet(IpPrefix.valueOf("192.168.3.1/24"),
+                        IpPrefix.valueOf("192.168.4.1/24")),
+                MacAddress.valueOf("00:00:00:00:00:03"));
+
+        expect(hostService.getAddressBindings()).andReturn(portAddresses).anyTimes();
+
+        replay(hostService);
+
+        adaptor = new HostToInterfaceAdaptor(hostService);
+    }
+
+    /**
+     * Creates both a PortAddresses and an Interface for the given inputs and
+     * places them in the correct global data stores.
+     *
+     * @param cp the connect point
+     * @param ips the set of IP addresses
+     * @param mac the MAC address
+     */
+    private void createPortAddressesAndInterface(
+            ConnectPoint cp, Set<IpPrefix> ips, MacAddress mac) {
+        PortAddresses pa = new PortAddresses(cp, ips, mac);
+        portAddresses.add(pa);
+        expect(hostService.getAddressBindingsForPort(cp)).andReturn(pa).anyTimes();
+
+        Interface intf = new Interface(cp, ips, mac);
+        interfaces.put(cp, intf);
+    }
+
+    /**
+     * Tests {@link HostToInterfaceAdaptor#getInterfaces()}.
+     * Verifies that the set of interfaces returned matches what is expected
+     * based on the input PortAddresses data.
+     */
+    @Test
+    public void testGetInterfaces() {
+        Set<Interface> adaptorIntfs = adaptor.getInterfaces();
+
+        assertEquals(3, adaptorIntfs.size());
+        assertTrue(adaptorIntfs.contains(this.interfaces.get(CP1)));
+        assertTrue(adaptorIntfs.contains(this.interfaces.get(CP2)));
+        assertTrue(adaptorIntfs.contains(this.interfaces.get(CP3)));
+    }
+
+    /**
+     * Tests {@link HostToInterfaceAdaptor#getInterface(ConnectPoint)}.
+     * Verifies that the correct interface is returned for a given connect
+     * point.
+     */
+    @Test
+    public void testGetInterface() {
+        assertEquals(this.interfaces.get(CP1), adaptor.getInterface(CP1));
+        assertEquals(this.interfaces.get(CP2), adaptor.getInterface(CP2));
+        assertEquals(this.interfaces.get(CP3), adaptor.getInterface(CP3));
+
+        // Try and get an interface for a connect point with no addresses
+        reset(hostService);
+        expect(hostService.getAddressBindingsForPort(NON_EXISTENT_CP))
+                .andReturn(DEFAULT_PA).anyTimes();
+        replay(hostService);
+
+        assertNull(adaptor.getInterface(NON_EXISTENT_CP));
+    }
+
+    /**
+     * Tests {@link HostToInterfaceAdaptor#getInterface(ConnectPoint)} in the
+     * case that the input connect point is null.
+     * Verifies that a NullPointerException is thrown.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testGetInterfaceNull() {
+        adaptor.getInterface(null);
+    }
+
+    /**
+     * Tests {@link HostToInterfaceAdaptor#getMatchingInterface(IpAddress)}.
+     * Verifies that the correct interface is returned based on the given IP
+     * address.
+     */
+    @Test
+    public void testGetMatchingInterface() {
+        assertEquals(this.interfaces.get(CP1),
+                adaptor.getMatchingInterface(IpAddress.valueOf("192.168.1.100")));
+        assertEquals(this.interfaces.get(CP2),
+                adaptor.getMatchingInterface(IpAddress.valueOf("192.168.2.100")));
+        assertEquals(this.interfaces.get(CP3),
+                adaptor.getMatchingInterface(IpAddress.valueOf("192.168.3.100")));
+        assertEquals(this.interfaces.get(CP3),
+                adaptor.getMatchingInterface(IpAddress.valueOf("192.168.4.100")));
+
+        // Try and match an address we don't have subnet configured for
+        assertNull(adaptor.getMatchingInterface(IpAddress.valueOf("1.1.1.1")));
+    }
+
+    /**
+     * Tests {@link HostToInterfaceAdaptor#getMatchingInterface(IpAddress)} in the
+     * case that the input IP address is null.
+     * Verifies that a NullPointerException is thrown.
+     */
+    @Test(expected = NullPointerException.class)
+    public void testGetMatchingInterfaceNull() {
+        adaptor.getMatchingInterface(null);
+    }
+
+}
diff --git a/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java b/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java
index 628754a..68b3244 100644
--- a/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java
@@ -18,10 +18,13 @@
  */
 package org.onlab.onos.cli;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.karaf.shell.commands.Option;
 import org.apache.karaf.shell.console.OsgiCommandSupport;
 import org.onlab.onos.ApplicationId;
 import org.onlab.onos.CoreService;
+import org.onlab.onos.net.Annotations;
 import org.onlab.osgi.DefaultServiceDirectory;
 import org.onlab.osgi.ServiceNotFoundException;
 
@@ -76,6 +79,34 @@
     }
 
     /**
+     * Produces a string image of the specified key/value annotations.
+     *
+     * @param annotations key/value annotations
+     * @return string image with ", k1=v1, k2=v2, ..." pairs
+     */
+    public static String annotations(Annotations annotations) {
+        StringBuilder sb = new StringBuilder();
+        for (String key : annotations.keys()) {
+            sb.append(", ").append(key).append('=').append(annotations.value(key));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Produces a JSON object from the specified key/value annotations.
+     *
+     * @param annotations key/value annotations
+     * @return JSON object
+     */
+    public static ObjectNode annotations(ObjectMapper mapper, Annotations annotations) {
+        ObjectNode result = mapper.createObjectNode();
+        for (String key : annotations.keys()) {
+            result.put(key, annotations.value(key));
+        }
+        return result;
+    }
+
+    /**
      * Executes this command.
      */
     protected abstract void execute();
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/DevicePortsListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/DevicePortsListCommand.java
index f2c280e..3be8e5c 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/DevicePortsListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/DevicePortsListCommand.java
@@ -43,7 +43,7 @@
          description = "Lists all ports or all ports of a device")
 public class DevicePortsListCommand extends DevicesListCommand {
 
-    private static final String FMT = "  port=%s, state=%s";
+    private static final String FMT = "  port=%s, state=%s%s";
 
     @Option(name = "-e", aliases = "--enabled", description = "Show only enabled ports",
             required = false, multiValued = false)
@@ -112,7 +112,8 @@
             if (isIncluded(port)) {
                 ports.add(mapper.createObjectNode()
                                   .put("port", port.number().toString())
-                                  .put("isEnabled", port.isEnabled()));
+                                  .put("isEnabled", port.isEnabled())
+                                  .set("annotations", annotations(mapper, port.annotations())));
             }
         }
         return result.put("device", device.id().toString()).set("ports", ports);
@@ -131,7 +132,8 @@
         Collections.sort(ports, Comparators.PORT_COMPARATOR);
         for (Port port : ports) {
             if (isIncluded(port)) {
-                print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled");
+                print(FMT, port.number(), port.isEnabled() ? "enabled" : "disabled",
+                      annotations(port.annotations()));
             }
         }
     }
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/DevicesListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/DevicesListCommand.java
index 095e2c0..543954e 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/DevicesListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/DevicesListCommand.java
@@ -41,7 +41,7 @@
 public class DevicesListCommand extends AbstractShellCommand {
 
     private static final String FMT =
-            "id=%s, available=%s, role=%s, type=%s, mfr=%s, hw=%s, sw=%s, serial=%s";
+            "id=%s, available=%s, role=%s, type=%s, mfr=%s, hw=%s, sw=%s, serial=%s%s";
 
     @Override
     protected void execute() {
@@ -89,7 +89,8 @@
                     .put("mfr", device.manufacturer())
                     .put("hw", device.hwVersion())
                     .put("sw", device.swVersion())
-                    .put("serial", device.serialNumber());
+                    .put("serial", device.serialNumber())
+                    .set("annotations", annotations(mapper, device.annotations()));
         }
         return result;
     }
@@ -117,7 +118,7 @@
             print(FMT, device.id(), service.isAvailable(device.id()),
                   service.getRole(device.id()), device.type(),
                   device.manufacturer(), device.hwVersion(), device.swVersion(),
-                  device.serialNumber());
+                  device.serialNumber(), annotations(device.annotations()));
         }
     }
 
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/HostsListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/HostsListCommand.java
index 2291f4e..0265116 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/HostsListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/HostsListCommand.java
@@ -42,7 +42,7 @@
 public class HostsListCommand extends AbstractShellCommand {
 
     private static final String FMT =
-            "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s";
+            "id=%s, mac=%s, location=%s/%s, vlan=%s, ip(s)=%s%s";
 
     @Override
     protected void execute() {
@@ -80,6 +80,7 @@
                 .put("vlan", host.vlan().toString());
         result.set("location", loc);
         result.set("ips", ips);
+        result.set("annotations", annotations(mapper, host.annotations()));
         return result;
     }
 
@@ -105,7 +106,8 @@
             print(FMT, host.id(), host.mac(),
                   host.location().deviceId(),
                   host.location().port(),
-                  host.vlan(), host.ipAddresses());
+                  host.vlan(), host.ipAddresses(),
+                  annotations(host.annotations()));
         }
     }
 }
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/LinksListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/LinksListCommand.java
index e6867f6..7889dcf 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/LinksListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/LinksListCommand.java
@@ -38,7 +38,7 @@
          description = "Lists all infrastructure links")
 public class LinksListCommand extends AbstractShellCommand {
 
-    private static final String FMT = "src=%s/%s, dst=%s/%s, type=%s";
+    private static final String FMT = "src=%s/%s, dst=%s/%s, type=%s%s";
     private static final String COMPACT = "%s/%s-%s/%s";
 
     @Argument(index = 0, name = "uri", description = "Device ID",
@@ -85,6 +85,7 @@
         ObjectNode result = mapper.createObjectNode();
         result.set("src", json(mapper, link.src()));
         result.set("dst", json(mapper, link.dst()));
+        result.set("annotations", annotations(mapper, link.annotations()));
         return result;
     }
 
@@ -109,7 +110,8 @@
      */
     public static String linkString(Link link) {
         return String.format(FMT, link.src().deviceId(), link.src().port(),
-                             link.dst().deviceId(), link.dst().port(), link.type());
+                             link.dst().deviceId(), link.dst().port(), link.type(),
+                             annotations(link.annotations()));
     }
 
     /**
diff --git a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
index 9934b8d..ec73ce5 100644
--- a/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
+++ b/core/api/src/main/java/org/onlab/onos/net/device/DeviceProvider.java
@@ -13,7 +13,7 @@
 
     /**
      * Triggers an asynchronous probe of the specified device, intended to
-     * determine whether the host is present or not. An indirect result of this
+     * determine whether the device is present or not. An indirect result of this
      * should be invocation of
      * {@link org.onlab.onos.net.device.DeviceProviderService#deviceConnected} )} or
      * {@link org.onlab.onos.net.device.DeviceProviderService#deviceDisconnected}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java
similarity index 74%
rename from core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java
rename to core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java
index 72a9847..38f0211 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperation.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperation.java
@@ -1,5 +1,22 @@
-package org.onlab.onos.net.intent;
-//TODO is this the right package?
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationEntry.java
similarity index 67%
rename from core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java
rename to core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationEntry.java
index 4e57d33..2ea7053 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationEntry.java
@@ -1,5 +1,22 @@
-package org.onlab.onos.net.intent;
-//TODO is this the right package?
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.Objects;
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationResult.java b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationResult.java
index 43fd694..6352b53 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationResult.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationResult.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.List;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationTarget.java b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationTarget.java
new file mode 100644
index 0000000..e73e3a8
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/BatchOperationTarget.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
+
+/**
+ * An interface of the class which is assigned to BatchOperation.
+ */
+public interface BatchOperationTarget {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java
index e9889cd..841e948 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/CompletedBatchOperation.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.List;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
index cf448cb..59aed23 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowEntry.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
index a6593a8..53a94bb 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultFlowRule.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
index f175bd3..abb29a6 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficSelector.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.HashMap;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
index 5e64c64..b4d8c3e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/DefaultTrafficTreatment.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.LinkedList;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowEntry.java
index cdccaa9..1e6ce52 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowEntry.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
index 52eac0a..142e352 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowId.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import com.google.common.base.Objects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
index 3ac277d..718edfe 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRule.java
@@ -1,7 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.net.DeviceId;
-import org.onlab.onos.net.intent.BatchOperationTarget;
 
 /**
  * Represents a generalized match &amp; action pair to be applied to
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchEntry.java
index d5a1472..ee85ea8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchEntry.java
@@ -1,7 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.net.flow.FlowRuleBatchEntry.FlowRuleOperation;
-import org.onlab.onos.net.intent.BatchOperationEntry;
 
 
 public class FlowRuleBatchEntry
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchOperation.java
index 74ef165..f078fb9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchOperation.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleBatchOperation.java
@@ -1,9 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.Collection;
 
-import org.onlab.onos.net.intent.BatchOperation;
-
 public class FlowRuleBatchOperation
     extends BatchOperation<FlowRuleBatchEntry> {
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
index 97efa5a..e511be6 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleEvent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.event.AbstractEvent;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleListener.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleListener.java
index 114732b..eddaf05 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleListener.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleListener.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.event.EventListener;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
index 3592e39..0b2c3d8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProvider.java
@@ -1,9 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.concurrent.Future;
 
 import org.onlab.onos.ApplicationId;
-import org.onlab.onos.net.intent.BatchOperation;
 import org.onlab.onos.net.provider.Provider;
 
 /**
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderRegistry.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderRegistry.java
index 099d9f4..25b00c4 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderRegistry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderRegistry.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.net.provider.ProviderRegistry;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
index 8164579..bacff0d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleProviderService.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.net.DeviceId;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
index 6d04810..0b6f6c7 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleService.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.concurrent.Future;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
index abb9a10..63b7f77 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStore.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.ApplicationId;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
index 119712b..4e5ebf6 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/FlowRuleStoreDelegate.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.store.StoreDelegate;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/StoredFlowEntry.java b/core/api/src/main/java/org/onlab/onos/net/flow/StoredFlowEntry.java
index e68ed68..9ba53e9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/StoredFlowEntry.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/StoredFlowEntry.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/TrafficSelector.java b/core/api/src/main/java/org/onlab/onos/net/flow/TrafficSelector.java
index 41bceb8..b4d566c 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/TrafficSelector.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/TrafficSelector.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.Set;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/TrafficTreatment.java
index fe21328..a576138 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/TrafficTreatment.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import java.util.List;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/Treatment.java b/core/api/src/main/java/org/onlab/onos/net/flow/Treatment.java
index 8318b66..877da65 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/Treatment.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/Treatment.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow;
 
 import org.onlab.onos.net.PortNumber;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
index ebd672c..fb5fb97 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criteria.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.criteria;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criterion.java b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criterion.java
index 567e100..5337852 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criterion.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/Criterion.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.criteria;
 
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/package-info.java b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/package-info.java
index 82eb210..fabf82e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/criteria/package-info.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/criteria/package-info.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
 /**
  * Traffic selection criteria model.
  */
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
index f05d238..084ffe4 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instruction.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.instructions;
 
 /**
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
index b2ebdee..988c52f 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/Instructions.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.instructions;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
index 2152532..35acd16 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L2ModificationInstruction.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.instructions;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
index 7ec8c84..8aff5df 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/L3ModificationInstruction.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.flow.instructions;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/package-info.java b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/package-info.java
index 01b68ad..067cd01 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/instructions/package-info.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/instructions/package-info.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
 /**
  * Traffic treatment model.
  */
diff --git a/core/api/src/main/java/org/onlab/onos/net/flow/package-info.java b/core/api/src/main/java/org/onlab/onos/net/flow/package-info.java
index 76bee78..8fd6008 100644
--- a/core/api/src/main/java/org/onlab/onos/net/flow/package-info.java
+++ b/core/api/src/main/java/org/onlab/onos/net/flow/package-info.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
 /**
  * Flow rule model &amp; related services API definitions.
  */
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java b/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java
deleted file mode 100644
index c678f31..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/BatchOperationTarget.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.onlab.onos.net.intent;
-//TODO is this the right package?
-
-/**
- * An interface of the class which is assigned to BatchOperation.
- */
-public interface BatchOperationTarget {
-
-}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java
index 8d634a4..710ae4e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/ConnectivityIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.collect.ImmutableSet;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
index 2d42f58..795f681 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/HostToHostIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java b/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java
index 4c11f57..b5fefb2 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/Intent.java
@@ -1,7 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.NetworkResource;
+import org.onlab.onos.net.flow.BatchOperationTarget;
 
 import java.util.Collection;
 import java.util.Objects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java
deleted file mode 100644
index b450d71..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentBatchOperation.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.onlab.onos.net.intent;
-
-/**
- * A list of intent operations.
- */
-public class IntentBatchOperation extends
-        BatchOperation<BatchOperationEntry<IntentBatchOperation.Operator, ?>> {
-    /**
-     * The intent operators.
-     */
-    public enum Operator {
-        ADD,
-        REMOVE,
-    }
-
-    /**
-     * Adds an add-intent operation.
-     *
-     * @param intent the intent to be added
-     * @return the IntentBatchOperation object if succeeded, null otherwise
-     */
-    public IntentBatchOperation addAddIntentOperation(Intent intent) {
-        return (null == super.addOperation(
-                new BatchOperationEntry<Operator, Intent>(Operator.ADD, intent)))
-                ? null : this;
-    }
-
-    /**
-     * Adds a remove-intent operation.
-     *
-     * @param id the ID of intent to be removed
-     * @return the IntentBatchOperation object if succeeded, null otherwise
-     */
-    public IntentBatchOperation addRemoveIntentOperation(IntentId id) {
-        return (null == super.addOperation(
-                new BatchOperationEntry<Operator, IntentId>(Operator.REMOVE, id)))
-                ? null : this;
-    }
-}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java
index dbc3cc4..c54b601 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentCompiler.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import java.util.List;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
index 742a590..22a24f9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentEvent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import org.onlab.onos.event.AbstractEvent;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java
index fff55be..55ca32e 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentException.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 /**
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java
index 50e803c..31db2ec 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentExtensionService.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import java.util.Map;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java
index 08ab7fa..8cfe6fd 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentId.java
@@ -1,5 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
+import org.onlab.onos.net.flow.BatchOperationTarget;
+
 /**
  * Intent identifier suitable as an external key.
  * <p/>
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java
index c403846..22669e5 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentInstaller.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import java.util.List;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java
index c00c1f6..aa1a4a0 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentListener.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import org.onlab.onos.event.EventListener;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java
new file mode 100644
index 0000000..4135ed8
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperation.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
+
+/**
+ * Abstraction of an intent-related operation, e.g. add, remove, replace.
+ */
+public class IntentOperation {
+
+    private final Type type;
+    private final IntentId intentId;
+    private final Intent intent;
+
+    /**
+     * Operation type.
+     */
+    enum Type {
+        /**
+         * Indicates that an intent should be added.
+         */
+        SUBMIT,
+
+        /**
+         * Indicates that an intent should be removed.
+         */
+        WITHDRAW,
+
+        /**
+         * Indicates that an intent should be replaced with another.
+         */
+        REPLACE
+    }
+
+    /**
+     * Creates an intent operation.
+     *
+     * @param type operation type
+     * @param intentId identifier of the intent subject to the operation
+     * @param intent intent subject
+     */
+    IntentOperation(Type type, IntentId intentId, Intent intent) {
+        this.type = type;
+        this.intentId = intentId;
+        this.intent = intent;
+    }
+
+    /**
+     * Returns the type of the operation.
+     *
+     * @return operation type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the identifier of the intent to which this operation applies.
+     *
+     * @return intent identifier
+     */
+    public IntentId intentId() {
+        return intentId;
+    }
+
+    /**
+     * Returns the intent to which this operation applied. For remove,
+     * this can be null.
+     *
+     * @return intent that is the subject of the operation; null for remove
+     */
+    public Intent intent() {
+        return intent;
+    }
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java
index 470d98b..32f0414 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentOperations.java
@@ -1,10 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.onlab.onos.net.intent.IntentOperation.Type.REPLACE;
+import static org.onlab.onos.net.intent.IntentOperation.Type.SUBMIT;
+import static org.onlab.onos.net.intent.IntentOperation.Type.WITHDRAW;
+
 /**
- * Abstraction of a batch of intent submit/withdraw operations.
+ * Batch of intent submit/withdraw/replace operations.
  */
-public interface IntentOperations {
+public final class IntentOperations {
 
-    // TODO: elaborate once the revised BatchOperation scheme is in place
+    private final List<IntentOperation> operations;
 
+    /**
+     * Creates a batch of intent operations using the supplied list.
+     *
+     * @param operations list of intent operations
+     */
+    private IntentOperations(List<IntentOperation> operations) {
+        this.operations = operations;
+    }
+
+    /**
+     * List of operations that need to be executed as a unit.
+     *
+     * @return list of intent operations
+     */
+    public List<IntentOperation> operations() {
+        return operations;
+    }
+
+    /**
+     * Returns a builder for intent operation batches.
+     *
+     * @return intent operations builder
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for batches of intent operations.
+     */
+    public static final class Builder {
+
+        private final ImmutableList.Builder<IntentOperation> builder = ImmutableList.builder();
+
+        // Public construction is forbidden.
+        private Builder() {
+        }
+
+        /**
+         * Adds an intent submit operation.
+         *
+         * @param intent intent to be submitted
+         * @return self
+         */
+        public Builder addSubmitOperation(Intent intent) {
+            checkNotNull(intent, "Intent cannot be null");
+            builder.add(new IntentOperation(SUBMIT, intent.id(), intent));
+            return this;
+        }
+
+        /**
+         * Adds an intent submit operation.
+         *
+         * @param oldIntentId intent to be replaced
+         * @param newIntent   replacement intent
+         * @return self
+         */
+        public Builder addReplaceOperation(IntentId oldIntentId, Intent newIntent) {
+            checkNotNull(oldIntentId, "Intent ID cannot be null");
+            checkNotNull(newIntent, "Intent cannot be null");
+            builder.add(new IntentOperation(REPLACE, oldIntentId, newIntent));
+            return this;
+        }
+
+        /**
+         * Adds an intent submit operation.
+         *
+         * @param intentId identifier of the intent to be withdrawn
+         * @return self
+         */
+        public Builder addWithdrawOperation(IntentId intentId) {
+            checkNotNull(intentId, "Intent ID cannot be null");
+            builder.add(new IntentOperation(WITHDRAW, intentId, null));
+            return this;
+        }
+
+        /**
+         * Builds a batch of intent operations.
+         *
+         * @return immutable batch of intent operations
+         */
+        public IntentOperations build() {
+            return new IntentOperations(builder.build());
+        }
+
+    }
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
index 700066d..6b89a68 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentService.java
@@ -1,7 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 
 import java.util.List;
+import java.util.concurrent.Future;
 
 /**
  * Service for application submitting or withdrawing their intents.
@@ -28,6 +47,14 @@
     void withdraw(Intent intent);
 
     /**
+     * Replaces the specified intent with a new one.
+     *
+     * @param oldIntentId identifier of the old intent being replaced
+     * @param newIntent new intent replacing the old one
+     */
+    void replace(IntentId oldIntentId, Intent newIntent);
+
+    /**
      * Submits a batch of submit &amp; withdraw operations. Such a batch is
      * assumed to be processed together.
      * <p/>
@@ -36,7 +63,7 @@
      *
      * @param operations batch of intent operations
      */
-    void execute(IntentOperations operations);
+    Future<IntentOperations> execute(IntentOperations operations);
 
     /**
      * Returns an iterable of intents currently in the system.
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java
index bd140af..38662d2 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentState.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 /**
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java
index c234b0f..7a62d61 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStore.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import org.onlab.onos.store.Store;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java
index 6c37db8..ab117d2 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/IntentStoreDelegate.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import org.onlab.onos.store.StoreDelegate;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
index 1b465aa..65d1ba8 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/LinkCollectionIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java
index 7c638aa..13324d0 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
index 1e41120..d7996c9 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PathIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java
index d170c27..7b91cdf 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/PointToPointIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
index 62e36e7..e5790d0 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntent.java
@@ -1,3 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.net.intent;
 
 import com.google.common.base.MoreObjects;
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java b/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java
index 3e5e46f..d7efa52 100644
--- a/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java
+++ b/core/api/src/main/java/org/onlab/onos/net/intent/package-info.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
 /**
  * Set of abstractions for conveying high-level intents for treatment of
  * selected network traffic by allowing applications to express the
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
index 5020459..cb982ba 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/FakeIntentManager.java
@@ -9,6 +9,7 @@
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 /**
  * Fake implementation of the intent service to assist in developing tests of
@@ -171,11 +172,17 @@
     }
 
     @Override
-    public void execute(IntentOperations operations) {
+    public void replace(IntentId oldIntentId, Intent newIntent) {
         // TODO: implement later
     }
 
     @Override
+    public Future<IntentOperations> execute(IntentOperations operations) {
+        // TODO: implement later
+        return null;
+    }
+
+    @Override
     public Set<Intent> getIntents() {
         return Collections.unmodifiableSet(new HashSet<>(intents.values()));
     }
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 fd47dc7..a157e50 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
@@ -161,6 +161,17 @@
         }
     }
 
+    // Queries a device for port information.
+    private void queryPortInfo(DeviceId deviceId) {
+        Device device = store.getDevice(deviceId);
+        // FIXME: Device might not be there yet. (eventual consistent)
+        if (device == null) {
+            return;
+        }
+        DeviceProvider provider = getProvider(device.providerId());
+        provider.triggerProbe(device);
+    }
+
     @Override
     public void removeDevice(DeviceId deviceId) {
         checkNotNull(deviceId, DEVICE_ID_NULL);
@@ -210,8 +221,6 @@
             log.info("Device {} connected", deviceId);
             // check my Role
             MastershipRole role = mastershipService.requestRoleFor(deviceId);
-            log.info("## - our role for {} is {} [master is {}]", deviceId, role,
-                    mastershipService.getMasterFor(deviceId));
             if (role != MastershipRole.MASTER) {
                 // TODO: Do we need to explicitly tell the Provider that
                 // this instance is no longer the MASTER? probably not
@@ -265,7 +274,6 @@
             // but if I was the last STANDBY connection, etc. and no one else
             // was there to mark the device offline, this instance may need to
             // temporarily request for Master Role and mark offline.
-            log.info("## for {} role is {}", deviceId, mastershipService.getLocalRole(deviceId));
             if (!mastershipService.getLocalRole(deviceId).equals(MastershipRole.MASTER)) {
                 log.debug("Device {} disconnected, but I am not the master", deviceId);
                 //let go of ability to be backup
@@ -373,7 +381,6 @@
             final DeviceId did = event.subject();
             final NodeId myNodeId = clusterService.getLocalNode().id();
 
-            log.info("## got Mastershipevent for dev {}", did);
             if (myNodeId.equals(event.roleInfo().master())) {
                 MastershipTerm term = termService.getMastershipTerm(did);
 
@@ -384,7 +391,6 @@
                     return;
                 }
 
-                log.info("## setting term for CPS as new master for {}", did);
                 // only set the new term if I am the master
                 deviceClockProviderService.setMastershipTerm(did, term);
 
@@ -404,6 +410,7 @@
                                     device.serialNumber(), device.chassisId()));
                 }
                 //TODO re-collect device information to fix potential staleness
+                queryPortInfo(did);
                 applyRole(did, MastershipRole.MASTER);
             } else if (event.roleInfo().backups().contains(myNodeId)) {
                 applyRole(did, MastershipRole.STANDBY);
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
index bfdc57e..3a3d476 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IntentManager.java
@@ -126,7 +126,13 @@
 
     // FIXME: implement this method
     @Override
-    public void execute(IntentOperations operations) {
+    public void replace(IntentId oldIntentId, Intent newIntent) {
+        throw new UnsupportedOperationException("execute() is not implemented yet");
+    }
+
+    // FIXME: implement this method
+    @Override
+    public Future<IntentOperations> execute(IntentOperations operations) {
         throw new UnsupportedOperationException("execute() is not implemented yet");
     }
 
diff --git a/core/net/src/test/java/org/onlab/onos/event/impl/TestEventDispatcher.java b/core/net/src/test/java/org/onlab/onos/event/impl/TestEventDispatcher.java
index 9eb3980..d2cbc24 100644
--- a/core/net/src/test/java/org/onlab/onos/event/impl/TestEventDispatcher.java
+++ b/core/net/src/test/java/org/onlab/onos/event/impl/TestEventDispatcher.java
@@ -15,6 +15,7 @@
         implements EventDeliveryService {
 
     @Override
+    @SuppressWarnings("unchecked")
     public void post(Event event) {
         EventSink sink = getSink(event.getClass());
         checkState(sink != null, "No sink for event %s", event);
diff --git a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
index cb966dc..a2fbc9a 100644
--- a/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
+++ b/core/net/src/test/java/org/onlab/onos/net/flow/impl/FlowRuleManagerTest.java
@@ -1,13 +1,10 @@
 package org.onlab.onos.net.flow.impl;
 
-import static java.util.Collections.EMPTY_LIST;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+
+
 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.*;
 
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -53,7 +50,7 @@
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.flow.criteria.Criterion;
 import org.onlab.onos.net.flow.instructions.Instruction;
-import org.onlab.onos.net.intent.BatchOperation;
+import org.onlab.onos.net.flow.BatchOperation;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore;
@@ -63,6 +60,16 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
+import static java.util.Collections.EMPTY_LIST;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
+import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
+
 /**
  * Test codifying the flow rule service & flow rule provider service contracts.
  */
@@ -175,6 +182,7 @@
 
     // TODO: If preserving iteration order is a requirement, redo FlowRuleStore.
     //backing store is sensitive to the order of additions/removals
+    @SuppressWarnings("unchecked")
     private boolean validateState(Map<FlowRule, FlowEntryState> expected) {
         Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected);
         Iterable<FlowEntry> rules = service.getFlowEntries(DID);
@@ -542,6 +550,7 @@
             }
 
             @Override
+            @SuppressWarnings("unchecked")
             public CompletedBatchOperation get()
                     throws InterruptedException, ExecutionException {
                 return new CompletedBatchOperation(true, EMPTY_LIST);
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 ac9fc3e..21941b5 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
@@ -290,12 +290,17 @@
     private DeviceEvent updateDevice(ProviderId providerId,
                                      Device oldDevice,
                                      Device newDevice, Timestamp newTimestamp) {
-
         // We allow only certain attributes to trigger update
-        if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) ||
-            !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) ||
-            !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) {
+        boolean propertiesChanged =
+                !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) ||
+                        !Objects.equals(oldDevice.swVersion(), newDevice.swVersion());
+        boolean annotationsChanged =
+                !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations());
 
+        // Primary providers can respond to all changes, but ancillary ones
+        // should respond only to annotation changes.
+        if ((providerId.isAncillary() && annotationsChanged) ||
+                (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) {
             boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice);
             if (!replaced) {
                 verify(replaced,
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
index 5f97afd..c789c96 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
@@ -35,6 +35,8 @@
                                Class<InternalDeviceEvent> type) {
         ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
         DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
+
+        @SuppressWarnings("unchecked")
         Timestamped<DeviceDescription> deviceDescription
             = (Timestamped<DeviceDescription>) kryo.readClassAndObject(input);
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
index 4f4a9e6..2facb7e 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
@@ -37,6 +37,8 @@
                                Class<InternalPortEvent> type) {
         ProviderId providerId = (ProviderId) kryo.readClassAndObject(input);
         DeviceId deviceId = (DeviceId) kryo.readClassAndObject(input);
+
+        @SuppressWarnings("unchecked")
         Timestamped<List<PortDescription>> portDescriptions
             = (Timestamped<List<PortDescription>>) kryo.readClassAndObject(input);
 
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
index fbfaf9d..c1be1f5 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
@@ -70,15 +70,16 @@
 
     public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
 
-    // collection of Description given from various providers
+    // Collection of Description given from various providers
     private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>>
-                                deviceDescs = Maps.newConcurrentMap();
+            deviceDescs = Maps.newConcurrentMap();
 
-    // cache of Device and Ports generated by compositing descriptions from providers
+    // Cache of Device and Ports generated by compositing descriptions from providers
     private final ConcurrentMap<DeviceId, Device> devices = Maps.newConcurrentMap();
-    private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>> devicePorts = Maps.newConcurrentMap();
+    private final ConcurrentMap<DeviceId, ConcurrentMap<PortNumber, Port>>
+            devicePorts = Maps.newConcurrentMap();
 
-    // available(=UP) devices
+    // Available (=UP) devices
     private final Set<DeviceId> availableDevices = Sets.newConcurrentHashSet();
 
 
@@ -113,19 +114,17 @@
 
     @Override
     public DeviceEvent createOrUpdateDevice(ProviderId providerId,
-                                     DeviceId deviceId,
-                                     DeviceDescription deviceDescription) {
-
+                                            DeviceId deviceId,
+                                            DeviceDescription deviceDescription) {
         Map<ProviderId, DeviceDescriptions> providerDescs
-            = getOrCreateDeviceDescriptions(deviceId);
+                = getOrCreateDeviceDescriptions(deviceId);
 
         synchronized (providerDescs) {
             // locking per device
-
             DeviceDescriptions descs
-                = getOrCreateProviderDeviceDescriptions(providerDescs,
-                                                        providerId,
-                                                        deviceDescription);
+                    = getOrCreateProviderDeviceDescriptions(providerDescs,
+                                                            providerId,
+                                                            deviceDescription);
 
             Device oldDevice = devices.get(deviceId);
             // update description
@@ -145,12 +144,11 @@
     // Creates the device and returns the appropriate event if necessary.
     // Guarded by deviceDescs value (=Device lock)
     private DeviceEvent createDevice(ProviderId providerId, Device newDevice) {
-
         // update composed device cache
         Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice);
         verify(oldDevice == null,
-                "Unexpected Device in cache. PID:%s [old=%s, new=%s]",
-                providerId, oldDevice, newDevice);
+               "Unexpected Device in cache. PID:%s [old=%s, new=%s]",
+               providerId, oldDevice, newDevice);
 
         if (!providerId.isAncillary()) {
             availableDevices.add(newDevice.id());
@@ -162,17 +160,24 @@
     // Updates the device and returns the appropriate event if necessary.
     // Guarded by deviceDescs value (=Device lock)
     private DeviceEvent updateDevice(ProviderId providerId, Device oldDevice, Device newDevice) {
-
         // We allow only certain attributes to trigger update
-        if (!Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) ||
-            !Objects.equals(oldDevice.swVersion(), newDevice.swVersion()) ||
-            !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations())) {
+        boolean propertiesChanged =
+                !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) ||
+                        !Objects.equals(oldDevice.swVersion(), newDevice.swVersion());
+        boolean annotationsChanged =
+                !AnnotationsUtil.isEqual(oldDevice.annotations(), newDevice.annotations());
+
+        // Primary providers can respond to all changes, but ancillary ones
+        // should respond only to annotation changes.
+        if ((providerId.isAncillary() && annotationsChanged) ||
+                (!providerId.isAncillary() && (propertiesChanged || annotationsChanged))) {
 
             boolean replaced = devices.replace(newDevice.id(), oldDevice, newDevice);
             if (!replaced) {
+                // FIXME: Is the enclosing if required here?
                 verify(replaced,
-                        "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]",
-                        providerId, oldDevice, devices.get(newDevice.id())
+                       "Replacing devices cache failed. PID:%s [expected:%s, found:%s, new=%s]",
+                       providerId, oldDevice, devices.get(newDevice.id())
                         , newDevice);
             }
             if (!providerId.isAncillary()) {
@@ -193,7 +198,7 @@
     @Override
     public DeviceEvent markOffline(DeviceId deviceId) {
         Map<ProviderId, DeviceDescriptions> providerDescs
-            = getOrCreateDeviceDescriptions(deviceId);
+                = getOrCreateDeviceDescriptions(deviceId);
 
         // locking device
         synchronized (providerDescs) {
@@ -212,9 +217,8 @@
 
     @Override
     public List<DeviceEvent> updatePorts(ProviderId providerId,
-                                      DeviceId deviceId,
-                                      List<PortDescription> portDescriptions) {
-
+                                         DeviceId deviceId,
+                                         List<PortDescription> portDescriptions) {
         Device device = devices.get(deviceId);
         checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
 
@@ -226,8 +230,8 @@
             DeviceDescriptions descs = descsMap.get(providerId);
             // every provider must provide DeviceDescription.
             checkArgument(descs != null,
-                    "Device description for Device ID %s from Provider %s was not found",
-                    deviceId, providerId);
+                          "Device description for Device ID %s from Provider %s was not found",
+                          deviceId, providerId);
 
             Map<PortNumber, Port> ports = getPortMap(deviceId);
 
@@ -247,8 +251,8 @@
                 newPort = composePort(device, number, descsMap);
 
                 events.add(oldPort == null ?
-                        createPort(device, newPort, ports) :
-                        updatePort(device, oldPort, newPort, ports));
+                                   createPort(device, newPort, ports) :
+                                   updatePort(device, oldPort, newPort, ports));
             }
 
             events.addAll(pruneOldPorts(device, ports, processed));
@@ -272,7 +276,7 @@
                                    Port newPort,
                                    Map<PortNumber, Port> ports) {
         if (oldPort.isEnabled() != newPort.isEnabled() ||
-            !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) {
+                !AnnotationsUtil.isEqual(oldPort.annotations(), newPort.annotations())) {
 
             ports.put(oldPort.number(), newPort);
             return new DeviceEvent(PORT_UPDATED, device, newPort);
@@ -303,7 +307,7 @@
     // exist, it creates and registers a new one.
     private ConcurrentMap<PortNumber, Port> getPortMap(DeviceId deviceId) {
         return createIfAbsentUnchecked(devicePorts, deviceId,
-                NewConcurrentHashMap.<PortNumber, Port>ifNeeded());
+                                       NewConcurrentHashMap.<PortNumber, Port>ifNeeded());
     }
 
     private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptions(
@@ -325,9 +329,8 @@
 
     // Guarded by deviceDescs value (=Device lock)
     private DeviceDescriptions getOrCreateProviderDeviceDescriptions(
-                            Map<ProviderId, DeviceDescriptions> device,
-                            ProviderId providerId, DeviceDescription deltaDesc) {
-
+            Map<ProviderId, DeviceDescriptions> device,
+            ProviderId providerId, DeviceDescription deltaDesc) {
         synchronized (device) {
             DeviceDescriptions r = device.get(providerId);
             if (r == null) {
@@ -340,7 +343,7 @@
 
     @Override
     public DeviceEvent updatePortStatus(ProviderId providerId, DeviceId deviceId,
-                                 PortDescription portDescription) {
+                                        PortDescription portDescription) {
         Device device = devices.get(deviceId);
         checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
 
@@ -351,8 +354,8 @@
             DeviceDescriptions descs = descsMap.get(providerId);
             // assuming all providers must give DeviceDescription first
             checkArgument(descs != null,
-                    "Device description for Device ID %s from Provider %s was not found",
-                    deviceId, providerId);
+                          "Device description for Device ID %s from Provider %s was not found",
+                          deviceId, providerId);
 
             ConcurrentMap<PortNumber, Port> ports = getPortMap(deviceId);
             final PortNumber number = portDescription.portNumber();
@@ -404,19 +407,19 @@
             availableDevices.remove(deviceId);
             descs.clear();
             return device == null ? null :
-                new DeviceEvent(DEVICE_REMOVED, device, null);
+                    new DeviceEvent(DEVICE_REMOVED, device, null);
         }
     }
 
     /**
      * Returns a Device, merging description given from multiple Providers.
      *
-     * @param deviceId device identifier
+     * @param deviceId      device identifier
      * @param providerDescs Collection of Descriptions from multiple providers
      * @return Device instance
      */
     private Device composeDevice(DeviceId deviceId,
-            Map<ProviderId, DeviceDescriptions> providerDescs) {
+                                 Map<ProviderId, DeviceDescriptions> providerDescs) {
 
         checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied");
 
@@ -447,21 +450,21 @@
             annotations = merge(annotations, e.getValue().getDeviceDesc().annotations());
         }
 
-        return new DefaultDevice(primary, deviceId , type, manufacturer,
-                            hwVersion, swVersion, serialNumber,
-                            chassisId, annotations);
+        return new DefaultDevice(primary, deviceId, type, manufacturer,
+                                 hwVersion, swVersion, serialNumber,
+                                 chassisId, annotations);
     }
 
     /**
      * Returns a Port, merging description given from multiple Providers.
      *
-     * @param device device the port is on
-     * @param number port number
+     * @param device   device the port is on
+     * @param number   port number
      * @param descsMap Collection of Descriptions from multiple providers
      * @return Port instance
      */
     private Port composePort(Device device, PortNumber number,
-                Map<ProviderId, DeviceDescriptions> descsMap) {
+                             Map<ProviderId, DeviceDescriptions> descsMap) {
 
         ProviderId primary = pickPrimaryPID(descsMap);
         DeviceDescriptions primDescs = descsMap.get(primary);
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
index 6fd02bc..1375a20 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitch.java
@@ -110,8 +110,7 @@
      *
      * @param role the failed role
      */
-    void returnRoleAssertFailure(RoleState role);
-
+    public void returnRoleAssertFailure(RoleState role);
 
     /**
      * Indicates if this switch is optical.
@@ -120,5 +119,4 @@
      */
     public boolean isOptical();
 
-
 }
diff --git a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
index 53217da..33e5bdf 100644
--- a/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
+++ b/openflow/api/src/main/java/org/onlab/onos/openflow/controller/OpenFlowSwitchListener.java
@@ -20,6 +20,12 @@
     public void switchRemoved(Dpid dpid);
 
     /**
+     * Notify that the switch has changed in some way.
+     * @param dpid the switch that changed
+     */
+    public void switchChanged(Dpid dpid);
+
+    /**
      * Notify that a port has changed.
      * @param dpid the switch on which the change happened.
      * @param status the new state of the port.
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
index 009cd3f..5047867 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OFChannelHandler.java
@@ -565,6 +565,9 @@
             @Override
             void processOFStatisticsReply(OFChannelHandler h,
                     OFStatsReply m) {
+                if (m.getStatsType().equals(OFStatsType.PORT_DESC)) {
+                    h.sw.setPortDescReply((OFPortDescStatsReply) m);
+                }
                 h.dispatchMessage(m);
             }
 
@@ -608,6 +611,12 @@
                 h.dispatchMessage(m);
             }
 
+            @Override
+            void processOFFeaturesReply(OFChannelHandler h, OFFeaturesReply  m) {
+                h.sw.setFeaturesReply(m);
+                h.dispatchMessage(m);
+            }
+
         };
 
         private final boolean handshakeComplete;
diff --git a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
index 565ccb9..cd9b760 100644
--- a/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/openflow/ctl/src/main/java/org/onlab/onos/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -27,6 +27,8 @@
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPacketIn;
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
+import org.projectfloodlight.openflow.protocol.OFStatsReply;
+import org.projectfloodlight.openflow.protocol.OFStatsType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -146,6 +148,11 @@
                 l.portChanged(dpid, (OFPortStatus) msg);
             }
             break;
+        case FEATURES_REPLY:
+            for (OpenFlowSwitchListener l : ofSwitchListener) {
+                l.switchChanged(dpid);
+            }
+            break;
         case PACKET_IN:
             OpenFlowPacketContext pktCtx = DefaultOpenFlowPacketContext
             .packetContextFromPacketIn(this.getSwitch(dpid),
@@ -154,9 +161,15 @@
                 p.handlePacket(pktCtx);
             }
             break;
+        case STATS_REPLY:
+            OFStatsReply reply = (OFStatsReply) msg;
+            if (reply.getStatsType().equals(OFStatsType.PORT_DESC)) {
+                for (OpenFlowSwitchListener l : ofSwitchListener) {
+                    l.switchChanged(dpid);
+                }
+            }
         case FLOW_REMOVED:
         case ERROR:
-        case STATS_REPLY:
         case BARRIER_REPLY:
             executor.submit(new OFMessageHandler(dpid, msg));
             break;
diff --git a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
index fcc7810..984e8ae 100644
--- a/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onlab/onos/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -23,7 +23,9 @@
 import org.onlab.onos.openflow.controller.OpenFlowSwitch;
 import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
 import org.onlab.onos.openflow.controller.RoleState;
+import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver;
 import org.onlab.packet.ChassisId;
+import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
 import org.projectfloodlight.openflow.protocol.OFPortDesc;
 import org.projectfloodlight.openflow.protocol.OFPortState;
@@ -89,6 +91,28 @@
     @Override
     public void triggerProbe(Device device) {
         LOG.info("Triggering probe on device {}", device.id());
+
+        // 1. check device liveness
+        // FIXME if possible, we might want this to be part of
+        // OpenFlowSwitch interface so the driver interface isn't misused.
+        OpenFlowSwitch sw = controller.getSwitch(dpid(device.id().uri()));
+        if (!((OpenFlowSwitchDriver) sw).isConnected()) {
+            providerService.deviceDisconnected(device.id());
+            return;
+        }
+
+        // 2. Prompt an update of port information. Do we have an XID for this?
+        OFFactory fact = sw.factory();
+        switch (fact.getVersion()) {
+            case OF_10:
+                sw.sendMsg(fact.buildFeaturesRequest().setXid(0).build());
+                break;
+            case OF_13:
+                sw.sendMsg(fact.buildPortDescStatsRequest().setXid(0).build());
+                break;
+            default:
+                LOG.warn("Unhandled protocol version");
+        }
     }
 
     @Override
@@ -141,6 +165,17 @@
             providerService.deviceDisconnected(deviceId(uri(dpid)));
         }
 
+
+        @Override
+        public void switchChanged(Dpid dpid) {
+            if (providerService == null) {
+                return;
+            }
+            DeviceId did = deviceId(uri(dpid));
+            OpenFlowSwitch sw = controller.getSwitch(dpid);
+            providerService.updatePorts(did, buildPortDescriptions(sw.getPorts()));
+        }
+
         @Override
         public void portChanged(Dpid dpid, OFPortStatus status) {
             PortDescription portDescription = buildPortDescription(status.getDesc());
diff --git a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
index 4a21add..6fb54e8 100644
--- a/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
+++ b/providers/openflow/flow/src/main/java/org/onlab/onos/provider/of/flow/impl/OpenFlowRuleProvider.java
@@ -31,7 +31,7 @@
 import org.onlab.onos.net.flow.FlowRuleProvider;
 import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
 import org.onlab.onos.net.flow.FlowRuleProviderService;
-import org.onlab.onos.net.intent.BatchOperation;
+import org.onlab.onos.net.flow.BatchOperation;
 import org.onlab.onos.net.provider.AbstractProvider;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.net.topology.TopologyService;
@@ -243,6 +243,10 @@
         }
 
         @Override
+        public void switchChanged(Dpid dpid) {
+        }
+
+        @Override
         public void portChanged(Dpid dpid, OFPortStatus status) {
             //TODO: Decide whether to evict flows internal store.
         }
@@ -323,6 +327,7 @@
             }
             return false;
         }
+
     }
 
     private class InstallationFuture implements Future<CompletedBatchOperation> {
diff --git a/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java b/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
index 7f16eaa..c3f5a68 100644
--- a/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
+++ b/providers/openflow/link/src/main/java/org/onlab/onos/provider/of/link/impl/OpenFlowLinkProvider.java
@@ -118,6 +118,12 @@
                     DeviceId.deviceId("of:" + Long.toHexString(dpid.value())));
         }
 
+
+        @Override
+        public void switchChanged(Dpid dpid) {
+            //might not need to do anything since DeviceManager is notified
+        }
+
         @Override
         public void portChanged(Dpid dpid, OFPortStatus status) {
             LinkDiscovery ld = discoverers.get(dpid);
diff --git a/utils/osgi/src/main/java/org/onlab/osgi/TestServiceDirectory.java b/utils/osgi/src/main/java/org/onlab/osgi/TestServiceDirectory.java
index 2915d4b..7fecbc3 100644
--- a/utils/osgi/src/main/java/org/onlab/osgi/TestServiceDirectory.java
+++ b/utils/osgi/src/main/java/org/onlab/osgi/TestServiceDirectory.java
@@ -6,6 +6,7 @@
 /**
  * Service directory implementation suitable for testing.
  */
+@SuppressWarnings("unchecked")
 public class TestServiceDirectory implements ServiceDirectory {
 
     private ClassToInstanceMap<Object> services = MutableClassToInstanceMap.create();
diff --git a/web/gui/src/main/webapp/geometry.js b/web/gui/src/main/webapp/geometry.js
new file mode 100644
index 0000000..71533cb
--- /dev/null
+++ b/web/gui/src/main/webapp/geometry.js
@@ -0,0 +1,107 @@
+/*
+ Geometry library - based on work by Mike Bostock.
+ */
+
+(function() {
+
+    if (typeof geo == 'undefined') {
+        geo = {};
+    }
+
+    var tolerance = 1e-10;
+
+    function eq(a, b) {
+        return (Math.abs(a - b) < tolerance);
+    }
+
+    function gt(a, b) {
+        return (a - b > -tolerance);
+    }
+
+    function lt(a, b) {
+        return gt(b, a);
+    }
+
+    geo.eq = eq;
+    geo.gt = gt;
+    geo.lt = lt;
+
+    geo.LineSegment = function(x1, y1, x2, y2) {
+        this.x1 = x1;
+        this.y1 = y1;
+        this.x2 = x2;
+        this.y2 = y2;
+
+        // Ax + By = C
+        this.a = y2 - y1;
+        this.b = x1 - x2;
+        this.c = x1 * this.a + y1 * this.b;
+
+        if (eq(this.a, 0) && eq(this.b, 0)) {
+            throw new Error(
+                'Cannot construct a LineSegment with two equal endpoints.');
+        }
+    };
+
+    geo.LineSegment.prototype.intersect = function(that) {
+        var d = (this.x1 - this.x2) * (that.y1 - that.y2) -
+            (this.y1 - this.y2) * (that.x1 - that.x2);
+
+        if (eq(d, 0)) {
+            // The two lines are parallel or very close.
+            return {
+                x : NaN,
+                y : NaN
+            };
+        }
+
+        var t1  = this.x1 * this.y2 - this.y1 * this.x2,
+            t2  = that.x1 * that.y2 - that.y1 * that.x2,
+            x   = (t1 * (that.x1 - that.x2) - t2 * (this.x1 - this.x2)) / d,
+            y   = (t1 * (that.y1 - that.y2) - t2 * (this.y1 - this.y2)) / d,
+            in1 = (gt(x, Math.min(this.x1, this.x2)) && lt(x, Math.max(this.x1, this.x2)) &&
+                gt(y, Math.min(this.y1, this.y2)) && lt(y, Math.max(this.y1, this.y2))),
+            in2 = (gt(x, Math.min(that.x1, that.x2)) && lt(x, Math.max(that.x1, that.x2)) &&
+                gt(y, Math.min(that.y1, that.y2)) && lt(y, Math.max(that.y1, that.y2)));
+
+        return {
+            x   : x,
+            y   : y,
+            in1 : in1,
+            in2 : in2
+        };
+    };
+
+    geo.LineSegment.prototype.x = function(y) {
+        // x = (C - By) / a;
+        if (this.a) {
+            return (this.c - this.b * y) / this.a;
+        } else {
+            // a == 0 -> horizontal line
+            return NaN;
+        }
+    };
+
+    geo.LineSegment.prototype.y = function(x) {
+        // y = (C - Ax) / b;
+        if (this.b) {
+            return (this.c - this.a * x) / this.b;
+        } else {
+            // b == 0 -> vertical line
+            return NaN;
+        }
+    };
+
+    geo.LineSegment.prototype.length = function() {
+        return Math.sqrt(
+                (this.y2 - this.y1) * (this.y2 - this.y1) +
+                (this.x2 - this.x1) * (this.x2 - this.x1));
+    };
+
+    geo.LineSegment.prototype.offset = function(x, y) {
+        return new geo.LineSegment(
+                this.x1 + x, this.y1 + y,
+                this.x2 + x, this.y2 + y);
+    };
+
+})();
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 3b0d290..ebf25c5 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -14,6 +14,7 @@
     <link rel="stylesheet" href="base.css">
     <link rel="stylesheet" href="onos.css">
 
+    <script src="geometry.js"></script>
     <script src="onosui.js"></script>
 
 </head>
@@ -32,20 +33,20 @@
         <div id="view"></div>
     </div>
 
-    // Initialize the UI...
+    <!-- Initialize the UI...-->
     <script type="text/javascript">
         var ONOS = $.onos({note: "config, if needed"});
     </script>
 
-    // include module files
-    // + mast.js
-    // + nav.js
-    // + .... application views
+    <!-- include module files-->
+    <!-- + mast.js-->
+    <!-- + nav.js-->
+    <!-- + .... application views-->
 
-    // for now, we are just bootstrapping the network visualization
+    <!-- for now, we are just bootstrapping the network visualization-->
     <script src="network.js" type="text/javascript"></script>
 
-    // finally, build the UI
+    <!-- finally, build the UI-->
     <script type="text/javascript">
         $(ONOS.buildUi);
     </script>
diff --git a/web/gui/src/main/webapp/network.js b/web/gui/src/main/webapp/network.js
index 81105dc..80d11b7 100644
--- a/web/gui/src/main/webapp/network.js
+++ b/web/gui/src/main/webapp/network.js
@@ -10,11 +10,16 @@
     var api = onos.api;
 
     var config = {
+            layering: false,
             jsonUrl: 'network.json',
+            iconUrl: {
+                pkt: 'pkt.png',
+                opt: 'opt.png'
+            },
             mastHeight: 32,
             force: {
-                linkDistance: 150,
-                linkStrength: 0.9,
+                linkDistance: 240,
+                linkStrength: 0.8,
                 charge: -400,
                 ticksWithoutCollisions: 50,
                 marginLR: 20,
@@ -26,8 +31,9 @@
                 }
             },
             labels: {
-                padLR: 3,
-                padTB: 2,
+                imgPad: 22,
+                padLR: 8,
+                padTB: 6,
                 marginLR: 3,
                 marginTB: 2
             },
@@ -53,7 +59,7 @@
         d3.json(config.jsonUrl, function (err, data) {
             if (err) {
                 alert('Oops! Error reading JSON...\n\n' +
-                    'URL: ' + jsonUrl + '\n\n' +
+                    'URL: ' + config.jsonUrl + '\n\n' +
                     'Error: ' + err.message);
                 return;
             }
@@ -100,7 +106,7 @@
 
         network.data.nodes.forEach(function(n) {
             var ypc = yPosConstraintForNode(n),
-                ix = Math.random() * 0.8 * nw + 0.1 * nw,
+                ix = Math.random() * 0.6 * nw + 0.2 * nw,
                 iy = ypc * nh,
                 node = {
                     id: n.id,
@@ -153,10 +159,48 @@
             .attr('height', view.height)
             .append('g')
             .attr('transform', config.force.translate());
+//            .attr('id', 'zoomable')
+//            .call(d3.behavior.zoom().on("zoom", zoomRedraw));
 
-        // TODO: svg.append('defs')
-        // TODO: glow/blur stuff
+//        function zoomRedraw() {
+//            d3.select("#zoomable").attr("transform",
+//                    "translate(" + d3.event.translate + ")"
+//                    + " scale(" + d3.event.scale + ")");
+//        }
+
+        // TODO: svg.append('defs') for markers?
+
+        // TODO: move glow/blur stuff to util script
+        var glow = network.svg.append('filter')
+            .attr('x', '-50%')
+            .attr('y', '-50%')
+            .attr('width', '200%')
+            .attr('height', '200%')
+            .attr('id', 'blue-glow');
+
+        glow.append('feColorMatrix')
+            .attr('type', 'matrix')
+            .attr('values', '0 0 0 0  0 ' +
+                '0 0 0 0  0 ' +
+                '0 0 0 0  .7 ' +
+                '0 0 0 1  0 ');
+
+        glow.append('feGaussianBlur')
+            .attr('stdDeviation', 3)
+            .attr('result', 'coloredBlur');
+
+        glow.append('feMerge').selectAll('feMergeNode')
+            .data(['coloredBlur', 'SourceGraphic'])
+            .enter().append('feMergeNode')
+            .attr('in', String);
+
         // TODO: legend (and auto adjust on scroll)
+//        $('#view').on('scroll', function() {
+//
+//        });
+
+
+
 
         network.link = network.svg.append('g').selectAll('.link')
             .data(network.force.links(), function(d) {return d.id})
@@ -164,37 +208,103 @@
             .attr('class', 'link');
 
         // TODO: drag behavior
-        // TODO: closest node deselect
+        network.draggedThreshold = d3.scale.linear()
+            .domain([0, 0.1])
+            .range([5, 20])
+            .clamp(true);
 
-        // TODO: add drag, mouseover, mouseout behaviors
+        function dragged(d) {
+            var threshold = network.draggedThreshold(network.force.alpha()),
+                dx = d.oldX - d.px,
+                dy = d.oldY - d.py;
+            if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
+                d.dragged = true;
+            }
+            return d.dragged;
+        }
+
+        network.drag = d3.behavior.drag()
+            .origin(function(d) { return d; })
+            .on('dragstart', function(d) {
+                d.oldX = d.x;
+                d.oldY = d.y;
+                d.dragged = false;
+                d.fixed |= 2;
+            })
+            .on('drag', function(d) {
+                d.px = d3.event.x;
+                d.py = d3.event.y;
+                if (dragged(d)) {
+                    if (!network.force.alpha()) {
+                        network.force.alpha(.025);
+                    }
+                }
+            })
+            .on('dragend', function(d) {
+                if (!dragged(d)) {
+                    selectObject(d, this);
+                }
+                d.fixed &= ~6;
+            });
+
+        $('#view').on('click', function(e) {
+            if (!$(e.target).closest('.node').length) {
+                deselectObject();
+            }
+        });
+
+
         network.node = network.svg.selectAll('.node')
             .data(network.force.nodes(), function(d) {return d.id})
             .enter().append('g')
-            .attr('class', 'node')
+            .attr('class', function(d) {
+                return 'node ' + d.type;
+            })
             .attr('transform', function(d) {
                 return translate(d.x, d.y);
             })
-        //        .call(network.drag)
-            .on('mouseover', function(d) {})
-            .on('mouseout', function(d) {});
+            .call(network.drag)
+            .on('mouseover', function(d) {
+                if (!selected.obj) {
+                    if (network.mouseoutTimeout) {
+                        clearTimeout(network.mouseoutTimeout);
+                        network.mouseoutTimeout = null;
+                    }
+                    highlightObject(d);
+                }
+            })
+            .on('mouseout', function(d) {
+                if (!selected.obj) {
+                    if (network.mouseoutTimeout) {
+                        clearTimeout(network.mouseoutTimeout);
+                        network.mouseoutTimeout = null;
+                    }
+                    network.mouseoutTimeout = setTimeout(function() {
+                        highlightObject(null);
+                    }, 160);
+                }
+            });
 
-        // TODO: augment stroke and fill functions
         network.nodeRect = network.node.append('rect')
-            // TODO: css for node rects
             .attr('rx', 5)
             .attr('ry', 5)
-            .attr('stroke', function(d) { return '#000'})
-            .attr('fill', function(d) { return '#ddf'})
-            .attr('width', 60)
-            .attr('height', 24);
+            .attr('width', 126)
+            .attr('height', 40);
 
         network.node.each(function(d) {
             var node = d3.select(this),
-                rect = node.select('rect');
-            var text = node.append('text')
-                .text(d.id)
-                .attr('dx', '1em')
-                .attr('dy', '2.1em');
+                rect = node.select('rect'),
+                img = node.append('svg:image')
+                    .attr('x', -16)
+                    .attr('y', -16)
+                    .attr('width', 32)
+                    .attr('height', 32)
+                    .attr('xlink:href', iconUrl(d)),
+                text = node.append('text')
+                    .text(d.id)
+                    .attr('dy', '1.1em'),
+                dummy;
+
         });
 
         // this function is scheduled to happen soon after the given thread ends
@@ -207,12 +317,64 @@
                     first = true;
 
                 // NOTE: probably unnecessary code if we only have one line.
+                text.each(function() {
+                    var box = this.getBBox();
+                    if (first || box.x < bounds.x1) {
+                        bounds.x1 = box.x;
+                    }
+                    if (first || box.y < bounds.y1) {
+                        bounds.y1 = box.y;
+                    }
+                    if (first || box.x + box.width < bounds.x2) {
+                        bounds.x2 = box.x + box.width;
+                    }
+                    if (first || box.y + box.height < bounds.y2) {
+                        bounds.y2 = box.y + box.height;
+                    }
+                    first = false;
+                }).attr('text-anchor', 'middle');
+
+                var lab = config.labels,
+                    oldWidth = bounds.x2 - bounds.x1;
+
+                bounds.x1 -= oldWidth / 2;
+                bounds.x2 -= oldWidth / 2;
+
+                bounds.x1 -= (lab.padLR + lab.imgPad);
+                bounds.y1 -= lab.padTB;
+                bounds.x2 += lab.padLR;
+                bounds.y2 += lab.padTB;
+
+                node.select('rect')
+                    .attr('x', bounds.x1)
+                    .attr('y', bounds.y1)
+                    .attr('width', bounds.x2 - bounds.x1)
+                    .attr('height', bounds.y2 - bounds.y1);
+
+                node.select('image')
+                    .attr('x', bounds.x1);
+
+                d.extent = {
+                    left: bounds.x1 - lab.marginLR,
+                    right: bounds.x2 + lab.marginLR,
+                    top: bounds.y1 - lab.marginTB,
+                    bottom: bounds.y2 + lab.marginTB
+                };
+
+                d.edge = {
+                    left   : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x1, bounds.y2),
+                    right  : new geo.LineSegment(bounds.x2, bounds.y1, bounds.x2, bounds.y2),
+                    top    : new geo.LineSegment(bounds.x1, bounds.y1, bounds.x2, bounds.y1),
+                    bottom : new geo.LineSegment(bounds.x1, bounds.y2, bounds.x2, bounds.y2)
+                };
+
+                // ====
             });
 
             network.numTicks = 0;
             network.preventCollisions = false;
             network.force.start();
-            for (var i = 0; i < config.ticksWithoutCollisions; i++) {
+            for (var i = 0; i < config.force.ticksWithoutCollisions; i++) {
                 network.force.tick();
             }
             network.preventCollisions = true;
@@ -221,22 +383,78 @@
 
     }
 
+    function iconUrl(d) {
+        return config.iconUrl[d.type];
+    }
+
     function translate(x, y) {
         return 'translate(' + x + ',' + y + ')';
     }
 
+    function preventCollisions() {
+        var quadtree = d3.geom.quadtree(network.nodes);
+
+        network.nodes.forEach(function(n) {
+            var nx1 = n.x + n.extent.left,
+                nx2 = n.x + n.extent.right,
+                ny1 = n.y + n.extent.top,
+                ny2 = n.y + n.extent.bottom;
+
+            quadtree.visit(function(quad, x1, y1, x2, y2) {
+                if (quad.point && quad.point !== n) {
+                    // check if the rectangles intersect
+                    var p = quad.point,
+                        px1 = p.x + p.extent.left,
+                        px2 = p.x + p.extent.right,
+                        py1 = p.y + p.extent.top,
+                        py2 = p.y + p.extent.bottom,
+                        ix = (px1 <= nx2 && nx1 <= px2 && py1 <= ny2 && ny1 <= py2);
+                    if (ix) {
+                        var xa1 = nx2 - px1, // shift n left , p right
+                            xa2 = px2 - nx1, // shift n right, p left
+                            ya1 = ny2 - py1, // shift n up   , p down
+                            ya2 = py2 - ny1, // shift n down , p up
+                            adj = Math.min(xa1, xa2, ya1, ya2);
+
+                        if (adj == xa1) {
+                            n.x -= adj / 2;
+                            p.x += adj / 2;
+                        } else if (adj == xa2) {
+                            n.x += adj / 2;
+                            p.x -= adj / 2;
+                        } else if (adj == ya1) {
+                            n.y -= adj / 2;
+                            p.y += adj / 2;
+                        } else if (adj == ya2) {
+                            n.y += adj / 2;
+                            p.y -= adj / 2;
+                        }
+                    }
+                    return ix;
+                }
+            });
+
+        });
+    }
 
     function tick(e) {
         network.numTicks++;
 
-        // adjust the y-coord of each node, based on y-pos constraints
-//        network.nodes.forEach(function (n) {
-//            var z = e.alpha * n.constraint.weight;
-//            if (!isNaN(n.constraint.y)) {
-//                n.y = (n.constraint.y * z + n.y * (1 - z));
-//            }
-//        });
+        if (config.layering) {
+            // adjust the y-coord of each node, based on y-pos constraints
+            network.nodes.forEach(function (n) {
+                var z = e.alpha * n.constraint.weight;
+                if (!isNaN(n.constraint.y)) {
+                    n.y = (n.constraint.y * z + n.y * (1 - z));
+                }
+            });
+        }
 
+        if (network.preventCollisions) {
+            preventCollisions();
+        }
+
+        // TODO: use intersection technique for source end of link also
         network.link
             .attr('x1', function(d) {
                 return d.source.x;
@@ -244,11 +462,24 @@
             .attr('y1', function(d) {
                 return d.source.y;
             })
-            .attr('x2', function(d) {
-                return d.target.x;
-            })
-            .attr('y2', function(d) {
-                return d.target.y;
+            .each(function(d) {
+                var x = d.target.x,
+                    y = d.target.y,
+                    line = new geo.LineSegment(d.source.x, d.source.y, x, y);
+
+                for (var e in d.target.edge) {
+                    var ix = line.intersect(d.target.edge[e].offset(x,y));
+                    if (ix.in1 && ix.in2) {
+                        x = ix.x;
+                        y = ix.y;
+                        break;
+                    }
+                }
+
+                d3.select(this)
+                    .attr('x2', x)
+                    .attr('y2', y);
+
             });
 
         network.node
diff --git a/web/gui/src/main/webapp/network.json b/web/gui/src/main/webapp/network.json
index 74a276a..b4f1b6e 100644
--- a/web/gui/src/main/webapp/network.json
+++ b/web/gui/src/main/webapp/network.json
@@ -7,50 +7,50 @@
     },
     "nodes": [
         {
-            "id": "switch-1",
+            "id": "sample1",
             "type": "opt",
             "status": "good"
         },
         {
-            "id": "switch-2",
+            "id": "00:00:00:00:00:00:00:02",
             "type": "opt",
             "status": "good"
         },
         {
-            "id": "switch-3",
+            "id": "00:00:00:00:00:00:00:03",
             "type": "opt",
             "status": "good"
         },
         {
-            "id": "switch-4",
+            "id": "00:00:00:00:00:00:00:04",
             "type": "opt",
             "status": "good"
         },
         {
-            "id": "switch-11",
+            "id": "00:00:00:00:00:00:00:11",
             "type": "pkt",
             "status": "good"
         },
         {
-            "id": "switch-12",
+            "id": "00:00:00:00:00:00:00:12",
             "type": "pkt",
             "status": "good"
         },
         {
-            "id": "switch-13",
+            "id": "00:00:00:00:00:00:00:13",
             "type": "pkt",
             "status": "good"
         }
     ],
     "links": [
-        { "src": "switch-1", "dst": "switch-2" },
-        { "src": "switch-1", "dst": "switch-3" },
-        { "src": "switch-1", "dst": "switch-4" },
-        { "src": "switch-2", "dst": "switch-3" },
-        { "src": "switch-2", "dst": "switch-4" },
-        { "src": "switch-3", "dst": "switch-4" },
-        { "src": "switch-13", "dst": "switch-3" },
-        { "src": "switch-12", "dst": "switch-2" },
-        { "src": "switch-11", "dst": "switch-1" }
+        { "src": "sample1", "dst": "00:00:00:00:00:00:00:02" },
+        { "src": "sample1", "dst": "00:00:00:00:00:00:00:03" },
+        { "src": "sample1", "dst": "00:00:00:00:00:00:00:04" },
+        { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:03" },
+        { "src": "00:00:00:00:00:00:00:02", "dst": "00:00:00:00:00:00:00:04" },
+        { "src": "00:00:00:00:00:00:00:03", "dst": "00:00:00:00:00:00:00:04" },
+        { "src": "00:00:00:00:00:00:00:13", "dst": "00:00:00:00:00:00:00:03" },
+        { "src": "00:00:00:00:00:00:00:12", "dst": "00:00:00:00:00:00:00:02" },
+        { "src": "00:00:00:00:00:00:00:11", "dst": "sample1" }
     ]
 }
diff --git a/web/gui/src/main/webapp/onos.css b/web/gui/src/main/webapp/onos.css
index 328e109..340ae79 100644
--- a/web/gui/src/main/webapp/onos.css
+++ b/web/gui/src/main/webapp/onos.css
@@ -13,7 +13,7 @@
  */
 
 span.title {
-    color: red;
+    color: darkblue;
     font-size: 16pt;
     font-style: italic;
 }
@@ -30,7 +30,7 @@
  * === DEBUGGING ======
  */
 svg {
-    border: 1px dashed red;
+    /*border: 1px dashed red;*/
 }
 
 
@@ -64,36 +64,47 @@
     -moz-transition: opacity 250ms;
 }
 
-.node text {
-    fill: #000;
+/*differentiate between packet and optical nodes*/
+svg .node.pkt rect {
+    fill: #77a;
+}
+
+svg .node.opt rect {
+    fill: #7a7;
+}
+
+svg .node text {
+    fill: white;
     font: 10px sans-serif;
     pointer-events: none;
 }
 
-.node.selected rect {
+svg .node.selected rect {
     filter: url(#blue-glow);
 }
 
-.link.inactive,
-.node.inactive rect,
-.node.inactive text {
+svg .link.inactive,
+svg .node.inactive rect,
+svg .node.inactive text,
+svg .node.inactive image {
     opacity: .2;
 }
 
-.node.inactive.selected rect,
-.node.inactive.selected text {
+svg .node.inactive.selected rect,
+svg .node.inactive.selected text,
+svg .node.inactive.selected image {
     opacity: .6;
 }
 
-.legend {
+svg .legend {
     position: fixed;
 }
 
-.legend .category rect {
+svg .legend .category rect {
     stroke-width: 1px;
 }
 
-.legend .category text {
+svg .legend .category text {
     fill: #000;
     font: 10px sans-serif;
     pointer-events: none;
@@ -110,15 +121,15 @@
 #frame {
     width: 100%;
     height: 100%;
-    background-color: #ffd;
+    background-color: #cdf;
 }
 
 #mast {
     height: 32px;
-    background-color: #dda;
+    background-color: #abe;
     vertical-align: baseline;
 }
 
 #main {
-    background-color: #99b;
+    background-color: #99c;
 }
diff --git a/web/gui/src/main/webapp/opt.png b/web/gui/src/main/webapp/opt.png
new file mode 100644
index 0000000..2f2c88e
--- /dev/null
+++ b/web/gui/src/main/webapp/opt.png
Binary files differ
diff --git a/web/gui/src/main/webapp/pkt.png b/web/gui/src/main/webapp/pkt.png
new file mode 100644
index 0000000..1b1d5a3
--- /dev/null
+++ b/web/gui/src/main/webapp/pkt.png
Binary files differ