You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by mn...@apache.org on 2010/01/12 18:14:00 UTC

svn commit: r898425 - in /incubator/aries/trunk/application: application-api/src/main/java/org/apache/aries/application/ application-api/src/main/java/org/apache/aries/application/management/ application-management/src/main/java/org/apache/aries/applic...

Author: mnuttall
Date: Tue Jan 12 17:13:59 2010
New Revision: 898425

URL: http://svn.apache.org/viewvc?rev=898425&view=rev
Log:
ARIES-89: Implement application support: Construct AriesApplication when DEPLOYMENT.MF exists. Store and reload an .eba in unit test. 

Added:
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/ResolveConstraint.java
Removed:
    incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/ExplodedEBA.java
Modified:
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/DeploymentMetadataFactory.java
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplication.java
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationManager.java
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/LocalPlatform.java
    incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationImpl.java
    incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationManagerImpl.java
    incubator/aries/trunk/application/application-management/src/test/java/org/apache/aries/application/management/impl/AriesApplicationManagerImplTest.java
    incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataFactoryImpl.java
    incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataImpl.java
    incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/utils/filesystem/IOUtils.java

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/DeploymentMetadataFactory.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/DeploymentMetadataFactory.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/DeploymentMetadataFactory.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/DeploymentMetadataFactory.java Tue Jan 12 17:13:59 2010
@@ -19,8 +19,10 @@
 
 package org.apache.aries.application;
 
+import java.io.IOException;
 import java.util.Set;
 
+import org.apache.aries.application.filesystem.IFile;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.BundleInfo;
 
@@ -34,4 +36,9 @@
    */
   public DeploymentMetadata createDeploymentMetadata (AriesApplication app, Set<BundleInfo> bundleInfo);
   
+  /**
+   * Create a DeploymentMetadata instance from an IFile
+   */
+  public DeploymentMetadata createDeploymentMetadata (IFile src) throws IOException;
+  
 }

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplication.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplication.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplication.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplication.java Tue Jan 12 17:13:59 2010
@@ -44,5 +44,5 @@
 
   /** Stores any changes to disk using this implementations storage form */
   public void store(File f) throws FileNotFoundException, IOException;
-  public void store(OutputStream in) throws FileNotFoundException, IOException;
+  public void store(OutputStream out) throws FileNotFoundException, IOException;
 }

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationManager.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationManager.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationManager.java Tue Jan 12 17:13:59 2010
@@ -38,4 +38,5 @@
   public void uninstall(ApplicationContext app);
   public void addApplicationListener(ApplicationListener l);
   public void removeApplicationListener(ApplicationListener l);
+  AriesApplication resolve (AriesApplication originalApp, ResolveConstraint ... constraints);
 }

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/LocalPlatform.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/LocalPlatform.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/LocalPlatform.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/LocalPlatform.java Tue Jan 12 17:13:59 2010
@@ -20,6 +20,7 @@
 package org.apache.aries.application.management;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * This is a difficult interface to name properly. It holds methods that need to 
@@ -28,5 +29,6 @@
  */
 public interface LocalPlatform {
 
-  public File getTemporaryDirectory();
+  public File getTemporaryDirectory() throws IOException;
+  public File getTemporaryFile() throws IOException;
 }

Added: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/ResolveConstraint.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/ResolveConstraint.java?rev=898425&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/ResolveConstraint.java (added)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/ResolveConstraint.java Tue Jan 12 17:13:59 2010
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.aries.application.management;
+
+import org.osgi.framework.Version;
+
+/**
+ * An administrator may wish to change the content of an installed application. 
+ * A ResolveConstraint records one of the desired elements of the newly re-resolved
+ * application. 
+ */
+public interface ResolveConstraint {
+  public String getBundleName();
+  public Version getVersion();
+
+}

Modified: incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationImpl.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationImpl.java (original)
+++ incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationImpl.java Tue Jan 12 17:13:59 2010
@@ -58,6 +58,15 @@
     
   }
   
+  public AriesApplicationImpl(ApplicationMetadata meta, DeploymentMetadata dep, 
+      Set<BundleInfo> bundleInfo, LocalPlatform lp) {
+    _applicationMetadata = meta;
+    _bundleInfo = bundleInfo;
+    _deploymentMetadata = dep;
+    _localPlatform = lp;
+    
+  }
+  
   public ApplicationMetadata getApplicationMetadata() {
     return _applicationMetadata;
   }
@@ -77,6 +86,10 @@
   public void setModifiedBundles (Map<String, InputStream> modifiedBundles) {
     _modifiedBundles = modifiedBundles;
   }
+  
+  public void setLocalPlatform (LocalPlatform lp) { 
+    _localPlatform = lp;
+  }
 
   public void store(File f) throws FileNotFoundException, IOException {
     OutputStream os = new FileOutputStream (f);
@@ -84,10 +97,14 @@
     os.close();
   }
 
+  /**
+   * Construct an eba in a temporary directory
+   * Copy the eba to the target output stream 
+   * Delete the temporary directory.
+   * Leave target output stream open
+   */
   public void store(OutputStream targetStream) throws FileNotFoundException, IOException {
-    // Construct an eba in a temporary directory
-    // Copy the eba to the target output stream 
-    // Delete the temporary directory. 
+ 
     //
     // This code will be run on various application server platforms, each of which
     // will have its own policy about where to create temporary directories. We 
@@ -129,7 +146,20 @@
       }
     }
 
-    // TODO: Write the migrated bundles out
+    // Write the migrated bundles out
+    if (_modifiedBundles != null) { 
+      for (Map.Entry<String, InputStream> modifiedBundle : _modifiedBundles.entrySet()) { 
+        out = IOUtils.getOutputStream(tempDir, modifiedBundle.getKey());
+        IOUtils.copy(modifiedBundle.getValue(), out);
+        IOUtils.close(out);
+      }
+    }
     
+    // We now have an exploded eba in tempDir which we need to copy into targetStream
+    IOUtils.zipUp(tempDir, targetStream);
+    if (!IOUtils.deleteRecursive(tempDir))
+    {
+      // TODO: Log a warning
+    }
   }
 }

Modified: incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationManagerImpl.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationManagerImpl.java (original)
+++ incubator/aries/trunk/application/application-management/src/main/java/org/apache/aries/application/management/impl/AriesApplicationManagerImpl.java Tue Jan 12 17:13:59 2010
@@ -19,8 +19,11 @@
 
 package org.apache.aries.application.management.impl;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -45,7 +48,9 @@
 import org.apache.aries.application.management.BundleInfo;
 import org.apache.aries.application.management.LocalPlatform;
 import org.apache.aries.application.management.ManagementException;
+import org.apache.aries.application.management.ResolveConstraint;
 import org.apache.aries.application.utils.AppConstants;
+import org.apache.aries.application.utils.filesystem.FileSystem;
 import org.apache.aries.application.utils.filesystem.IOUtils;
 import org.apache.aries.application.utils.manifest.BundleManifest;
 import org.apache.aries.application.utils.manifest.ManifestDefaultsInjector;
@@ -86,71 +91,68 @@
    * as per http://incubator.apache.org/aries/applications.html 
    */
   public AriesApplication createApplication(IDirectory ebaFile) throws ManagementException {
-    ApplicationMetadata applicationMetadata;
-    DeploymentMetadata deploymentMetadata;
+    ApplicationMetadata applicationMetadata = null;
+    DeploymentMetadata deploymentMetadata = null;
     Map<String, InputStream> modifiedBundles = new HashMap<String, InputStream>();
     AriesApplicationImpl application = null;
     
-    /* Locate META-INF/APPLICATION.MF and ensure that the 
-     * manifest has the necessary fields set
-     */
     try { 
-      Manifest applicationManifest = parseManifest (ebaFile, AppConstants.APPLICATION_MF);
+      Manifest applicationManifest = parseApplicationManifest (ebaFile);
       ManifestDefaultsInjector.updateManifest(applicationManifest, ebaFile.getName(), ebaFile); 
       applicationMetadata = _applicationMetadataManager.createApplicationMetadata(applicationManifest);
 
-      Manifest deploymentManifest = parseManifest (ebaFile, AppConstants.DEPLOYMENT_MF);
-      if (deploymentManifest != null) {
-        // If there's a deployment.mf present, check it matches applicationManifest, and if so, use it
-        // TODO: Implement this bit
-      } else { 
-        //  -- Process any other files in the .eba, i.e. migrate wars to wabs, plain jars to bundles
+      IFile deploymentManifest = ebaFile.getFile(AppConstants.DEPLOYMENT_MF);
+      if (deploymentManifest != null) { 
+        deploymentMetadata = _deploymentMetadataFactory.createDeploymentMetadata(deploymentManifest);
+      }
+      /* We require that all other .jar and .war files included by-value be valid bundles
+       * because a DEPLOYMENT.MF has been provided. If no DEPLOYMENT.MF, migrate 
+       * wars to wabs, plain jars to bundles
+       */
         
-        Set<BundleInfo> extraBundlesInfo = new HashSet<BundleInfo>();
-        for (IFile f : ebaFile) { 
-          if (f.isDirectory()) { 
-            continue;
-          }
-          
-          BundleManifest bm = getBundleManifest (f);
-          if (bm != null) {
-            if (bm.isValid()) {
-              extraBundlesInfo.add(new BundleInfoImpl(bm, f.toURL().toExternalForm()));
-            } else { 
-              // We have a jar that needs converting to a bundle, or a war to migrate to a WAB
-              InputStream convertedBinary = null;
-              Iterator<BundleConverter> converters = _bundleConverters.iterator();
-              while (converters.hasNext() && convertedBinary == null) { 
-                try { 
-                  // WarToWabConverter can extract application.xml via
-                  // eba.getFile(AppConstants.APPLICATION_XML);
-                  convertedBinary = converters.next().convert(ebaFile, f);
-                } catch (ServiceException sx) {
-                  // We'll get this if our optional BundleConverter has not been injected. 
-                }
-              }
-              if (convertedBinary != null) { 
-                modifiedBundles.put (f.getName(), convertedBinary);
-                InputStream is = null;
-                try { 
-                  is = f.open();
-                  bm = BundleManifest.fromBundle(is);
-                } finally { 
-                  IOUtils.close(is);
-                }
-                extraBundlesInfo.add(new BundleInfoImpl(bm, f.getName()));
+      Set<BundleInfo> extraBundlesInfo = new HashSet<BundleInfo>();
+      for (IFile f : ebaFile) { 
+        if (f.isDirectory()) { 
+          continue;
+        }
+        
+        BundleManifest bm = getBundleManifest (f);
+        if (bm != null) {
+          if (bm.isValid()) {
+            extraBundlesInfo.add(new BundleInfoImpl(bm, f.toURL().toExternalForm()));
+          } else if (deploymentMetadata != null) {
+            throw new ManagementException ("Invalid bundle " + f.getName() + " found when DEPLOYMENT.MF present");
+          } else { 
+            // We have a jar that needs converting to a bundle, or a war to migrate to a WAB
+            InputStream convertedBinary = null;
+            Iterator<BundleConverter> converters = _bundleConverters.iterator();
+            while (converters.hasNext() && convertedBinary == null) { 
+              try { 
+                // WarToWabConverter can extract application.xml via
+                // eba.getFile(AppConstants.APPLICATION_XML);
+                convertedBinary = converters.next().convert(ebaFile, f);
+              } catch (ServiceException sx) {
+                // We'll get this if our optional BundleConverter has not been injected. 
               }
             }
-          } 
-        }
-               
-        application = new AriesApplicationImpl (applicationMetadata, extraBundlesInfo, _localPlatform);
-        Set<BundleInfo> additionalBundlesRequired = _resolver.resolve(application);
-        deploymentMetadata = _deploymentMetadataFactory.createDeploymentMetadata(application, additionalBundlesRequired);
-        application.setDeploymentMetadata(deploymentMetadata);
+            if (convertedBinary != null) { 
+              modifiedBundles.put (f.getName(), convertedBinary);
+              bm = BundleManifest.fromBundle(f);
+              extraBundlesInfo.add(new BundleInfoImpl(bm, f.getName()));
+            }
+          }
+        } 
+        if (deploymentMetadata != null) { 
+          application = new AriesApplicationImpl (applicationMetadata, deploymentMetadata, extraBundlesInfo, _localPlatform);
+        } else { 
+          application = new AriesApplicationImpl (applicationMetadata, extraBundlesInfo, _localPlatform);
+          Set<BundleInfo> additionalBundlesRequired = _resolver.resolve(application);
+          deploymentMetadata = _deploymentMetadataFactory.createDeploymentMetadata(application, additionalBundlesRequired);
+          application.setDeploymentMetadata(deploymentMetadata);
         
-        // Store a reference to any modified bundles
-        application.setModifiedBundles (modifiedBundles);
+          // Store a reference to any modified bundles
+          application.setModifiedBundles (modifiedBundles);
+        }
         
       }
     } catch (IOException iox) { 
@@ -161,12 +163,36 @@
     return application;
   }
 
+  /**
+   * Create an application from a URL. 
+   * The first version of this method isn't smart enough to check whether
+   * the input URL is file://
+   */
   public AriesApplication createApplication(URL url) throws ManagementException {
-    // If URL isn't file://, we need to download the asset from that url and 
-    // then call createApplication(File)
-    return null;
+    OutputStream os = null;
+    AriesApplication app = null;
+    try { 
+      File tempFile = _localPlatform.getTemporaryFile();
+      InputStream is = url.openStream();
+      os = new FileOutputStream (tempFile);
+      IOUtils.copy(is, os);
+      IDirectory downloadedSource = FileSystem.getFSRoot(tempFile);
+      app = createApplication (downloadedSource);
+    } catch (IOException iox) {
+      throw new ManagementException (iox);
+    }
+      finally { 
+      IOUtils.close(os);
+    }
+    return app;
   }
 
+  public AriesApplication resolve(AriesApplication originalApp,
+      ResolveConstraint... constraints) {
+    // TODO Auto-generated method stub
+    return null;
+  } 
+  
   public ApplicationContext getApplicationContext(AriesApplication app) {
     // TODO Auto-generated method stub
     return null;
@@ -199,15 +225,14 @@
 
 
   /**
-   * Locate and parse an application or deployment.mf in an eba
-   * @param ebaFile An aries application file
-   * @param fileName META-INF/APPLICATION.MF or META-INF/DEPLOYMENT.MF
+   * Locate and parse an application.mf in an eba
+   * @param source An aries application file
    * @return parsed manifest, or null
    * @throws IOException
    */
-  private Manifest parseManifest (IDirectory source, String fileName) throws IOException {
+  private Manifest parseApplicationManifest (IDirectory source) throws IOException {
     Manifest result = null;
-    IFile f = source.getFile(fileName);
+    IFile f = source.getFile(AppConstants.APPLICATION_MF);
     if (f != null) { 
       InputStream is = null;
       try { 
@@ -238,7 +263,6 @@
       IOUtils.close(in);
     }    
     return mf;
-  } 
-  
-  
+  }
+
 }

Modified: incubator/aries/trunk/application/application-management/src/test/java/org/apache/aries/application/management/impl/AriesApplicationManagerImplTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-management/src/test/java/org/apache/aries/application/management/impl/AriesApplicationManagerImplTest.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-management/src/test/java/org/apache/aries/application/management/impl/AriesApplicationManagerImplTest.java (original)
+++ incubator/aries/trunk/application/application-management/src/test/java/org/apache/aries/application/management/impl/AriesApplicationManagerImplTest.java Tue Jan 12 17:13:59 2010
@@ -20,9 +20,11 @@
 package org.apache.aries.application.management.impl;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -36,6 +38,7 @@
 import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.DeploymentMetadataFactory;
 import org.apache.aries.application.filesystem.IDirectory;
+import org.apache.aries.application.filesystem.IFile;
 import org.apache.aries.application.impl.ApplicationMetadataManagerImpl;
 import org.apache.aries.application.impl.ContentImpl;
 import org.apache.aries.application.impl.DeploymentContentImpl;
@@ -44,33 +47,50 @@
 import org.apache.aries.application.management.AriesApplicationResolver;
 import org.apache.aries.application.management.BundleConverter;
 import org.apache.aries.application.management.BundleInfo;
+import org.apache.aries.application.management.LocalPlatform;
+import org.apache.aries.application.management.ManagementException;
 import org.apache.aries.application.utils.filesystem.FileSystem;
 import org.apache.aries.application.utils.filesystem.IOUtils;
 import org.apache.aries.application.utils.manifest.BundleManifest;
 import org.apache.aries.unittest.utils.EbaUnitTestUtils;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.osgi.framework.Version;
 
+/**
+ * Initial, simple test that creates and stores an AriesApplication. No
+ * BundleConverters are used in this test. 
+ */
 public class AriesApplicationManagerImplTest {
   
-  class DummyResolver implements AriesApplicationResolver {
-
+  static class DummyResolver implements AriesApplicationResolver {
     Set<BundleInfo> nextResult;
     public Set<BundleInfo> resolve(AriesApplication app) {
       return nextResult;
     } 
-    
     void setNextResult (Set<BundleInfo> r) { 
       nextResult = r;
     }
-    
+  }
+  
+  static class DummyLocalPlatform implements LocalPlatform {
+    public File getTemporaryDirectory() throws IOException {
+      File f = File.createTempFile("ebaTmp", null);
+      f.delete();
+      f.mkdir();
+      return f;
+    } 
+    public File getTemporaryFile () throws IOException { 
+      // Not used
+      return File.createTempFile("ebaTmp", null);
+    }
   }
 
   static final String TEST_EBA = "./ariesApplicationManagerImplTest/test.eba";
   
   @BeforeClass 
-  public static void setup() throws Exception { 
+  public static void preTest() throws Exception { 
     new File("ariesApplicationManagerImplTest").mkdir();
     EbaUnitTestUtils.createEba("../src/test/resources/bundles/test.eba", TEST_EBA);
     File src = new File ("../src/test/resources/bundles/repository/a.handy.persistence.library.jar");
@@ -78,36 +98,29 @@
     IOUtils.zipUp(src, dest);
   }
   
-  @Test
-  public void testCreate() throws Exception { 
-    AriesApplicationManagerImpl appMgr = new AriesApplicationManagerImpl ();
-    ApplicationMetadataManager appMetaMgr = new ApplicationMetadataManagerImpl ();
+  AriesApplicationManagerImpl _appMgr;
+  ApplicationMetadataManager _appMetaMgr;
+  DummyResolver _resolver;
+  
+  @Before
+  public void setup() { 
+    _appMgr = new AriesApplicationManagerImpl ();
+    _appMetaMgr = new ApplicationMetadataManagerImpl ();
+
     DeploymentMetadataFactory dmf = new DeploymentMetadataFactoryImpl();
     List<BundleConverter> bundleConverters = new ArrayList<BundleConverter>();
-    DummyResolver resolver = new DummyResolver();
-    
-    appMgr.setApplicationMetadataManager(appMetaMgr);
-    appMgr.setDeploymentMetadataFactory(dmf);
-    appMgr.setBundleConverters(bundleConverters);
-    appMgr.setResolver(resolver);
-    
-    // This next block is a very long winded way of constructing a BundleInfoImpl
-    // against the existing (BundleManifest bm, String location) constructor. If we 
-    // find we need a String-based BundleInfoImpl constructor for other reasons, 
-    // we could change to using it here. 
-    Set<BundleInfo> nextResolverResult = new HashSet<BundleInfo>();
-    String persistenceLibraryLocation = "../src/test/resources/bundles/repository/a.handy.persistence.library.jar";
-    File persistenceLibrary = new File (persistenceLibraryLocation);
-    BundleManifest mf = BundleManifest.fromBundle(persistenceLibrary);
-    BundleInfo resolvedPersistenceLibrary = new BundleInfoImpl(mf, persistenceLibraryLocation); 
-    Field v = BundleInfoImpl.class.getDeclaredField("_version");
-    v.setAccessible(true);
-    v.set(resolvedPersistenceLibrary, new Version("1.1.0"));
-    nextResolverResult.add(resolvedPersistenceLibrary);
-    resolver.setNextResult(nextResolverResult);
+    _resolver = new DummyResolver();
     
-    IDirectory testEba = FileSystem.getFSRoot(new File(TEST_EBA));
-    AriesApplication app = appMgr.createApplication(testEba);
+    _appMgr.setApplicationMetadataManager(_appMetaMgr);
+    _appMgr.setDeploymentMetadataFactory(dmf);
+    _appMgr.setBundleConverters(bundleConverters);
+    _appMgr.setResolver(_resolver);
+    _appMgr.setLocalPlatform(new DummyLocalPlatform());
+  }
+  
+  @Test
+  public void testCreate() throws Exception { 
+    AriesApplication app = createApplication (TEST_EBA);
     
     ApplicationMetadata appMeta = app.getApplicationMetadata();
     assertEquals (appMeta.getApplicationName(), "Test application");
@@ -132,4 +145,57 @@
     assertTrue (dcList.contains(dc3));
   
   }
+  
+  @Test
+  public void testStoreAndReload() throws Exception { 
+    AriesApplication app = createApplication (TEST_EBA);
+    File dest = new File ("ariesApplicationManagerImplTest/stored.eba");
+    app.store(dest);
+    
+    /* Dest should be a zip file with four entries:
+     *  /foo.bar.widgets.jar
+     *  /my.business.logic.jar
+     *  /META-INF/APPLICATION.MF
+     *  /META-INF/DEPLOYMENT.MF
+     */
+    
+    IDirectory storedEba = FileSystem.getFSRoot(dest);
+    assertNotNull (storedEba);
+    assertEquals (storedEba.listFiles().size(), 3);
+    IFile ifile = storedEba.getFile("META-INF/APPLICATION.MF");
+    assertNotNull (ifile);
+    ifile = storedEba.getFile ("META-INF/DEPLOYMENT.MF");
+    assertNotNull (ifile);
+    ifile = storedEba.getFile ("foo.bar.widgets.jar");
+    assertNotNull (ifile);
+    ifile = storedEba.getFile ("my.business.logic.jar");
+    assertNotNull (ifile);
+    
+    AriesApplication newApp = _appMgr.createApplication(storedEba);
+    DeploymentMetadata dm = newApp.getDeploymentMetadata();
+    assertEquals (dm.getApplicationDeploymentContents().size(), 3);
+    assertEquals (dm.getApplicationSymbolicName(), app.getApplicationMetadata().getApplicationSymbolicName());
+    assertEquals (dm.getApplicationVersion(), app.getApplicationMetadata().getApplicationVersion());
+  }
+  
+  private AriesApplication createApplication (String fileName) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ManagementException  { 
+    // This next block is a very long winded way of constructing a BundleInfoImpl
+    // against the existing (BundleManifest bm, String location) constructor. If we 
+    // find we need a String-based BundleInfoImpl constructor for other reasons, 
+    // we could change to using it here. 
+    Set<BundleInfo> nextResolverResult = new HashSet<BundleInfo>();
+    String persistenceLibraryLocation = "../src/test/resources/bundles/repository/a.handy.persistence.library.jar";
+    File persistenceLibrary = new File (persistenceLibraryLocation);
+    BundleManifest mf = BundleManifest.fromBundle(persistenceLibrary);
+    BundleInfo resolvedPersistenceLibrary = new BundleInfoImpl(mf, persistenceLibraryLocation); 
+    Field v = BundleInfoImpl.class.getDeclaredField("_version");
+    v.setAccessible(true);
+    v.set(resolvedPersistenceLibrary, new Version("1.1.0"));
+    nextResolverResult.add(resolvedPersistenceLibrary);
+    _resolver.setNextResult(nextResolverResult);
+    
+    IDirectory testEba = FileSystem.getFSRoot(new File(TEST_EBA));
+    AriesApplication app = _appMgr.createApplication(testEba);
+    return app;
+  }
 }

Modified: incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataFactoryImpl.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataFactoryImpl.java (original)
+++ incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataFactoryImpl.java Tue Jan 12 17:13:59 2010
@@ -19,10 +19,12 @@
 
 package org.apache.aries.application.impl;
 
+import java.io.IOException;
 import java.util.Set;
 
 import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.DeploymentMetadataFactory;
+import org.apache.aries.application.filesystem.IFile;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.BundleInfo;
 
@@ -32,4 +34,8 @@
       Set<BundleInfo> additionalBundlesRequired) {
     return new DeploymentMetadataImpl (app, additionalBundlesRequired);
   }
+  
+  public DeploymentMetadata createDeploymentMetadata(IFile src) throws IOException { 
+    return new DeploymentMetadataImpl (src);
+  }
 }

Modified: incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataImpl.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataImpl.java (original)
+++ incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/impl/DeploymentMetadataImpl.java Tue Jan 12 17:13:59 2010
@@ -23,6 +23,7 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -35,9 +36,11 @@
 import org.apache.aries.application.Content;
 import org.apache.aries.application.DeploymentContent;
 import org.apache.aries.application.DeploymentMetadata;
+import org.apache.aries.application.filesystem.IFile;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.BundleInfo;
 import org.apache.aries.application.utils.AppConstants;
+import org.apache.aries.application.utils.manifest.ManifestProcessor;
 import org.osgi.framework.Version;
 
 public class DeploymentMetadataImpl implements DeploymentMetadata {
@@ -60,6 +63,30 @@
       _deploymentContent.add(dci);
     }
   }
+  
+  /**
+   * Construct a DeploymentMetadata from an IFile
+   * @param src
+   * @throws IOException
+   */
+  public DeploymentMetadataImpl (IFile src) throws IOException { 
+    InputStream is = src.open();
+    try { 
+      // Populate application symbolic name and version fields
+      Manifest mf = ManifestProcessor.parseManifest(is);
+      _applicationMetadata = new ApplicationMetadataImpl (mf);
+
+      Attributes attributes = mf.getMainAttributes();
+      String deploymentContent = attributes.getValue(AppConstants.DEPLOYMENT_CONTENT);
+      List<String> dcList = ManifestProcessor.split(deploymentContent, ",");
+      _deploymentContent = new ArrayList<DeploymentContent>();
+      for (String s : dcList) { 
+        _deploymentContent.add(new DeploymentContentImpl(s));
+      }
+    } finally { 
+      is.close();
+    }
+  }
 
   public List<DeploymentContent> getApplicationDeploymentContents() {
     return Collections.unmodifiableList(_deploymentContent);
@@ -84,7 +111,6 @@
     fos.close();
   }
 
-
   public void store(OutputStream out) throws IOException {
     // We weren't built from a Manifest, so construct one. 
     Manifest mf = new Manifest();
@@ -96,6 +122,8 @@
     mf.write(out);
   }
   
+  
+  
   private String getDeploymentContentsAsString () { 
     StringBuilder builder = new StringBuilder();
     for (DeploymentContent dc : getApplicationDeploymentContents()) {

Modified: incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/utils/filesystem/IOUtils.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/utils/filesystem/IOUtils.java?rev=898425&r1=898424&r2=898425&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/utils/filesystem/IOUtils.java (original)
+++ incubator/aries/trunk/application/application-utils/src/main/java/org/apache/aries/application/utils/filesystem/IOUtils.java Tue Jan 12 17:13:59 2010
@@ -110,23 +110,30 @@
     }
   }
   
-  /**
-   * Zip up all contents of rootDir (recursively) into targetFile
+  /** 
+   * Zip up all contents of rootDir (recursively) into targetStream
    */
   @SuppressWarnings("unchecked")
-  public static void zipUp(File rootDir, File targetFile) throws IOException
+  public static void zipUp (File rootDir, OutputStream targetStream) throws IOException
   {
-    ZipOutputStream out = null; 
-    try {
-      out = new ZipOutputStream(new FileOutputStream(targetFile));
+    ZipOutputStream out = null;
+    try { 
+      out = new ZipOutputStream (targetStream);
       zipUpRecursive(out, "", rootDir, (Set<String>) Collections.EMPTY_SET);
-    }
-    finally {
+    } finally { 
       close(out);
     }
   }
   
   /**
+   * Zip up all contents of rootDir (recursively) into targetFile
+   */
+  public static void zipUp(File rootDir, File targetFile) throws IOException
+  {
+    zipUp (rootDir, new FileOutputStream (targetFile));
+  }
+  
+  /**
    * Jar up all the contents of rootDir (recursively) into targetFile and add the manifest
    */
   public static void jarUp(File rootDir, File targetFile, Manifest manifest) throws IOException