Implement path protection for point to point intents

Change-Id: I3f3627e7c2a7e3ab017e46655692ab70fdeae413
diff --git a/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java b/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
index df90c41..921c279 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/FlowRuleIntent.java
@@ -35,6 +35,7 @@
 public class FlowRuleIntent extends Intent {
 
     private final Collection<FlowRule> flowRules;
+    private PathIntent.ProtectionType type;
 
     /**
      * Creates a flow rule intent with the specified flow rules and resources.
@@ -48,7 +49,19 @@
     }
 
     /**
-     * Creates an flow rule intent with the specified key, flow rules to be set, and
+     * Creates a flow rule intent with the specified flow rules, resources, and type.
+     *
+     * @param appId application id
+     * @param flowRules flow rules to be set
+     * @param resources network resource to be set
+     */
+    public FlowRuleIntent(ApplicationId appId, List<FlowRule> flowRules, Collection<NetworkResource> resources,
+                          PathIntent.ProtectionType type) {
+        this(appId, null, flowRules, resources, type);
+    }
+
+    /**
+     * Creates a flow rule intent with the specified key, flow rules to be set, and
      * required network resources.
      *
      * @param appId     application id
@@ -58,8 +71,32 @@
      */
     public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules,
                           Collection<NetworkResource> resources) {
+        this(appId, key, flowRules, resources, PathIntent.ProtectionType.PRIMARY);
+    }
+
+    /**
+     * Creates a flow rule intent with the specified key, flow rules to be set, and
+     * required network resources.
+     *
+     * @param appId     application id
+     * @param key       key
+     * @param flowRules flow rules
+     * @param resources network resources
+     */
+    public FlowRuleIntent(ApplicationId appId, Key key, Collection<FlowRule> flowRules,
+                          Collection<NetworkResource> resources, PathIntent.ProtectionType primary) {
         super(appId, key, resources, DEFAULT_INTENT_PRIORITY);
         this.flowRules = ImmutableList.copyOf(checkNotNull(flowRules));
+        this.type = primary;
+    }
+
+    /**
+     * Creates a flow rule intent with all the same characteristics as the given
+     * one except for the flow rule type.
+     */
+    public FlowRuleIntent(FlowRuleIntent intent, PathIntent.ProtectionType type) {
+        this(intent.appId(), intent.key(), intent.flowRules(),
+              intent.resources(), type);
     }
 
     /**
@@ -68,6 +105,7 @@
     protected FlowRuleIntent() {
         super();
         this.flowRules = null;
+        this.type = PathIntent.ProtectionType.PRIMARY;
     }
 
     /**
@@ -84,6 +122,10 @@
         return true;
     }
 
+    public PathIntent.ProtectionType type() {
+        return type;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
diff --git a/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java b/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java
index 63fff1d..f2a0e45 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/IntentCompiler.java
@@ -31,7 +31,7 @@
      * Compiles the specified intent into other intents.
      *
      * @param intent      intent to be compiled
-     * @param installable previously compilation result; optional
+     * @param installable previous compilation result; optional
      * @return list of resulting intents
      * @throws IntentException if issues are encountered while compiling the intent
      */
diff --git a/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java b/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java
index b674c06..7ac22b3 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/PathIntent.java
@@ -36,10 +36,11 @@
 public class PathIntent extends ConnectivityIntent {
 
     private final Path path;
+    private ProtectionType type;
 
     /**
      * Creates a new point-to-point intent with the supplied ingress/egress
-     * ports and using the specified explicit path.
+     * ports and using the specified explicit path. Path is primary by default.
      *
      * @param appId     application identifier
      * @param key       intent key
@@ -57,10 +58,38 @@
                          Path path,
                          List<Constraint> constraints,
                          int priority) {
+        this(appId, key, selector, treatment, path, constraints, priority,
+             ProtectionType.PRIMARY);
+    }
+
+    /**
+     * Creates a new point-to-point intent with the supplied ingress/egress
+     * ports and using the specified explicit path, which can be classified
+     * as PRIMARY or BACKUP.
+     *
+     * @param appId     application identifier
+     * @param key       intent key
+     * @param selector  traffic selector
+     * @param treatment treatment
+     * @param path      traversed links
+     * @param constraints  optional list of constraints
+     * @param priority  priority to use for the generated flows
+     * @param type      PRIMARY or BACKUP
+     * @throws NullPointerException {@code path} is null
+     */
+    protected PathIntent(ApplicationId appId,
+                         Key key,
+                         TrafficSelector selector,
+                         TrafficTreatment treatment,
+                         Path path,
+                         List<Constraint> constraints,
+                         int priority,
+                         ProtectionType type) {
         super(appId, key, resources(path.links()), selector, treatment, constraints,
-                priority);
+              priority);
         PathIntent.validate(path.links());
         this.path = path;
+        this.type = type;
     }
 
     /**
@@ -69,6 +98,7 @@
     protected PathIntent() {
         super();
         this.path = null;
+        this.type = ProtectionType.PRIMARY;
     }
 
     /**
@@ -85,6 +115,7 @@
      */
     public static class Builder extends ConnectivityIntent.Builder {
         Path path;
+        ProtectionType type;
 
         protected Builder() {
             // Hide default constructor
@@ -131,6 +162,11 @@
             return this;
         }
 
+        public Builder setType(ProtectionType type) {
+            this.type = type;
+            return this;
+        }
+
         /**
          * Builds a path intent from the accumulated parameters.
          *
@@ -145,7 +181,8 @@
                     treatment,
                     path,
                     constraints,
-                    priority
+                    priority,
+                    type == null ? ProtectionType.PRIMARY : type
             );
         }
     }
@@ -183,6 +220,10 @@
         return path;
     }
 
+    public ProtectionType type() {
+        return type;
+    }
+
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
@@ -195,7 +236,25 @@
                 .add("treatment", treatment())
                 .add("constraints", constraints())
                 .add("path", path)
+                .add("type", type)
                 .toString();
     }
 
+    // for path protection purposes
+    public enum ProtectionType {
+        /**
+         * Intent within primary path.
+         */
+        PRIMARY,
+        /**
+         * Intent within backup path.
+         */
+        BACKUP,
+        /**
+         * Intent whose flow rule serves as the fast failover
+         * between primary and backup paths.
+         */
+        FAILOVER
+    }
+
 }
diff --git a/core/api/src/main/java/org/onosproject/net/intent/constraint/ProtectionConstraint.java b/core/api/src/main/java/org/onosproject/net/intent/constraint/ProtectionConstraint.java
new file mode 100644
index 0000000..d4d2c74
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/intent/constraint/ProtectionConstraint.java
@@ -0,0 +1,58 @@
+/*
+ * 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.constraint;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.net.Link;
+import org.onosproject.net.Path;
+import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.intent.Intent;
+import org.onosproject.net.intent.PointToPointIntent;
+import org.onosproject.net.intent.ResourceContext;
+
+/**
+ * Constraint that determines whether to employ path protection.
+ */
+@Beta
+public class ProtectionConstraint implements Constraint {
+    // doesn't use LinkResourceService
+    @Override
+    public double cost(Link link, ResourceContext context) {
+        return 1;
+    }
+
+    // doesn't use LinkResourceService
+    @Override
+    public boolean validate(Path path, ResourceContext context) {
+        return true;
+    }
+
+    /**
+     * Determines whether to utilize path protection for the given intent.
+     *
+     * @param intent  intent to be inspected
+     * @return        whether the intent has a ProtectionConstraint
+     */
+    public static boolean requireProtectedPath(Intent intent) {
+        if (intent instanceof PointToPointIntent) {
+            PointToPointIntent pointToPointIntent = (PointToPointIntent) intent;
+            return pointToPointIntent.constraints().stream()
+                    .anyMatch(p -> p instanceof ProtectionConstraint);
+        }
+        return false;
+    }
+}
diff --git a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
index a87263a..d3db258 100644
--- a/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
+++ b/core/api/src/test/java/org/onosproject/net/intent/PointToPointIntentTest.java
@@ -26,7 +26,7 @@
 public class PointToPointIntentTest extends ConnectivityIntentTest {
 
     /**
-     * Checks that the MultiPointToSinglePointIntent class is immutable.
+     * Checks that the PointToPointIntent class is immutable.
      */
     @Test
     public void checkImmutability() {