Merge "Applied some fixes to Intents"
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 206552e..885b851 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
@@ -19,6 +19,7 @@
 import org.onlab.onos.net.NetworkResource;
 import org.onlab.onos.net.flow.BatchOperationTarget;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Objects;
 
@@ -93,9 +94,10 @@
      * @param fields intent fields
      * @return intent identifier
      */
-    protected static IntentId id(Object... fields) {
+    protected static IntentId id(Class<?> intentClass, Object... fields) {
         // FIXME: spread the bits across the full long spectrum
-        return IntentId.valueOf(Objects.hash(fields));
+        return IntentId.valueOf(Objects.hash(intentClass.getName(),
+                                             Arrays.hashCode(fields)));
     }
 
     /**
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
index 7499f6d..1c81f1f 100644
--- 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
@@ -15,6 +15,8 @@
  */
 package org.onlab.onos.net.resource;
 
+import java.util.Objects;
+
 /**
  * Representation of allocated lambda resource.
  */
@@ -45,4 +47,21 @@
     public Lambda lambda() {
         return lambda;
     }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(lambda);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        final LambdaResourceAllocation other = (LambdaResourceAllocation) obj;
+        return Objects.equals(this.lambda, other.lambda);
+    }
 }
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 7b1d7a9..31df87a 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
@@ -407,6 +407,8 @@
             List<Intent> installables = store.getInstallableIntents(intent.id());
             if (installables != null) {
                 for (Intent installable : installables) {
+                    trackerService.removeTrackedResources(intent.id(),
+                                                          installable.resources());
                     List<FlowRuleBatchOperation> batches = getInstaller(installable).uninstall(installable);
                     uninstallWork.addAll(batches);
                 }
diff --git a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java
index f0747dd..5faae4d 100644
--- a/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java
+++ b/core/net/src/main/java/org/onlab/onos/net/intent/impl/OpticalPathIntentInstaller.java
@@ -94,7 +94,26 @@
     @Override
     public List<FlowRuleBatchOperation> install(OpticalPathIntent intent) {
         LinkResourceAllocations allocations = assignWavelength(intent);
+        return generateRules(intent, allocations, FlowRuleOperation.ADD);
+    }
 
+    @Override
+    public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
+        LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
+        return generateRules(intent, allocations, FlowRuleOperation.REMOVE);
+    }
+
+    private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
+        LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
+                                                                                 intent.path().links())
+                .addLambdaRequest();
+        LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
+        return retLambda;
+    }
+
+    private List<FlowRuleBatchOperation> generateRules(OpticalPathIntent intent,
+                                                       LinkResourceAllocations allocations,
+                                                       FlowRuleOperation operation) {
         TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
         selectorBuilder.matchInport(intent.src().port());
 
@@ -128,7 +147,7 @@
                                                 100,
                                                 true);
 
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
+            rules.add(new FlowRuleBatchEntry(operation, rule));
 
             prev = link.dst();
             selectorBuilder.matchInport(link.dst().port());
@@ -136,28 +155,20 @@
         }
 
         // build the last T port rule
-        TrafficTreatment treatmentLast = builder()
-                .setOutput(intent.dst().port()).build();
+        TrafficTreatment.Builder treatmentLast = builder();
+        treatmentLast.setOutput(intent.dst().port());
         FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
                                             selectorBuilder.build(),
-                                            treatmentLast,
+                                            treatmentLast.build(),
                                             100,
                                             appId,
                                             100,
                                             true);
-        rules.add(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule));
+        rules.add(new FlowRuleBatchEntry(operation, rule));
 
         return Lists.newArrayList(new FlowRuleBatchOperation(rules));
     }
 
-    private LinkResourceAllocations assignWavelength(OpticalPathIntent intent) {
-        LinkResourceRequest.Builder request = DefaultLinkResourceRequest.builder(intent.id(),
-                                                                                 intent.path().links())
-                .addLambdaRequest();
-        LinkResourceAllocations retLambda = resourceService.requestResources(request.build());
-        return retLambda;
-    }
-
     /*private Lambda assignWavelength(List<Link> links) {
         // TODO More wavelength assignment algorithm
         int wavenum = 0;
@@ -194,64 +205,4 @@
         }
         return false;
     }*/
-
-    @Override
-    public List<FlowRuleBatchOperation> uninstall(OpticalPathIntent intent) {
-        LinkResourceAllocations allocations = resourceService.getAllocations(intent.id());
-
-        TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder();
-        selectorBuilder.matchInport(intent.src().port());
-
-        TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
-
-        List<FlowRuleBatchEntry> rules = Lists.newLinkedList();
-        ConnectPoint prev = intent.src();
-
-        //TODO throw exception if the lambda was not retrieved successfully
-        for (Link link : intent.path().links()) {
-            Lambda la = null;
-            for (ResourceAllocation allocation : allocations.getResourceAllocation(link)) {
-                if (allocation.type() == ResourceType.LAMBDA) {
-                    la = ((LambdaResourceAllocation) allocation).lambda();
-                    break;
-                }
-            }
-
-            if (la == null) {
-                log.info("Lambda was not retrieved successfully");
-                return null;
-            }
-
-            treatmentBuilder.setOutput(link.src().port());
-            treatmentBuilder.setLambda((short) la.toInt());
-
-            FlowRule rule = new DefaultFlowRule(prev.deviceId(),
-                                                selectorBuilder.build(),
-                                                treatmentBuilder.build(),
-                                                100,
-                                                appId,
-                                                100,
-                                                true);
-            rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
-
-            prev = link.dst();
-            selectorBuilder.matchInport(link.dst().port());
-            selectorBuilder.matchLambda((short) la.toInt());
-        }
-
-        // build the last T port rule
-        TrafficTreatment treatmentLast = builder()
-                .setOutput(intent.dst().port()).build();
-        FlowRule rule = new DefaultFlowRule(intent.dst().deviceId(),
-                                            selectorBuilder.build(),
-                                            treatmentLast,
-                                            100,
-                                            appId,
-                                            100,
-                                            true);
-        rules.add(new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule));
-
-        return Lists.newArrayList(new FlowRuleBatchOperation(rules));
-    }
-
 }
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/DistributedLinkResourceStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/DistributedLinkResourceStore.java
new file mode 100644
index 0000000..41172cd
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/DistributedLinkResourceStore.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2014 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.onlab.onos.store.resource.impl;
+
+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.Link;
+import org.onlab.onos.net.intent.IntentId;
+import org.onlab.onos.net.resource.Bandwidth;
+import org.onlab.onos.net.resource.BandwidthResourceAllocation;
+import org.onlab.onos.net.resource.Lambda;
+import org.onlab.onos.net.resource.LambdaResourceAllocation;
+import org.onlab.onos.net.resource.LinkResourceAllocations;
+import org.onlab.onos.net.resource.LinkResourceStore;
+import org.onlab.onos.net.resource.ResourceAllocation;
+import org.onlab.onos.net.resource.ResourceType;
+import org.slf4j.Logger;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Manages link resources using trivial in-memory structures implementation.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedLinkResourceStore implements LinkResourceStore {
+    private final Logger log = getLogger(getClass());
+    private Map<IntentId, LinkResourceAllocations> linkResourceAllocationsMap;
+    private Map<Link, Set<LinkResourceAllocations>> allocatedResources;
+    private Map<Link, Set<ResourceAllocation>> freeResources;
+
+    @Activate
+    public void activate() {
+        linkResourceAllocationsMap = new HashMap<>();
+        allocatedResources = new HashMap<>();
+        freeResources = new HashMap<>();
+
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+    /**
+     * Returns free resources for a given link obtaining from topology
+     * information.
+     *
+     * @param link the target link
+     * @return free resources
+     */
+    private Set<ResourceAllocation> readOriginalFreeResources(Link link) {
+        // TODO read capacity and lambda resources from topology
+        Set<ResourceAllocation> allocations = new HashSet<>();
+        for (int i = 1; i <= 100; i++) {
+            allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
+        }
+        allocations.add(new BandwidthResourceAllocation(Bandwidth.valueOf(1000000)));
+        return allocations;
+    }
+
+    /**
+     * Finds and returns {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object from a given
+     * set.
+     *
+     * @param freeRes a set of ResourceAllocation object.
+     * @return {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object if found, otherwise
+     *         {@link org.onlab.onos.net.resource.BandwidthResourceAllocation} object with 0 bandwidth
+     *
+     */
+    private BandwidthResourceAllocation getBandwidth(Set<ResourceAllocation> freeRes) {
+        for (ResourceAllocation res : freeRes) {
+            if (res.type() == ResourceType.BANDWIDTH) {
+                return (BandwidthResourceAllocation) res;
+            }
+        }
+        return new BandwidthResourceAllocation(Bandwidth.valueOf(0));
+    }
+
+    /**
+     * Subtracts given resources from free resources for given link.
+     *
+     * @param link the target link
+     * @param allocations the resources to be subtracted
+     */
+    private void subtractFreeResources(Link link, LinkResourceAllocations allocations) {
+        // TODO Use lock or version for updating freeResources.
+        checkNotNull(link);
+        Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
+        Set<ResourceAllocation> subRes = allocations.getResourceAllocation(link);
+        for (ResourceAllocation res : subRes) {
+            switch (res.type()) {
+            case BANDWIDTH:
+                BandwidthResourceAllocation ba = getBandwidth(freeRes);
+                double requestedBandwidth =
+                        ((BandwidthResourceAllocation) res).bandwidth().toDouble();
+                double newBandwidth = ba.bandwidth().toDouble() - requestedBandwidth;
+                checkState(newBandwidth >= 0.0);
+                freeRes.remove(ba);
+                freeRes.add(new BandwidthResourceAllocation(
+                        Bandwidth.valueOf(newBandwidth)));
+                break;
+            case LAMBDA:
+                checkState(freeRes.remove(res));
+                break;
+            default:
+                break;
+            }
+        }
+        freeResources.put(link, freeRes);
+
+    }
+
+    /**
+     * Adds given resources to free resources for given link.
+     *
+     * @param link the target link
+     * @param allocations the resources to be added
+     */
+    private void addFreeResources(Link link, LinkResourceAllocations allocations) {
+        // TODO Use lock or version for updating freeResources.
+        Set<ResourceAllocation> freeRes = new HashSet<>(getFreeResources(link));
+        Set<ResourceAllocation> addRes = allocations.getResourceAllocation(link);
+        for (ResourceAllocation res : addRes) {
+            switch (res.type()) {
+            case BANDWIDTH:
+                BandwidthResourceAllocation ba = getBandwidth(freeRes);
+                double requestedBandwidth =
+                        ((BandwidthResourceAllocation) res).bandwidth().toDouble();
+                double newBandwidth = ba.bandwidth().toDouble() + requestedBandwidth;
+                freeRes.remove(ba);
+                freeRes.add(new BandwidthResourceAllocation(
+                        Bandwidth.valueOf(newBandwidth)));
+                break;
+            case LAMBDA:
+                checkState(freeRes.add(res));
+                break;
+            default:
+                break;
+            }
+        }
+        freeResources.put(link, freeRes);
+    }
+
+    @Override
+    public Set<ResourceAllocation> getFreeResources(Link link) {
+        checkNotNull(link);
+        Set<ResourceAllocation> freeRes = freeResources.get(link);
+        if (freeRes == null) {
+            freeRes = readOriginalFreeResources(link);
+        }
+
+        return freeRes;
+    }
+
+    @Override
+    public void allocateResources(LinkResourceAllocations allocations) {
+        checkNotNull(allocations);
+        linkResourceAllocationsMap.put(allocations.intendId(), allocations);
+        for (Link link : allocations.links()) {
+            subtractFreeResources(link, allocations);
+            Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
+            if (linkAllocs == null) {
+                linkAllocs = new HashSet<>();
+            }
+            linkAllocs.add(allocations);
+            allocatedResources.put(link, linkAllocs);
+        }
+    }
+
+    @Override
+    public void releaseResources(LinkResourceAllocations allocations) {
+        checkNotNull(allocations);
+        linkResourceAllocationsMap.remove(allocations);
+        for (Link link : allocations.links()) {
+            addFreeResources(link, allocations);
+            Set<LinkResourceAllocations> linkAllocs = allocatedResources.get(link);
+            if (linkAllocs == null) {
+                log.error("Missing resource allocation.");
+            } else {
+                linkAllocs.remove(allocations);
+            }
+            allocatedResources.put(link, linkAllocs);
+        }
+    }
+
+    @Override
+    public LinkResourceAllocations getAllocations(IntentId intentId) {
+        checkNotNull(intentId);
+        return linkResourceAllocationsMap.get(intentId);
+    }
+
+    @Override
+    public Iterable<LinkResourceAllocations> getAllocations(Link link) {
+        checkNotNull(link);
+        Set<LinkResourceAllocations> result = allocatedResources.get(link);
+        if (result == null) {
+            result = Collections.emptySet();
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    @Override
+    public Iterable<LinkResourceAllocations> getAllocations() {
+        return Collections.unmodifiableCollection(linkResourceAllocationsMap.values());
+    }
+
+}
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/package-info.java b/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/package-info.java
new file mode 100644
index 0000000..1e34e37
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/resource/impl/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Implementation of distributed packet store.
+ */
+package org.onlab.onos.store.resource.impl;
\ No newline at end of file
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 b91e8fc..2a4c10c 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
@@ -71,11 +71,14 @@
 import org.onlab.onos.net.intent.IntentState;
 import org.onlab.onos.net.intent.LinkCollectionIntent;
 import org.onlab.onos.net.intent.MultiPointToSinglePointIntent;
+import org.onlab.onos.net.intent.OpticalConnectivityIntent;
+import org.onlab.onos.net.intent.OpticalPathIntent;
 import org.onlab.onos.net.intent.PathIntent;
 import org.onlab.onos.net.intent.PointToPointIntent;
 import org.onlab.onos.net.link.DefaultLinkDescription;
 import org.onlab.onos.net.packet.DefaultOutboundPacket;
 import org.onlab.onos.net.provider.ProviderId;
+import org.onlab.onos.net.resource.LinkResourceRequest;
 import org.onlab.onos.store.Timestamp;
 import org.onlab.packet.ChassisId;
 import org.onlab.packet.IpAddress;
@@ -182,7 +185,10 @@
                     HostToHostIntent.class,
                     PointToPointIntent.class,
                     MultiPointToSinglePointIntent.class,
-                    LinkCollectionIntent.class
+                    LinkCollectionIntent.class,
+                    OpticalConnectivityIntent.class,
+                    OpticalPathIntent.class,
+                    LinkResourceRequest.class
                     )
             .register(DefaultApplicationId.class, new DefaultApplicationIdSerializer())
             .register(URI.class, new URISerializer())