Implementing the UiLayoutManager.

Change-Id: I0a3424f7e3b13a3c18e668a5eed5151755bce4f9
diff --git a/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java b/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
index 0aa7db0..989c807 100644
--- a/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
+++ b/core/api/src/main/java/org/onosproject/ui/UiTopoLayoutService.java
@@ -16,8 +16,9 @@
 package org.onosproject.ui;
 
 import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
 
-import java.util.List;
+import java.util.Set;
 
 /**
  * Service for managing {@link UiTopoLayout} instances.
@@ -25,20 +26,28 @@
 public interface UiTopoLayoutService {
 
     /**
-     * Returns the list of available layouts.
+     * Returns the set of available layouts.
      *
-     * @return available layouts
+     * @return set of available layouts
      */
-    List<UiTopoLayout> getLayouts();
+    Set<UiTopoLayout> getLayouts();
 
     /**
-     * Adds a layout to the system.
+     * Adds a layout to the system or updates an existing one.
      *
-     * @param layout the layout to add
+     * @param layout the layout to add or update
      * @return an indication of success
      */
     boolean addLayout(UiTopoLayout layout);
 
+
+    /**
+     * Returns the layout with the specified identifier.
+     * @param layoutId layout identifier
+     * @return layout or null if no such layout is found
+     */
+    UiTopoLayout getLayout(UiTopoLayoutId layoutId);
+
     /**
      * Removes a layout from the system.
      *
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
index 105b0da..289bb8f 100644
--- a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayout.java
@@ -24,6 +24,37 @@
  */
 public class UiTopoLayout {
 
-    private Region backingRegion;
+    private final UiTopoLayoutId id;
+    private final Region region;
 
+    /**
+     * Created a new UI topology layout.
+     *
+     * @param id     layout identifier
+     * @param region backing region
+     */
+    public UiTopoLayout(UiTopoLayoutId id, Region region) {
+        this.id = id;
+        this.region = region;
+    }
+
+    /**
+     * Returns the UI layout identifier.
+     *
+     * @return identifier of the layout
+     */
+    public UiTopoLayoutId id() {
+        return id;
+    }
+
+    /**
+     * Returns the backing region with which this layout is associated.
+     *
+     * @return backing region
+     */
+    public Region region() {
+        return region;
+    }
+
+    // TODO: additional properties pertinent to the layout
 }
diff --git a/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayoutId.java b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayoutId.java
new file mode 100644
index 0000000..2fa8717
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/ui/model/topo/UiTopoLayoutId.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 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.ui.model.topo;
+
+import org.onlab.util.Identifier;
+
+/**
+ * Identifier of a topology layout.
+ */
+public final class UiTopoLayoutId extends Identifier<String> {
+
+    // For serialization
+    private UiTopoLayoutId() {
+    }
+
+    private UiTopoLayoutId(String value) {
+        super(value);
+    }
+
+    /**
+     * Returns the layout identifier created from the specified value.
+     *
+     * @param value string value
+     * @return layout identifier
+     */
+    public static UiTopoLayoutId layoutId(String value) {
+        return new UiTopoLayoutId(value);
+    }
+}
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
index ed9eead..3488707 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/UiExtensionManager.java
@@ -189,7 +189,6 @@
     @Deactivate
     public void deactivate() {
         prefs.removeListener(prefsListener);
-        prefs.destroy();
         UiWebSocketServlet.closeAll();
         unregister(core);
         log.info("Stopped");
diff --git a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
index a8959df..bc58121 100644
--- a/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
+++ b/web/gui/src/main/java/org/onosproject/ui/impl/topo/UiTopoLayoutManager.java
@@ -16,16 +16,26 @@
 
 package org.onosproject.ui.impl.topo;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
 import org.onosproject.ui.UiTopoLayoutService;
 import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Manages the user interface topology layouts.
@@ -35,39 +45,54 @@
 @Service
 public class UiTopoLayoutManager implements UiTopoLayoutService {
 
-//    private static final ClassLoader CL =
-//            UiTopoLayoutManager.class.getClassLoader();
-
     private final Logger log = LoggerFactory.getLogger(getClass());
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    private ConsistentMap<UiTopoLayoutId, UiTopoLayout> layouts;
+    private Map<UiTopoLayoutId, UiTopoLayout> layoutMap;
+
     @Activate
     public void activate() {
-        // TODO: implement starting stuff
+        KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
+                .register(KryoNamespaces.API)
+                .register(UiTopoLayout.class);
+
+        layouts = storageService.<UiTopoLayoutId, UiTopoLayout>consistentMapBuilder()
+                .withSerializer(Serializer.using(kryoBuilder.build()))
+                .withName("onos-topo-layouts")
+                .withRelaxedReadConsistency()
+                .build();
+        layoutMap = layouts.asJavaMap();
+
         log.info("Started");
     }
 
     @Deactivate
     public void deactivate() {
-        // TODO: implement stopping stuff
         log.info("Stopped");
     }
 
 
     @Override
-    public List<UiTopoLayout> getLayouts() {
-        // TODO: implement
-        return null;
+    public Set<UiTopoLayout> getLayouts() {
+        return ImmutableSet.copyOf(layoutMap.values());
     }
 
     @Override
     public boolean addLayout(UiTopoLayout layout) {
-        // TODO: implement
-        return false;
+        return layouts.put(layout.id(), layout) == null;
+    }
+
+    @Override
+    public UiTopoLayout getLayout(UiTopoLayoutId layoutId) {
+        return layoutMap.get(layoutId);
     }
 
     @Override
     public boolean removeLayout(UiTopoLayout layout) {
-        // TODO: implement
-        return false;
+        return layouts.remove(layout.id()) != null;
     }
+
 }
diff --git a/web/gui/src/test/java/org/onosproject/ui/impl/topo/UiTopoLayoutManagerTest.java b/web/gui/src/test/java/org/onosproject/ui/impl/topo/UiTopoLayoutManagerTest.java
new file mode 100644
index 0000000..c58e1a2
--- /dev/null
+++ b/web/gui/src/test/java/org/onosproject/ui/impl/topo/UiTopoLayoutManagerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 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.ui.impl.topo;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.net.region.DefaultRegion;
+import org.onosproject.net.region.Region;
+import org.onosproject.net.region.RegionId;
+import org.onosproject.store.service.TestStorageService;
+import org.onosproject.ui.UiTopoLayoutService;
+import org.onosproject.ui.model.topo.UiTopoLayout;
+import org.onosproject.ui.model.topo.UiTopoLayoutId;
+
+import static org.junit.Assert.*;
+
+/**
+ * Suite of unit tests for the UI topology layout manager.
+ */
+public class UiTopoLayoutManagerTest {
+
+    private UiTopoLayoutService svc;
+    private UiTopoLayoutManager mgr;
+
+    private static final UiTopoLayout L1 =
+            new UiTopoLayout(UiTopoLayoutId.layoutId("l1"),
+                             new DefaultRegion(RegionId.regionId("r1"), "R1",
+                                               Region.Type.CAMPUS, null));
+    private static final UiTopoLayout L2 =
+            new UiTopoLayout(UiTopoLayoutId.layoutId("l2"),
+                             new DefaultRegion(RegionId.regionId("r2"), "R2",
+                                               Region.Type.CAMPUS, null));
+
+    @Before
+    public void setUp() {
+        mgr = new UiTopoLayoutManager();
+        svc = mgr;
+        mgr.storageService = new TestStorageService();
+        mgr.activate();
+    }
+
+    @After
+    public void tearDown() {
+        mgr.deactivate();
+        mgr.storageService = null;
+    }
+
+    @Test
+    public void basics() {
+        assertTrue("should be no layout", svc.getLayouts().isEmpty());
+        svc.addLayout(L1);
+        svc.addLayout(L2);
+        assertEquals("incorrect number of layouts", 2, svc.getLayouts().size());
+        assertEquals("incorrect layout", L1.id(), svc.getLayout(L1.id()).id());
+        assertEquals("incorrect layout", L2.id(), svc.getLayout(L2.id()).id());
+        svc.removeLayout(L1);
+        assertEquals("incorrect number of layouts", 1, svc.getLayouts().size());
+        assertNull("layout should be gone", svc.getLayout(L1.id()));
+        assertEquals("incorrect layout", L2.id(), svc.getLayout(L2.id()).id());
+    }
+
+
+}
\ No newline at end of file