[ONOS-5932] New FlowObjective compiler for LinkCollection Intent

Change-Id: I50ca991bf0997a24dd18cf68c060c2c0912f294c
diff --git a/core/api/src/test/java/org/onosproject/net/NetTestTools.java b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
index dd03a09..86ee0f7 100644
--- a/core/api/src/test/java/org/onosproject/net/NetTestTools.java
+++ b/core/api/src/test/java/org/onosproject/net/NetTestTools.java
@@ -234,6 +234,12 @@
                 .build();
     }
 
+    public static TrafficSelector ethDstSelector(String macAddress) {
+        return DefaultTrafficSelector.builder()
+                .matchEthDst(MacAddress.valueOf(macAddress))
+                .build();
+    }
+
     /**
      * Builds an empty treatment.
      *
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
index 40f7f77..e14115c 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/IntentConfigurableRegistrator.java
@@ -17,6 +17,7 @@
 package org.onosproject.net.intent.impl.compiler;
 
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -35,6 +36,7 @@
 import org.slf4j.Logger;
 
 import java.util.Map;
+import java.util.Set;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -79,8 +81,22 @@
             label = "Indicates whether or not to use copy ttl in the link collection compiler")
     private boolean useCopyTtl = DEFAULT_COPY_TTL;
 
+    /**
+     * Temporary for switching old compiler and new compiler.
+     * @deprecated 1.10 Kingfisher
+     */
+    private static final String DEFAULT_FLOW_OBJECTIVE_COMPILER =
+            "org.onosproject.net.intent.impl.compiler.LinkCollectionIntentFlowObjectiveCompiler";
+    @Deprecated
+    @Property(name = "defaultFlowObjectiveCompiler",
+            value = DEFAULT_FLOW_OBJECTIVE_COMPILER,
+            label = "Default compiler to generate flow objective")
+    private String defaultFlowObjectiveCompiler = DEFAULT_FLOW_OBJECTIVE_COMPILER;
+
     private final Map<Class<Intent>, IntentCompiler<Intent>> flowRuleBased = Maps.newConcurrentMap();
-    private final Map<Class<Intent>, IntentCompiler<Intent>> flowObjectiveBased = Maps.newConcurrentMap();
+
+    // FIXME: temporary code for switching old compiler to new compiler
+    private final Map<Class<Intent>, Set<IntentCompiler<Intent>>> flowObjectiveBased = Maps.newConcurrentMap();
 
     @Activate
     public void activate() {
@@ -101,6 +117,9 @@
             log.info("Settings: labelSelection={}", labelSelection);
             log.info("Settings: useFlowOptimization={}", useFlowOptimization);
             log.info("Settings: useCopyTtl={}", useCopyTtl);
+
+            // FIXME: temporary code for switching old compiler to new compiler
+            log.info("Settings: defaultFlowObjectiveCompiler={}", defaultFlowObjectiveCompiler);
             return;
         }
 
@@ -118,6 +137,21 @@
             log.info("Settings: useFlowObjectives={}", useFlowObjectives);
         }
 
+        // FIXME: temporary code for switching old compiler to new compiler
+        String newDefaultFlowObjectiveCompiler;
+        try {
+            String s = Tools.get(context.getProperties(), "defaultFlowObjectiveCompiler");
+            newDefaultFlowObjectiveCompiler = isNullOrEmpty(s) ? defaultFlowObjectiveCompiler : s.trim();
+        } catch (ClassCastException e) {
+            newDefaultFlowObjectiveCompiler = defaultFlowObjectiveCompiler;
+        }
+
+        if (!defaultFlowObjectiveCompiler.equals(newDefaultFlowObjectiveCompiler)) {
+            defaultFlowObjectiveCompiler = newDefaultFlowObjectiveCompiler;
+            changeCompilers();
+            log.info("Settings: defaultFlowObjectiveCompiler={}", defaultFlowObjectiveCompiler);
+        }
+
         String newLabelSelection;
         try {
             String s = Tools.get(context.getProperties(), "labelSelection");
@@ -173,7 +207,15 @@
     <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler,
                                              boolean flowBased) {
         if (flowBased) {
-            flowObjectiveBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
+            // FIXME: temporary code for switching old compiler to new compiler
+            flowObjectiveBased.compute((Class<Intent>) cls, (clz, compilers) -> {
+                if (compilers == null) {
+                    compilers = Sets.newHashSet();
+                }
+
+                compilers.add((IntentCompiler<Intent>) compiler);
+                return compilers;
+            });
         } else {
             flowRuleBased.put((Class<Intent>) cls, (IntentCompiler<Intent>) compiler);
         }
@@ -204,7 +246,15 @@
     private void changeCompilers() {
         if (useFlowObjectives) {
             flowRuleBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
-            flowObjectiveBased.forEach((cls, compiler) -> extensionService.registerCompiler(cls, compiler));
+            // FIXME: temporary code for switching old compiler to new compiler
+            flowObjectiveBased.forEach((cls, compilers) -> {
+                compilers.forEach(compiler -> {
+                    // filter out flow objective compiler which doesn't match
+                    if (compiler.getClass().getName().equals(defaultFlowObjectiveCompiler)) {
+                        extensionService.registerCompiler(cls, compiler);
+                    }
+                });
+            });
         } else {
             flowObjectiveBased.forEach((cls, compiler) -> extensionService.unregisterCompiler(cls));
             flowRuleBased.forEach((cls, compiler) -> extensionService.registerCompiler(cls, compiler));
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
index 0aa4e87..9396ab5 100644
--- a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentFlowObjectiveCompiler.java
@@ -52,7 +52,9 @@
 
 /**
  * Compiler to produce flow objectives from link collections.
+ * @deprecated 1.10 Kingfisher
  */
+@Deprecated
 @Component(immediate = true)
 public class LinkCollectionIntentFlowObjectiveCompiler
         extends LinkCollectionCompiler<Objective>
diff --git a/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java
new file mode 100644
index 0000000..2af0be5
--- /dev/null
+++ b/core/net/src/main/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompiler.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl.compiler;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
+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.util.Identifier;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.EthCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flowobjective.DefaultFilteringObjective;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.DefaultNextObjective;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.intent.FlowObjectiveIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentCompiler;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.resource.impl.LabelAllocator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.onosproject.net.flow.instructions.Instruction.Type.OUTPUT;
+
+/**
+ * Compiler to produce flow objectives from link collections.
+ */
+@Component(immediate = true)
+public class LinkCollectionIntentObjectiveCompiler
+        extends LinkCollectionCompiler<Objective>
+        implements IntentCompiler<LinkCollectionIntent> {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected IntentConfigurableRegistrator registrator;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowObjectiveService flowObjectiveService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ResourceService resourceService;
+
+    private ApplicationId appId;
+
+    @Activate
+    public void activate() {
+        appId = coreService.registerApplication("org.onosproject.net.intent");
+        registrator.registerCompiler(LinkCollectionIntent.class, this, true);
+        if (labelAllocator == null) {
+            labelAllocator = new LabelAllocator(resourceService);
+        }
+    }
+
+
+    @Deactivate
+    public void deactivate() {
+        registrator.unregisterCompiler(LinkCollectionIntent.class, true);
+    }
+
+    @Override
+    public List<Intent> compile(LinkCollectionIntent intent, List<Intent> installable) {
+
+        SetMultimap<DeviceId, PortNumber> inputPorts = HashMultimap.create();
+        SetMultimap<DeviceId, PortNumber> outputPorts = HashMultimap.create();
+        Map<ConnectPoint, Identifier<?>> labels = ImmutableMap.of();
+
+        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
+
+        computePorts(intent, inputPorts, outputPorts);
+
+        if (encapConstraint.isPresent()) {
+            labels = labelAllocator.assignLabelToPorts(intent.links(),
+                                                       intent.id(),
+                                                       encapConstraint.get().encapType());
+        }
+
+        List<Objective> objectives = new ArrayList<>();
+        List<DeviceId> devices = new ArrayList<>();
+        for (DeviceId deviceId: outputPorts.keySet()) {
+            List<Objective> deviceObjectives =
+                    createRules(intent,
+                                deviceId,
+                                inputPorts.get(deviceId),
+                                outputPorts.get(deviceId),
+                                labels);
+            deviceObjectives.forEach(objective -> {
+                objectives.add(objective);
+                devices.add(deviceId);
+            });
+        }
+        return Collections.singletonList(
+                new FlowObjectiveIntent(appId, intent.key(), devices,
+                                        objectives,
+                                        intent.resources(),
+                                        intent.resourceGroup()));
+    }
+
+    @Override
+    protected List<Objective> createRules(LinkCollectionIntent intent,
+                                          DeviceId deviceId,
+                                          Set<PortNumber> inPorts,
+                                          Set<PortNumber> outPorts,
+                                          Map<ConnectPoint, Identifier<?>> labels) {
+
+        List<Objective> objectives = new ArrayList<>(inPorts.size() * 2);
+
+        /*
+         * Looking for the encapsulation constraint
+         */
+        Optional<EncapsulationConstraint> encapConstraint = this.getIntentEncapConstraint(intent);
+
+        inPorts.forEach(inport -> {
+
+            ForwardingInstructions instructions = this.createForwardingInstruction(
+                    encapConstraint,
+                    intent,
+                    inport,
+                    outPorts,
+                    deviceId,
+                    labels
+            );
+
+            Set<TrafficTreatment> treatmentsWithDifferentPort =
+                    Sets.newHashSet();
+
+            TrafficTreatment.Builder treatmentBuilder =
+                    DefaultTrafficTreatment.builder();
+
+            for (Instruction inst : instructions.treatment().allInstructions()) {
+                if (inst.type() == OUTPUT) {
+                    treatmentBuilder.add(inst);
+                    treatmentsWithDifferentPort.add(treatmentBuilder.build());
+                    treatmentBuilder = DefaultTrafficTreatment.builder();
+                } else {
+                    treatmentBuilder.add(inst);
+                }
+            }
+
+            EthCriterion ethDst = (EthCriterion) instructions.selector()
+                    .getCriterion(Criterion.Type.ETH_DST);
+            boolean broadcastObjective = ethDst != null &&
+                    (ethDst.mac().isBroadcast() || ethDst.mac().isMulticast());
+
+            if (treatmentsWithDifferentPort.size() < 2 && !broadcastObjective) {
+                objectives.addAll(createSimpleNextObjective(instructions, intent));
+            } else {
+                objectives.addAll(createBroadcastObjective(instructions,
+                                                           treatmentsWithDifferentPort,
+                                                           intent));
+            }
+        });
+
+        return objectives;
+    }
+
+    private List<Objective> createBroadcastObjective(ForwardingInstructions instructions,
+                                                     Set<TrafficTreatment> treatmentsWithDifferentPort,
+                                                     LinkCollectionIntent intent) {
+        List<Objective> objectives = Lists.newArrayList();
+        FilteringObjective filteringObjective;
+        ForwardingObjective forwardingObjective;
+        NextObjective nextObjective;
+
+        Integer nextId = flowObjectiveService.allocateNextId();
+
+        forwardingObjective = buildForwardingObjective(instructions.selector(),
+                                                       nextId, intent.priority());
+
+        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
+        nxBuilder.withId(nextId)
+                .withMeta(instructions.selector())
+                .withType(NextObjective.Type.BROADCAST)
+                .fromApp(appId)
+                .withPriority(intent.priority())
+                .makePermanent();
+
+        treatmentsWithDifferentPort.forEach(nxBuilder::addTreatment);
+        nextObjective = nxBuilder.add();
+
+        filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());
+
+        objectives.add(filteringObjective);
+        objectives.add(forwardingObjective);
+        objectives.add(nextObjective);
+
+        return objectives;
+    }
+
+    private List<Objective> createSimpleNextObjective(ForwardingInstructions instructions,
+                                                      LinkCollectionIntent intent) {
+        List<Objective> objectives = Lists.newArrayList();
+        FilteringObjective filteringObjective;
+        ForwardingObjective forwardingObjective;
+        NextObjective nextObjective;
+
+        Integer nextId = flowObjectiveService.allocateNextId();
+
+        forwardingObjective = buildForwardingObjective(instructions.selector(),
+                                                       nextId, intent.priority());
+
+        DefaultNextObjective.Builder nxBuilder = DefaultNextObjective.builder();
+        nextObjective = nxBuilder.withId(nextId)
+                .withMeta(instructions.selector())
+                .addTreatment(instructions.treatment())
+                .withType(NextObjective.Type.SIMPLE)
+                .fromApp(appId)
+                .makePermanent()
+                .withPriority(intent.priority())
+                .add();
+
+        filteringObjective = buildFilteringObjective(instructions.selector(), intent.priority());
+
+        objectives.add(filteringObjective);
+        objectives.add(forwardingObjective);
+        objectives.add(nextObjective);
+
+        return objectives;
+    }
+
+    private ForwardingObjective buildForwardingObjective(TrafficSelector selector, Integer nextId, int priority) {
+        return DefaultForwardingObjective.builder()
+                .withMeta(selector)
+                .withSelector(selector)
+                .nextStep(nextId)
+                .fromApp(appId)
+                .withPriority(priority)
+                .withFlag(ForwardingObjective.Flag.SPECIFIC)
+                .makePermanent()
+                .add();
+    }
+
+    private FilteringObjective buildFilteringObjective(TrafficSelector selector, int priority) {
+        FilteringObjective.Builder builder = DefaultFilteringObjective.builder();
+        builder.fromApp(appId)
+                .permit()
+                .makePermanent()
+                .withPriority(priority);
+
+        Criterion inPortCriterion =
+                selector.getCriterion(Criterion.Type.IN_PORT);
+
+        if (inPortCriterion != null) {
+            builder.withKey(inPortCriterion);
+        }
+
+        selector.criteria().forEach(builder::addCondition);
+        return builder.add();
+    }
+
+}
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java
index bd2c7c7..f6e5dc8 100644
--- a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/AbstractLinkCollectionTest.java
@@ -24,6 +24,7 @@
 import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
+import org.onosproject.net.ResourceGroup;
 import org.onosproject.net.flow.FlowRule;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -66,6 +67,7 @@
 
     final ConnectPoint of1p1 = connectPoint("of1", 1);
     final ConnectPoint of1p2 = connectPoint("of1", 2);
+    final ConnectPoint of1p3 = connectPoint("of1", 3);
     final ConnectPoint of2p1 = connectPoint("of2", 1);
     final ConnectPoint of2p2 = connectPoint("of2", 2);
     final ConnectPoint of2p3 = connectPoint("of2", 3);
@@ -124,6 +126,9 @@
     final TrafficSelector mpls100Selector = mplsSelector("100");
     final TrafficSelector mpls200Selector = mplsSelector("200");
     final TrafficSelector ipPrefixSelector = ipPrefixDstSelector("192.168.100.0/24");
+    final TrafficSelector ethDstSelector = ethDstSelector("C0:FF:EE:C0:FF:EE");
+    final ResourceGroup resourceGroup1 = ResourceGroup.of(1L);
+    final ResourceGroup resourceGroup2 = ResourceGroup.of(1L);
 
     final List<Constraint> constraintsForVlan = vlanConstraint();
     final List<Constraint> constraintsForMPLS = mplsConstraint();
diff --git a/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java
new file mode 100644
index 0000000..22ecf48
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/intent/impl/compiler/LinkCollectionIntentObjectiveCompilerTest.java
@@ -0,0 +1,862 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.net.intent.impl.compiler;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.cfg.ComponentConfigAdapter;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DefaultLink;
+import org.onosproject.net.FilteredConnectPoint;
+import org.onosproject.net.Link;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flow.criteria.Criterion;
+import org.onosproject.net.flow.criteria.PortCriterion;
+import org.onosproject.net.flowobjective.FilteringObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.NextObjective;
+import org.onosproject.net.flowobjective.Objective;
+import org.onosproject.net.intent.FlowObjectiveIntent;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.IntentExtensionService;
+import org.onosproject.net.intent.LinkCollectionIntent;
+import org.onosproject.net.resource.MockResourceService;
+import org.onosproject.net.resource.ResourceService;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import static org.easymock.EasyMock.*;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.nullValue;
+import static org.onosproject.net.Link.Type.DIRECT;
+import static org.onosproject.net.NetTestTools.PID;
+
+public class LinkCollectionIntentObjectiveCompilerTest extends AbstractLinkCollectionTest {
+
+    private LinkCollectionIntentObjectiveCompiler compiler;
+    private FlowObjectiveServiceAdapter flowObjectiveService;
+
+    private NextObjective nextObjective;
+    private ForwardingObjective forwardingObjective;
+    private FilteringObjective filteringObjective;
+
+    private ResourceService resourceService;
+
+    @Before
+    public void setUp() {
+        compiler = new LinkCollectionIntentObjectiveCompiler();
+        coreService = createMock(CoreService.class);
+        expect(coreService.registerApplication("org.onosproject.net.intent"))
+                .andReturn(appId);
+        flowObjectiveService = new FlowObjectiveServiceAdapter();
+        resourceService = new MockResourceService();
+        compiler.coreService = coreService;
+        compiler.flowObjectiveService = flowObjectiveService;
+
+        Intent.bindIdGenerator(idGenerator);
+
+        intentExtensionService = createMock(IntentExtensionService.class);
+        intentExtensionService.registerCompiler(LinkCollectionIntent.class, compiler);
+        intentExtensionService.unregisterCompiler(LinkCollectionIntent.class);
+
+        registrator = new IntentConfigurableRegistrator();
+        registrator.extensionService = intentExtensionService;
+        registrator.cfgService = new ComponentConfigAdapter();
+        registrator.activate();
+
+        compiler.registrator = registrator;
+        compiler.resourceService = resourceService;
+
+        LinkCollectionCompiler.optimize = false;
+        LinkCollectionCompiler.copyTtl = false;
+
+        replay(coreService, intentExtensionService);
+
+    }
+
+    @After
+    public void tearDown() {
+        Intent.unbindIdGenerator(idGenerator);
+    }
+
+    /**
+     * We test the proper compilation of a simple link collection intent
+     * with connect points, empty trivial treatment and empty trivial selector.
+     */
+    @Test
+    public void testCompile() {
+        compiler.activate();
+
+        LinkCollectionIntent intent = LinkCollectionIntent.builder()
+                .appId(appId)
+                .selector(selector)
+                .treatment(treatment)
+                .links(links)
+                .filteredIngressPoints(ImmutableSet.of(new FilteredConnectPoint(d1p1)))
+                .filteredEgressPoints(ImmutableSet.of(new FilteredConnectPoint(d3p1)))
+                .build();
+
+        List<Intent> result = compiler.compile(intent, Collections.emptyList());
+        assertThat(result, hasSize(1));
+        assertThat(result.get(0), instanceOf(FlowObjectiveIntent.class));
+
+        FlowObjectiveIntent foIntent = (FlowObjectiveIntent) result.get(0);
+        List<Objective> objectives = foIntent.objectives();
+        assertThat(objectives, hasSize(9));
+
+        /*
+         * First set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(0);
+        forwardingObjective = (ForwardingObjective) objectives.get(1);
+        nextObjective = (NextObjective) objectives.get(2);
+
+        // expect selector and treatment
+        TrafficSelector expectSelector = DefaultTrafficSelector.builder()
+                .matchInPort(PortNumber.portNumber(1))
+                .build();
+        TrafficTreatment expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(1))
+                .build();
+        PortCriterion inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * Second set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(3);
+        forwardingObjective = (ForwardingObjective) objectives.get(4);
+        nextObjective = (NextObjective) objectives.get(5);
+
+
+        expectSelector = DefaultTrafficSelector.builder()
+                .matchInPort(PortNumber.portNumber(0))
+                .build();
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for second next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for second forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 3rd set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(6);
+        forwardingObjective = (ForwardingObjective) objectives.get(7);
+        nextObjective = (NextObjective) objectives.get(8);
+
+        expectSelector = DefaultTrafficSelector.builder()
+                .matchInPort(PortNumber.portNumber(1))
+                .build();
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for 3rd next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for 3rd forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        compiler.deactivate();
+    }
+
+    /**
+     * Single point to multi point case. Scenario is the follow:
+     *
+     * -1 of1 2-1 of2 2--1 of3 2-
+     *             3
+     *             `-1 of4 2-
+     *
+     * We test the proper compilation of sp2mp with trivial selector,
+     * empty treatment and points.
+     *
+     */
+    @Test
+    public void testFilteredConnectPointForSp() {
+        compiler.activate();
+        Set<Link> testLinks = ImmutableSet.of(
+                DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
+                DefaultLink.builder().providerId(PID).src(of2p2).dst(of3p1).type(DIRECT).build(),
+                DefaultLink.builder().providerId(PID).src(of2p3).dst(of4p1).type(DIRECT).build()
+        );
+
+        Set<FilteredConnectPoint> ingress = ImmutableSet.of(
+                new FilteredConnectPoint(of1p1, vlan100Selector)
+        );
+
+        Set<FilteredConnectPoint> egress = ImmutableSet.of(
+                new FilteredConnectPoint(of3p2, vlan100Selector),
+                new FilteredConnectPoint(of4p2, vlan100Selector)
+        );
+
+        TrafficSelector broadcastSelector = DefaultTrafficSelector.builder()
+                .matchEthDst(MacAddress.BROADCAST)
+                .build();
+
+        LinkCollectionIntent intent = LinkCollectionIntent.builder()
+                .appId(appId)
+                .selector(broadcastSelector)
+                .treatment(treatment)
+                .links(testLinks)
+                .filteredIngressPoints(ingress)
+                .filteredEgressPoints(egress)
+                .applyTreatmentOnEgress(true)
+                .resourceGroup(resourceGroup1)
+                .build();
+
+        List<Intent> result = compiler.compile(intent, Collections.emptyList());
+        assertThat(result, hasSize(1));
+        assertThat(result.get(0), instanceOf(FlowObjectiveIntent.class));
+
+        FlowObjectiveIntent foIntent = (FlowObjectiveIntent) result.get(0);
+        List<Objective> objectives = foIntent.objectives();
+        assertThat(objectives, hasSize(12));
+
+        /*
+         * First set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(0);
+        forwardingObjective = (ForwardingObjective) objectives.get(1);
+        nextObjective = (NextObjective) objectives.get(2);
+
+        // expect selector and treatment
+        TrafficSelector expectSelector = DefaultTrafficSelector.builder()
+                .matchInPort(PortNumber.portNumber(1))
+                .matchVlanId(VlanId.vlanId("100"))
+                .matchEthDst(MacAddress.BROADCAST)
+                .build();
+        TrafficTreatment expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(2))
+                .build();
+
+        PortCriterion inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.BROADCAST));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * Second set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(3);
+        forwardingObjective = (ForwardingObjective) objectives.get(4);
+        nextObjective = (NextObjective) objectives.get(5);
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for second next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.BROADCAST));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for second forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 3rd set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(6);
+        forwardingObjective = (ForwardingObjective) objectives.get(7);
+        nextObjective = (NextObjective) objectives.get(8);
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for 3rd next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.BROADCAST));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for 3rd forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 4th set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(9);
+        forwardingObjective = (ForwardingObjective) objectives.get(10);
+        nextObjective = (NextObjective) objectives.get(11);
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for 3rd next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.BROADCAST));
+
+        // have 2 treatments in this objective
+        assertThat(nextObjective.next(), hasSize(2));
+        expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(2))
+                .build();
+        assertThat(nextObjective.next(), hasItem(expectTreatment));
+
+        expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(3))
+                .build();
+        assertThat(nextObjective.next(), hasItem(expectTreatment));
+
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for 3rd forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        compiler.deactivate();
+    }
+
+    /**
+     * Multi point to single point intent with filtered connect point.
+     * Scenario is the follow:
+     *
+     * -1 of1 2-1 of2 2-1 of4 2-
+     *             3
+     * -1 of3 2---/
+     *
+     */
+    @Test
+    public void testFilteredConnectPointForMp() {
+        compiler.activate();
+        Set<Link> testLinks = ImmutableSet.of(
+                DefaultLink.builder().providerId(PID).src(of1p2).dst(of2p1).type(DIRECT).build(),
+                DefaultLink.builder().providerId(PID).src(of3p2).dst(of2p3).type(DIRECT).build(),
+                DefaultLink.builder().providerId(PID).src(of2p2).dst(of4p1).type(DIRECT).build()
+        );
+
+        Set<FilteredConnectPoint> ingress = ImmutableSet.of(
+                new FilteredConnectPoint(of3p1, vlan100Selector),
+                new FilteredConnectPoint(of1p1, vlan100Selector)
+        );
+
+        Set<FilteredConnectPoint> egress = ImmutableSet.of(
+                new FilteredConnectPoint(of4p2, vlan100Selector)
+        );
+
+
+
+        LinkCollectionIntent intent = LinkCollectionIntent.builder()
+                .appId(appId)
+                .selector(ethDstSelector)
+                .treatment(treatment)
+                .links(testLinks)
+                .filteredIngressPoints(ingress)
+                .filteredEgressPoints(egress)
+                .build();
+
+        List<Intent> result = compiler.compile(intent, Collections.emptyList());
+        assertThat(result, hasSize(1));
+        assertThat(result.get(0), instanceOf(FlowObjectiveIntent.class));
+
+        FlowObjectiveIntent foIntent = (FlowObjectiveIntent) result.get(0);
+        List<Objective> objectives = foIntent.objectives();
+        assertThat(objectives, hasSize(15));
+
+        TrafficSelector expectSelector = DefaultTrafficSelector
+                .builder(ethDstSelector)
+                .matchInPort(PortNumber.portNumber(1))
+                .matchVlanId(VlanId.vlanId("100"))
+                .build();
+
+        TrafficTreatment expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(2))
+                .build();
+
+        /*
+         * First set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(0);
+        forwardingObjective = (ForwardingObjective) objectives.get(1);
+        nextObjective = (NextObjective) objectives.get(2);
+
+        PortCriterion inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * Second set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(3);
+        forwardingObjective = (ForwardingObjective) objectives.get(4);
+        nextObjective = (NextObjective) objectives.get(5);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 3rd set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(6);
+        forwardingObjective = (ForwardingObjective) objectives.get(7);
+        nextObjective = (NextObjective) objectives.get(8);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 4th set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(9);
+        forwardingObjective = (ForwardingObjective) objectives.get(10);
+        nextObjective = (NextObjective) objectives.get(11);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * 5th set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(12);
+        forwardingObjective = (ForwardingObjective) objectives.get(13);
+        nextObjective = (NextObjective) objectives.get(14);
+
+        expectSelector = DefaultTrafficSelector.builder(ethDstSelector)
+                .matchVlanId(VlanId.vlanId("100"))
+                .matchInPort(PortNumber.portNumber(3))
+                .build();
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+        compiler.deactivate();
+    }
+
+    /**
+     * Multiple point to single point intent with only one switch.
+     * We test the proper compilation of mp2sp with
+     * trivial selector, trivial treatment and 1 hop.
+     */
+    @Test
+    public void singleHopTestForMp() {
+        compiler.activate();
+        Set<Link> testLinks = ImmutableSet.of();
+
+        Set<FilteredConnectPoint> ingress = ImmutableSet.of(
+                new FilteredConnectPoint(of1p1, vlan100Selector),
+                new FilteredConnectPoint(of1p2, vlan100Selector)
+        );
+
+        Set<FilteredConnectPoint> egress = ImmutableSet.of(
+                new FilteredConnectPoint(of1p3, vlan100Selector)
+        );
+
+
+        LinkCollectionIntent intent = LinkCollectionIntent.builder()
+                .appId(appId)
+                .selector(ethDstSelector)
+                .treatment(treatment)
+                .links(testLinks)
+                .filteredIngressPoints(ingress)
+                .filteredEgressPoints(egress)
+                .build();
+
+        List<Intent> result = compiler.compile(intent, Collections.emptyList());
+        assertThat(result, hasSize(1));
+        assertThat(result.get(0), instanceOf(FlowObjectiveIntent.class));
+
+        FlowObjectiveIntent foIntent = (FlowObjectiveIntent) result.get(0);
+        List<Objective> objectives = foIntent.objectives();
+        assertThat(objectives, hasSize(6));
+
+        TrafficSelector expectSelector = DefaultTrafficSelector
+                .builder(ethDstSelector)
+                .matchInPort(PortNumber.portNumber(1))
+                .matchVlanId(VlanId.vlanId("100"))
+                .build();
+
+        TrafficTreatment expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(3))
+                .build();
+
+        /*
+         * First set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(0);
+        forwardingObjective = (ForwardingObjective) objectives.get(1);
+        nextObjective = (NextObjective) objectives.get(2);
+
+        PortCriterion inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        /*
+         * Second set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(3);
+        forwardingObjective = (ForwardingObjective) objectives.get(4);
+        nextObjective = (NextObjective) objectives.get(5);
+
+        expectSelector = DefaultTrafficSelector.builder(ethDstSelector)
+                .matchInPort(PortNumber.portNumber(2))
+                .matchVlanId(VlanId.vlanId("100"))
+                .build();
+
+        inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.SIMPLE));
+        assertThat(nextObjective.next(), hasSize(1));
+        assertThat(nextObjective.next().iterator().next(), is(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+        compiler.deactivate();
+    }
+
+    /**
+     * Single point to multiple point intent with only one switch.
+     * We test the proper compilation of sp2mp with
+     * trivial selector, trivial treatment and 1 hop.
+     */
+    @Test
+    public void singleHopTestForSp() {
+        compiler.activate();
+        Set<Link> testLinks = ImmutableSet.of();
+
+        Set<FilteredConnectPoint> ingress = ImmutableSet.of(
+                new FilteredConnectPoint(of1p1, vlan100Selector)
+        );
+
+        Set<FilteredConnectPoint> egress = ImmutableSet.of(
+                new FilteredConnectPoint(of1p2, vlan100Selector),
+                new FilteredConnectPoint(of1p3, vlan100Selector)
+        );
+
+
+        LinkCollectionIntent intent = LinkCollectionIntent.builder()
+                .appId(appId)
+                .selector(ethDstSelector)
+                .treatment(treatment)
+                .links(testLinks)
+                .filteredIngressPoints(ingress)
+                .filteredEgressPoints(egress)
+                .applyTreatmentOnEgress(true)
+                .resourceGroup(resourceGroup2)
+                .build();
+
+        List<Intent> result = compiler.compile(intent, Collections.emptyList());
+        assertThat(result, hasSize(1));
+        assertThat(result.get(0), instanceOf(FlowObjectiveIntent.class));
+
+        FlowObjectiveIntent foIntent = (FlowObjectiveIntent) result.get(0);
+        List<Objective> objectives = foIntent.objectives();
+        assertThat(objectives, hasSize(3));
+
+        TrafficSelector expectSelector = DefaultTrafficSelector
+                .builder(ethDstSelector)
+                .matchInPort(PortNumber.portNumber(1))
+                .matchVlanId(VlanId.vlanId("100"))
+                .build();
+
+        TrafficTreatment expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(3))
+                .build();
+
+        /*
+         * First set of objective
+         */
+        filteringObjective = (FilteringObjective) objectives.get(0);
+        forwardingObjective = (ForwardingObjective) objectives.get(1);
+        nextObjective = (NextObjective) objectives.get(2);
+
+        PortCriterion inPortCriterion =
+                (PortCriterion) expectSelector.getCriterion(Criterion.Type.IN_PORT);
+
+        // test case for first filtering objective
+        assertThat(filteringObjective.key(), is(inPortCriterion));
+        assertThat(filteringObjective.priority(), is(intent.priority()));
+        assertThat(filteringObjective.meta(), nullValue());
+        assertThat(filteringObjective.appId(), is(appId));
+        assertThat(filteringObjective.permanent(), is(true));
+        assertThat(filteringObjective.conditions(), is(Lists.newArrayList(expectSelector.criteria())));
+
+        // test case for first next objective
+        assertThat(nextObjective.type(), is(NextObjective.Type.BROADCAST));
+        assertThat(nextObjective.next(), hasSize(2));
+        assertThat(nextObjective.next(), hasItem(expectTreatment));
+        expectTreatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.portNumber(3))
+                .build();
+        assertThat(nextObjective.next(), hasItem(expectTreatment));
+        assertThat(nextObjective.meta(), is(expectSelector));
+        assertThat(nextObjective.op(), is(Objective.Operation.ADD));
+
+        // test case for first forwarding objective
+        assertThat(forwardingObjective.op(), is(Objective.Operation.ADD));
+        assertThat(forwardingObjective.selector(), is(expectSelector));
+        assertThat(forwardingObjective.nextId(), is(nextObjective.id()));
+        assertThat(forwardingObjective.flag(), is(ForwardingObjective.Flag.SPECIFIC));
+
+        compiler.deactivate();
+
+    }
+
+
+}