Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
diff --git a/apps/ifwd/src/main/java/org/onlab/onos/ifwd/IntentReactiveForwarding.java b/apps/ifwd/src/main/java/org/onlab/onos/ifwd/IntentReactiveForwarding.java
index fded98f..defdf08 100644
--- a/apps/ifwd/src/main/java/org/onlab/onos/ifwd/IntentReactiveForwarding.java
+++ b/apps/ifwd/src/main/java/org/onlab/onos/ifwd/IntentReactiveForwarding.java
@@ -1,12 +1,12 @@
 package org.onlab.onos.ifwd;
 
-import static org.slf4j.LoggerFactory.getLogger;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.CoreService;
 import org.onlab.onos.net.Host;
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.PortNumber;
@@ -16,7 +16,6 @@
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.intent.HostToHostIntent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.packet.DefaultOutboundPacket;
 import org.onlab.onos.net.packet.InboundPacket;
@@ -28,6 +27,8 @@
 import org.onlab.packet.Ethernet;
 import org.slf4j.Logger;
 
+import static org.slf4j.LoggerFactory.getLogger;
+
 /**
  * WORK-IN-PROGRESS: Sample reactive forwarding application using intent framework.
  */
@@ -37,6 +38,9 @@
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected TopologyService topologyService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -49,11 +53,11 @@
     protected HostService hostService;
 
     private ReactivePacketProcessor processor = new ReactivePacketProcessor();
-
-    private static long intentId = 0x123000;
+    private ApplicationId appId;
 
     @Activate
     public void activate() {
+        appId = coreService.registerApplication("org.onlab.onos.ifwd");
         packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
         log.info("Started");
     }
@@ -126,9 +130,8 @@
         TrafficSelector selector = DefaultTrafficSelector.builder().build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
 
-        HostToHostIntent intent =
-                new HostToHostIntent(new IntentId(intentId++), srcId, dstId,
-                                     selector, treatment);
+        HostToHostIntent intent = new HostToHostIntent(appId, srcId, dstId,
+                                                       selector, treatment);
 
         intentService.submit(intent);
     }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
index 3917f5a..400dba0 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/PeerConnectivityManager.java
@@ -1,13 +1,11 @@
 package org.onlab.onos.sdnip;
 
-import java.util.List;
-
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.DefaultTrafficSelector;
 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.sdnip.config.BgpPeer;
@@ -22,6 +20,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.List;
+
 /**
  * Manages the connectivity requirements between peers.
  */
@@ -38,11 +38,13 @@
     private final InterfaceService interfaceService;
     private final IntentService intentService;
 
-    // TODO this sucks.
-    private int intentId = 0;
+    private final ApplicationId appId;
 
-    public PeerConnectivityManager(SdnIpConfigService configInfoService,
-            InterfaceService interfaceService, IntentService intentService) {
+    public PeerConnectivityManager(ApplicationId appId,
+                                   SdnIpConfigService configInfoService,
+                                   InterfaceService interfaceService,
+                                   IntentService intentService) {
+        this.appId = appId;
         this.configInfoService = configInfoService;
         this.interfaceService = interfaceService;
         this.intentService = intentService;
@@ -53,15 +55,15 @@
         if (interfaceService.getInterfaces().isEmpty()) {
 
             log.warn("The interface in configuration file is empty. "
-                    + "Thus, the SDN-IP application can not be started.");
+                             + "Thus, the SDN-IP application can not be started.");
         } else if (configInfoService.getBgpPeers().isEmpty()) {
 
             log.warn("The BGP peer in configuration file is empty."
-                    + "Thus, the SDN-IP application can not be started.");
+                             + "Thus, the SDN-IP application can not be started.");
         } else if (configInfoService.getBgpSpeakers() == null) {
 
             log.error("The BGP speaker in configuration file is empty. "
-                    + "Thus, the SDN-IP application can not be started.");
+                              + "Thus, the SDN-IP application can not be started.");
             return;
         }
 
@@ -80,7 +82,7 @@
         for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
                 .values()) {
             log.debug("Start to set up BGP paths for BGP speaker: {}",
-                    bgpSpeaker);
+                      bgpSpeaker);
             ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint();
 
             List<InterfaceAddress> interfaceAddresses =
@@ -89,14 +91,14 @@
             for (BgpPeer bgpPeer : configInfoService.getBgpPeers().values()) {
 
                 log.debug("Start to set up BGP paths between BGP speaker: {} "
-                        + "to BGP peer: {}", bgpSpeaker, bgpPeer);
+                                  + "to BGP peer: {}", bgpSpeaker, bgpPeer);
 
                 Interface peerInterface = interfaceService.getInterface(
                         bgpPeer.connectPoint());
                 if (peerInterface == null) {
                     log.error("Can not find the corresponding Interface from "
-                            + "configuration for BGP peer {}",
-                            bgpPeer.ipAddress());
+                                      + "configuration for BGP peer {}",
+                              bgpPeer.ipAddress());
                     continue;
                 }
 
@@ -110,7 +112,7 @@
                 }
                 if (bgpdAddress == null) {
                     log.debug("There is no interface IP address for bgpPeer: {}"
-                            + " on interface {}", bgpPeer, bgpPeer.connectPoint());
+                                      + " on interface {}", bgpPeer, bgpPeer.connectPoint());
                     return;
                 }
 
@@ -123,7 +125,7 @@
                 // TODO: The usage of PacketMatchBuilder will be improved, then we
                 // only need to new the PacketMatchBuilder once.
                 // By then, the code here will be improved accordingly.
-                 TrafficSelector selector = DefaultTrafficSelector.builder()
+                TrafficSelector selector = DefaultTrafficSelector.builder()
                         .matchEthType(Ethernet.TYPE_IPV4)
                         .matchIPProtocol(IPv4.PROTOCOL_TCP)
                         .matchIPSrc(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
@@ -134,13 +136,13 @@
                 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                         .build();
 
-                PointToPointIntent intentMatchDstTcpPort = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                PointToPointIntent intentMatchDstTcpPort =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdConnectPoint, bgpdPeerConnectPoint);
                 intentService.submit(intentMatchDstTcpPort);
                 log.debug("Submitted BGP path intent matching dst TCP port 179 "
-                        + "from BGPd {} to peer {}: {}",
-                        bgpdAddress, bgpdPeerAddress, intentMatchDstTcpPort);
+                                  + "from BGPd {} to peer {}: {}",
+                          bgpdAddress, bgpdPeerAddress, intentMatchDstTcpPort);
 
                 // install intent for BGP path from BGPd to BGP peer matching
                 // source TCP port 179
@@ -152,13 +154,13 @@
                         .matchTcpSrc(BGP_PORT)
                         .build();
 
-                PointToPointIntent intentMatchSrcTcpPort = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                PointToPointIntent intentMatchSrcTcpPort =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdConnectPoint, bgpdPeerConnectPoint);
                 intentService.submit(intentMatchSrcTcpPort);
                 log.debug("Submitted BGP path intent matching src TCP port 179"
-                        + "from BGPd {} to peer {}: {}",
-                        bgpdAddress, bgpdPeerAddress, intentMatchSrcTcpPort);
+                                  + "from BGPd {} to peer {}: {}",
+                          bgpdAddress, bgpdPeerAddress, intentMatchSrcTcpPort);
 
                 // install intent for reversed BGP path from BGP peer to BGPd
                 // matching destination TCP port 179
@@ -170,13 +172,13 @@
                         .matchTcpDst(BGP_PORT)
                         .build();
 
-                PointToPointIntent reversedIntentMatchDstTcpPort = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                PointToPointIntent reversedIntentMatchDstTcpPort =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdPeerConnectPoint, bgpdConnectPoint);
                 intentService.submit(reversedIntentMatchDstTcpPort);
                 log.debug("Submitted BGP path intent matching dst TCP port 179"
-                        + "from BGP peer {} to BGPd {} : {}",
-                        bgpdPeerAddress, bgpdAddress, reversedIntentMatchDstTcpPort);
+                                  + "from BGP peer {} to BGPd {} : {}",
+                          bgpdPeerAddress, bgpdAddress, reversedIntentMatchDstTcpPort);
 
                 // install intent for reversed BGP path from BGP peer to BGPd
                 // matching source TCP port 179
@@ -188,13 +190,13 @@
                         .matchTcpSrc(BGP_PORT)
                         .build();
 
-                PointToPointIntent reversedIntentMatchSrcTcpPort = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                PointToPointIntent reversedIntentMatchSrcTcpPort =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdPeerConnectPoint, bgpdConnectPoint);
                 intentService.submit(reversedIntentMatchSrcTcpPort);
                 log.debug("Submitted BGP path intent matching src TCP port 179"
-                        + "from BGP peer {} to BGPd {} : {}",
-                        bgpdPeerAddress, bgpdAddress, reversedIntentMatchSrcTcpPort);
+                                  + "from BGP peer {} to BGPd {} : {}",
+                          bgpdPeerAddress, bgpdAddress, reversedIntentMatchSrcTcpPort);
 
             }
         }
@@ -212,7 +214,7 @@
         for (BgpSpeaker bgpSpeaker : configInfoService.getBgpSpeakers()
                 .values()) {
             log.debug("Start to set up ICMP paths for BGP speaker: {}",
-                    bgpSpeaker);
+                      bgpSpeaker);
             ConnectPoint bgpdConnectPoint = bgpSpeaker.connectPoint();
             List<InterfaceAddress> interfaceAddresses = bgpSpeaker
                     .interfaceAddresses();
@@ -224,8 +226,8 @@
 
                 if (peerInterface == null) {
                     log.error("Can not find the corresponding Interface from "
-                            + "configuration for BGP peer {}",
-                            bgpPeer.ipAddress());
+                                      + "configuration for BGP peer {}",
+                              bgpPeer.ipAddress());
                     continue;
                 }
                 IpAddress bgpdAddress = null;
@@ -239,8 +241,8 @@
                 }
                 if (bgpdAddress == null) {
                     log.debug("There is no IP address for bgpPeer: {} on "
-                            + "interface port: {}", bgpPeer,
-                            bgpPeer.connectPoint());
+                                      + "interface port: {}", bgpPeer,
+                              bgpPeer.connectPoint());
                     return;
                 }
 
@@ -258,12 +260,12 @@
                 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                         .build();
 
-                PointToPointIntent intent = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdConnectPoint, bgpdPeerConnectPoint);
+                PointToPointIntent intent =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdConnectPoint, bgpdPeerConnectPoint);
                 intentService.submit(intent);
                 log.debug("Submitted ICMP path intent from BGPd {} to peer {} :"
-                        + " {}", bgpdAddress, bgpdPeerAddress, intent);
+                                  + " {}", bgpdAddress, bgpdPeerAddress, intent);
 
                 // install intent for reversed ICMP path from BGP peer to BGPd
                 selector = DefaultTrafficSelector.builder()
@@ -273,18 +275,15 @@
                         .matchIPDst(IpPrefix.valueOf(bgpdAddress.toInt(), IPV4_BIT_LENGTH))
                         .build();
 
-                PointToPointIntent reversedIntent = new PointToPointIntent(
-                        nextIntentId(), selector, treatment,
-                        bgpdPeerConnectPoint, bgpdConnectPoint);
+                PointToPointIntent reversedIntent =
+                        new PointToPointIntent(appId, selector, treatment,
+                                               bgpdPeerConnectPoint, bgpdConnectPoint);
                 intentService.submit(reversedIntent);
                 log.debug("Submitted ICMP path intent from BGP peer {} to BGPd"
-                        + " {} : {}",
-                        bgpdPeerAddress, bgpdAddress, reversedIntent);
+                                  + " {} : {}",
+                          bgpdPeerAddress, bgpdAddress, reversedIntent);
             }
         }
     }
 
-    private IntentId nextIntentId() {
-        return new IntentId(intentId++);
-    }
 }
diff --git a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
index d610361..ca25a76 100644
--- a/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
+++ b/apps/sdnip/src/main/java/org/onlab/onos/sdnip/Router.java
@@ -1,5 +1,41 @@
 package org.onlab.onos.sdnip;
 
+import com.google.common.base.Objects;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.googlecode.concurrenttrees.common.KeyValuePair;
+import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
+import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
+import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.net.ConnectPoint;
+import org.onlab.onos.net.Host;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
+import org.onlab.onos.net.flow.TrafficSelector;
+import org.onlab.onos.net.flow.TrafficTreatment;
+import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
+import org.onlab.onos.net.flow.criteria.Criterion;
+import org.onlab.onos.net.flow.criteria.Criterion.Type;
+import org.onlab.onos.net.host.HostEvent;
+import org.onlab.onos.net.host.HostListener;
+import org.onlab.onos.net.host.HostService;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentService;
+import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
+import org.onlab.onos.sdnip.config.BgpPeer;
+import org.onlab.onos.sdnip.config.Interface;
+import org.onlab.onos.sdnip.config.SdnIpConfigService;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -15,47 +51,10 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.Semaphore;
 
-import org.apache.commons.lang3.tuple.Pair;
-import org.onlab.onos.net.ConnectPoint;
-import org.onlab.onos.net.Host;
-import org.onlab.onos.net.flow.DefaultTrafficSelector;
-import org.onlab.onos.net.flow.DefaultTrafficTreatment;
-import org.onlab.onos.net.flow.TrafficSelector;
-import org.onlab.onos.net.flow.TrafficTreatment;
-import org.onlab.onos.net.flow.criteria.Criteria.IPCriterion;
-import org.onlab.onos.net.flow.criteria.Criterion;
-import org.onlab.onos.net.flow.criteria.Criterion.Type;
-import org.onlab.onos.net.host.HostEvent;
-import org.onlab.onos.net.host.HostListener;
-import org.onlab.onos.net.host.HostService;
-import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
-import org.onlab.onos.net.intent.IntentService;
-import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
-import org.onlab.onos.sdnip.config.BgpPeer;
-import org.onlab.onos.sdnip.config.Interface;
-import org.onlab.onos.sdnip.config.SdnIpConfigService;
-import org.onlab.packet.Ethernet;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onlab.packet.MacAddress;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.googlecode.concurrenttrees.common.KeyValuePair;
-import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
-import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
-import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
-
 /**
  * This class processes BGP route update, translates each update into a intent
  * and submits the intent.
- *
+ * <p/>
  * TODO: Make it thread-safe.
  */
 public class Router implements RouteListener {
@@ -82,8 +81,7 @@
     private ExecutorService bgpUpdatesExecutor;
     private ExecutorService bgpIntentsSynchronizerExecutor;
 
-    // TODO temporary
-    private int intentId = Integer.MAX_VALUE / 2;
+    private final ApplicationId appId;
 
     //
     // State to deal with SDN-IP Leader election and pushing Intents
@@ -99,14 +97,15 @@
     /**
      * Class constructor.
      *
-     * @param intentService the intent service
-     * @param hostService the host service
+     * @param intentService     the intent service
+     * @param hostService       the host service
      * @param configInfoService the configuration service
-     * @param interfaceService the interface service
+     * @param interfaceService  the interface service
      */
-    public Router(IntentService intentService, HostService hostService,
-            SdnIpConfigService configInfoService, InterfaceService interfaceService) {
-
+    public Router(ApplicationId appId, IntentService intentService,
+                  HostService hostService, SdnIpConfigService configInfoService,
+                  InterfaceService interfaceService) {
+        this.appId = appId;
         this.intentService = intentService;
         this.hostService = hostService;
         this.configInfoService = configInfoService;
@@ -123,7 +122,7 @@
                 new ThreadFactoryBuilder().setNameFormat("bgp-updates-%d").build());
         bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor(
                 new ThreadFactoryBuilder()
-                .setNameFormat("bgp-intents-synchronizer-%d").build());
+                        .setNameFormat("bgp-intents-synchronizer-%d").build());
 
         this.hostService.addListener(new InternalHostListener());
     }
@@ -198,7 +197,7 @@
                     intentsSynchronizerSemaphore.drainPermits();
                 } catch (InterruptedException e) {
                     log.debug("Interrupted while waiting to become " +
-                              "Intent Synchronization leader");
+                                      "Intent Synchronization leader");
                     interrupted = true;
                     break;
                 }
@@ -221,15 +220,15 @@
                 try {
                     RouteUpdate update = routeUpdates.take();
                     switch (update.type()) {
-                    case UPDATE:
-                        processRouteAdd(update.routeEntry());
-                        break;
-                    case DELETE:
-                        processRouteDelete(update.routeEntry());
-                        break;
-                    default:
-                        log.error("Unknown update Type: {}", update.type());
-                        break;
+                        case UPDATE:
+                            processRouteAdd(update.routeEntry());
+                            break;
+                        case DELETE:
+                            processRouteDelete(update.routeEntry());
+                            break;
+                        default:
+                            log.error("Unknown update Type: {}", update.type());
+                            break;
                     }
                 } catch (InterruptedException e) {
                     log.debug("Interrupted while taking from updates queue", e);
@@ -257,7 +256,7 @@
             log.debug("Syncing SDN-IP Route Intents...");
 
             Map<IpPrefix, MultiPointToSinglePointIntent> fetchedIntents =
-                new HashMap<>();
+                    new HashMap<>();
 
             //
             // Fetch all intents, and classify the Multi-Point-to-Point Intents
@@ -272,7 +271,7 @@
                     continue;
                 }
                 MultiPointToSinglePointIntent mp2pIntent =
-                    (MultiPointToSinglePointIntent) intent;
+                        (MultiPointToSinglePointIntent) intent;
                 /*Match match = mp2pIntent.getMatch();
                 if (!(match instanceof PacketMatch)) {
                     continue;
@@ -309,18 +308,18 @@
             //    Intent.
             //
             Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>>
-                storeInMemoryIntents = new LinkedList<>();
+                    storeInMemoryIntents = new LinkedList<>();
             Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>>
-                addIntents = new LinkedList<>();
+                    addIntents = new LinkedList<>();
             Collection<Pair<IpPrefix, MultiPointToSinglePointIntent>>
-                deleteIntents = new LinkedList<>();
+                    deleteIntents = new LinkedList<>();
             for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry :
-                     pushedRouteIntents.entrySet()) {
+                    pushedRouteIntents.entrySet()) {
                 IpPrefix prefix = entry.getKey();
                 MultiPointToSinglePointIntent inMemoryIntent =
-                    entry.getValue();
+                        entry.getValue();
                 MultiPointToSinglePointIntent fetchedIntent =
-                    fetchedIntents.get(prefix);
+                        fetchedIntents.get(prefix);
 
                 if (fetchedIntent == null) {
                     //
@@ -354,7 +353,7 @@
             // Any remaining FETCHED Intents have to be deleted/withdrawn
             //
             for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry :
-                     fetchedIntents.entrySet()) {
+                    fetchedIntents.entrySet()) {
                 IpPrefix prefix = entry.getKey();
                 MultiPointToSinglePointIntent fetchedIntent = entry.getValue();
                 deleteIntents.add(Pair.of(prefix, fetchedIntent));
@@ -368,17 +367,17 @@
             // 3. Add intents: check if the leader before each operation
             //
             for (Pair<IpPrefix, MultiPointToSinglePointIntent> pair :
-                     storeInMemoryIntents) {
+                    storeInMemoryIntents) {
                 IpPrefix prefix = pair.getLeft();
                 MultiPointToSinglePointIntent intent = pair.getRight();
                 log.debug("Intent synchronization: updating in-memory " +
-                          "Intent for prefix: {}", prefix);
+                                  "Intent for prefix: {}", prefix);
                 pushedRouteIntents.put(prefix, intent);
             }
             //
             isActivatedLeader = true;           // Allow push of Intents
             for (Pair<IpPrefix, MultiPointToSinglePointIntent> pair :
-                     deleteIntents) {
+                    deleteIntents) {
                 IpPrefix prefix = pair.getLeft();
                 MultiPointToSinglePointIntent intent = pair.getRight();
                 if (!isElectedLeader) {
@@ -386,12 +385,12 @@
                     return;
                 }
                 log.debug("Intent synchronization: deleting Intent for " +
-                          "prefix: {}", prefix);
+                                  "prefix: {}", prefix);
                 intentService.withdraw(intent);
             }
             //
             for (Pair<IpPrefix, MultiPointToSinglePointIntent> pair :
-                     addIntents) {
+                    addIntents) {
                 IpPrefix prefix = pair.getLeft();
                 MultiPointToSinglePointIntent intent = pair.getRight();
                 if (!isElectedLeader) {
@@ -399,7 +398,7 @@
                     return;
                 }
                 log.debug("Intent synchronization: adding Intent for " +
-                          "prefix: {}", prefix);
+                                  "prefix: {}", prefix);
                 intentService.submit(intent);
             }
             if (!isElectedLeader) {
@@ -419,8 +418,8 @@
      * false
      */
     private boolean compareMultiPointToSinglePointIntents(
-                                MultiPointToSinglePointIntent intent1,
-                                MultiPointToSinglePointIntent intent2) {
+            MultiPointToSinglePointIntent intent1,
+            MultiPointToSinglePointIntent intent2) {
         /*Match match1 = intent1.getMatch();
         Match match2 = intent2.getMatch();
         Action action1 = intent1.getAction();
@@ -457,8 +456,8 @@
             IpPrefix prefix = routeEntry.prefix();
             IpAddress nextHop = null;
             RouteEntry foundRouteEntry =
-                bgpRoutes.put(RouteEntry.createBinaryString(prefix),
-                              routeEntry);
+                    bgpRoutes.put(RouteEntry.createBinaryString(prefix),
+                                  routeEntry);
             if (foundRouteEntry != null) {
                 nextHop = foundRouteEntry.nextHop();
             }
@@ -500,7 +499,7 @@
 
         // See if we know the MAC address of the next hop
         //MacAddress nextHopMacAddress =
-            //proxyArp.getMacAddress(routeEntry.getNextHop());
+        //proxyArp.getMacAddress(routeEntry.getNextHop());
         MacAddress nextHopMacAddress = null;
         Set<Host> hosts = hostService.getHostsByIp(
                 routeEntry.nextHop().toPrefix());
@@ -526,8 +525,8 @@
      * Adds a route intent given a prefix and a next hop IP address. This
      * method will find the egress interface for the intent.
      *
-     * @param prefix IP prefix of the route to add
-     * @param nextHopIpAddress IP address of the next hop
+     * @param prefix            IP prefix of the route to add
+     * @param nextHopIpAddress  IP address of the next hop
      * @param nextHopMacAddress MAC address of the next hop
      */
     private void addRouteIntentToNextHop(IpPrefix prefix,
@@ -540,14 +539,14 @@
             // Route to a peer
             log.debug("Route to peer {}", nextHopIpAddress);
             BgpPeer peer =
-                configInfoService.getBgpPeers().get(nextHopIpAddress);
+                    configInfoService.getBgpPeers().get(nextHopIpAddress);
             egressInterface =
-                interfaceService.getInterface(peer.connectPoint());
+                    interfaceService.getInterface(peer.connectPoint());
         } else {
             // Route to non-peer
             log.debug("Route to non-peer {}", nextHopIpAddress);
             egressInterface =
-                interfaceService.getMatchingInterface(nextHopIpAddress);
+                    interfaceService.getMatchingInterface(nextHopIpAddress);
             if (egressInterface == null) {
                 log.warn("No outgoing interface found for {}",
                          nextHopIpAddress);
@@ -564,17 +563,17 @@
      * Intent will match dst IP prefix and rewrite dst MAC address at all other
      * border switches, then forward packets according to dst MAC address.
      *
-     * @param prefix IP prefix from route
-     * @param egressInterface egress Interface connected to next hop router
+     * @param prefix            IP prefix from route
+     * @param egressInterface   egress Interface connected to next hop router
      * @param nextHopMacAddress MAC address of next hop router
      */
     private void doAddRouteIntent(IpPrefix prefix, Interface egressInterface,
-            MacAddress nextHopMacAddress) {
+                                  MacAddress nextHopMacAddress) {
         log.debug("Adding intent for prefix {}, next hop mac {}",
                   prefix, nextHopMacAddress);
 
         MultiPointToSinglePointIntent pushedIntent =
-            pushedRouteIntents.get(prefix);
+                pushedRouteIntents.get(prefix);
 
         // Just for testing.
         if (pushedIntent != null) {
@@ -603,14 +602,14 @@
 
         // Rewrite the destination MAC address
         //ModifyDstMacAction modifyDstMacAction =
-                //new ModifyDstMacAction(nextHopMacAddress);
+        //new ModifyDstMacAction(nextHopMacAddress);
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .setEthDst(nextHopMacAddress)
                 .build();
 
         MultiPointToSinglePointIntent intent =
-                new MultiPointToSinglePointIntent(nextIntentId(),
-                        selector, treatment, ingressPorts, egressPort);
+                new MultiPointToSinglePointIntent(appId, selector, treatment,
+                                                  ingressPorts, egressPort);
 
         if (isElectedLeader && isActivatedLeader) {
             log.debug("Intent installation: adding Intent for prefix: {}",
@@ -665,11 +664,11 @@
         IpPrefix prefix = routeEntry.prefix();
 
         MultiPointToSinglePointIntent intent =
-            pushedRouteIntents.remove(prefix);
+                pushedRouteIntents.remove(prefix);
 
         if (intent == null) {
             log.debug("There is no intent in pushedRouteIntents to delete " +
-                      "for prefix: {}", prefix);
+                              "for prefix: {}", prefix);
         } else {
             if (isElectedLeader && isActivatedLeader) {
                 log.debug("Intent installation: deleting Intent for prefix: {}",
@@ -683,8 +682,8 @@
      * This method handles the prefixes which are waiting for ARP replies for
      * MAC addresses of next hops.
      *
-     * @param ipAddress next hop router IP address, for which we sent ARP
-     * request out
+     * @param ipAddress  next hop router IP address, for which we sent ARP
+     *                   request out
      * @param macAddress MAC address which is relative to the ipAddress
      */
     //@Override
@@ -692,22 +691,22 @@
     public void arpResponse(IpAddress ipAddress, MacAddress macAddress) {
         log.debug("Received ARP response: {} => {}", ipAddress, macAddress);
 
-         // We synchronize on this to prevent changes to the radix tree
-         // while we're pushing intents. If the tree changes, the
-         // tree and intents could get out of sync.
+        // We synchronize on this to prevent changes to the radix tree
+        // while we're pushing intents. If the tree changes, the
+        // tree and intents could get out of sync.
         synchronized (this) {
 
             Set<RouteEntry> routesToPush =
-                routesWaitingOnArp.removeAll(ipAddress);
+                    routesWaitingOnArp.removeAll(ipAddress);
 
             for (RouteEntry routeEntry : routesToPush) {
                 // These will always be adds
                 IpPrefix prefix = routeEntry.prefix();
                 String binaryString = RouteEntry.createBinaryString(prefix);
                 RouteEntry foundRouteEntry =
-                    bgpRoutes.getValueForExactKey(binaryString);
+                        bgpRoutes.getValueForExactKey(binaryString);
                 if (foundRouteEntry != null &&
-                    foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
+                        foundRouteEntry.nextHop().equals(routeEntry.nextHop())) {
                     log.debug("Pushing prefix {} next hop {}",
                               routeEntry.prefix(), routeEntry.nextHop());
                     // We only push prefix flows if the prefix is still in the
@@ -718,8 +717,8 @@
                     addRouteIntentToNextHop(prefix, ipAddress, macAddress);
                 } else {
                     log.debug("Received ARP response, but {}/{} is no longer in"
-                            + " the radix tree", routeEntry.prefix(),
-                            routeEntry.nextHop());
+                                      + " the radix tree", routeEntry.prefix(),
+                              routeEntry.nextHop());
                 }
             }
         }
@@ -745,15 +744,6 @@
     }
 
     /**
-     * Generates a new unique intent ID.
-     *
-     * @return the new intent ID.
-     */
-    private IntentId nextIntentId() {
-        return new IntentId(intentId++);
-    }
-
-    /**
      * Listener for host events.
      */
     class InternalHostListener implements HostListener {
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 529e60a..54aa9e5 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
@@ -10,6 +10,8 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.CoreService;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.sdnip.bgp.BgpRouteEntry;
@@ -24,9 +26,14 @@
 @Service
 public class SdnIp implements SdnIpService {
 
+    private static final String SDN_ID_APP = "org.onlab.onos.sdnip";
+
     private final Logger log = getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected IntentService intentService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -46,10 +53,11 @@
 
         InterfaceService interfaceService = new HostToInterfaceAdaptor(hostService);
 
-        peerConnectivity = new PeerConnectivityManager(config, interfaceService, intentService);
+        ApplicationId appId = coreService.registerApplication(SDN_ID_APP);
+        peerConnectivity = new PeerConnectivityManager(appId, config, interfaceService, intentService);
         peerConnectivity.start();
 
-        router = new Router(intentService, hostService, config, interfaceService);
+        router = new Router(appId, intentService, hostService, config, interfaceService);
         router.start();
 
         bgpSessionManager = new BgpSessionManager(router);
diff --git a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
index 0ecea00..962a6ec 100644
--- a/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
+++ b/apps/sdnip/src/test/java/org/onlab/onos/sdnip/PeerConnectivityManagerTest.java
@@ -1,23 +1,11 @@
 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.reportMatcher;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
+import com.google.common.collect.Sets;
 import org.easymock.IArgumentMatcher;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
@@ -25,7 +13,6 @@
 import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.sdnip.bgp.BgpConstants;
@@ -40,13 +27,32 @@
 import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 
-import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
 
 /**
  * Unit tests for PeerConnectivityManager interface.
  */
 public class PeerConnectivityManagerTest {
 
+    private static final ApplicationId APPID = new ApplicationId() {
+        @Override
+        public short id() {
+            return 0;
+        }
+
+        @Override
+        public String name() {
+            return "foo";
+        }
+    };
+
     private PeerConnectivityManager peerConnectivityManager;
     private IntentService intentService;
     private SdnIpConfigService configInfoService;
@@ -81,9 +87,6 @@
     private final ConnectPoint s2Eth1 =
             new ConnectPoint(deviceId2, PortNumber.portNumber(1));
 
-    // We don't compare the intent ID so all expected intents can use the same ID
-    private final IntentId testIntentId = new IntentId(0);
-
     private final TrafficTreatment noTreatment =
             DefaultTrafficTreatment.builder().build();
 
@@ -257,7 +260,7 @@
         }
 
         PointToPointIntent intent = new PointToPointIntent(
-                testIntentId, builder.build(), noTreatment,
+                APPID, builder.build(), noTreatment,
                 srcConnectPoint, dstConnectPoint);
 
         intentList.add(intent);
@@ -429,7 +432,7 @@
                 .build();
 
         PointToPointIntent intent = new PointToPointIntent(
-                testIntentId, selector, noTreatment,
+                APPID, selector, noTreatment,
                 srcConnectPoint, dstConnectPoint);
 
         intentList.add(intent);
@@ -511,7 +514,7 @@
         intentService = createMock(IntentService.class);
         replay(intentService);
 
-        peerConnectivityManager = new PeerConnectivityManager(configInfoService,
+        peerConnectivityManager = new PeerConnectivityManager(APPID, configInfoService,
                 interfaceService, intentService);
     }
 
@@ -557,7 +560,7 @@
             providedIntentString = providedIntent.toString();
 
             PointToPointIntent matchIntent =
-                    new PointToPointIntent(providedIntent.id(),
+                    new PointToPointIntent(providedIntent.appId(),
                             intent.selector(), intent.treatment(),
                             intent.ingressPoint(), intent.egressPoint());
 
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 839d2841..5c68a22 100644
--- a/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/AbstractShellCommand.java
@@ -2,6 +2,8 @@
 
 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.osgi.DefaultServiceDirectory;
 import org.onlab.osgi.ServiceNotFoundException;
 
@@ -27,6 +29,15 @@
     }
 
     /**
+     * Returns application ID for the CLI.
+     *
+     * @return command-line application identifier
+     */
+    protected ApplicationId appId() {
+        return get(CoreService.class).registerApplication("org.onlab.onos.cli");
+    }
+
+    /**
      * Prints the arguments using the specified format.
      *
      * @param format format string; see {@link String#format}
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
index 837a0a7..5a75a17 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddHostToHostIntentCommand.java
@@ -9,7 +9,6 @@
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.HostToHostIntent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 
 /**
@@ -27,8 +26,6 @@
               required = true, multiValued = false)
     String two = null;
 
-    private static long id = 0x7870001;
-
     @Override
     protected void execute() {
         IntentService service = get(IntentService.class);
@@ -39,9 +36,8 @@
         TrafficSelector selector = DefaultTrafficSelector.builder().build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
 
-        HostToHostIntent intent =
-                new HostToHostIntent(new IntentId(id++), oneId, twoId,
-                                     selector, treatment);
+        HostToHostIntent intent = new HostToHostIntent(appId(), oneId, twoId,
+                                                       selector, treatment);
         service.submit(intent);
     }
 
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
index cdae8a6..56bbdaf 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddMultiPointToSinglePointIntentCommand.java
@@ -1,8 +1,5 @@
 package org.onlab.onos.cli.net;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.onos.cli.AbstractShellCommand;
@@ -14,11 +11,16 @@
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
 import org.onlab.packet.Ethernet;
 
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.PortNumber.portNumber;
+
 /**
  * Installs point-to-point connectivity intents.
  */
@@ -31,8 +33,6 @@
               required = true, multiValued = true)
     String[] deviceStrings = null;
 
-    private static long id = 0x7070001;
-
     @Override
     protected void execute() {
         IntentService service = get(IntentService.class);
@@ -42,33 +42,26 @@
         }
 
         String egressDeviceString = deviceStrings[deviceStrings.length - 1];
-        DeviceId egressDeviceId = DeviceId.deviceId(getDeviceId(egressDeviceString));
-        PortNumber egressPortNumber =
-                PortNumber.portNumber(getPortNumber(egressDeviceString));
+        DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
+        PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
         ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
         Set<ConnectPoint> ingressPoints = new HashSet<>();
 
         for (int index = 0; index < deviceStrings.length - 1; index++) {
             String ingressDeviceString = deviceStrings[index];
-            DeviceId ingressDeviceId = DeviceId.deviceId(getDeviceId(ingressDeviceString));
-            PortNumber ingressPortNumber =
-                    PortNumber.portNumber(getPortNumber(ingressDeviceString));
+            DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
+            PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
             ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
             ingressPoints.add(ingress);
         }
 
-
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
 
-        Intent intent =
-                new MultiPointToSinglePointIntent(new IntentId(id++),
-                                                  selector,
-                                                  treatment,
-                                                  ingressPoints,
-                                                  egress);
+        Intent intent = new MultiPointToSinglePointIntent(appId(), selector, treatment,
+                                                          ingressPoints, egress);
         service.submit(intent);
     }
 
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
index 89ec7f6..bd24366 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/AddPointToPointIntentCommand.java
@@ -11,11 +11,13 @@
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.packet.Ethernet;
 
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.PortNumber.portNumber;
+
 /**
  * Installs point-to-point connectivity intents.
  */
@@ -33,20 +35,16 @@
               required = true, multiValued = false)
     String egressDeviceString = null;
 
-    private static long id = 0x7470001;
-
     @Override
     protected void execute() {
         IntentService service = get(IntentService.class);
 
-        DeviceId ingressDeviceId = DeviceId.deviceId(getDeviceId(ingressDeviceString));
-        PortNumber ingressPortNumber =
-                PortNumber.portNumber(getPortNumber(ingressDeviceString));
+        DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
+        PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
         ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
 
-        DeviceId egressDeviceId = DeviceId.deviceId(getDeviceId(egressDeviceString));
-        PortNumber egressPortNumber =
-                PortNumber.portNumber(getPortNumber(egressDeviceString));
+        DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
+        PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
         ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
 
         TrafficSelector selector = DefaultTrafficSelector.builder()
@@ -54,12 +52,8 @@
                 .build();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
 
-        Intent intent =
-                new PointToPointIntent(new IntentId(id++),
-                                                 selector,
-                                                 treatment,
-                                                 ingress,
-                                                 egress);
+        Intent intent = new PointToPointIntent(appId(), selector, treatment,
+                                               ingress, egress);
         service.submit(intent);
     }
 
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java
index 4c3ed8e..bd010ae 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/IntentPushTestCommand.java
@@ -1,8 +1,5 @@
 package org.onlab.onos.cli.net;
 
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
 import org.onlab.onos.cli.AbstractShellCommand;
@@ -16,20 +13,25 @@
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentEvent;
 import org.onlab.onos.net.intent.IntentEvent.Type;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentListener;
 import org.onlab.onos.net.intent.IntentService;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.MacAddress;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.onlab.onos.net.DeviceId.deviceId;
+import static org.onlab.onos.net.PortNumber.portNumber;
+
 /**
  * Installs point-to-point connectivity intents.
  */
 @Command(scope = "onos", name = "push-test-intents",
          description = "Installs random intents to test throughput")
 public class IntentPushTestCommand extends AbstractShellCommand
-    implements IntentListener {
+        implements IntentListener {
 
     @Argument(index = 0, name = "ingressDevice",
               description = "Ingress Device/Port Description",
@@ -42,8 +44,8 @@
     String egressDeviceString = null;
 
     @Argument(index = 2, name = "count",
-            description = "Number of intents to push",
-            required = true, multiValued = false)
+              description = "Number of intents to push",
+              required = true, multiValued = false)
     String countString = null;
 
 
@@ -57,14 +59,12 @@
     protected void execute() {
         service = get(IntentService.class);
 
-        DeviceId ingressDeviceId = DeviceId.deviceId(getDeviceId(ingressDeviceString));
-        PortNumber ingressPortNumber =
-                PortNumber.portNumber(getPortNumber(ingressDeviceString));
+        DeviceId ingressDeviceId = deviceId(getDeviceId(ingressDeviceString));
+        PortNumber ingressPortNumber = portNumber(getPortNumber(ingressDeviceString));
         ConnectPoint ingress = new ConnectPoint(ingressDeviceId, ingressPortNumber);
 
-        DeviceId egressDeviceId = DeviceId.deviceId(getDeviceId(egressDeviceString));
-        PortNumber egressPortNumber =
-                PortNumber.portNumber(getPortNumber(egressDeviceString));
+        DeviceId egressDeviceId = deviceId(getDeviceId(egressDeviceString));
+        PortNumber egressPortNumber = portNumber(getPortNumber(egressDeviceString));
         ConnectPoint egress = new ConnectPoint(egressDeviceId, egressPortNumber);
 
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
@@ -79,14 +79,10 @@
         start = System.currentTimeMillis();
         for (int i = 0; i < count; i++) {
             TrafficSelector s = selector
-                                .matchEthSrc(MacAddress.valueOf(i))
-                                .build();
-            Intent intent =
-                    new PointToPointIntent(new IntentId(id++),
-                                                     s,
-                                                     treatment,
-                                                     ingress,
-                                                     egress);
+                    .matchEthSrc(MacAddress.valueOf(i))
+                    .build();
+            Intent intent = new PointToPointIntent(appId(), s, treatment,
+                                                   ingress, egress);
             service.submit(intent);
         }
         try {
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/IntentRemoveCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/IntentRemoveCommand.java
index 7684da4..df5f335 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/IntentRemoveCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/IntentRemoveCommand.java
@@ -7,6 +7,8 @@
 import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentService;
 
+import java.math.BigInteger;
+
 /**
  * Removes host-to-host connectivity intent.
  */
@@ -22,13 +24,11 @@
     protected void execute() {
         IntentService service = get(IntentService.class);
 
-        int radix = id.startsWith("0x") ? 16 : 10;
-        if (radix == 16) {
+        if (id.startsWith("0x")) {
             id = id.replaceFirst("0x", "");
         }
-        IntentId intentId = new IntentId(Long.parseLong(id, radix));
 
-
+        IntentId intentId = IntentId.valueOf(new BigInteger(id, 16).longValue());
         Intent intent = service.getIntent(intentId);
         if (intent != null) {
             service.withdraw(intent);
diff --git a/cli/src/main/java/org/onlab/onos/cli/net/IntentsListCommand.java b/cli/src/main/java/org/onlab/onos/cli/net/IntentsListCommand.java
index a0c9845..e200cd0 100644
--- a/cli/src/main/java/org/onlab/onos/cli/net/IntentsListCommand.java
+++ b/cli/src/main/java/org/onlab/onos/cli/net/IntentsListCommand.java
@@ -18,7 +18,8 @@
         IntentService service = get(IntentService.class);
         for (Intent intent : service.getIntents()) {
             IntentState state = service.getIntentState(intent.id());
-            print("%s %s %s", intent.id(), state, intent);
+            print("id=%s, state=%s, appId=%s, %s",
+                  intent.id(), state, intent.appId().name(), intent);
         }
     }
 
diff --git a/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java b/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
index bf7442e..45b96ab 100644
--- a/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
+++ b/core/api/src/main/java/org/onlab/onos/cluster/RoleInfo.java
@@ -1,11 +1,9 @@
 package org.onlab.onos.cluster;
 
-import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
-import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.ImmutableList;
 
 /**
  * A container for detailed role information for a device,
@@ -18,9 +16,7 @@
 
     public RoleInfo(NodeId master, List<NodeId> backups) {
         this.master = master;
-        this.backups = new LinkedList<>();
-
-        this.backups.addAll(checkNotNull(backups));
+        this.backups = ImmutableList.copyOf(backups);
     }
 
     public NodeId master() {
@@ -28,7 +24,7 @@
     }
 
     public List<NodeId> backups() {
-        return Collections.unmodifiableList(backups);
+        return backups;
     }
 
     @Override
@@ -57,10 +53,10 @@
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("master: \n\t").append(master).append("\n");
-        builder.append("backups: \n");
+        builder.append("master:").append(master).append(",");
+        builder.append("backups:");
         for (NodeId n : backups) {
-            builder.append("\t").append(n).append("\n");
+            builder.append(" ").append(n);
         }
         return builder.toString();
     }
diff --git a/core/api/src/main/java/org/onlab/onos/net/Link.java b/core/api/src/main/java/org/onlab/onos/net/Link.java
index be2f99bf..1ae5b9d 100644
--- a/core/api/src/main/java/org/onlab/onos/net/Link.java
+++ b/core/api/src/main/java/org/onlab/onos/net/Link.java
@@ -3,7 +3,7 @@
 /**
  * Abstraction of a network infrastructure link.
  */
-public interface Link extends Annotated, Provided {
+public interface Link extends Annotated, Provided, NetworkResource {
 
     /**
      * Coarse representation of the link type.
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 a388b48..f51d75e 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
@@ -8,7 +8,6 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -27,7 +26,7 @@
      * @param criteria criteria
      */
     private DefaultTrafficSelector(Set<Criterion> criteria) {
-        this.criteria = Collections.unmodifiableSet(criteria);
+        this.criteria = ImmutableSet.copyOf(criteria);
     }
 
     @Override
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 269347a..d202217 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
@@ -7,7 +7,8 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
-import java.util.Collections;
+import com.google.common.collect.ImmutableList;
+
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
@@ -25,7 +26,7 @@
      * @param instructions treatment instructions
      */
     private DefaultTrafficTreatment(List<Instruction> instructions) {
-        this.instructions = Collections.unmodifiableList(instructions);
+        this.instructions = ImmutableList.copyOf(instructions);
     }
 
     @Override
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 b17449d..97efa5a 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
@@ -24,7 +24,18 @@
         /**
          * Signifies that a rule has been updated.
          */
-        RULE_UPDATED
+        RULE_UPDATED,
+
+        // internal event between Manager <-> Store
+
+        /*
+         * Signifies that a request to add flow rule has been added to the store.
+         */
+        RULE_ADD_REQUESTED,
+        /*
+         * Signifies that a request to remove flow rule has been added to the store.
+         */
+        RULE_REMOVE_REQUESTED,
     }
 
     /**
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 5ce7eb1..abb9a10 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
@@ -44,16 +44,18 @@
      * Stores a new flow rule without generating events.
      *
      * @param rule the flow rule to add
+     * @return true if the rule should be handled locally
      */
-    void storeFlowRule(FlowRule rule);
+    boolean storeFlowRule(FlowRule rule);
 
     /**
      * Marks a flow rule for deletion. Actual deletion will occur
      * when the provider indicates that the flow has been removed.
      *
      * @param rule the flow rule to delete
+     * @return true if the rule should be handled locally
      */
-    void deleteFlowRule(FlowRule rule);
+    boolean deleteFlowRule(FlowRule rule);
 
     /**
      * Stores a new flow rule, or updates an existing entry.
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java
deleted file mode 100644
index c8a4a05..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/AbstractIntent.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.onlab.onos.net.intent;
-
-/**
- * Base intent implementation.
- */
-public abstract class AbstractIntent implements Intent {
-
-    private final IntentId id;
-
-    /**
-     * Creates a base intent with the specified identifier.
-     *
-     * @param id intent identifier
-     */
-    protected AbstractIntent(IntentId id) {
-        this.id = id;
-    }
-
-    /**
-     * Constructor for serializer.
-     */
-    protected AbstractIntent() {
-        this.id = null;
-    }
-
-    @Override
-    public IntentId id() {
-        return id;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        AbstractIntent that = (AbstractIntent) o;
-        return id.equals(that.id);
-    }
-
-    @Override
-    public int hashCode() {
-        return id.hashCode();
-    }
-
-}
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 ed0c5cc..8d634a4 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,15 +1,20 @@
 package org.onlab.onos.net.intent;
 
-import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.NetworkResource;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
+import java.util.Collection;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Abstraction of connectivity intent for traffic matching some criteria.
  */
-public abstract class ConnectivityIntent extends AbstractIntent {
+public abstract class ConnectivityIntent extends Intent {
 
     // TODO: other forms of intents should be considered for this family:
     //   point-to-point with constraints (waypoints/obstacles)
@@ -19,24 +24,26 @@
     //   ...
 
     private final TrafficSelector selector;
-    // TODO: should consider which is better for multiple actions,
-    // defining compound action class or using list of actions.
     private final TrafficTreatment treatment;
 
     /**
-     * Creates a connectivity intent that matches on the specified intent
-     * and applies the specified treatement.
+     * Creates a connectivity intent that matches on the specified selector
+     * and applies the specified treatment.
      *
-     * @param intentId   intent identifier
-     * @param selector   traffic selector
-     * @param treatement treatement
+     * @param id        intent identifier
+     * @param appId     application identifier
+     * @param resources required network resources (optional)
+     * @param selector  traffic selector
+     * @param treatment treatment
      * @throws NullPointerException if the selector or treatement is null
      */
-    protected ConnectivityIntent(IntentId intentId, TrafficSelector selector,
-                                 TrafficTreatment treatement) {
-        super(intentId);
+    protected ConnectivityIntent(IntentId id, ApplicationId appId,
+                                 Collection<NetworkResource> resources,
+                                 TrafficSelector selector,
+                                 TrafficTreatment treatment) {
+        super(id, appId, resources);
         this.selector = checkNotNull(selector);
-        this.treatment = checkNotNull(treatement);
+        this.treatment = checkNotNull(treatment);
     }
 
     /**
@@ -66,19 +73,14 @@
         return treatment;
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (!super.equals(o)) {
-            return false;
-        }
-        ConnectivityIntent that = (ConnectivityIntent) o;
-        return Objects.equal(this.selector, that.selector)
-                && Objects.equal(this.treatment, that.treatment);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(super.hashCode(), selector, treatment);
+    /**
+     * Produces a collection of network resources from the given links.
+     *
+     * @param links collection of links
+     * @return collection of link resources
+     */
+    protected static Collection<NetworkResource> resources(Collection<Link> links) {
+        return ImmutableSet.<NetworkResource>copyOf(links);
     }
 
 }
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 7a894be6..83fe92a 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,12 +1,11 @@
 package org.onlab.onos.net.intent;
 
 import com.google.common.base.MoreObjects;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import java.util.Objects;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -18,25 +17,33 @@
     private final HostId two;
 
     /**
-     * Creates a new point-to-point intent with the supplied ingress/egress
-     * ports.
+     * Creates a new host-to-host intent with the supplied host pair.
      *
-     * @param intentId  intent identifier
+     * @param appId     application identifier
      * @param one       first host
      * @param two       second host
      * @param selector  action
      * @param treatment ingress port
-     * @throws NullPointerException if {@code ingressPort} or {@code egressPort}
-     *                              is null.
+     * @throws NullPointerException if {@code one} or {@code two} is null.
      */
-    public HostToHostIntent(IntentId intentId, HostId one, HostId two,
+    public HostToHostIntent(ApplicationId appId, HostId one, HostId two,
                             TrafficSelector selector,
                             TrafficTreatment treatment) {
-        super(intentId, selector, treatment);
+        super(id(HostToHostIntent.class, min(one, two), max(one, two),
+                 selector, treatment),
+              appId, null, selector, treatment);
         this.one = checkNotNull(one);
         this.two = checkNotNull(two);
     }
 
+    private static HostId min(HostId one, HostId two) {
+        return one.hashCode() < two.hashCode() ? one : two;
+    }
+
+    private static HostId max(HostId one, HostId two) {
+        return one.hashCode() > two.hashCode() ? one : two;
+    }
+
     /**
      * Returns identifier of the first host.
      *
@@ -56,31 +63,10 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        HostToHostIntent that = (HostToHostIntent) o;
-        return Objects.equals(this.one, that.one)
-                && Objects.equals(this.two, that.two);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), one, two);
-    }
-
-    @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
+                .add("appId", appId())
                 .add("selector", selector())
                 .add("treatment", treatment())
                 .add("one", one)
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/IdGenerator.java b/core/api/src/main/java/org/onlab/onos/net/intent/IdGenerator.java
deleted file mode 100644
index 0bba622..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/IdGenerator.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.onlab.onos.net.intent;
-//TODO is this the right package?
-
-/**
- * A generalized interface for ID generation
- *
- * {@link #getNewId()} generates a globally unique ID instance on
- * each invocation.
- *
- * @param <T> the type of ID
- */
-// TODO: do we need to define a base marker interface for ID,
-// then changed the type parameter to <T extends BaseId> something
-// like that?
-public interface IdGenerator<T> {
-    /**
-     * Returns a globally unique ID instance.
-     *
-     * @return globally unique ID instance
-     */
-    T getNewId();
-}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java
deleted file mode 100644
index 488695c..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/InstallableIntent.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.onlab.onos.net.intent;
-
-import org.onlab.onos.net.Link;
-
-import java.util.Collection;
-
-/**
- * Abstraction of an intent that can be installed into
- * the underlying system without additional compilation.
- */
-public interface InstallableIntent extends Intent {
-
-    /**
-     * Returns the collection of links that are required for this installable
-     * intent to exist.
-     *
-     * @return collection of links
-     */
-    // FIXME: replace this with 'NetworkResource'
-    Collection<Link> requiredLinks();
-
-}
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 3e339d1..f23a448 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,15 +1,109 @@
 package org.onlab.onos.net.intent;
 
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.net.NetworkResource;
+
+import java.util.Collection;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
 /**
  * Abstraction of an application level intent.
  * <p/>
  * Make sure that an Intent should be immutable when a new type is defined.
  */
-public interface Intent extends BatchOperationTarget {
+public abstract class Intent implements BatchOperationTarget {
+
+    private final IntentId id;
+    private final ApplicationId appId;
+    private final Collection<NetworkResource> resources;
+
+    /**
+     * Constructor for serializer.
+     */
+    protected Intent() {
+        this.id = null;
+        this.appId = null;
+        this.resources = null;
+    }
+
+    /**
+     * Creates a new intent.
+     *
+     * @param id        intent identifier
+     * @param appId     application identifier
+     * @param resources required network resources (optional)
+     */
+    protected Intent(IntentId id, ApplicationId appId,
+                     Collection<NetworkResource> resources) {
+        this.appId = checkNotNull(appId, "Application ID cannot be null");
+        this.id = checkNotNull(id, "Fingerprint cannot be null");
+        this.resources = resources;
+    }
+
     /**
      * Returns the intent identifier.
      *
+     * @return intent fingerprint
+     */
+    public IntentId id() {
+        return id;
+    }
+
+    /**
+     * Returns the identifier of the application that requested the intent.
+     *
+     * @return application identifier
+     */
+    public ApplicationId appId() {
+        return appId;
+    }
+
+    /**
+     * Returns the collection of resources required for this intent.
+     *
+     * @return collection of resources; may be null
+     */
+    public Collection<NetworkResource> resources() {
+        return resources;
+    }
+
+    /**
+     * Produces an intent identifier backed by hash-like fingerprint for the
+     * specified class of intent and its constituent fields.
+     *
+     * @param fields intent fields
      * @return intent identifier
      */
-    IntentId id();
+    protected static IntentId id(Object... fields) {
+        return IntentId.valueOf(Objects.hash(fields));
+    }
+
+    /**
+     * Indicates whether or not the intent is installable.
+     *
+     * @return true if installable
+     */
+    public boolean isInstallable() {
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final Intent other = (Intent) obj;
+        return Objects.equals(this.id, other.id);
+    }
+
 }
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 8deb372..50e803c 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
@@ -38,7 +38,7 @@
      * @param installer intent installer
      * @param <T>       the type of installable intent
      */
-    <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer);
+    <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer);
 
     /**
      * Unregisters the installer for the given installable intent class.
@@ -46,12 +46,12 @@
      * @param cls installable intent class
      * @param <T> the type of installable intent
      */
-    <T extends InstallableIntent> void unregisterInstaller(Class<T> cls);
+    <T extends Intent> void unregisterInstaller(Class<T> cls);
 
     /**
      * Returns immutable set of bindings of currently registered intent installers.
      *
      * @return the set of installer bindings
      */
-    Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers();
+    Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers();
 }
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 8f132c0..08ab7fa 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
@@ -7,43 +7,37 @@
  */
 public final class IntentId implements BatchOperationTarget {
 
-    private static final int DEC = 10;
-    private static final int HEX = 16;
-
-    private final long id;
+    private final long fingerprint;
 
     /**
      * Creates an intent identifier from the specified string representation.
      *
-     * @param value long value
+     * @param fingerprint long value
      * @return intent identifier
      */
-    public static IntentId valueOf(String value) {
-        long id = value.toLowerCase().startsWith("0x")
-                ? Long.parseLong(value.substring(2), HEX)
-                : Long.parseLong(value, DEC);
-        return new IntentId(id);
+    public static IntentId valueOf(long fingerprint) {
+        return new IntentId(fingerprint);
     }
 
     /**
      * Constructor for serializer.
      */
-    protected IntentId() {
-        this.id = 0;
+    IntentId() {
+        this.fingerprint = 0;
     }
 
     /**
      * Constructs the ID corresponding to a given long value.
      *
-     * @param id the underlying value of this ID
+     * @param fingerprint the underlying value of this ID
      */
-    public IntentId(long id) {
-        this.id = id;
+    IntentId(long fingerprint) {
+        this.fingerprint = fingerprint;
     }
 
     @Override
     public int hashCode() {
-        return (int) (id ^ (id >>> 32));
+        return (int) (fingerprint ^ (fingerprint >>> 32));
     }
 
     @Override
@@ -51,18 +45,16 @@
         if (obj == this) {
             return true;
         }
-
         if (!(obj instanceof IntentId)) {
             return false;
         }
-
         IntentId that = (IntentId) obj;
-        return this.id == that.id;
+        return this.fingerprint == that.fingerprint;
     }
 
     @Override
     public String toString() {
-        return "0x" + Long.toHexString(id);
+        return "0x" + Long.toHexString(fingerprint);
     }
 
 }
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 468017f..c403846 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
@@ -7,7 +7,7 @@
 /**
  * Abstraction of entity capable of installing intents to the environment.
  */
-public interface IntentInstaller<T extends InstallableIntent> {
+public interface IntentInstaller<T extends Intent> {
     /**
      * Installs the specified intent to the environment.
      *
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 d693c9b..c234b0f 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
@@ -77,8 +77,7 @@
      * @param intentId           original intent identifier
      * @param installableIntents compiled installable intents
      */
-    void addInstallableIntents(IntentId intentId,
-                               List<InstallableIntent> installableIntents);
+    void addInstallableIntents(IntentId intentId, List<Intent> installableIntents);
 
     /**
      * Returns the list of the installable events associated with the specified
@@ -87,7 +86,7 @@
      * @param intentId original intent identifier
      * @return compiled installable intents
      */
-    List<InstallableIntent> getInstallableIntents(IntentId intentId);
+    List<Intent> getInstallableIntents(IntentId intentId);
 
     // TODO: this should be triggered from with the store as a result of removeIntent call
 
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 6a8b002..4c193ee 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,21 +1,19 @@
 package org.onlab.onos.net.intent;
 
-import java.util.Collection;
-import java.util.Objects;
-import java.util.Set;
-
+import com.google.common.base.MoreObjects;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import com.google.common.base.MoreObjects;
+import java.util.Set;
 
 /**
  * Abstraction of a connectivity intent that is implemented by a set of path
  * segments.
  */
-public final class LinkCollectionIntent extends ConnectivityIntent implements InstallableIntent {
+public final class LinkCollectionIntent extends ConnectivityIntent {
 
     private final Set<Link> links;
 
@@ -25,34 +23,33 @@
      * Creates a new point-to-point intent with the supplied ingress/egress
      * ports and using the specified explicit path.
      *
-     * @param id          intent identifier
+     * @param appId       application identifier
      * @param selector    traffic match
      * @param treatment   action
      * @param links       traversed links
      * @param egressPoint egress point
      * @throws NullPointerException {@code path} is null
      */
-    public LinkCollectionIntent(IntentId id,
+    public LinkCollectionIntent(ApplicationId appId,
                                 TrafficSelector selector,
                                 TrafficTreatment treatment,
                                 Set<Link> links,
                                 ConnectPoint egressPoint) {
-        super(id, selector, treatment);
+        super(id(LinkCollectionIntent.class, selector, treatment, links, egressPoint),
+              appId, resources(links), selector, treatment);
         this.links = links;
         this.egressPoint = egressPoint;
     }
 
+    /**
+     * Constructor for serializer.
+     */
     protected LinkCollectionIntent() {
         super();
         this.links = null;
         this.egressPoint = null;
     }
 
-    @Override
-    public Collection<Link> requiredLinks() {
-        return links;
-    }
-
     /**
      * Returns the set of links that represent the network connections needed
      * by this intent.
@@ -73,34 +70,17 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        LinkCollectionIntent that = (LinkCollectionIntent) o;
-
-        return Objects.equals(this.links, that.links) &&
-                Objects.equals(this.egressPoint, that.egressPoint);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), links, egressPoint);
+    public boolean isInstallable() {
+        return true;
     }
 
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
-                .add("match", selector())
-                .add("action", treatment())
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
                 .add("links", links())
                 .add("egress", egressPoint())
                 .toString();
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 8ee4a9e..7c638aa 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
@@ -2,11 +2,11 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Sets;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import java.util.Objects;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -22,11 +22,11 @@
 
     /**
      * Creates a new multi-to-single point connectivity intent for the specified
-     * traffic match and action.
+     * traffic selector and treatment.
      *
-     * @param id           intent identifier
-     * @param match        traffic match
-     * @param action       action
+     * @param appId         application identifier
+     * @param selector      traffic selector
+     * @param treatment     treatment
      * @param ingressPoints set of ports from which ingress traffic originates
      * @param egressPoint   port to which traffic will egress
      * @throws NullPointerException     if {@code ingressPoints} or
@@ -34,15 +34,16 @@
      * @throws IllegalArgumentException if the size of {@code ingressPoints} is
      *                                  not more than 1
      */
-    public MultiPointToSinglePointIntent(IntentId id, TrafficSelector match,
-                                         TrafficTreatment action,
+    public MultiPointToSinglePointIntent(ApplicationId appId,
+                                         TrafficSelector selector,
+                                         TrafficTreatment treatment,
                                          Set<ConnectPoint> ingressPoints,
                                          ConnectPoint egressPoint) {
-        super(id, match, action);
+        super(id(MultiPointToSinglePointIntent.class, selector, treatment,
+                 ingressPoints, egressPoint), appId, null, selector, treatment);
 
         checkNotNull(ingressPoints);
-        checkArgument(!ingressPoints.isEmpty(),
-                      "there should be at least one ingress port");
+        checkArgument(!ingressPoints.isEmpty(), "Ingress point set cannot be empty");
 
         this.ingressPoints = Sets.newHashSet(ingressPoints);
         this.egressPoint = checkNotNull(egressPoint);
@@ -77,35 +78,14 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        MultiPointToSinglePointIntent that = (MultiPointToSinglePointIntent) o;
-        return Objects.equals(this.ingressPoints, that.ingressPoints)
-                && Objects.equals(this.egressPoint, that.egressPoint);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), ingressPoints, egressPoint);
-    }
-
-    @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
-                .add("match", selector())
-                .add("action", treatment())
-                .add("ingressPoints", ingressPoints())
-                .add("egressPoint", egressPoint())
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingress", ingressPoints())
+                .add("egress", egressPoint())
                 .toString();
     }
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java
deleted file mode 100644
index b99eb70..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/OpticalConnectivityIntent.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.onlab.onos.net.intent;
-
-import org.onlab.onos.net.ConnectPoint;
-
-// TODO: consider if this intent should be sub-class of ConnectivityIntent
-
-/**
- * An optical layer Intent for a connectivity from a transponder port to another
- * transponder port.
- * <p/>
- * This class doesn't accepts lambda specifier. This class computes path between
- * ports and assign lambda automatically. The lambda can be specified using
- * OpticalPathFlow class.
- */
-public class OpticalConnectivityIntent extends AbstractIntent {
-    protected ConnectPoint src;
-    protected ConnectPoint dst;
-
-    /**
-     * Constructor.
-     *
-     * @param id  ID for this new Intent object.
-     * @param src The source transponder port.
-     * @param dst The destination transponder port.
-     */
-    public OpticalConnectivityIntent(IntentId id, ConnectPoint src, ConnectPoint dst) {
-        super(id);
-        this.src = src;
-        this.dst = dst;
-    }
-
-    /**
-     * Constructor for serializer.
-     */
-    protected OpticalConnectivityIntent() {
-        super();
-        this.src = null;
-        this.dst = null;
-    }
-
-    /**
-     * Gets source transponder port.
-     *
-     * @return The source transponder port.
-     */
-    public ConnectPoint getSrcConnectPoint() {
-        return src;
-    }
-
-    /**
-     * Gets destination transponder port.
-     *
-     * @return The source transponder port.
-     */
-    public ConnectPoint getDst() {
-        return dst;
-    }
-}
diff --git a/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java b/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java
deleted file mode 100644
index 893d70e..0000000
--- a/core/api/src/main/java/org/onlab/onos/net/intent/PacketConnectivityIntent.java
+++ /dev/null
@@ -1,177 +0,0 @@
-package org.onlab.onos.net.intent;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.onlab.onos.net.ConnectPoint;
-import org.onlab.onos.net.flow.TrafficSelector;
-
-// TODO: consider if this intent should be sub-class of Connectivity intent
-/**
- * A packet layer Intent for a connectivity from a set of ports to a set of
- * ports.
- * <p>
- * TODO: Design methods to support the ReactiveForwarding and the SDN-IP. <br>
- * NOTE: Should this class support modifier methods? Should this object a
- * read-only object?
- */
-public class PacketConnectivityIntent extends AbstractIntent {
-    protected Set<ConnectPoint> srcConnectPoints;
-    protected TrafficSelector selector;
-    protected Set<ConnectPoint> dstConnectPoints;
-    protected boolean canSetupOpticalFlow;
-    protected int idleTimeoutValue;
-    protected int hardTimeoutValue;
-
-    /**
-     * Creates a connectivity intent for the packet layer.
-     * <p>
-     * When the "canSetupOpticalFlow" option is true, this intent will compute
-     * the packet/optical converged path, decompose it to the OpticalPathFlow
-     * and the PacketPathFlow objects, and execute the operations to add them
-     * considering the dependency between the packet and optical layers.
-     *
-     * @param id ID for this new Intent object.
-     * @param srcConnectPoints The set of source switch ports.
-     * @param match Traffic specifier for this object.
-     * @param dstConnectPoints The set of destination switch ports.
-     * @param canSetupOpticalFlow The flag whether this intent can create
-     *        optical flows if needed.
-     */
-    public PacketConnectivityIntent(IntentId id,
-            Collection<ConnectPoint> srcConnectPoints, TrafficSelector match,
-            Collection<ConnectPoint> dstConnectPoints, boolean canSetupOpticalFlow) {
-        super(id);
-        this.srcConnectPoints = new HashSet<ConnectPoint>(srcConnectPoints);
-        this.selector = match;
-        this.dstConnectPoints = new HashSet<ConnectPoint>(dstConnectPoints);
-        this.canSetupOpticalFlow = canSetupOpticalFlow;
-        this.idleTimeoutValue = 0;
-        this.hardTimeoutValue = 0;
-
-        // TODO: check consistency between these parameters.
-    }
-
-    /**
-     * Constructor for serializer.
-     */
-    protected PacketConnectivityIntent() {
-        super();
-        this.srcConnectPoints = null;
-        this.selector = null;
-        this.dstConnectPoints = null;
-        this.canSetupOpticalFlow = false;
-        this.idleTimeoutValue = 0;
-        this.hardTimeoutValue = 0;
-    }
-
-    /**
-     * Gets the set of source switch ports.
-     *
-     * @return the set of source switch ports.
-     */
-    public Collection<ConnectPoint> getSrcConnectPoints() {
-        return Collections.unmodifiableCollection(srcConnectPoints);
-    }
-
-    /**
-     * Gets the traffic specifier.
-     *
-     * @return The traffic specifier.
-     */
-    public TrafficSelector getMatch() {
-        return selector;
-    }
-
-    /**
-     * Gets the set of destination switch ports.
-     *
-     * @return the set of destination switch ports.
-     */
-    public Collection<ConnectPoint> getDstConnectPoints() {
-        return Collections.unmodifiableCollection(dstConnectPoints);
-    }
-
-    /**
-     * Adds the specified port to the set of source ports.
-     *
-     * @param port ConnectPoint object to be added
-     */
-    public void addSrcConnectPoint(ConnectPoint port) {
-        // TODO implement it.
-    }
-
-    /**
-     * Adds the specified port to the set of destination ports.
-     *
-     * @param port ConnectPoint object to be added
-     */
-    public void addDstConnectPoint(ConnectPoint port) {
-        // TODO implement it.
-    }
-
-    /**
-     * Removes the specified port from the set of source ports.
-     *
-     * @param port ConnectPoint object to be removed
-     */
-    public void removeSrcConnectPoint(ConnectPoint port) {
-        // TODO implement it.
-    }
-
-    /**
-     * Removes the specified port from the set of destination ports.
-     *
-     * @param port ConnectPoint object to be removed
-     */
-    public void removeDstConnectPoint(ConnectPoint port) {
-        // TODO implement it.
-    }
-
-    /**
-     * Sets idle-timeout value.
-     *
-     * @param timeout Idle-timeout value (seconds)
-     */
-    public void setIdleTimeout(int timeout) {
-        idleTimeoutValue = timeout;
-    }
-
-    /**
-     * Sets hard-timeout value.
-     *
-     * @param timeout Hard-timeout value (seconds)
-     */
-    public void setHardTimeout(int timeout) {
-        hardTimeoutValue = timeout;
-    }
-
-    /**
-     * Gets idle-timeout value.
-     *
-     * @return Idle-timeout value (seconds)
-     */
-    public int getIdleTimeout() {
-        return idleTimeoutValue;
-    }
-
-    /**
-     * Gets hard-timeout value.
-     *
-     * @return Hard-timeout value (seconds)
-     */
-    public int getHardTimeout() {
-        return hardTimeoutValue;
-    }
-
-    /**
-     * Returns whether this intent can create optical flows if needed.
-     *
-     * @return whether this intent can create optical flows.
-     */
-    public boolean canSetupOpticalFlow() {
-        return canSetupOpticalFlow;
-    }
-}
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 ff2e917..1e41120 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,19 +1,15 @@
 package org.onlab.onos.net.intent;
 
 import com.google.common.base.MoreObjects;
-import org.onlab.onos.net.ConnectPoint;
-import org.onlab.onos.net.Link;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import java.util.Collection;
-import java.util.Objects;
-
 /**
  * Abstraction of explicitly path specified connectivity intent.
  */
-public class PathIntent extends PointToPointIntent implements InstallableIntent {
+public class PathIntent extends ConnectivityIntent {
 
     private final Path path;
 
@@ -21,21 +17,22 @@
      * Creates a new point-to-point intent with the supplied ingress/egress
      * ports and using the specified explicit path.
      *
-     * @param id          intent identifier
-     * @param match       traffic match
-     * @param action      action
-     * @param ingressPort ingress port
-     * @param egressPort  egress port
-     * @param path        traversed links
+     * @param appId     application identifier
+     * @param selector  traffic selector
+     * @param treatment treatment
+     * @param path      traversed links
      * @throws NullPointerException {@code path} is null
      */
-    public PathIntent(IntentId id, TrafficSelector match, TrafficTreatment action,
-                      ConnectPoint ingressPort, ConnectPoint egressPort,
-                      Path path) {
-        super(id, match, action, ingressPort, egressPort);
+    public PathIntent(ApplicationId appId, TrafficSelector selector,
+                      TrafficTreatment treatment, Path path) {
+        super(id(PathIntent.class, selector, treatment, path), appId,
+              resources(path.links()), selector, treatment);
         this.path = path;
     }
 
+    /**
+     * Constructor for serializer.
+     */
     protected PathIntent() {
         super();
         this.path = null;
@@ -51,46 +48,19 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        PathIntent that = (PathIntent) o;
-
-        if (!path.equals(that.path)) {
-            return false;
-        }
-
+    public boolean isInstallable() {
         return true;
     }
 
     @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), path);
-    }
-
-    @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
-                .add("match", selector())
-                .add("action", treatment())
-                .add("ingressPort", ingressPoint())
-                .add("egressPort", egressPoint())
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
                 .add("path", path)
                 .toString();
     }
 
-    @Override
-    public Collection<Link> requiredLinks() {
-        return path.links();
-    }
-
 }
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 7b7c18a..d170c27 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,12 +1,11 @@
 package org.onlab.onos.net.intent;
 
 import com.google.common.base.MoreObjects;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import java.util.Objects;
-
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -21,18 +20,19 @@
      * Creates a new point-to-point intent with the supplied ingress/egress
      * ports.
      *
-     * @param id           intent identifier
+     * @param appId        application identifier
      * @param selector     traffic selector
      * @param treatment    treatment
      * @param ingressPoint ingress port
      * @param egressPoint  egress port
      * @throws NullPointerException if {@code ingressPoint} or {@code egressPoints} is null.
      */
-    public PointToPointIntent(IntentId id, TrafficSelector selector,
+    public PointToPointIntent(ApplicationId appId, TrafficSelector selector,
                               TrafficTreatment treatment,
                               ConnectPoint ingressPoint,
                               ConnectPoint egressPoint) {
-        super(id, selector, treatment);
+        super(id(PointToPointIntent.class, selector, treatment, ingressPoint, egressPoint),
+              appId, null, selector, treatment);
         this.ingressPoint = checkNotNull(ingressPoint);
         this.egressPoint = checkNotNull(egressPoint);
     }
@@ -66,35 +66,14 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        PointToPointIntent that = (PointToPointIntent) o;
-        return Objects.equals(this.ingressPoint, that.ingressPoint)
-                && Objects.equals(this.egressPoint, that.egressPoint);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), ingressPoint, egressPoint);
-    }
-
-    @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
-                .add("match", selector())
-                .add("action", treatment())
-                .add("ingressPoint", ingressPoint)
-                .add("egressPoints", egressPoint)
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingress", ingressPoint)
+                .add("egress", egressPoint)
                 .toString();
     }
 
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 2a17bfe..62e36e7 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
@@ -2,11 +2,11 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Sets;
+import org.onlab.onos.ApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
-import java.util.Objects;
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -23,7 +23,7 @@
     /**
      * Creates a new single-to-multi point connectivity intent.
      *
-     * @param id           intent identifier
+     * @param appId        application identifier
      * @param selector     traffic selector
      * @param treatment    treatment
      * @param ingressPoint port on which traffic will ingress
@@ -33,16 +33,15 @@
      * @throws IllegalArgumentException if the size of {@code egressPoints} is
      *                                  not more than 1
      */
-    public SinglePointToMultiPointIntent(IntentId id, TrafficSelector selector,
+    public SinglePointToMultiPointIntent(ApplicationId appId,
+                                         TrafficSelector selector,
                                          TrafficTreatment treatment,
                                          ConnectPoint ingressPoint,
                                          Set<ConnectPoint> egressPoints) {
-        super(id, selector, treatment);
-
+        super(id(SinglePointToMultiPointIntent.class, selector, treatment,
+                 ingressPoint, egressPoints), appId, null, selector, treatment);
         checkNotNull(egressPoints);
-        checkArgument(!egressPoints.isEmpty(),
-                      "there should be at least one egress port");
-
+        checkArgument(!egressPoints.isEmpty(), "Egress point set cannot be empty");
         this.ingressPoint = checkNotNull(ingressPoint);
         this.egressPoints = Sets.newHashSet(egressPoints);
     }
@@ -75,35 +74,14 @@
     }
 
     @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        if (!super.equals(o)) {
-            return false;
-        }
-
-        SinglePointToMultiPointIntent that = (SinglePointToMultiPointIntent) o;
-        return Objects.equals(this.ingressPoint, that.ingressPoint)
-                && Objects.equals(this.egressPoints, that.egressPoints);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(super.hashCode(), ingressPoint, egressPoints);
-    }
-
-    @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
                 .add("id", id())
-                .add("match", selector())
-                .add("action", treatment())
-                .add("ingressPoint", ingressPoint)
-                .add("egressPort", egressPoints)
+                .add("appId", appId())
+                .add("selector", selector())
+                .add("treatment", treatment())
+                .add("ingress", ingressPoint)
+                .add("egress", egressPoints)
                 .toString();
     }
 
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceAllocation.java b/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceAllocation.java
new file mode 100644
index 0000000..b542533
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceAllocation.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Representation of allocated bandwidth resource.
+ */
+public interface BandwidthResourceAllocation extends BandwidthResourceRequest {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceRequest.java b/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceRequest.java
new file mode 100644
index 0000000..2ea24b8
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/BandwidthResourceRequest.java
@@ -0,0 +1,13 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Representation of a request for bandwidth resource.
+ */
+public interface BandwidthResourceRequest {
+    /**
+     * Returns the bandwidth resource.
+     *
+     * @return the bandwidth resource
+     */
+    Bandwidth bandwidth();
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/Lambda.java b/core/api/src/main/java/org/onlab/onos/net/resource/Lambda.java
index 86ea08e..73c9488 100644
--- a/core/api/src/main/java/org/onlab/onos/net/resource/Lambda.java
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/Lambda.java
@@ -30,6 +30,7 @@
 
     /**
      * Returns lambda as an int value.
+     *
      * @return lambda as an int value
      */
     public int toInt() {
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceAllocation.java b/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceAllocation.java
new file mode 100644
index 0000000..1ed63b4
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceAllocation.java
@@ -0,0 +1,13 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Representation of allocated lambda resource.
+ */
+public interface LambdaResourceAllocation extends LambdaResourceRequest {
+    /**
+     * Returns the lambda resource.
+     *
+     * @return the lambda resource
+     */
+    Lambda lambda();
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceRequest.java b/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceRequest.java
new file mode 100644
index 0000000..dfb3b81
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LambdaResourceRequest.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Representation of a request for lambda resource.
+ */
+public interface LambdaResourceRequest {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceAllocations.java b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceAllocations.java
new file mode 100644
index 0000000..a3d3e87
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceAllocations.java
@@ -0,0 +1,16 @@
+package org.onlab.onos.net.resource;
+
+import org.onlab.onos.net.Link;
+
+/**
+ * Representation of allocated link resources.
+ */
+public interface LinkResourceAllocations extends LinkResourceRequest {
+    /**
+     * Returns allocated resource for the given link.
+     *
+     * @param link the target link
+     * @return allocated resource for the link
+     */
+    ResourceAllocation getResourceAllocation(Link link);
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceRequest.java b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceRequest.java
new file mode 100644
index 0000000..3f9bf79
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceRequest.java
@@ -0,0 +1,34 @@
+package org.onlab.onos.net.resource;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.onlab.onos.net.Link;
+import org.onlab.onos.net.intent.IntentId;
+
+/**
+ * Representation of a request for link resource.
+ */
+public interface LinkResourceRequest extends ResourceRequest {
+
+    /**
+     * Returns the {@link IntentId} associated with the request.
+     *
+     * @return the {@link IntentId} associated with the request
+     */
+    IntentId intendId();
+
+    /**
+     * Returns the set of target links.
+     *
+     * @return the set of target links
+     */
+    Collection<Link> links();
+
+    /**
+     * Returns the set of resource requests.
+     *
+     * @return the set of resource requests
+     */
+    Set<ResourceRequest> resources();
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
index d2736b6..1ea5723 100644
--- a/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/LinkResourceService.java
@@ -1,10 +1,7 @@
 package org.onlab.onos.net.resource;
 
-import java.util.Map;
-
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.intent.IntentId;
-import org.onlab.onos.net.intent.PathIntent;
 
 /**
  * Service for providing link resource allocation.
@@ -12,49 +9,48 @@
 public interface LinkResourceService {
 
     /**
-     * Allocates resources along the path.
-     * <p>
-     * Tries to allocate given resources on the links along the path specified
-     * by the given intent.
+     * Requests resources.
      *
-     * @param res resources to be allocated
-     * @param intent an intent to be used for specifying the path
+     * @param req resources to be allocated
+     * @return allocated resources
      */
-    void allocateResource(LinkResources res, PathIntent intent);
+    LinkResourceAllocations requestResources(LinkResourceRequest req);
 
     /**
-     * Releases resources along the path.
+     * Releases resources.
      *
-     * @param intentId an ID for the intent for specifying the path
+     * @param allocations resources to be released
      */
-    void releaseResource(IntentId intentId);
+    void releaseResources(LinkResourceAllocations allocations);
 
     /**
-     * Returns all allocated resources to each link.
+     * Returns all allocated resources.
      *
-     * @return allocated resources to each link with {@link IntentId}
+     * @return allocated resources
      */
-    Map<Link, Map<IntentId, LinkResources>> allocatedResources();
+    Iterable<LinkResourceAllocations> getAllocations();
 
     /**
      * Returns all allocated resources to given link.
      *
      * @param link a target link
-     * @return allocated resources to the target link with {@link IntentId}
+     * @return allocated resources
      */
-    Map<IntentId, LinkResources> allocatedResources(Link link);
+    Iterable<LinkResourceAllocations> getAllocations(Link link);
 
     /**
-     * Returns available resources for each link.
+     * Returns all IDs of intents using the given link.
      *
-     * @return available resources for each link
+     * @param link a target link
+     * @return IDs of intents using the link
      */
-    Map<Link, LinkResources> availableResources();
+    Iterable<IntentId> getIntents(Link link);
 
     /**
      * Returns available resources for given link.
+     *
      * @param link a target link
      * @return available resources for the target link
      */
-    LinkResources availableResources(Link link);
+    ResourceRequest getAvailableResources(Link link);
 }
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/ResourceAllocation.java b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceAllocation.java
new file mode 100644
index 0000000..5cc1414
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceAllocation.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Abstraction of allocated resource.
+ */
+public interface ResourceAllocation extends ResourceRequest {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/ResourceId.java b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceId.java
new file mode 100644
index 0000000..5c4c9fc
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceId.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Representation of ID for allocated resource.
+ */
+public interface ResourceId {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/ResourceRequest.java b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceRequest.java
new file mode 100644
index 0000000..bc3d904
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/ResourceRequest.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.net.resource;
+
+/**
+ * Abstraction of resource request.
+ */
+public interface ResourceRequest {
+
+}
diff --git a/core/api/src/main/java/org/onlab/onos/net/resource/package-info.java b/core/api/src/main/java/org/onlab/onos/net/resource/package-info.java
new file mode 100644
index 0000000..4e07a28
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/net/resource/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Services for reserving network resources, e.g.&nbsp;bandwidth, lambdas.
+ */
+package org.onlab.onos.net.resource;
\ No newline at end of file
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/ConnectivityIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/ConnectivityIntentTest.java
index 10a0069..03b101a 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/ConnectivityIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/ConnectivityIntentTest.java
@@ -2,6 +2,8 @@
 
 import java.util.Set;
 
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.PortNumber;
@@ -15,6 +17,8 @@
  */
 public abstract class ConnectivityIntentTest extends IntentTest {
 
+    public static final ApplicationId APPID = new TestApplicationId("foo");
+
     public static final IntentId IID = new IntentId(123);
     public static final TrafficSelector MATCH = DefaultTrafficSelector.builder().build();
     public static final TrafficTreatment NOP = DefaultTrafficTreatment.builder().build();
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 58c5a9c..4b3fd37 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
@@ -18,11 +18,11 @@
 
     private final Map<IntentId, Intent> intents = new HashMap<>();
     private final Map<IntentId, IntentState> intentStates = new HashMap<>();
-    private final Map<IntentId, List<InstallableIntent>> installables = new HashMap<>();
+    private final Map<IntentId, List<Intent>> installables = new HashMap<>();
     private final Set<IntentListener> listeners = new HashSet<>();
 
     private final Map<Class<? extends Intent>, IntentCompiler<? extends Intent>> compilers = new HashMap<>();
-    private final Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> installers
+    private final Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> installers
         = new HashMap<>();
 
     private final ExecutorService executor = Executors.newSingleThreadExecutor();
@@ -54,7 +54,7 @@
             @Override
             public void run() {
                 try {
-                    List<InstallableIntent> installable = getInstallable(intent.id());
+                    List<Intent> installable = getInstallable(intent.id());
                     executeWithdrawingPhase(intent, installable);
                 } catch (IntentException e) {
                     exceptions.add(e);
@@ -73,7 +73,7 @@
         return compiler;
     }
 
-    private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
+    private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
         @SuppressWarnings("unchecked")
         IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent
                 .getClass());
@@ -87,9 +87,9 @@
         setState(intent, IntentState.COMPILING);
         try {
             // For the fake, we compile using a single level pass
-            List<InstallableIntent> installable = new ArrayList<>();
+            List<Intent> installable = new ArrayList<>();
             for (Intent compiled : getCompiler(intent).compile(intent)) {
-                installable.add((InstallableIntent) compiled);
+                installable.add((Intent) compiled);
             }
             executeInstallingPhase(intent, installable);
 
@@ -100,10 +100,10 @@
     }
 
     private void executeInstallingPhase(Intent intent,
-                                        List<InstallableIntent> installable) {
+                                        List<Intent> installable) {
         setState(intent, IntentState.INSTALLING);
         try {
-            for (InstallableIntent ii : installable) {
+            for (Intent ii : installable) {
                 registerSubclassInstallerIfNeeded(ii);
                 getInstaller(ii).install(ii);
             }
@@ -118,10 +118,10 @@
     }
 
     private void executeWithdrawingPhase(Intent intent,
-                                         List<InstallableIntent> installable) {
+                                         List<Intent> installable) {
         setState(intent, IntentState.WITHDRAWING);
         try {
-            for (InstallableIntent ii : installable) {
+            for (Intent ii : installable) {
                 getInstaller(ii).uninstall(ii);
             }
             removeInstallable(intent.id());
@@ -139,7 +139,7 @@
         intentStates.put(intent.id(), state);
     }
 
-    private void putInstallable(IntentId id, List<InstallableIntent> installable) {
+    private void putInstallable(IntentId id, List<Intent> installable) {
         installables.put(id, installable);
     }
 
@@ -147,8 +147,8 @@
         installables.remove(id);
     }
 
-    private List<InstallableIntent> getInstallable(IntentId id) {
-        List<InstallableIntent> installable = installables.get(id);
+    private List<Intent> getInstallable(IntentId id) {
+        List<Intent> installable = installables.get(id);
         if (installable != null) {
             return installable;
         } else {
@@ -228,19 +228,19 @@
     }
 
     @Override
-    public <T extends InstallableIntent> void registerInstaller(Class<T> cls,
+    public <T extends Intent> void registerInstaller(Class<T> cls,
             IntentInstaller<T> installer) {
         installers.put(cls, installer);
     }
 
     @Override
-    public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
+    public <T extends Intent> void unregisterInstaller(Class<T> cls) {
         installers.remove(cls);
     }
 
     @Override
-    public Map<Class<? extends InstallableIntent>,
-    IntentInstaller<? extends InstallableIntent>> getInstallers() {
+    public Map<Class<? extends Intent>,
+    IntentInstaller<? extends Intent>> getInstallers() {
         return Collections.unmodifiableMap(installers);
     }
 
@@ -261,13 +261,13 @@
         }
     }
 
-    private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
+    private void registerSubclassInstallerIfNeeded(Intent intent) {
         if (!installers.containsKey(intent.getClass())) {
             Class<?> cls = intent.getClass();
             while (cls != Object.class) {
-                // As long as we're within the InstallableIntent class
+                // As long as we're within the Intent class
                 // descendants
-                if (InstallableIntent.class.isAssignableFrom(cls)) {
+                if (Intent.class.isAssignableFrom(cls)) {
                     IntentInstaller<?> installer = installers.get(cls);
                     if (installer != null) {
                         installers.put(intent.getClass(), installer);
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdGenerator.java b/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdGenerator.java
deleted file mode 100644
index 0ca669b..0000000
--- a/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdGenerator.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.onlab.onos.net.intent;
-
-/**
- * This interface is for generator of IntentId. It is defined only for
- * testing purpose to keep type safety on mock creation.
- *
- * <p>
- * {@link #getNewId()} generates a globally unique {@link IntentId} instance
- * on each invocation. Application developers should not generate IntentId
- * by themselves. Instead use an implementation of this interface.
- * </p>
- */
-public interface IntentIdGenerator extends IdGenerator<IntentId> {
-}
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdTest.java
index 2a0824c..471e397 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/IntentIdTest.java
@@ -44,14 +44,8 @@
 
     @Test
     public void valueOf() {
-        IntentId id = new IntentId(12345);
-        assertEquals("incorrect valueOf", id, IntentId.valueOf("12345"));
-    }
-
-    @Test
-    public void valueOfHex() {
         IntentId id = new IntentId(0xdeadbeefL);
-        assertEquals("incorrect valueOf", id, IntentId.valueOf(id.toString()));
+        assertEquals("incorrect valueOf", id, IntentId.valueOf(0xdeadbeefL));
     }
 
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/IntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/IntentTest.java
index a6cedf9..084017b 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/IntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/IntentTest.java
@@ -1,14 +1,12 @@
 package org.onlab.onos.net.intent;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.junit.Test;
+import static org.junit.Assert.*;
 
 /**
  * Base facilities to test various intent tests.
@@ -33,11 +31,7 @@
 
         assertTrue("should be equal", one.equals(like));
         assertEquals("incorrect hashCode", one.hashCode(), like.hashCode());
-
         assertFalse("should not be equal", one.equals(another));
-
-        assertFalse("should not be equal", one.equals(null));
-        assertFalse("should not be equal", one.equals("foo"));
     }
 
     @Test
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntentTest.java
index 66d294a..83bec15 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/MultiPointToSinglePointIntentTest.java
@@ -12,7 +12,7 @@
     @Test
     public void basics() {
         MultiPointToSinglePointIntent intent = createOne();
-        assertEquals("incorrect id", IID, intent.id());
+        assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
         assertEquals("incorrect ingress", PS1, intent.ingressPoints());
         assertEquals("incorrect egress", P2, intent.egressPoint());
@@ -20,11 +20,11 @@
 
     @Override
     protected MultiPointToSinglePointIntent createOne() {
-        return new MultiPointToSinglePointIntent(IID, MATCH, NOP, PS1, P2);
+        return new MultiPointToSinglePointIntent(APPID, MATCH, NOP, PS1, P2);
     }
 
     @Override
     protected MultiPointToSinglePointIntent createAnother() {
-        return new MultiPointToSinglePointIntent(IID, MATCH, NOP, PS2, P1);
+        return new MultiPointToSinglePointIntent(APPID, MATCH, NOP, PS2, P1);
     }
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
index 7c15c37..715c998 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/PathIntentTest.java
@@ -16,21 +16,19 @@
     @Test
     public void basics() {
         PathIntent intent = createOne();
-        assertEquals("incorrect id", IID, intent.id());
+        assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
         assertEquals("incorrect action", NOP, intent.treatment());
-        assertEquals("incorrect ingress", P1, intent.ingressPoint());
-        assertEquals("incorrect egress", P2, intent.egressPoint());
         assertEquals("incorrect path", PATH1, intent.path());
     }
 
     @Override
     protected PathIntent createOne() {
-        return new PathIntent(IID, MATCH, NOP, P1, P2, PATH1);
+        return new PathIntent(APPID, MATCH, NOP, PATH1);
     }
 
     @Override
     protected PathIntent createAnother() {
-        return new PathIntent(IID, MATCH, NOP, P1, P3, PATH2);
+        return new PathIntent(APPID, MATCH, NOP, PATH2);
     }
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/PointToPointIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/PointToPointIntentTest.java
index e0c5562..9fbc255 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/PointToPointIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/PointToPointIntentTest.java
@@ -12,7 +12,7 @@
     @Test
     public void basics() {
         PointToPointIntent intent = createOne();
-        assertEquals("incorrect id", IID, intent.id());
+        assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
         assertEquals("incorrect ingress", P1, intent.ingressPoint());
         assertEquals("incorrect egress", P2, intent.egressPoint());
@@ -20,11 +20,11 @@
 
     @Override
     protected PointToPointIntent createOne() {
-        return new PointToPointIntent(IID, MATCH, NOP, P1, P2);
+        return new PointToPointIntent(APPID, MATCH, NOP, P1, P2);
     }
 
     @Override
     protected PointToPointIntent createAnother() {
-        return new PointToPointIntent(IID, MATCH, NOP, P2, P1);
+        return new PointToPointIntent(APPID, MATCH, NOP, P2, P1);
     }
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntentTest.java b/core/api/src/test/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntentTest.java
index 64c9292..a1c68ee 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntentTest.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/SinglePointToMultiPointIntentTest.java
@@ -12,7 +12,7 @@
     @Test
     public void basics() {
         SinglePointToMultiPointIntent intent = createOne();
-        assertEquals("incorrect id", IID, intent.id());
+        assertEquals("incorrect id", APPID, intent.appId());
         assertEquals("incorrect match", MATCH, intent.selector());
         assertEquals("incorrect ingress", P1, intent.ingressPoint());
         assertEquals("incorrect egress", PS2, intent.egressPoints());
@@ -20,11 +20,11 @@
 
     @Override
     protected SinglePointToMultiPointIntent createOne() {
-        return new SinglePointToMultiPointIntent(IID, MATCH, NOP, P1, PS2);
+        return new SinglePointToMultiPointIntent(APPID, MATCH, NOP, P1, PS2);
     }
 
     @Override
     protected SinglePointToMultiPointIntent createAnother() {
-        return new SinglePointToMultiPointIntent(IID, MATCH, NOP, P2, PS1);
+        return new SinglePointToMultiPointIntent(APPID, MATCH, NOP, P2, PS1);
     }
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/TestInstallableIntent.java b/core/api/src/test/java/org/onlab/onos/net/intent/TestInstallableIntent.java
index 3265925..9476190 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/TestInstallableIntent.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/TestInstallableIntent.java
@@ -1,25 +1,18 @@
 package org.onlab.onos.net.intent;
-//TODO is this the right package?
 
-import org.onlab.onos.net.Link;
-
-import java.util.Collection;
+import org.onlab.onos.TestApplicationId;
 
 /**
  * An installable intent used in the unit test.
- *
- * FIXME: we don't want to expose this class publicly, but the current Kryo
- * serialization mechanism does not allow this class to be private and placed
- * on testing directory.
  */
-public class TestInstallableIntent extends AbstractIntent implements InstallableIntent {
+public class TestInstallableIntent extends Intent {
     /**
      * Constructs an instance with the specified intent ID.
      *
      * @param id intent ID
      */
     public TestInstallableIntent(IntentId id) {
-        super(id);
+        super(id, new TestApplicationId("foo"), null);
     }
 
     /**
@@ -30,7 +23,8 @@
     }
 
     @Override
-    public Collection<Link> requiredLinks() {
-        return null;
+    public boolean isInstallable() {
+        return true;
     }
+
 }
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/TestIntent.java b/core/api/src/test/java/org/onlab/onos/net/intent/TestIntent.java
index 2f30727..a9d1656 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/TestIntent.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/TestIntent.java
@@ -1,21 +1,18 @@
 package org.onlab.onos.net.intent;
-//TODO is this the right package?
+
+import org.onlab.onos.TestApplicationId;
 
 /**
  * An intent used in the unit test.
- *
- * FIXME: we don't want to expose this class publicly, but the current Kryo
- * serialization mechanism does not allow this class to be private and placed
- * on testing directory.
  */
-public class TestIntent extends AbstractIntent {
+public class TestIntent extends Intent {
     /**
      * Constructs an instance with the specified intent ID.
      *
      * @param id intent ID
      */
     public TestIntent(IntentId id) {
-        super(id);
+        super(id, new TestApplicationId("foo"), null);
     }
 
     /**
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassInstallableIntent.java b/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassInstallableIntent.java
index 40765c2..bfeb985 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassInstallableIntent.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassInstallableIntent.java
@@ -1,14 +1,9 @@
 package org.onlab.onos.net.intent;
-//TODO is this the right package?
 
 /**
  * An intent used in the unit test.
- *
- * FIXME: we don't want to expose this class publicly, but the current Kryo
- * serialization mechanism does not allow this class to be private and placed
- * on testing directory.
  */
-public class TestSubclassInstallableIntent extends TestInstallableIntent implements InstallableIntent {
+public class TestSubclassInstallableIntent extends TestInstallableIntent {
     /**
      * Constructs an instance with the specified intent ID.
      *
diff --git a/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassIntent.java b/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassIntent.java
index 43bb0dd..c8d6996 100644
--- a/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassIntent.java
+++ b/core/api/src/test/java/org/onlab/onos/net/intent/TestSubclassIntent.java
@@ -1,12 +1,7 @@
 package org.onlab.onos.net.intent;
-//TODO is this the right package?
 
 /**
  * An intent used in the unit test.
- *
- * FIXME: we don't want to expose this class publicly, but the current Kryo
- * serialization mechanism does not allow this class to be private and placed
- * on testing directory.
  */
 public class TestSubclassIntent extends TestIntent {
     /**
diff --git a/core/net/src/main/java/org/onlab/onos/impl/CoreManager.java b/core/net/src/main/java/org/onlab/onos/impl/CoreManager.java
index edfc080..da1f8c9 100644
--- a/core/net/src/main/java/org/onlab/onos/impl/CoreManager.java
+++ b/core/net/src/main/java/org/onlab/onos/impl/CoreManager.java
@@ -27,6 +27,7 @@
     private static Version version = Version.version("1.0.0-SNAPSHOT");
 
     private final Map<Short, DefaultApplicationId> appIds = new ConcurrentHashMap<>();
+    private final Map<String, DefaultApplicationId> appIdsByName = new ConcurrentHashMap<>();
 
     // TODO: work in progress
 
@@ -50,9 +51,13 @@
 
     @Override
     public ApplicationId registerApplication(String name) {
-        short id = (short) ID_DISPENSER.getAndIncrement();
-        DefaultApplicationId appId = new DefaultApplicationId(id, name);
-        appIds.put(id, appId);
+        DefaultApplicationId appId = appIdsByName.get(name);
+        if (appId == null) {
+            short id = (short) ID_DISPENSER.getAndIncrement();
+            appId = new DefaultApplicationId(id, name);
+            appIds.put(id, appId);
+            appIdsByName.put(name, appId);
+        }
         return appId;
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
index 9ea99c3..525946e 100644
--- a/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
+++ b/core/net/src/main/java/org/onlab/onos/net/flow/impl/FlowRuleManager.java
@@ -104,24 +104,52 @@
     public void applyFlowRules(FlowRule... flowRules) {
         for (int i = 0; i < flowRules.length; i++) {
             FlowRule f = flowRules[i];
-            final Device device = deviceService.getDevice(f.deviceId());
-            final FlowRuleProvider frp = getProvider(device.providerId());
-            store.storeFlowRule(f);
-            frp.applyFlowRule(f);
+            boolean local = store.storeFlowRule(f);
+            if (local) {
+                // TODO: aggregate all local rules and push down once?
+                applyFlowRulesToProviders(f);
+            }
+        }
+    }
+
+    private void applyFlowRulesToProviders(FlowRule... flowRules) {
+        DeviceId did = null;
+        FlowRuleProvider frp = null;
+        for (FlowRule f : flowRules) {
+            if (!f.deviceId().equals(did)) {
+                did = f.deviceId();
+                final Device device = deviceService.getDevice(did);
+                frp = getProvider(device.providerId());
+            }
+            if (frp != null) {
+                frp.applyFlowRule(f);
+            }
         }
     }
 
     @Override
     public void removeFlowRules(FlowRule... flowRules) {
         FlowRule f;
-        FlowRuleProvider frp;
-        Device device;
         for (int i = 0; i < flowRules.length; i++) {
             f = flowRules[i];
-            device = deviceService.getDevice(f.deviceId());
-            store.deleteFlowRule(f);
-            if (device != null) {
+            boolean local = store.deleteFlowRule(f);
+            if (local) {
+                // TODO: aggregate all local rules and push down once?
+                removeFlowRulesFromProviders(f);
+            }
+        }
+    }
+
+    private void removeFlowRulesFromProviders(FlowRule... flowRules) {
+        DeviceId did = null;
+        FlowRuleProvider frp = null;
+        for (FlowRule f : flowRules) {
+            if (!f.deviceId().equals(did)) {
+                did = f.deviceId();
+                final Device device = deviceService.getDevice(did);
                 frp = getProvider(device.providerId());
+            }
+            if (frp != null) {
                 frp.removeFlowRule(f);
             }
         }
@@ -135,8 +163,11 @@
 
         for (FlowRule f : rules) {
             store.deleteFlowRule(f);
+            // FIXME: only accept request and push to provider on internal event
             device = deviceService.getDevice(f.deviceId());
             frp = getProvider(device.providerId());
+            // FIXME: flows removed from store and flows removed from might diverge
+            //        get rid of #removeRulesById?
             frp.removeRulesById(id, f);
         }
     }
@@ -352,7 +383,23 @@
     private class InternalStoreDelegate implements FlowRuleStoreDelegate {
         @Override
         public void notify(FlowRuleEvent event) {
-            eventDispatcher.post(event);
+            switch (event.type()) {
+            case RULE_ADD_REQUESTED:
+                applyFlowRulesToProviders(event.subject());
+                break;
+            case RULE_REMOVE_REQUESTED:
+                removeFlowRulesFromProviders(event.subject());
+                break;
+
+            case RULE_ADDED:
+            case RULE_REMOVED:
+            case RULE_UPDATED:
+                // only dispatch events related to switch
+                eventDispatcher.post(event);
+                break;
+            default:
+                break;
+            }
         }
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java
deleted file mode 100644
index 00b64da..0000000
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/AbstractBlockAllocatorBasedIdGenerator.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.onlab.onos.net.intent.impl;
-
-import org.onlab.onos.net.intent.IdGenerator;
-
-/**
- * Base class of {@link IdGenerator} implementations which use {@link IdBlockAllocator} as
- * backend.
- *
- * @param <T> the type of ID
- */
-public abstract class AbstractBlockAllocatorBasedIdGenerator<T> implements IdGenerator<T> {
-    protected final IdBlockAllocator allocator;
-    protected IdBlock idBlock;
-
-    /**
-     * Constructs an ID generator which use {@link IdBlockAllocator} as backend.
-     *
-     * @param allocator
-     */
-    protected AbstractBlockAllocatorBasedIdGenerator(IdBlockAllocator allocator) {
-        this.allocator = allocator;
-        this.idBlock = allocator.allocateUniqueIdBlock();
-    }
-
-    @Override
-    public synchronized T getNewId() {
-        try {
-            return convertFrom(idBlock.getNextId());
-        } catch (UnavailableIdException e) {
-            idBlock = allocator.allocateUniqueIdBlock();
-            return convertFrom(idBlock.getNextId());
-        }
-    }
-
-    /**
-     * Returns an ID instance of {@code T} type from the long value.
-     *
-     * @param value original long value
-     * @return ID instance
-     */
-    protected abstract T convertFrom(long value);
-}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java
deleted file mode 100644
index f331aa2..0000000
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/DummyIdBlockAllocator.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.onlab.onos.net.intent.impl;
-
-public class DummyIdBlockAllocator implements IdBlockAllocator {
-    private long blockTop;
-    private static final long BLOCK_SIZE = 0x1000000L;
-
-    /**
-     * Returns a block of IDs which are unique and unused.
-     * Range of IDs is fixed size and is assigned incrementally as this method
-     * called.
-     *
-     * @return an IdBlock containing a set of unique IDs
-     */
-    @Override
-    public IdBlock allocateUniqueIdBlock() {
-        synchronized (this)  {
-            long blockHead = blockTop;
-            long blockTail = blockTop + BLOCK_SIZE;
-
-            IdBlock block = new IdBlock(blockHead, BLOCK_SIZE);
-            blockTop = blockTail;
-
-            return block;
-        }
-    }
-
-    @Override
-    public IdBlock allocateUniqueIdBlock(long range) {
-        throw new UnsupportedOperationException("Not supported yet");
-    }
-}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
index 50faf38..e769982 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/HostToHostIntentCompiler.java
@@ -11,11 +11,9 @@
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.intent.HostToHostIntent;
-import org.onlab.onos.net.intent.IdGenerator;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentCompiler;
 import org.onlab.onos.net.intent.IntentExtensionService;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.topology.PathService;
 
@@ -41,12 +39,8 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
-    protected IdGenerator<IntentId> intentIdGenerator;
-
     @Activate
     public void activate() {
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         intentManager.registerCompiler(HostToHostIntent.class, this);
     }
 
@@ -70,13 +64,10 @@
     // Creates a path intent from the specified path and original connectivity intent.
     private Intent createPathIntent(Path path, Host src, Host dst,
                                     HostToHostIntent intent) {
-
         TrafficSelector selector = builder(intent.selector())
                 .matchEthSrc(src.mac()).matchEthDst(dst.mac()).build();
-
-        return new PathIntent(intentIdGenerator.getNewId(),
-                              selector, intent.treatment(),
-                              path.src(), path.dst(), path);
+        return new PathIntent(intent.appId(), selector, intent.treatment(),
+                              path);
     }
 
     private Path getPath(HostId one, HostId two) {
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java
deleted file mode 100644
index ce418ea..0000000
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlock.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.onlab.onos.net.intent.impl;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.util.Objects;
-import java.util.concurrent.atomic.AtomicLong;
-
-import com.google.common.base.MoreObjects;
-
-/**
- * A class representing an ID space.
- */
-public final class IdBlock {
-    private final long start;
-    private final long size;
-
-    private final AtomicLong currentId;
-
-    /**
-     * Constructs a new ID block with the specified size and initial value.
-     *
-     * @param start initial value of the block
-     * @param size size of the block
-     * @throws IllegalArgumentException if the size is less than or equal to 0
-     */
-    public IdBlock(long start, long size) {
-        checkArgument(size > 0, "size should be more than 0, but %s", size);
-
-        this.start = start;
-        this.size = size;
-
-        this.currentId = new AtomicLong(start);
-    }
-
-    // TODO: consider if this method is needed or not
-    /**
-     * Returns the initial value.
-     *
-     * @return initial value
-     */
-    public long getStart() {
-        return start;
-    }
-
-    // TODO: consider if this method is needed or not
-    /**
-     * Returns the last value.
-     *
-     * @return last value
-     */
-    public long getEnd() {
-        return start + size - 1;
-    }
-
-    /**
-     * Returns the block size.
-     *
-     * @return block size
-     */
-    public long getSize() {
-        return size;
-    }
-
-    /**
-     * Returns the next ID in the block.
-     *
-     * @return next ID
-     * @throws UnavailableIdException if there is no available ID in the block.
-     */
-    public long getNextId() {
-        final long id = currentId.getAndIncrement();
-        if (id > getEnd()) {
-            throw new UnavailableIdException(String.format(
-                    "used all IDs in allocated space (size: %d, end: %d, current: %d)",
-                    size, getEnd(), id
-            ));
-        }
-
-        return id;
-    }
-
-    // TODO: Do we really need equals and hashCode? Should it contain currentId?
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        IdBlock that = (IdBlock) o;
-        return Objects.equals(this.start, that.start)
-                && Objects.equals(this.size, that.size)
-                && Objects.equals(this.currentId.get(), that.currentId.get());
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(start, size, currentId);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(getClass())
-                .add("start", start)
-                .add("size", size)
-                .add("currentId", currentId)
-                .toString();
-    }
-}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java
deleted file mode 100644
index 1adac02..0000000
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocator.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package org.onlab.onos.net.intent.impl;
-
-/**
- * An interface that gives unique ID spaces.
- */
-public interface IdBlockAllocator {
-    /**
-     * Allocates a unique Id Block.
-     *
-     * @return Id Block.
-     */
-    IdBlock allocateUniqueIdBlock();
-
-    /**
-     * Allocates next unique id and retrieve a new range of ids if needed.
-     *
-     * @param range range to use for the identifier
-     * @return Id Block.
-     */
-    IdBlock allocateUniqueIdBlock(long range);
-}
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java
deleted file mode 100644
index 9620e59..0000000
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/IdBlockAllocatorBasedIntentIdGenerator.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.onlab.onos.net.intent.impl;
-
-import org.onlab.onos.net.intent.IntentId;
-
-/**
- * An implementation of {@link org.onlab.onos.net.intent.IdGenerator} of intent ID,
- * which uses {@link IdBlockAllocator}.
- */
-public class IdBlockAllocatorBasedIntentIdGenerator extends AbstractBlockAllocatorBasedIdGenerator<IntentId> {
-
-    /**
-     * Constructs an intent ID generator, which uses the specified ID block allocator
-     * to generate a global unique intent ID.
-     *
-     * @param allocator the ID block allocator to use for generating intent IDs
-     */
-    public IdBlockAllocatorBasedIntentIdGenerator(IdBlockAllocator allocator) {
-        super(allocator);
-    }
-
-    @Override
-    protected IntentId convertFrom(long value) {
-        return new IntentId(value);
-    }
-}
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 ff1e948..03d5ce8 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
@@ -1,30 +1,8 @@
 package org.onlab.onos.net.intent.impl;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static org.onlab.onos.net.intent.IntentState.COMPILING;
-import static org.onlab.onos.net.intent.IntentState.FAILED;
-import static org.onlab.onos.net.intent.IntentState.INSTALLED;
-import static org.onlab.onos.net.intent.IntentState.INSTALLING;
-import static org.onlab.onos.net.intent.IntentState.RECOMPILING;
-import static org.onlab.onos.net.intent.IntentState.WITHDRAWING;
-import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
-import static org.onlab.util.Tools.namedThreads;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -36,7 +14,6 @@
 import org.onlab.onos.net.flow.CompletedBatchOperation;
 import org.onlab.onos.net.flow.FlowRuleBatchOperation;
 import org.onlab.onos.net.flow.FlowRuleService;
-import org.onlab.onos.net.intent.InstallableIntent;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentCompiler;
 import org.onlab.onos.net.intent.IntentEvent;
@@ -52,9 +29,24 @@
 import org.onlab.onos.net.intent.IntentStoreDelegate;
 import org.slf4j.Logger;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import static org.onlab.onos.net.intent.IntentState.*;
+import static org.onlab.util.Tools.namedThreads;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * An implementation of Intent Manager.
@@ -71,8 +63,8 @@
     // Collections for compiler, installer, and listener are ONOS instance local
     private final ConcurrentMap<Class<? extends Intent>,
             IntentCompiler<? extends Intent>> compilers = new ConcurrentHashMap<>();
-    private final ConcurrentMap<Class<? extends InstallableIntent>,
-            IntentInstaller<? extends InstallableIntent>> installers = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Class<? extends Intent>,
+            IntentInstaller<? extends Intent>> installers = new ConcurrentHashMap<>();
 
     private final AbstractListenerRegistry<IntentEvent, IntentListener>
             listenerRegistry = new AbstractListenerRegistry<>();
@@ -186,17 +178,17 @@
     }
 
     @Override
-    public <T extends InstallableIntent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
+    public <T extends Intent> void registerInstaller(Class<T> cls, IntentInstaller<T> installer) {
         installers.put(cls, installer);
     }
 
     @Override
-    public <T extends InstallableIntent> void unregisterInstaller(Class<T> cls) {
+    public <T extends Intent> void unregisterInstaller(Class<T> cls) {
         installers.remove(cls);
     }
 
     @Override
-    public Map<Class<? extends InstallableIntent>, IntentInstaller<? extends InstallableIntent>> getInstallers() {
+    public Map<Class<? extends Intent>, IntentInstaller<? extends Intent>> getInstallers() {
         return ImmutableMap.copyOf(installers);
     }
 
@@ -223,7 +215,7 @@
      * @param <T>    the type of installable intent
      * @return intent installer corresponding to the specified installable intent
      */
-    private <T extends InstallableIntent> IntentInstaller<T> getInstaller(T intent) {
+    private <T extends Intent> IntentInstaller<T> getInstaller(T intent) {
         @SuppressWarnings("unchecked")
         IntentInstaller<T> installer = (IntentInstaller<T>) installers.get(intent.getClass());
         if (installer == null) {
@@ -243,7 +235,7 @@
 
         try {
             // Compile the intent into installable derivatives.
-            List<InstallableIntent> installable = compileIntent(intent);
+            List<Intent> installable = compileIntent(intent);
 
             // If all went well, associate the resulting list of installable
             // intents with the top-level intent and proceed to install.
@@ -264,12 +256,12 @@
      * @param intent intent
      * @return result of compilation
      */
-    private List<InstallableIntent> compileIntent(Intent intent) {
-        if (intent instanceof InstallableIntent) {
-            return ImmutableList.of((InstallableIntent) intent);
+    private List<Intent> compileIntent(Intent intent) {
+        if (intent.isInstallable()) {
+            return ImmutableList.of(intent);
         }
 
-        List<InstallableIntent> installable = new ArrayList<>();
+        List<Intent> installable = new ArrayList<>();
         // TODO do we need to registerSubclassCompiler?
         for (Intent compiled : getCompiler(intent).compile(intent)) {
             installable.addAll(compileIntent(compiled));
@@ -290,12 +282,12 @@
 
         List<FlowRuleBatchOperation> installWork = Lists.newArrayList();
         try {
-            List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
+            List<Intent> installables = store.getInstallableIntents(intent.id());
             if (installables != null) {
-                for (InstallableIntent installable : installables) {
+                for (Intent installable : installables) {
                     registerSubclassInstallerIfNeeded(installable);
                     trackerService.addTrackedResources(intent.id(),
-                                                       installable.requiredLinks());
+                                                       installable.resources());
                     List<FlowRuleBatchOperation> batch = getInstaller(installable).install(installable);
                     installWork.addAll(batch);
                 }
@@ -324,14 +316,13 @@
 
         try {
             // Compile the intent into installable derivatives.
-            List<InstallableIntent> installable = compileIntent(intent);
+            List<Intent> installable = compileIntent(intent);
 
             // If all went well, compare the existing list of installable
             // intents with the newly compiled list. If they are the same,
             // bail, out since the previous approach was determined not to
             // be viable.
-            List<InstallableIntent> originalInstallable =
-                    store.getInstallableIntents(intent.id());
+            List<Intent> originalInstallable = store.getInstallableIntents(intent.id());
 
             if (Objects.equals(originalInstallable, installable)) {
                 eventDispatcher.post(store.setState(intent, FAILED));
@@ -376,9 +367,9 @@
     private void uninstallIntent(Intent intent, IntentState nextState) {
         List<FlowRuleBatchOperation> uninstallWork = Lists.newArrayList();
         try {
-            List<InstallableIntent> installables = store.getInstallableIntents(intent.id());
+            List<Intent> installables = store.getInstallableIntents(intent.id());
             if (installables != null) {
-                for (InstallableIntent installable : installables) {
+                for (Intent installable : installables) {
                     List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
                     uninstallWork.addAll(batches);
                 }
@@ -422,12 +413,12 @@
      *
      * @param intent intent
      */
-    private void registerSubclassInstallerIfNeeded(InstallableIntent intent) {
+    private void registerSubclassInstallerIfNeeded(Intent intent) {
         if (!installers.containsKey(intent.getClass())) {
             Class<?> cls = intent.getClass();
             while (cls != Object.class) {
-                // As long as we're within the InstallableIntent class descendants
-                if (InstallableIntent.class.isAssignableFrom(cls)) {
+                // As long as we're within the Intent class descendants
+                if (Intent.class.isAssignableFrom(cls)) {
                     IntentInstaller<?> installer = installers.get(cls);
                     if (installer != null) {
                         installers.put(intent.getClass(), installer);
@@ -505,8 +496,8 @@
         private final IntentState nextState;
 
         public IntentInstallMonitor(Intent intent,
-                List<FlowRuleBatchOperation> work,
-                IntentState nextState) {
+                                    List<FlowRuleBatchOperation> work,
+                                    IntentState nextState) {
             this.intent = intent;
             this.work = work;
             // TODO how many Futures can be outstanding? one?
@@ -531,9 +522,7 @@
         }
 
         /**
-         * Apply a list of FlowRules.
-         *
-         * @param rules rules to apply
+         * Applies the next batch.
          */
         private Future<CompletedBatchOperation> applyNextBatch() {
             if (work.isEmpty()) {
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java
index 6ce12d6..cfc8d73 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/MultiPointToSinglePointIntentCompiler.java
@@ -1,10 +1,5 @@
 package org.onlab.onos.net.intent.impl;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -13,16 +8,19 @@
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.Path;
-import org.onlab.onos.net.intent.IdGenerator;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentCompiler;
 import org.onlab.onos.net.intent.IntentExtensionService;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.LinkCollectionIntent;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.net.topology.PathService;
 
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 /**
  * An intent compiler for
  * {@link org.onlab.onos.net.intent.MultiPointToSinglePointIntent}.
@@ -37,12 +35,8 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected PathService pathService;
 
-    protected IdGenerator<IntentId> intentIdGenerator;
-
     @Activate
     public void activate() {
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         intentManager.registerCompiler(MultiPointToSinglePointIntent.class, this);
     }
 
@@ -60,9 +54,9 @@
             links.addAll(path.links());
         }
 
-        Intent result = new LinkCollectionIntent(intentIdGenerator.getNewId(),
-                intent.selector(), intent.treatment(),
-                links, intent.egressPoint());
+        Intent result = new LinkCollectionIntent(intent.appId(),
+                                                 intent.selector(), intent.treatment(),
+                                                 links, intent.egressPoint());
         return Arrays.asList(result);
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
index 7ba4e26..90e878e 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTracker.java
@@ -11,6 +11,7 @@
 import org.onlab.onos.event.Event;
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.LinkKey;
+import org.onlab.onos.net.NetworkResource;
 import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.link.LinkEvent;
 import org.onlab.onos.net.topology.TopologyEvent;
@@ -27,8 +28,8 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
 import static org.onlab.onos.net.LinkKey.linkKey;
+import static org.onlab.onos.net.link.LinkEvent.Type.LINK_REMOVED;
 import static org.onlab.util.Tools.namedThreads;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -81,16 +82,22 @@
     }
 
     @Override
-    public void addTrackedResources(IntentId intentId, Collection<Link> resources) {
-        for (Link link : resources) {
-            intentsByLink.put(linkKey(link), intentId);
+    public void addTrackedResources(IntentId intentId,
+                                    Collection<NetworkResource> resources) {
+        for (NetworkResource resource : resources) {
+            if (resource instanceof Link) {
+                intentsByLink.put(linkKey((Link) resource), intentId);
+            }
         }
     }
 
     @Override
-    public void removeTrackedResources(IntentId intentId, Collection<Link> resources) {
-        for (Link link : resources) {
-            intentsByLink.remove(linkKey(link), intentId);
+    public void removeTrackedResources(IntentId intentId,
+                                       Collection<NetworkResource> resources) {
+        for (NetworkResource resource : resources) {
+            if (resource instanceof Link) {
+                intentsByLink.remove(linkKey((Link) resource), intentId);
+            }
         }
     }
 
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
index 15496ff..9acd215 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/ObjectiveTrackerService.java
@@ -1,6 +1,6 @@
 package org.onlab.onos.net.intent.impl;
 
-import org.onlab.onos.net.Link;
+import org.onlab.onos.net.NetworkResource;
 import org.onlab.onos.net.intent.IntentId;
 
 import java.util.Collection;
@@ -28,17 +28,19 @@
     /**
      * Adds a path flow to be tracked.
      *
-     * @param intentId intent identity on whose behalf the path is being tracked
+     * @param intentId  intent identity on whose behalf the path is being tracked
      * @param resources resources to track
      */
-    public void addTrackedResources(IntentId intentId, Collection<Link> resources);
+    public void addTrackedResources(IntentId intentId,
+                                    Collection<NetworkResource> resources);
 
     /**
      * Removes a path flow to be tracked.
      *
-     * @param intentId intent identity on whose behalf the path is being tracked
+     * @param intentId  intent identity on whose behalf the path is being tracked
      * @param resources resources to stop tracking
      */
-    public void removeTrackedResources(IntentId intentId, Collection<Link> resources);
+    public void removeTrackedResources(IntentId intentId,
+                                       Collection<NetworkResource> resources);
 
 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
index 0556df0..25d50cc 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/PointToPointIntentCompiler.java
@@ -1,10 +1,5 @@
 package org.onlab.onos.net.intent.impl;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -16,16 +11,19 @@
 import org.onlab.onos.net.Link;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.host.HostService;
-import org.onlab.onos.net.intent.IdGenerator;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentCompiler;
 import org.onlab.onos.net.intent.IntentExtensionService;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.net.topology.PathService;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
 /**
  * A intent compiler for {@link org.onlab.onos.net.intent.HostToHostIntent}.
  */
@@ -43,12 +41,8 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected HostService hostService;
 
-    protected IdGenerator<IntentId> intentIdGenerator;
-
     @Activate
     public void activate() {
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        intentIdGenerator = new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         intentManager.registerCompiler(PointToPointIntent.class, this);
     }
 
@@ -67,23 +61,21 @@
         links.add(DefaultEdgeLink.createEdgeLink(intent.egressPoint(), false));
 
         return Arrays.asList(createPathIntent(new DefaultPath(PID, links, path.cost() + 2,
-                                              path.annotations()),
-                             intent));
+                                                              path.annotations()),
+                                              intent));
     }
 
     /**
      * Creates a path intent from the specified path and original
      * connectivity intent.
      *
-     * @param path path to create an intent for
+     * @param path   path to create an intent for
      * @param intent original intent
      */
     private Intent createPathIntent(Path path,
                                     PointToPointIntent intent) {
-
-        return new PathIntent(intentIdGenerator.getNewId(),
-                              intent.selector(), intent.treatment(),
-                              path.src(), path.dst(), path);
+        return new PathIntent(intent.appId(),
+                              intent.selector(), intent.treatment(), path);
     }
 
     /**
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/TestHostToHostIntent.java b/core/net/src/test/java/org/onlab/onos/net/intent/TestHostToHostIntent.java
index f5e2551..4ebee73 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/TestHostToHostIntent.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/TestHostToHostIntent.java
@@ -1,6 +1,8 @@
 package org.onlab.onos.net.intent;
 
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
@@ -16,15 +18,13 @@
  */
 public class TestHostToHostIntent {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
-    private HostToHostIntent makeHostToHost(long id, HostId one, HostId two) {
-        return new HostToHostIntent(new IntentId(id),
-                                    one,
-                                    two,
-                                    selector,
-                                    treatment);
+    private HostToHostIntent makeHostToHost(HostId one, HostId two) {
+        return new HostToHostIntent(APPID, one, two, selector, treatment);
     }
 
     /**
@@ -36,8 +36,8 @@
 
         HostId one = hid("00:00:00:00:00:01/-1");
         HostId two = hid("00:00:00:00:00:02/-1");
-        HostToHostIntent i1 = makeHostToHost(12, one, two);
-        HostToHostIntent i2 = makeHostToHost(12, one, two);
+        HostToHostIntent i1 = makeHostToHost(one, two);
+        HostToHostIntent i2 = makeHostToHost(one, two);
 
         assertThat(i1, is(equalTo(i2)));
     }
@@ -47,42 +47,25 @@
      * to different Hosts. These should compare not equal.
      */
     @Test
-    public void testLinksDifferentEquals() {
-
+    public void testSameEquals2() {
         HostId one = hid("00:00:00:00:00:01/-1");
         HostId two = hid("00:00:00:00:00:02/-1");
-        HostToHostIntent i1 = makeHostToHost(12, one, two);
-        HostToHostIntent i2 = makeHostToHost(12, two, one);
+        HostToHostIntent i1 = makeHostToHost(one, two);
+        HostToHostIntent i2 = makeHostToHost(two, one);
 
-        assertThat(i1, is(not(equalTo(i2))));
-    }
-
-    /**
-     * Tests the equals() method where two HostToHostIntents have different
-     * ids. These should compare not equal.
-     */
-
-    @Test
-    public void testBaseDifferentEquals() {
-        HostId one = hid("00:00:00:00:00:01/-1");
-        HostId two = hid("00:00:00:00:00:02/-1");
-        HostToHostIntent i1 = makeHostToHost(12, one, two);
-        HostToHostIntent i2 = makeHostToHost(11, one, two);
-
-        assertThat(i1, is(not(equalTo(i2))));
+        assertThat(i1, is(equalTo(i2)));
     }
 
     /**
      * Tests that the hashCode() values for two equivalent HostToHostIntent
      * objects are the same.
      */
-
     @Test
     public void testHashCodeEquals() {
         HostId one = hid("00:00:00:00:00:01/-1");
         HostId two = hid("00:00:00:00:00:02/-1");
-        HostToHostIntent i1 = makeHostToHost(12, one, two);
-        HostToHostIntent i2 = makeHostToHost(12, one, two);
+        HostToHostIntent i1 = makeHostToHost(one, two);
+        HostToHostIntent i2 = makeHostToHost(one, two);
 
         assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
     }
@@ -91,13 +74,27 @@
      * Tests that the hashCode() values for two distinct LinkCollectionIntent
      * objects are different.
      */
+    @Test
+    public void testHashCodeEquals2() {
+        HostId one = hid("00:00:00:00:00:01/-1");
+        HostId two = hid("00:00:00:00:00:02/-1");
+        HostToHostIntent i1 = makeHostToHost(one, two);
+        HostToHostIntent i2 = makeHostToHost(two, one);
 
+        assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
+    }
+
+    /**
+     * Tests that the hashCode() values for two distinct LinkCollectionIntent
+     * objects are different.
+     */
     @Test
     public void testHashCodeDifferent() {
         HostId one = hid("00:00:00:00:00:01/-1");
         HostId two = hid("00:00:00:00:00:02/-1");
-        HostToHostIntent i1 = makeHostToHost(12, one, two);
-        HostToHostIntent i2 = makeHostToHost(112, one, two);
+        HostId three = hid("00:00:00:00:00:32/-1");
+        HostToHostIntent i1 = makeHostToHost(one, two);
+        HostToHostIntent i2 = makeHostToHost(one, three);
 
         assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode()))));
     }
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/TestLinkCollectionIntent.java b/core/net/src/test/java/org/onlab/onos/net/intent/TestLinkCollectionIntent.java
index a7082b4..65aa71f 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/TestLinkCollectionIntent.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/TestLinkCollectionIntent.java
@@ -11,6 +11,8 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.Link;
@@ -23,6 +25,8 @@
  */
 public class TestLinkCollectionIntent {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private Link link1 = link("dev1", 1, "dev2", 2);
     private Link link2 = link("dev1", 1, "dev3", 2);
     private Link link3 = link("dev2", 1, "dev3", 2);
@@ -38,10 +42,9 @@
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
-    private LinkCollectionIntent makeLinkCollection(long id, Set<Link> links,
+    private LinkCollectionIntent makeLinkCollection(Set<Link> links,
             ConnectPoint egress) {
-        return new LinkCollectionIntent(new IntentId(id),
-                                        selector, treatment, links, egress);
+        return new LinkCollectionIntent(APPID, selector, treatment, links, egress);
     }
 
     @Before
@@ -64,8 +67,8 @@
         links2.add(link2);
         links2.add(link1);
 
-        LinkCollectionIntent i1 = makeLinkCollection(12, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(12, links2, egress1);
+        LinkCollectionIntent i1 = makeLinkCollection(links1, egress1);
+        LinkCollectionIntent i2 = makeLinkCollection(links2, egress1);
 
         assertThat(i1, is(equalTo(i2)));
     }
@@ -82,8 +85,8 @@
         links2.add(link3);
         links2.add(link1);
 
-        LinkCollectionIntent i1 = makeLinkCollection(12, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(12, links2, egress1);
+        LinkCollectionIntent i1 = makeLinkCollection(links1, egress1);
+        LinkCollectionIntent i2 = makeLinkCollection(links2, egress1);
 
         assertThat(i1, is(not(equalTo(i2))));
     }
@@ -102,26 +105,8 @@
         links2.add(link2);
         links2.add(link1);
 
-        LinkCollectionIntent i1 = makeLinkCollection(12, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(12, links2, egress2);
-
-        assertThat(i1, is(not(equalTo(i2))));
-    }
-
-    /**
-     * Tests the equals() method where two LinkCollectionIntents have different
-     * ids. These should compare not equal.
-     */
-    @Test
-    public void testBaseDifferentEquals() {
-        links1.add(link1);
-        links1.add(link2);
-
-        links2.add(link2);
-        links2.add(link1);
-
-        LinkCollectionIntent i1 = makeLinkCollection(1, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(2, links2, egress1);
+        LinkCollectionIntent i1 = makeLinkCollection(links1, egress1);
+        LinkCollectionIntent i2 = makeLinkCollection(links2, egress2);
 
         assertThat(i1, is(not(equalTo(i2))));
     }
@@ -140,8 +125,8 @@
         links2.add(link2);
         links2.add(link1);
 
-        LinkCollectionIntent i1 = makeLinkCollection(1, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(1, links2, egress1);
+        LinkCollectionIntent i1 = makeLinkCollection(links1, egress1);
+        LinkCollectionIntent i2 = makeLinkCollection(links2, egress1);
 
         assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
     }
@@ -158,8 +143,8 @@
         links2.add(link1);
         links2.add(link3);
 
-        LinkCollectionIntent i1 = makeLinkCollection(1, links1, egress1);
-        LinkCollectionIntent i2 = makeLinkCollection(1, links2, egress2);
+        LinkCollectionIntent i1 = makeLinkCollection(links1, egress1);
+        LinkCollectionIntent i2 = makeLinkCollection(links2, egress2);
 
         assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode()))));
     }
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/TestMultiPointToSinglePointIntent.java b/core/net/src/test/java/org/onlab/onos/net/intent/TestMultiPointToSinglePointIntent.java
index e921907..09dfcb2 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/TestMultiPointToSinglePointIntent.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/TestMultiPointToSinglePointIntent.java
@@ -1,14 +1,16 @@
 package org.onlab.onos.net.intent;
 
-import java.util.HashSet;
-import java.util.Set;
-
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
@@ -20,6 +22,8 @@
  */
 public class TestMultiPointToSinglePointIntent {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private ConnectPoint point1 = connectPoint("dev1", 1);
     private ConnectPoint point2 = connectPoint("dev2", 1);
     private ConnectPoint point3 = connectPoint("dev3", 1);
@@ -33,19 +37,14 @@
     /**
      * Creates a MultiPointToSinglePointIntent object.
      *
-     * @param id identifier to use for the new intent
      * @param ingress set of ingress points
-     * @param egress egress point
+     * @param egress  egress point
      * @return MultiPointToSinglePoint intent
      */
-    private MultiPointToSinglePointIntent makeIntent(long id,
-                       Set<ConnectPoint> ingress,
-                       ConnectPoint egress) {
-        return new MultiPointToSinglePointIntent(new IntentId(id),
-                                                 selector,
-                                                 treatment,
-                                                 ingress,
-                                                 egress);
+    private MultiPointToSinglePointIntent makeIntent(Set<ConnectPoint> ingress,
+                                                     ConnectPoint egress) {
+        return new MultiPointToSinglePointIntent(APPID, selector, treatment,
+                                                 ingress, egress);
     }
 
     /**
@@ -72,8 +71,8 @@
         ingress2.add(point3);
         ingress2.add(point2);
 
-        Intent i1 = makeIntent(12, ingress1, point1);
-        Intent i2 = makeIntent(12, ingress2, point1);
+        Intent i1 = makeIntent(ingress1, point1);
+        Intent i2 = makeIntent(ingress2, point1);
 
         assertThat(i1, is(equalTo(i2)));
     }
@@ -89,23 +88,8 @@
         ingress2.add(point3);
         ingress2.add(point2);
 
-        Intent i1 = makeIntent(12, ingress1, point1);
-        Intent i2 = makeIntent(12, ingress2, point1);
-
-        assertThat(i1, is(not(equalTo(i2))));
-    }
-
-    /**
-     * Tests the equals() method where two MultiPointToSinglePoint have different
-     * ids. These should compare not equal.
-     */
-    @Test
-    public void testBaseDifferentEquals() {
-        ingress1.add(point3);
-        ingress2.add(point3);
-
-        Intent i1 = makeIntent(12, ingress1, point1);
-        Intent i2 = makeIntent(11, ingress2, point1);
+        Intent i1 = makeIntent(ingress1, point1);
+        Intent i2 = makeIntent(ingress2, point1);
 
         assertThat(i1, is(not(equalTo(i2))));
     }
@@ -122,8 +106,8 @@
         ingress2.add(point3);
         ingress2.add(point2);
 
-        Intent i1 = makeIntent(12, ingress1, point1);
-        Intent i2 = makeIntent(12, ingress2, point1);
+        Intent i1 = makeIntent(ingress1, point1);
+        Intent i2 = makeIntent(ingress2, point1);
 
         assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
     }
@@ -139,8 +123,8 @@
         ingress2.add(point3);
         ingress2.add(point2);
 
-        Intent i1 = makeIntent(12, ingress1, point1);
-        Intent i2 = makeIntent(12, ingress2, point1);
+        Intent i1 = makeIntent(ingress1, point1);
+        Intent i2 = makeIntent(ingress2, point1);
 
 
         assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode()))));
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/TestPointToPointIntent.java b/core/net/src/test/java/org/onlab/onos/net/intent/TestPointToPointIntent.java
index 41769c6..e34d7ce 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/TestPointToPointIntent.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/TestPointToPointIntent.java
@@ -1,14 +1,14 @@
 package org.onlab.onos.net.intent;
 
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.*;
 import static org.onlab.onos.net.NetTestTools.connectPoint;
 
 /**
@@ -16,20 +16,17 @@
  */
 public class TestPointToPointIntent {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
     private ConnectPoint point1 = connectPoint("dev1", 1);
     private ConnectPoint point2 = connectPoint("dev2", 1);
 
-    private PointToPointIntent makePointToPoint(long id,
-                                                ConnectPoint ingress,
+    private PointToPointIntent makePointToPoint(ConnectPoint ingress,
                                                 ConnectPoint egress) {
-        return new PointToPointIntent(new IntentId(id),
-                                      selector,
-                                      treatment,
-                                      ingress,
-                                      egress);
+        return new PointToPointIntent(APPID, selector, treatment, ingress, egress);
     }
 
     /**
@@ -38,8 +35,8 @@
      */
     @Test
     public void testSameEquals() {
-        PointToPointIntent i1 = makePointToPoint(12, point1, point2);
-        PointToPointIntent i2 = makePointToPoint(12, point1, point2);
+        PointToPointIntent i1 = makePointToPoint(point1, point2);
+        PointToPointIntent i2 = makePointToPoint(point1, point2);
 
         assertThat(i1, is(equalTo(i2)));
     }
@@ -50,22 +47,8 @@
      */
     @Test
     public void testLinksDifferentEquals() {
-
-        PointToPointIntent i1 = makePointToPoint(12, point1, point2);
-        PointToPointIntent i2 = makePointToPoint(12, point2, point1);
-
-        assertThat(i1, is(not(equalTo(i2))));
-    }
-
-    /**
-     * Tests the equals() method where two HostToHostIntents have different
-     * ids. These should compare not equal.
-     */
-    @Test
-    public void testBaseDifferentEquals() {
-        PointToPointIntent i1 = makePointToPoint(12, point1, point2);
-        PointToPointIntent i2 = makePointToPoint(11, point1, point2);
-
+        PointToPointIntent i1 = makePointToPoint(point1, point2);
+        PointToPointIntent i2 = makePointToPoint(point2, point1);
 
         assertThat(i1, is(not(equalTo(i2))));
     }
@@ -76,8 +59,8 @@
      */
     @Test
     public void testHashCodeEquals() {
-        PointToPointIntent i1 = makePointToPoint(12, point1, point2);
-        PointToPointIntent i2 = makePointToPoint(12, point1, point2);
+        PointToPointIntent i1 = makePointToPoint(point1, point2);
+        PointToPointIntent i2 = makePointToPoint(point1, point2);
 
         assertThat(i1.hashCode(), is(equalTo(i2.hashCode())));
     }
@@ -88,8 +71,8 @@
      */
     @Test
     public void testHashCodeDifferent() {
-        PointToPointIntent i1 = makePointToPoint(12, point1, point2);
-        PointToPointIntent i2 = makePointToPoint(22, point1, point2);
+        PointToPointIntent i1 = makePointToPoint(point1, point2);
+        PointToPointIntent i2 = makePointToPoint(point2, point1);
 
         assertThat(i1.hashCode(), is(not(equalTo(i2.hashCode()))));
     }
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java
index bd61b7a..e853a29 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestHostToHostIntentCompiler.java
@@ -1,10 +1,10 @@
 package org.onlab.onos.net.intent.impl;
 
-import java.util.List;
-
 import org.hamcrest.Matchers;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.Host;
 import org.onlab.onos.net.HostId;
 import org.onlab.onos.net.flow.TrafficSelector;
@@ -12,16 +12,14 @@
 import org.onlab.onos.net.host.HostService;
 import org.onlab.onos.net.intent.HostToHostIntent;
 import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentTestsMocks;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.VlanId;
 
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
+import java.util.List;
+
+import static org.easymock.EasyMock.*;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasSize;
@@ -40,6 +38,8 @@
     private static final String HOST_ONE = HOST_ONE_MAC + "/" + HOST_ONE_VLAN;
     private static final String HOST_TWO = HOST_TWO_MAC + "/" + HOST_TWO_VLAN;
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
@@ -73,11 +73,8 @@
      * @return HostToHostIntent for the two hosts
      */
     private HostToHostIntent makeIntent(String oneIdString, String twoIdString) {
-        return new HostToHostIntent(new IntentId(12),
-                                    hid(oneIdString),
-                                    hid(twoIdString),
-                                    selector,
-                                    treatment);
+        return new HostToHostIntent(APPID, hid(oneIdString), hid(twoIdString),
+                                    selector, treatment);
     }
 
     /**
@@ -91,9 +88,6 @@
                 new HostToHostIntentCompiler();
         compiler.pathService = new IntentTestsMocks.MockPathService(hops);
         compiler.hostService = mockHostService;
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        compiler.intentIdGenerator =
-                new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         return compiler;
     }
 
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java
index 8d286cf..1c78e26 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestMultiPointToSinglePointIntentCompiler.java
@@ -1,24 +1,25 @@
 package org.onlab.onos.net.intent.impl;
 
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 import org.hamcrest.Matchers;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.ElementId;
 import org.onlab.onos.net.Path;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentTestsMocks;
 import org.onlab.onos.net.intent.LinkCollectionIntent;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
 import org.onlab.onos.net.topology.LinkWeight;
 import org.onlab.onos.net.topology.PathService;
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasSize;
@@ -32,6 +33,8 @@
  */
 public class TestMultiPointToSinglePointIntentCompiler {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
@@ -74,7 +77,7 @@
      * and an egress point.
      *
      * @param ingressIds array of ingress device ids
-     * @param egressId device id of the egress point
+     * @param egressId   device id of the egress point
      * @return MultiPointToSinglePoint intent
      */
     private MultiPointToSinglePointIntent makeIntent(String[] ingressIds, String egressId) {
@@ -82,15 +85,11 @@
         ConnectPoint egressPoint = connectPoint(egressId, 1);
 
         for (String ingressId : ingressIds) {
-                ingressPoints.add(connectPoint(ingressId, 1));
+            ingressPoints.add(connectPoint(ingressId, 1));
         }
 
-        return new MultiPointToSinglePointIntent(
-                new IntentId(12),
-                selector,
-                treatment,
-                ingressPoints,
-                egressPoint);
+        return new MultiPointToSinglePointIntent(APPID, selector, treatment,
+                                                 ingressPoints, egressPoint);
     }
 
     /**
@@ -103,9 +102,6 @@
         MultiPointToSinglePointIntentCompiler compiler =
                 new MultiPointToSinglePointIntentCompiler();
         compiler.pathService = new MockPathService(hops);
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        compiler.intentIdGenerator =
-                new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         return compiler;
     }
 
@@ -122,7 +118,7 @@
         assertThat(intent, is(notNullValue()));
 
         String[] hops = {"h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8",
-                         egress};
+                egress};
         MultiPointToSinglePointIntentCompiler compiler = makeCompiler(hops);
         assertThat(compiler, is(notNullValue()));
 
@@ -184,7 +180,7 @@
     @Test
     public void testMultiIngressCompilation() {
         String[] ingress = {"i1", "i2", "i3", "i4", "i5",
-                            "i6", "i7", "i8", "i9", "i10"};
+                "i6", "i7", "i8", "i9", "i10"};
         String egress = "e";
 
         MultiPointToSinglePointIntent intent = makeIntent(ingress, egress);
diff --git a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java
index e282347..5b50a22 100644
--- a/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java
+++ b/core/net/src/test/java/org/onlab/onos/net/intent/impl/TestPointToPointIntentCompiler.java
@@ -1,17 +1,18 @@
 package org.onlab.onos.net.intent.impl;
 
-import java.util.List;
-
 import org.hamcrest.Matchers;
 import org.junit.Test;
+import org.onlab.onos.ApplicationId;
+import org.onlab.onos.TestApplicationId;
 import org.onlab.onos.net.flow.TrafficSelector;
 import org.onlab.onos.net.flow.TrafficTreatment;
 import org.onlab.onos.net.intent.Intent;
-import org.onlab.onos.net.intent.IntentId;
 import org.onlab.onos.net.intent.IntentTestsMocks;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.intent.PointToPointIntent;
 
+import java.util.List;
+
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasSize;
@@ -24,6 +25,8 @@
  */
 public class TestPointToPointIntentCompiler {
 
+    private static final ApplicationId APPID = new TestApplicationId("foo");
+
     private TrafficSelector selector = new IntentTestsMocks.MockSelector();
     private TrafficTreatment treatment = new IntentTestsMocks.MockTreatment();
 
@@ -31,14 +34,12 @@
      * Creates a PointToPoint intent based on ingress and egress device Ids.
      *
      * @param ingressIdString string for id of ingress device
-     * @param egressIdString string for id of egress device
+     * @param egressIdString  string for id of egress device
      * @return PointToPointIntent for the two devices
      */
     private PointToPointIntent makeIntent(String ingressIdString,
                                           String egressIdString) {
-        return new PointToPointIntent(new IntentId(12),
-                                      selector,
-                                      treatment,
+        return new PointToPointIntent(APPID, selector, treatment,
                                       connectPoint(ingressIdString, 1),
                                       connectPoint(egressIdString, 1));
     }
@@ -53,9 +54,6 @@
         PointToPointIntentCompiler compiler =
                 new PointToPointIntentCompiler();
         compiler.pathService = new IntentTestsMocks.MockPathService(hops);
-        IdBlockAllocator idBlockAllocator = new DummyIdBlockAllocator();
-        compiler.intentIdGenerator =
-                new IdBlockAllocatorBasedIntentIdGenerator(idBlockAllocator);
         return compiler;
     }
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
index e5b2ed6..3da5d25 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/flow/impl/DistributedFlowRuleStore.java
@@ -2,6 +2,7 @@
 
 import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
 import static org.slf4j.LoggerFactory.getLogger;
+import static org.onlab.onos.store.flow.impl.FlowStoreMessageSubjects.*;
 
 import java.io.IOException;
 import java.util.Collection;
@@ -30,6 +31,7 @@
 import org.onlab.onos.store.AbstractStore;
 import org.onlab.onos.store.cluster.messaging.ClusterCommunicationService;
 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
+import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
 import org.onlab.onos.store.cluster.messaging.ClusterMessageResponse;
 import org.onlab.onos.store.flow.ReplicaInfo;
 import org.onlab.onos.store.flow.ReplicaInfoService;
@@ -80,10 +82,44 @@
     };
 
     // TODO: make this configurable
-    private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 1000;
+    private static final long FLOW_RULE_STORE_TIMEOUT_MILLIS = 5000;
 
     @Activate
     public void activate() {
+        clusterCommunicator.addSubscriber(STORE_FLOW_RULE, new ClusterMessageHandler() {
+
+            @Override
+            public void handle(ClusterMessage message) {
+                FlowRule rule = SERIALIZER.decode(message.payload());
+                log.info("received add request for {}", rule);
+                storeFlowEntryInternal(rule);
+                // FIXME what to respond.
+                try {
+                    // FIXME: #respond() not working. responded message is
+                    // handled by this sender node and never goes back.
+                    message.respond(SERIALIZER.encode("ACK"));
+                } catch (IOException e) {
+                    log.error("Failed to respond back", e);
+                }
+            }
+        });
+
+        clusterCommunicator.addSubscriber(DELETE_FLOW_RULE, new ClusterMessageHandler() {
+
+            @Override
+            public void handle(ClusterMessage message) {
+                FlowRule rule = SERIALIZER.decode(message.payload());
+                log.info("received delete request for {}", rule);
+                deleteFlowRuleInternal(rule);
+                // FIXME what to respond.
+                try {
+                    message.respond(SERIALIZER.encode("ACK"));
+                } catch (IOException e) {
+                    log.error("Failed to respond back", e);
+                }
+
+            }
+        });
         log.info("Started");
     }
 
@@ -131,13 +167,14 @@
     }
 
     @Override
-    public void storeFlowRule(FlowRule rule) {
+    public boolean storeFlowRule(FlowRule rule) {
         ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
         if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
-            storeFlowEntryInternal(rule);
-            return;
+            return storeFlowEntryInternal(rule);
         }
 
+        log.warn("Not my flow forwarding to {}", replicaInfo.master().orNull());
+
         ClusterMessage message = new ClusterMessage(
                 clusterService.getLocalNode().id(),
                 FlowStoreMessageSubjects.STORE_FLOW_RULE,
@@ -150,26 +187,29 @@
             // FIXME: throw a FlowStoreException
             throw new RuntimeException(e);
         }
+        return false;
     }
 
-    private synchronized void storeFlowEntryInternal(FlowRule flowRule) {
+    private synchronized boolean storeFlowEntryInternal(FlowRule flowRule) {
         StoredFlowEntry flowEntry = new DefaultFlowEntry(flowRule);
         DeviceId deviceId = flowRule.deviceId();
         // write to local copy.
         if (!flowEntries.containsEntry(deviceId, flowEntry)) {
             flowEntries.put(deviceId, flowEntry);
             flowEntriesById.put(flowRule.appId(), flowEntry);
+            notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, flowRule));
+            return true;
         }
         // write to backup.
         // TODO: write to a hazelcast map.
+        return false;
     }
 
     @Override
-    public synchronized void deleteFlowRule(FlowRule rule) {
+    public synchronized boolean deleteFlowRule(FlowRule rule) {
         ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
         if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
-            deleteFlowRuleInternal(rule);
-            return;
+            return deleteFlowRuleInternal(rule);
         }
 
         ClusterMessage message = new ClusterMessage(
@@ -184,15 +224,21 @@
             // FIXME: throw a FlowStoreException
             throw new RuntimeException(e);
         }
+        return false;
     }
 
-    private synchronized void deleteFlowRuleInternal(FlowRule flowRule) {
+    private synchronized boolean deleteFlowRuleInternal(FlowRule flowRule) {
         StoredFlowEntry entry = getFlowEntryInternal(flowRule);
         if (entry == null) {
-            return;
+            return false;
         }
         entry.setState(FlowEntryState.PENDING_REMOVE);
+
         // TODO: also update backup.
+
+        notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, flowRule));
+
+        return true;
     }
 
     @Override
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java
new file mode 100644
index 0000000..0deccfb
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/intent/impl/DistributedIntentStore.java
@@ -0,0 +1,108 @@
+package org.onlab.onos.store.intent.impl;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.onos.net.intent.Intent;
+import org.onlab.onos.net.intent.IntentEvent;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.intent.IntentState;
+import org.onlab.onos.net.intent.IntentStore;
+import org.onlab.onos.net.intent.IntentStoreDelegate;
+import org.onlab.onos.store.AbstractStore;
+import org.slf4j.Logger;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.onlab.onos.net.intent.IntentState.*;
+import static org.slf4j.LoggerFactory.getLogger;
+
+//FIXME: I LIE I AM NOT DISTRIBUTED
+@Component(immediate = true)
+@Service
+public class DistributedIntentStore
+        extends AbstractStore<IntentEvent, IntentStoreDelegate>
+        implements IntentStore {
+
+    private final Logger log = getLogger(getClass());
+    private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>();
+    private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>();
+    private final Map<IntentId, List<Intent>> installable = new ConcurrentHashMap<>();
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public IntentEvent createIntent(Intent intent) {
+        intents.put(intent.id(), intent);
+        return this.setState(intent, IntentState.SUBMITTED);
+    }
+
+    @Override
+    public IntentEvent removeIntent(IntentId intentId) {
+        Intent intent = intents.remove(intentId);
+        installable.remove(intentId);
+        IntentEvent event = this.setState(intent, WITHDRAWN);
+        states.remove(intentId);
+        return event;
+    }
+
+    @Override
+    public long getIntentCount() {
+        return intents.size();
+    }
+
+    @Override
+    public Iterable<Intent> getIntents() {
+        return ImmutableSet.copyOf(intents.values());
+    }
+
+    @Override
+    public Intent getIntent(IntentId intentId) {
+        return intents.get(intentId);
+    }
+
+    @Override
+    public IntentState getIntentState(IntentId id) {
+        return states.get(id);
+    }
+
+    @Override
+    public IntentEvent setState(Intent intent, IntentState state) {
+        IntentId id = intent.id();
+        states.put(id, state);
+        IntentEvent.Type type = (state == SUBMITTED ? IntentEvent.Type.SUBMITTED :
+                (state == INSTALLED ? IntentEvent.Type.INSTALLED :
+                        (state == FAILED ? IntentEvent.Type.FAILED :
+                                state == WITHDRAWN ? IntentEvent.Type.WITHDRAWN :
+                                        null)));
+        return type == null ? null : new IntentEvent(type, intent);
+    }
+
+    @Override
+    public void addInstallableIntents(IntentId intentId, List<Intent> result) {
+        installable.put(intentId, result);
+    }
+
+    @Override
+    public List<Intent> getInstallableIntents(IntentId intentId) {
+        return installable.get(intentId);
+    }
+
+    @Override
+    public void removeInstalledIntents(IntentId intentId) {
+        installable.remove(intentId);
+    }
+
+}
diff --git a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
index 38214d3..9de6d8c 100644
--- a/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
+++ b/core/store/serializers/src/main/java/org/onlab/onos/store/serializers/KryoNamespaces.java
@@ -8,6 +8,7 @@
 import org.onlab.onos.cluster.ControllerNode;
 import org.onlab.onos.cluster.DefaultControllerNode;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipTerm;
 import org.onlab.onos.net.ConnectPoint;
 import org.onlab.onos.net.DefaultAnnotations;
@@ -26,7 +27,12 @@
 import org.onlab.onos.net.device.DefaultDeviceDescription;
 import org.onlab.onos.net.device.DefaultPortDescription;
 import org.onlab.onos.net.flow.DefaultFlowRule;
+import org.onlab.onos.net.flow.DefaultTrafficSelector;
+import org.onlab.onos.net.flow.DefaultTrafficTreatment;
 import org.onlab.onos.net.flow.FlowId;
+import org.onlab.onos.net.flow.criteria.Criteria;
+import org.onlab.onos.net.flow.criteria.Criterion;
+import org.onlab.onos.net.flow.instructions.Instructions;
 import org.onlab.onos.net.host.DefaultHostDescription;
 import org.onlab.onos.net.host.HostDescription;
 import org.onlab.onos.net.link.DefaultLinkDescription;
@@ -88,7 +94,22 @@
                     HostDescription.class,
                     DefaultHostDescription.class,
                     DefaultFlowRule.class,
-                    FlowId.class
+                    FlowId.class,
+                    DefaultTrafficSelector.class,
+                    Criteria.PortCriterion.class,
+                    Criteria.EthCriterion.class,
+                    Criteria.EthTypeCriterion.class,
+                    Criteria.IPCriterion.class,
+                    Criteria.IPProtocolCriterion.class,
+                    Criteria.VlanIdCriterion.class,
+                    Criteria.VlanPcpCriterion.class,
+                    Criteria.TcpPortCriterion.class,
+                    Criterion.class,
+                    Criterion.Type.class,
+                    DefaultTrafficTreatment.class,
+                    Instructions.DropInstruction.class,
+                    Instructions.OutputInstruction.class,
+                    RoleInfo.class
                     )
             .register(URI.class, new URISerializer())
             .register(NodeId.class, new NodeIdSerializer())
diff --git a/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java b/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
index f76513d..1bd2097 100644
--- a/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
+++ b/core/store/serializers/src/test/java/org/onlab/onos/store/serializers/KryoSerializerTest.java
@@ -3,6 +3,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.onlab.onos.net.DeviceId.deviceId;
 import static org.onlab.onos.net.PortNumber.portNumber;
+import static java.util.Arrays.asList;
 
 import java.nio.ByteBuffer;
 
@@ -11,6 +12,7 @@
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onlab.onos.cluster.NodeId;
+import org.onlab.onos.cluster.RoleInfo;
 import org.onlab.onos.mastership.MastershipTerm;
 import org.onlab.onos.net.Annotations;
 import org.onlab.onos.net.ConnectPoint;
@@ -198,6 +200,12 @@
     }
 
     @Test
+    public void testRoleInfo() {
+        testSerialized(new RoleInfo(new NodeId("master"),
+                            asList(new NodeId("stby1"), new NodeId("stby2"))));
+    }
+
+    @Test
     public void testAnnotations() {
         // Annotations does not have equals defined, manually test equality
         final byte[] a1Bytes = serializer.encode(A1);
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
index 33ba95b..a96cacb 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleFlowRuleStore.java
@@ -148,8 +148,9 @@
     }
 
     @Override
-    public void storeFlowRule(FlowRule rule) {
+    public boolean storeFlowRule(FlowRule rule) {
         final boolean added = storeFlowRuleInternal(rule);
+        return added;
     }
 
     private boolean storeFlowRuleInternal(FlowRule rule) {
@@ -166,13 +167,14 @@
             }
             // new flow rule added
             existing.add(f);
-            // TODO: notify through delegate about remote event?
+            // TODO: Should we notify only if it's "remote" event?
+            //notifyDelegate(new FlowRuleEvent(Type.RULE_ADD_REQUESTED, rule));
             return true;
         }
     }
 
     @Override
-    public void deleteFlowRule(FlowRule rule) {
+    public boolean deleteFlowRule(FlowRule rule) {
 
         List<StoredFlowEntry> entries = getFlowEntries(rule.deviceId(), rule.id());
         synchronized (entries) {
@@ -180,12 +182,15 @@
                 if (entry.equals(rule)) {
                     synchronized (entry) {
                         entry.setState(FlowEntryState.PENDING_REMOVE);
-                        return;
+                        // TODO: Should we notify only if it's "remote" event?
+                        //notifyDelegate(new FlowRuleEvent(Type.RULE_REMOVE_REQUESTED, rule));
+                        return true;
                     }
                 }
             }
         }
         //log.warn("Cannot find rule {}", rule);
+        return false;
     }
 
     @Override
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
index c7f656a..0ec8612 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleIntentStore.java
@@ -1,20 +1,10 @@
 package org.onlab.onos.store.trivial.impl;
 
-import static org.onlab.onos.net.intent.IntentState.FAILED;
-import static org.onlab.onos.net.intent.IntentState.INSTALLED;
-import static org.onlab.onos.net.intent.IntentState.SUBMITTED;
-import static org.onlab.onos.net.intent.IntentState.WITHDRAWN;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Service;
-import org.onlab.onos.net.intent.InstallableIntent;
 import org.onlab.onos.net.intent.Intent;
 import org.onlab.onos.net.intent.IntentEvent;
 import org.onlab.onos.net.intent.IntentId;
@@ -24,7 +14,12 @@
 import org.onlab.onos.store.AbstractStore;
 import org.slf4j.Logger;
 
-import com.google.common.collect.ImmutableSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.onlab.onos.net.intent.IntentState.*;
+import static org.slf4j.LoggerFactory.getLogger;
 
 @Component(immediate = true)
 @Service
@@ -35,7 +30,7 @@
     private final Logger log = getLogger(getClass());
     private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>();
     private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>();
-    private final Map<IntentId, List<InstallableIntent>> installable =
+    private final Map<IntentId, List<Intent>> installable =
             new ConcurrentHashMap<>();
 
     @Activate
@@ -96,12 +91,12 @@
     }
 
     @Override
-    public void addInstallableIntents(IntentId intentId, List<InstallableIntent> result) {
+    public void addInstallableIntents(IntentId intentId, List<Intent> result) {
         installable.put(intentId, result);
     }
 
     @Override
-    public List<InstallableIntent> getInstallableIntents(IntentId intentId) {
+    public List<Intent> getInstallableIntents(IntentId intentId) {
         return installable.get(intentId);
     }
 
diff --git a/pom.xml b/pom.xml
index 40b872c..47dc489 100644
--- a/pom.xml
+++ b/pom.xml
@@ -572,7 +572,7 @@
                         <group>
                             <title>Sample Applications</title>
                             <packages>
-                                org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar
+                                org.onlab.onos.tvue:org.onlab.onos.fwd:org.onlab.onos.ifwd:org.onlab.onos.mobility:org.onlab.onos.proxyarp:org.onlab.onos.foo:org.onlab.onos.calendar:org.onlab.onos.sdnip:org.onlab.onos.sdnip.*:org.onlab.onos.optical:org.onlab.onos.optical.*
                             </packages>
                         </group>
                     </groups>
diff --git a/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java b/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java
index 42d801b..1bfe3bc 100644
--- a/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java
+++ b/utils/misc/src/main/java/org/onlab/util/KryoNamespace.java
@@ -171,6 +171,7 @@
         Kryo kryo = getKryo();
         try {
             kryo.writeClassAndObject(out, obj);
+            out.flush();
             return out.toBytes();
         } finally {
             putKryo(kryo);
@@ -188,6 +189,7 @@
         Kryo kryo = getKryo();
         try {
             kryo.writeClassAndObject(out, obj);
+            out.flush();
         } finally {
             putKryo(kryo);
         }