ONOS-785 Adding distributed store for apps & app admin CLIs

Change-Id: Ia7639f3258fca2a18ba513f0c95de0ab8ea7ceee
diff --git a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
index 90e6005..61cb2e3 100644
--- a/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
+++ b/core/common/src/main/java/org/onosproject/common/app/ApplicationArchive.java
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
+import java.nio.file.NoSuchFileException;
 import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
@@ -63,17 +64,25 @@
 
     private static Logger log = LoggerFactory.getLogger(ApplicationArchive.class);
     private static final String APP_XML = "app.xml";
+    private static final String M2_PREFIX = "m2";
+
+    private static final String KARAF_ROOT = ".";
+    private static final String M2_ROOT = "system/";
     private static final String APPS_ROOT = "data/apps/";
 
-    private File appsDir = new File(APPS_ROOT);
+    private File karafRoot = new File(KARAF_ROOT);
+    private File m2Dir = new File(karafRoot, M2_ROOT);
+    private File appsDir = new File(karafRoot, APPS_ROOT);
 
     /**
      * Sets the root directory where application artifacts are kept.
      *
      * @param appsRoot top-level applications directory path
      */
-    protected void setAppsRoot(String appsRoot) {
-        this.appsDir = new File(appsRoot);
+    protected void setRootPath(String appsRoot) {
+        this.karafRoot = new File(appsRoot);
+        this.appsDir = new File(karafRoot, APPS_ROOT);
+        this.m2Dir = new File(karafRoot, M2_ROOT);
     }
 
     /**
@@ -81,8 +90,8 @@
      *
      * @return top-level applications directory path
      */
-    protected String getAppsRoot() {
-        return appsDir.getPath();
+    protected String getRootPath() {
+        return karafRoot.getPath();
     }
 
     /**
@@ -238,10 +247,20 @@
     }
 
     // Installs application artifacts into M2 repository.
-    private void installArtifacts(ApplicationDescription desc) {
-        // FIXME: implement M2 repository copy
+    private void installArtifacts(ApplicationDescription desc) throws IOException {
+        try {
+            Tools.copyDirectory(appFile(desc.name(), M2_PREFIX), m2Dir);
+        } catch (NoSuchFileException e) {
+            log.debug("Application {} has no M2 artifacts", desc.name());
+        }
     }
 
+    /**
+     * Marks the app as active by creating token file in the app directory.
+     *
+     * @param appName application name
+     * @return true if file was created
+     */
     protected boolean setActive(String appName) {
         try {
             return appFile(appName, "active").createNewFile();
@@ -250,10 +269,22 @@
         }
     }
 
+    /**
+     * Clears the app as active by deleting token file in the app directory.
+     *
+     * @param appName application name
+     * @return true if file was deleted
+     */
     protected boolean clearActive(String appName) {
         return appFile(appName, "active").delete();
     }
 
+    /**
+     * Indicates whether the app was marked as active by checking for token file.
+     *
+     * @param appName application name
+     * @return true if the app is marked as active
+     */
     protected boolean isActive(String appName) {
         return appFile(appName, "active").exists();
     }
diff --git a/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java b/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java
index c1b8e82..3d86dda 100644
--- a/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java
+++ b/core/common/src/test/java/org/onosproject/common/app/ApplicationArchiveTest.java
@@ -17,13 +17,17 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.io.ByteStreams;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onlab.util.Tools;
 import org.onosproject.app.ApplicationDescription;
 import org.onosproject.app.ApplicationException;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Random;
 import java.util.Set;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -32,13 +36,20 @@
 
 public class ApplicationArchiveTest {
 
-    static final String ROOT = "/tmp/app-junit";
+    static final String ROOT = "/tmp/app-junit/" + new Random().nextInt();
 
     private ApplicationArchive aar = new ApplicationArchive();
 
     @Before
     public void setUp() {
-        aar.setAppsRoot(ROOT);
+        aar.setRootPath(ROOT);
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        if (new File(aar.getRootPath()).exists()) {
+            Tools.removeDirectory(aar.getRootPath());
+        }
     }
 
     private void validate(ApplicationDescription app) {
@@ -77,7 +88,8 @@
     public void purgeApp() throws IOException {
         saveApp();
         aar.purgeApplication(APP_NAME);
-        assertEquals("incorrect names", ImmutableSet.of(), aar.getApplicationNames());
+        assertEquals("incorrect names", ImmutableSet.<String>of(),
+                     aar.getApplicationNames());
     }
 
     @Test