[ONOS-4051] Path computation algorithm implementation (Coding & UT).

Change-Id: If94be2ba2a010a203003b7ce38289b516ab20f59
diff --git a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
index 2ff3a49..7ea9934 100644
--- a/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
+++ b/apps/pce/app/src/main/java/org/onosproject/pce/pceservice/PceManager.java
@@ -18,8 +18,10 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.incubator.net.tunnel.Tunnel.Type.MPLS;
 
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -34,8 +36,15 @@
 import org.onosproject.incubator.net.tunnel.TunnelId;
 import org.onosproject.incubator.net.tunnel.TunnelService;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.Path;
 import org.onosproject.net.intent.Constraint;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.resource.ResourceService;
+import org.onosproject.net.topology.LinkWeight;
+import org.onosproject.net.topology.PathService;
+import org.onosproject.net.topology.TopologyEdge;
 import org.onosproject.pce.pceservice.api.PceService;
+import org.onosproject.pce.pceservice.constraint.CapabilityConstraint;
 import org.onosproject.store.serializers.KryoNamespaces;
 import org.onosproject.store.service.DistributedSet;
 import org.onosproject.store.service.Serializer;
@@ -43,6 +52,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * Implementation of PCE service.
  */
@@ -66,6 +77,15 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected StorageService storageService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PathService pathService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ResourceService resourceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
     private ApplicationId appId;
 
     /**
@@ -92,6 +112,36 @@
         log.info("Stopped");
     }
 
+    /**
+     * Returns an edge-weight capable of evaluating links on the basis of the
+     * specified constraints.
+     *
+     * @param constraints path constraints
+     * @return edge-weight function
+     */
+    private LinkWeight weight(List<Constraint> constraints) {
+        return new TeConstraintBasedLinkWeight(constraints);
+    }
+
+    /**
+     * Computes a path between two devices.
+     *
+     * @param src ingress device
+     * @param dst egress device
+     * @param constraints path constraints
+     * @return computed path based on constraints
+     */
+    protected Set<Path> computePath(DeviceId src, DeviceId dst, List<Constraint> constraints) {
+        if (pathService == null) {
+            return null;
+        }
+        Set<Path> paths = pathService.getPaths(src, dst, weight(constraints));
+        if (!paths.isEmpty()) {
+            return paths;
+        }
+        return null;
+    }
+
     //[TODO:] handle requests in queue
     @Override
     public boolean setupPath(DeviceId src, DeviceId dst, String tunnelName, List<Constraint> constraints,
@@ -103,8 +153,8 @@
         checkNotNull(lspType);
 
         // TODO: compute and setup path.
-
-        return true;
+        //TODO: gets the path based on constraints and creates a tunnel in network via tunnel manager
+        return computePath(src, dst, constraints) != null ? true : false;
     }
 
 
@@ -159,4 +209,44 @@
         return value;
     }
 
+    protected class TeConstraintBasedLinkWeight implements LinkWeight {
+
+        private final List<Constraint> constraints;
+
+        /**
+         * Creates a new edge-weight function capable of evaluating links
+         * on the basis of the specified constraints.
+         *
+         * @param constraints path constraints
+         */
+        public TeConstraintBasedLinkWeight(List<Constraint> constraints) {
+            if (constraints == null) {
+                this.constraints = Collections.emptyList();
+            } else {
+                this.constraints = ImmutableList.copyOf(constraints);
+            }
+        }
+
+        @Override
+        public double weight(TopologyEdge edge) {
+            if (!constraints.iterator().hasNext()) {
+                //Takes default cost/hopcount as 1 if no constraints specified
+                return 1.0;
+            }
+
+            Iterator<Constraint> it = constraints.iterator();
+            double cost = 1;
+
+            //If any constraint fails return -1 also value of cost returned from cost constraint can't be negative
+            while (it.hasNext() && cost > 0) {
+                Constraint constraint = it.next();
+                if (constraint instanceof CapabilityConstraint) {
+                    cost = ((CapabilityConstraint) constraint).isValidLink(edge.link(), deviceService) ? 1 : -1;
+                } else {
+                    cost = constraint.cost(edge.link(), resourceService::isAvailable);
+                }
+            }
+            return cost;
+        }
+    }
 }
\ No newline at end of file