You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ma...@apache.org on 2010/09/04 23:35:01 UTC

svn commit: r992685 - in /incubator/aries/trunk/application: application-api/ application-api/src/main/java/org/apache/aries/application/management/ application-api/src/main/java/org/apache/aries/application/management/provider/ application-itests/src/...

Author: mahrwald
Date: Sat Sep  4 21:35:00 2010
New Revision: 992685

URL: http://svn.apache.org/viewvc?rev=992685&view=rev
Log:
ARIES-399: Initial commit

Added:
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/UpdateException.java
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/UpdateStrategy.java
    incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/UpdateAppTest.java
    incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/
    incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/IsolationTestUtils.java
    incubator/aries/trunk/application/application-runtime-isolated/src/test/
Modified:
    incubator/aries/trunk/application/application-api/pom.xml
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationContextManager.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/BundleConverter.java
    incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleFrameworkManager.java
    incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.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-runtime-framework-management/src/main/java/org/apache/aries/application/runtime/framework/management/BundleFrameworkManagerImpl.java
    incubator/aries/trunk/application/application-runtime-framework-management/src/main/resources/OSGI-INF/blueprint/bundle-framework-management.xml
    incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextImpl.java
    incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextManagerImpl.java
    incubator/aries/trunk/application/application-runtime/src/main/java/org/apache/aries/application/runtime/impl/ApplicationContextManagerImpl.java

Modified: incubator/aries/trunk/application/application-api/pom.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/pom.xml?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/pom.xml (original)
+++ incubator/aries/trunk/application/application-api/pom.xml Sat Sep  4 21:35:00 2010
@@ -36,6 +36,7 @@
             org.apache.aries.application;
             org.apache.aries.application.filesystem;
             org.apache.aries.application.management;
+            org.apache.aries.application.management.provider;
             org.apache.aries.application.modelling
         </aries.osgi.export.pkg>
     </properties>

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationContextManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationContextManager.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationContextManager.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/AriesApplicationContextManager.java Sat Sep  4 21:35:00 2010
@@ -21,6 +21,7 @@ package org.apache.aries.application.man
 
 import java.util.Set;
 
+import org.apache.aries.application.DeploymentMetadata;
 import org.osgi.framework.BundleException;
 
 /**
@@ -46,6 +47,13 @@ public interface AriesApplicationContext
   public Set<AriesApplicationContext> getApplicationContexts();
 
   /**
+   * Update the AriesApplication and return an updated application context.
+   * @throws UpdateException if the update failed
+   * @throws IllegalArgumentException if the app is not currently installed
+   */
+  public AriesApplicationContext update(AriesApplication app, DeploymentMetadata oldMetadata) throws UpdateException;
+  
+  /**
    * Remove the provided AriesApplicationContext from the running system.
    * 
    * @param app the application to remove.

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=992685&r1=992684&r2=992685&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 Sat Sep  4 21:35:00 2010
@@ -22,6 +22,7 @@ package org.apache.aries.application.man
 
 import java.net.URL;
 
+import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.filesystem.IDirectory;
 import org.osgi.framework.BundleException;
 
@@ -88,6 +89,19 @@ public interface AriesApplicationManager
   public void removeApplicationListener(AriesApplicationListener l);
   
   /**
+   * Update an application's deployment and apply the changes to the runtime if the application is deployed
+   * @param app The application to change
+   * @param depMf The new deployment metadata
+   * @return {@link AriesApplicationContext} Returns a new application context if the app
+   * is currently deployed, or null if the app is not currently installed
+   * 
+   * @throws UpdateException if the deployment changes could not be effected in the runtime
+   * @throws IllegalArgumentException if the deployment metadata does not correspond to the same application
+   * (same symbolic name and same version)
+   */
+  public AriesApplicationContext update(AriesApplication app, DeploymentMetadata depMf) throws UpdateException;
+  
+  /**
    * Resolve an AriesApplication against a set of constraints. Each ResolveConstraint
    * represents a single proposed change to the content of an application.
    * If no constraints are given, a default resolution will be performed.

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleConverter.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleConverter.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleConverter.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleConverter.java Sat Sep  4 21:35:00 2010
@@ -19,8 +19,6 @@
 
 package org.apache.aries.application.management;
 
-import java.io.InputStream;
-
 import org.apache.aries.application.filesystem.IDirectory;
 import org.apache.aries.application.filesystem.IFile;
 

Modified: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleFrameworkManager.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleFrameworkManager.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleFrameworkManager.java (original)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/BundleFrameworkManager.java Sat Sep  4 21:35:00 2010
@@ -20,9 +20,13 @@
 package org.apache.aries.application.management;
 
 import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
 
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
+import org.apache.aries.application.DeploymentContent;
+import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
 
 public interface BundleFrameworkManager
@@ -66,6 +70,20 @@ public interface BundleFrameworkManager
       AriesApplication app)
     throws BundleException;
   
+  public boolean allowsUpdate(DeploymentMetadata newMetadata, DeploymentMetadata oldMetadata);
+  
+  public interface BundleLocator {
+    public Map<DeploymentContent, BundleSuggestion> suggestBundle(Collection<DeploymentContent> bundles) throws ContextException;    
+  }
+  
+  public void updateBundles(
+      DeploymentMetadata newMetadata, 
+      DeploymentMetadata oldMetadata, 
+      AriesApplication app, 
+      BundleLocator locator,
+      Set<Bundle> bundles,
+      boolean startBundles) throws UpdateException;
+  
   /**
    * Starts a previously installed bundle 
    * @param b

Added: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/UpdateException.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/UpdateException.java?rev=992685&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/UpdateException.java (added)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/UpdateException.java Sat Sep  4 21:35:00 2010
@@ -0,0 +1,41 @@
+/*
+ * 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 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.apache.aries.application.management;
+
+public class UpdateException extends Exception {
+  private static final long serialVersionUID = -6118824314732969652L;
+
+  private Exception rollbackFailure;
+  private boolean rolledBack;
+  
+  public UpdateException(String message, Exception e, boolean rolledBack, Exception rollbackException) {
+    super(message, e);
+    
+    this.rollbackFailure = rollbackException;
+    this.rolledBack = rolledBack;    
+  }
+  
+  public boolean hasRolledBack() {
+    return rolledBack;
+  }
+  
+  public Exception getRollbackException() {
+    return rollbackFailure;
+  }
+}

Added: incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/UpdateStrategy.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/UpdateStrategy.java?rev=992685&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/UpdateStrategy.java (added)
+++ incubator/aries/trunk/application/application-api/src/main/java/org/apache/aries/application/management/provider/UpdateStrategy.java Sat Sep  4 21:35:00 2010
@@ -0,0 +1,101 @@
+/*
+ * 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 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.apache.aries.application.management.provider;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.aries.application.DeploymentContent;
+import org.apache.aries.application.DeploymentMetadata;
+import org.apache.aries.application.management.AriesApplication;
+import org.apache.aries.application.management.BundleFramework;
+import org.apache.aries.application.management.BundleRepository;
+import org.apache.aries.application.management.ContextException;
+import org.apache.aries.application.management.UpdateException;
+import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
+import org.osgi.framework.Bundle;
+
+/**
+ * Plug point for update implementation
+ */
+public interface UpdateStrategy {
+
+  /**
+   * Are the two deployments subject to update or do they require full reinstall
+   */
+  public boolean allowsUpdate(DeploymentMetadata newMetadata, DeploymentMetadata oldMetadata);
+  
+  /**
+   * Update an application
+   */
+  public void update(UpdateInfo paramUpdateInfo) throws UpdateException;
+
+  /**
+   * Representation for an update request
+   */
+  public static interface UpdateInfo
+  {
+    /**
+     * Find {@link BundleSuggestion} objects for new bundle requests
+     */
+    public Map<DeploymentContent, BundleRepository.BundleSuggestion> suggestBundle(Collection<DeploymentContent> bundles)
+      throws ContextException;
+
+    /**
+     * Register a new bundle with the application (i.e. a new bundle was installed)
+     */
+    public void register(Bundle bundle);
+
+    /**
+     * Unregister a bundle from the application (i.e. the bundle was uninstalled)
+     */
+    public void unregister(Bundle bundle);
+
+    /**
+     * Get a {@link BundleFramework} object for the shared framework
+     */
+    public BundleFramework getSharedFramework();
+
+    /**
+     * Get a {@link BundleFramework} object for the isolated framework corresponding 
+     * to the application to be updated
+     */
+    public BundleFramework getAppFramework();
+
+    /**
+     * Get the {@link DeploymentMetadata} that is currently active and to be phased out
+     */
+    public DeploymentMetadata getOldMetadata();
+
+    /**
+     * Get the {@link DeploymentMetadata} that is to be activated
+     */
+    public DeploymentMetadata getNewMetadata();
+
+    /**
+     * Get the {@link AriesApplication} object being updated
+     */
+    public AriesApplication getApplication();
+
+    /**
+     * Whether to start any newly installed bundles
+     */
+    public boolean startBundles();
+  }
+}

Modified: incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java (original)
+++ incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/IsolatedRuntimeTest.java Sat Sep  4 21:35:00 2010
@@ -18,33 +18,20 @@
  */
 package org.apache.aries.application.runtime.itests;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 import static org.ops4j.pax.exam.CoreOptions.equinox;
 import static org.ops4j.pax.exam.CoreOptions.options;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Hashtable;
-import java.util.Set;
-import java.util.jar.Attributes;
-
-import org.apache.aries.application.Content;
-import org.apache.aries.application.DeploymentContent;
 import org.apache.aries.application.VersionRange;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.AriesApplicationContext;
 import org.apache.aries.application.management.AriesApplicationManager;
-import org.apache.aries.application.management.BundleRepository;
 import org.apache.aries.application.management.RepositoryGenerator;
 import org.apache.aries.application.management.ResolveConstraint;
-import org.apache.aries.application.modelling.ModelledResource;
-import org.apache.aries.application.modelling.utils.ModellingManager;
+import org.apache.aries.application.runtime.itests.util.IsolationTestUtils;
 import org.apache.aries.application.utils.filesystem.FileSystem;
 import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
 import org.apache.aries.isolated.sample.HelloWorld;
@@ -56,15 +43,6 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.JUnit4TestRunner;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.Version;
-import org.osgi.service.framework.CompositeBundle;
-import org.osgi.util.tracker.ServiceTracker;
 
 @RunWith(JUnit4TestRunner.class)
 public class IsolatedRuntimeTest extends AbstractIntegrationTest {
@@ -181,6 +159,8 @@ public class IsolatedRuntimeTest extends
 
     ctx.stop();
     manager.uninstall(ctx);
+    
+    assertNull(IsolationTestUtils.findIsolatedAppBundleContext(bundleContext, "org.apache.aries.sample2"));
 
     ctx = manager.install(app);
     ctx.start();
@@ -206,67 +186,7 @@ public class IsolatedRuntimeTest extends
     AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class);
     AriesApplication app = manager.createApplication(FileSystem.getFSRoot(new File("test2.eba")));
     
-    BundleRepository repo = new BundleRepository() {
-      public int getCost() {
-        return 1;
-      }
-
-      public BundleSuggestion suggestBundleToUse(DeploymentContent content) {
-        if (content.getContentName().equals("org.apache.aries.isolated.sample")) {
-          return new BundleSuggestion() {
-
-            public Bundle install(BundleContext ctx, AriesApplication app) throws BundleException {
-              File f = new File("sample_2.0.0.jar");
-              try {
-                return ctx.installBundle(f.toURL().toString());                
-              } catch (MalformedURLException mue) {
-                throw new RuntimeException(mue);
-              }
-            }
-
-            public Version getVersion() {
-              return new Version("2.0.0");
-            }
-
-            public Set<Content> getImportPackage() {
-              return Collections.emptySet();
-            }
-
-            public Set<Content> getExportPackage() {
-              return Collections.emptySet();
-            }
-
-            public int getCost() {
-              return 1;
-            }
-          };
-        } else {
-          return null;
-        }
-      }        
-    };
-    
-    Hashtable<String, String> props = new Hashtable<String,String>();
-    props.put(BundleRepository.REPOSITORY_SCOPE, BundleRepository.GLOBAL_SCOPE);
-    
-    bundleContext.registerService(BundleRepository.class.getName(), repo, props);
-
-    RepositoryGenerator repoGen = getOsgiService(RepositoryGenerator.class);
-    RepositoryAdmin repoAdmin = getOsgiService(RepositoryAdmin.class);
-
-    Attributes attrs = new Attributes();
-    attrs.putValue("Bundle-ManifestVersion", "2");
-    attrs.putValue("Bundle-Version", "2.0.0");
-    attrs.putValue("Bundle-SymbolicName", "org.apache.aries.isolated.sample");
-    attrs.putValue("Manifest-Version", "1");
-
-    ModelledResource res = ModellingManager.getModelledResource(
-        new File("sample_2.0.0.jar").toURI().toString(), 
-        attrs,
-        Collections.EMPTY_LIST, Collections.EMPTY_LIST);
-
-    repoGen.generateRepository("repo.xml", Arrays.asList(res), new FileOutputStream("repo.xml"));
-    repoAdmin.addRepository(new File("repo.xml").toURI().toString());
+    IsolationTestUtils.prepareSampleBundleV2(bundleContext, getOsgiService(RepositoryGenerator.class), getOsgiService(RepositoryAdmin.class));
 
     AriesApplication newApp = manager.resolve(app, new ResolveConstraint() {
       public String getBundleName() {
@@ -292,54 +212,9 @@ public class IsolatedRuntimeTest extends
   
   private void assertHelloWorldService(String appName, String message) throws Exception
   {
-    BundleContext appContext = getAppIsolatedBundleContext(appName);
-    
-    if (appContext != null) {  
-      // Dive into the context and pull out the composite bundle for the app
-      Filter osgiFilter = FrameworkUtil.createFilter("(" + Constants.OBJECTCLASS + "=" + HelloWorld.class.getName() + ")");
-      ServiceTracker tracker = new ServiceTracker(appContext, 
-          osgiFilter,
-          null);
-      tracker.open();
-      
-      Object hw = tracker.waitForService(DEFAULT_TIMEOUT);
-      
-      tracker.close();
-      
-      // We can cast to our version of HelloWorld as it is in a different classloader
-      // so reflect into it to get the single method
-      Class returnClass = hw.getClass();
-      Method method = returnClass.getDeclaredMethod("getMessage",null);
-      String result = (String)method.invoke(hw);      
-      
-      assertEquals(message, result);
-    }
-    else {
-      fail("No service found inside application framework");
-    }
-    
-  }
-  
-  
-  private BundleContext getAppIsolatedBundleContext(String appName)
-  {
-    for (Bundle sharedBundle : bundleContext.getBundles())
-    {
-      if (sharedBundle.getSymbolicName().equals("shared.bundle.framework"))
-      {
-        BundleContext sharedContext = ((CompositeBundle)sharedBundle).getCompositeFramework().getBundleContext();
-        for (Bundle appBundle : sharedContext.getBundles())
-        {
-          if (appBundle.getSymbolicName().equals(appName))
-          {
-            return ((CompositeBundle)appBundle).getCompositeFramework().getBundleContext();
-          }
-        }
-        break;
-      }
-    }    
-    
-    return null;
+    HelloWorld hw = IsolationTestUtils.findHelloWorldService(bundleContext, appName);
+    assertNotNull(hw);
+    assertEquals(message, hw.getMessage());
   }
   
   @org.ops4j.pax.exam.junit.Configuration

Added: incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/UpdateAppTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/UpdateAppTest.java?rev=992685&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/UpdateAppTest.java (added)
+++ incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/UpdateAppTest.java Sat Sep  4 21:35:00 2010
@@ -0,0 +1,280 @@
+/*
+ * 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 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.apache.aries.application.runtime.itests;
+
+import static org.junit.Assert.*;
+import static org.ops4j.pax.exam.CoreOptions.equinox;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.aries.application.DeploymentContent;
+import org.apache.aries.application.DeploymentMetadata;
+import org.apache.aries.application.VersionRange;
+import org.apache.aries.application.management.AriesApplication;
+import org.apache.aries.application.management.AriesApplicationContext;
+import org.apache.aries.application.management.AriesApplicationManager;
+import org.apache.aries.application.management.BundleFramework;
+import org.apache.aries.application.management.RepositoryGenerator;
+import org.apache.aries.application.management.ResolveConstraint;
+import org.apache.aries.application.management.UpdateException;
+import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
+import org.apache.aries.application.management.provider.UpdateStrategy;
+import org.apache.aries.application.runtime.itests.util.IsolationTestUtils;
+import org.apache.aries.application.utils.filesystem.FileSystem;
+import org.apache.aries.application.utils.manifest.ManifestHeaderProcessor;
+import org.apache.aries.isolated.sample.HelloWorld;
+import org.apache.aries.unittest.fixture.ArchiveFixture;
+import org.apache.aries.unittest.fixture.ArchiveFixture.ZipFixture;
+import org.apache.felix.bundlerepository.RepositoryAdmin;
+import org.junit.Before;
+import org.junit.Test;
+import org.ops4j.pax.exam.Option;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class UpdateAppTest extends AbstractIntegrationTest {
+  private static final String SAMPLE_APP_NAME = "org.apache.aries.sample2";
+  /* Use @Before not @BeforeClass so as to ensure that these resources
+   * are created in the paxweb temp directory, and not in the svn tree 
+   */
+  static boolean createdApplications = false;
+  @Before
+  public static void createApplications() throws Exception {
+       
+    if (createdApplications) { 
+      return;
+    }
+    
+    ZipFixture testEba = ArchiveFixture.newZip()
+      .binary("META-INF/APPLICATION.MF", 
+          UpdateAppTest.class.getClassLoader().getResourceAsStream("isolated/APPLICATION.MF"))
+      .jar("sample.jar")
+        .manifest().symbolicName("org.apache.aries.isolated.sample")
+          .attribute("Bundle-Version", "1.0.0")
+          .end()
+        .binary("org/apache/aries/isolated/sample/HelloWorld.class", 
+            UpdateAppTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorld.class"))
+        .binary("org/apache/aries/isolated/sample/HelloWorldImpl.class", 
+            UpdateAppTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorldImpl.class"))
+        .binary("OSGI-INF/blueprint/aries.xml", 
+            UpdateAppTest.class.getClassLoader().getResourceAsStream("isolated/sample-blueprint.xml"))
+        .end();
+      
+    FileOutputStream fout = new FileOutputStream("test.eba");
+    testEba.writeOut(fout);
+    fout.close();
+    
+    ZipFixture sample2 = ArchiveFixture.newJar()
+      .manifest().symbolicName("org.apache.aries.isolated.sample")
+        .attribute("Bundle-Version", "2.0.0")
+      .end()
+      .binary("org/apache/aries/isolated/sample/HelloWorld.class", 
+          IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorld.class"))
+      .binary("org/apache/aries/isolated/sample/HelloWorldImpl.class", 
+          IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("org/apache/aries/isolated/sample/HelloWorldImpl.class"))
+      .binary("OSGI-INF/blueprint/aries.xml", 
+          IsolatedRuntimeTest.class.getClassLoader().getResourceAsStream("isolated/sample2-blueprint.xml"))
+      .end();
+    
+    fout = new FileOutputStream("sample_2.0.0.jar");
+    sample2.writeOut(fout);
+    fout.close();
+    
+    createdApplications = true;
+  }
+  
+  @Test
+  public void testFullUpdate() throws Exception {
+    AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class);
+    AriesApplication app = setupApp();
+    
+    updateApp(manager, app);
+
+    assertAppMessage("hello brave new world");
+  }
+  
+  @Test
+  public void testFineUpdate() throws Exception {
+    AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class);
+    AriesApplication app = setupApp();
+    
+    BundleContext oldCtx = IsolationTestUtils.findIsolatedAppBundleContext(bundleContext, SAMPLE_APP_NAME);
+    
+    installMockUpdateStrategy();
+    updateApp(manager, app);
+    
+    BundleContext newCtx = IsolationTestUtils.findIsolatedAppBundleContext(bundleContext, SAMPLE_APP_NAME);    
+    assertAppMessage("hello brave new world");
+    
+    assertTrue("We bounced the app where the update was supposed to do an update in place", oldCtx == newCtx);
+  }
+  
+  @Test
+  public void testUpdateThenStart() throws Exception
+  {
+    AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class);
+    AriesApplication app = manager.createApplication(FileSystem.getFSRoot(new File("test.eba")));
+    AriesApplicationContext ctx = manager.install(app);
+    app = ctx.getApplication();
+
+    BundleContext oldCtx = IsolationTestUtils.findIsolatedAppBundleContext(bundleContext, SAMPLE_APP_NAME);
+    
+    installMockUpdateStrategy();
+    ctx = updateApp(manager, app);
+    
+    BundleContext newCtx = IsolationTestUtils.findIsolatedAppBundleContext(bundleContext, SAMPLE_APP_NAME);    
+    
+    assertNull("App is not started yet but HelloWorld service is already there",
+        IsolationTestUtils.findHelloWorldService(bundleContext, SAMPLE_APP_NAME));
+    
+    ctx.start();
+    
+    assertAppMessage("hello brave new world");
+    
+    assertTrue("We bounced the app where the update was supposed to do an update in place", oldCtx == newCtx);
+  }
+  
+  private void installMockUpdateStrategy()
+  {
+    bundleContext.registerService(UpdateStrategy.class.getName(), new UpdateStrategy() {
+
+      public boolean allowsUpdate(DeploymentMetadata newMetadata, DeploymentMetadata oldMetadata) {
+        return true;
+      }
+
+      public void update(UpdateInfo info) throws UpdateException {
+        BundleFramework fwk = info.getAppFramework();
+        
+        Bundle old = null;
+        for (Bundle b : fwk.getBundles()) {
+          if (b.getSymbolicName().equals("org.apache.aries.isolated.sample")) {
+            old = b;
+            break;
+          }
+        }
+        
+        if (old == null) throw new RuntimeException("Could not find old bundle");
+        
+        try {
+          info.unregister(old);
+          fwk.uninstall(old);
+          
+          // only contains one element at most
+          Map<DeploymentContent, BundleSuggestion> suggestions = 
+            info.suggestBundle(info.getNewMetadata().getApplicationDeploymentContents());
+          
+          BundleSuggestion toInstall = suggestions.values().iterator().next();
+          
+          Bundle newBundle = fwk.install(toInstall, info.getApplication());
+          info.register(newBundle);
+          if (info.startBundles()) fwk.start(newBundle);
+          
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
+      }
+      
+    }, new Hashtable<String, String>());    
+  }
+  
+  private AriesApplication setupApp() throws Exception {
+    AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class);
+    AriesApplication app = manager.createApplication(FileSystem.getFSRoot(new File("test.eba")));
+    AriesApplicationContext ctx = manager.install(app);
+    app = ctx.getApplication();
+
+    ctx.start();
+    assertAppMessage("hello world");    
+    
+    return app;
+  }
+  
+  private AriesApplicationContext updateApp(AriesApplicationManager manager, AriesApplication app) throws Exception {
+    IsolationTestUtils.prepareSampleBundleV2(bundleContext, getOsgiService(RepositoryGenerator.class), getOsgiService(RepositoryAdmin.class));
+    
+    AriesApplication newApp = manager.resolve(app, new ResolveConstraint() {
+      public String getBundleName() {
+        return "org.apache.aries.isolated.sample";
+      }
+
+      public VersionRange getVersionRange() {
+        return ManifestHeaderProcessor.parseVersionRange("[2.0.0,2.0.0]", true);
+      }
+    });
+    
+    return manager.update(app, newApp.getDeploymentMetadata());
+  }
+  
+  private void assertAppMessage(String message) throws Exception {
+    HelloWorld hw = IsolationTestUtils.findHelloWorldService(bundleContext, SAMPLE_APP_NAME);
+    assertNotNull(hw);
+    assertEquals(message, hw.getMessage());
+  }
+
+  @org.ops4j.pax.exam.junit.Configuration
+  public static Option[] configuration() {
+    Option[] options = options(
+        // Log
+        mavenBundle("org.ops4j.pax.logging", "pax-logging-api"),
+        mavenBundle("org.ops4j.pax.logging", "pax-logging-service"),
+        // Felix Config Admin
+        mavenBundle("org.apache.felix", "org.apache.felix.configadmin"),
+        // Felix mvn url handler
+        mavenBundle("org.ops4j.pax.url", "pax-url-mvn"),
+
+        // this is how you set the default log level when using pax
+        // logging (logProfile)
+        systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
+
+        // Bundles
+        mavenBundle("org.apache.aries.transaction", "org.apache.aries.transaction.blueprint"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.api"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.utils"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.isolated"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.management"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.deployment.management"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.modeller"),
+        mavenBundle("org.apache.felix", "org.apache.felix.bundlerepository"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.resolver.obr"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.framework"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.framework.management"),
+        mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.repository"),
+        mavenBundle("org.apache.aries", "org.apache.aries.util"),
+        mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint"), 
+        mavenBundle("org.osgi", "org.osgi.compendium"),
+        mavenBundle("org.apache.geronimo.specs","geronimo-jta_1.1_spec"),
+        mavenBundle("org.apache.aries.testsupport", "org.apache.aries.testsupport.unit"),
+
+        // new VMOption("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5011"),
+
+        /*
+         * and add these imports:
+        import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartup;
+        import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+         */
+        equinox().version("3.5.0"));
+    options = updateOptions(options);
+    return options;
+  }
+}

Added: incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/IsolationTestUtils.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/IsolationTestUtils.java?rev=992685&view=auto
==============================================================================
--- incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/IsolationTestUtils.java (added)
+++ incubator/aries/trunk/application/application-itests/src/test/java/org/apache/aries/application/runtime/itests/util/IsolationTestUtils.java Sat Sep  4 21:35:00 2010
@@ -0,0 +1,186 @@
+/*
+ * 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 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.apache.aries.application.runtime.itests.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.jar.Attributes;
+
+import org.apache.aries.application.Content;
+import org.apache.aries.application.DeploymentContent;
+import org.apache.aries.application.management.AriesApplication;
+import org.apache.aries.application.management.BundleRepository;
+import org.apache.aries.application.management.RepositoryGenerator;
+import org.apache.aries.application.modelling.ModelledResource;
+import org.apache.aries.application.modelling.utils.ModellingManager;
+import org.apache.aries.isolated.sample.HelloWorld;
+import org.apache.felix.bundlerepository.RepositoryAdmin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.Version;
+import org.osgi.service.framework.CompositeBundle;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class IsolationTestUtils {
+  public static final long DEFAULT_TIMEOUT = 10000;
+  
+  /**
+   * Retrieve the bundle context for an isolated application framework
+   */
+  public static BundleContext findIsolatedAppBundleContext(BundleContext runtimeCtx, String appName)
+  {
+    for (Bundle sharedBundle : runtimeCtx.getBundles())
+    {
+      if (sharedBundle.getSymbolicName().equals("shared.bundle.framework"))
+      {
+        BundleContext sharedContext = ((CompositeBundle)sharedBundle).getCompositeFramework().getBundleContext();
+        for (Bundle appBundle : sharedContext.getBundles())
+        {
+          if (appBundle.getSymbolicName().equals(appName))
+          {
+            return ((CompositeBundle)appBundle).getCompositeFramework().getBundleContext();
+          }
+        }
+        break;
+      }
+    }    
+    
+    return null;
+  }
+  
+  /**
+   * Set up the necessary resources for installing version 2 of the org.apache.aries.isolated.sample sample bundle, 
+   * which returns the message "hello brave new world" rather than "hello world"
+   * 
+   * This means setting up a global bundle repository as well as a global OBR repository
+   */
+  public static void prepareSampleBundleV2(BundleContext runtimeCtx, RepositoryGenerator repoGen, RepositoryAdmin repoAdmin)
+    throws Exception
+  {
+    BundleRepository repo = new BundleRepository() {
+      public int getCost() {
+        return 1;
+      }
+
+      public BundleSuggestion suggestBundleToUse(DeploymentContent content) {
+        if (content.getContentName().equals("org.apache.aries.isolated.sample")) {
+          return new BundleSuggestion() {
+
+            public Bundle install(BundleContext ctx, AriesApplication app) throws BundleException {
+              File f = new File("sample_2.0.0.jar");
+              try {
+                return ctx.installBundle(f.toURL().toString());                
+              } catch (MalformedURLException mue) {
+                throw new RuntimeException(mue);
+              }
+            }
+
+            public Version getVersion() {
+              return new Version("2.0.0");
+            }
+
+            public Set<Content> getImportPackage() {
+              return Collections.emptySet();
+            }
+
+            public Set<Content> getExportPackage() {
+              return Collections.emptySet();
+            }
+
+            public int getCost() {
+              return 1;
+            }
+          };
+        } else {
+          return null;
+        }
+      }        
+    };
+    
+    Hashtable<String, String> props = new Hashtable<String,String>();
+    props.put(BundleRepository.REPOSITORY_SCOPE, BundleRepository.GLOBAL_SCOPE);
+    
+    runtimeCtx.registerService(BundleRepository.class.getName(), repo, props);
+
+    Attributes attrs = new Attributes();
+    attrs.putValue("Bundle-ManifestVersion", "2");
+    attrs.putValue("Bundle-Version", "2.0.0");
+    attrs.putValue("Bundle-SymbolicName", "org.apache.aries.isolated.sample");
+    attrs.putValue("Manifest-Version", "1");
+
+    ModelledResource res = ModellingManager.getModelledResource(
+        new File("sample_2.0.0.jar").toURI().toString(), 
+        attrs,
+        Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+
+    repoGen.generateRepository("repo.xml", Arrays.asList(res), new FileOutputStream("repo.xml"));
+    repoAdmin.addRepository(new File("repo.xml").toURI().toString());
+  }
+  
+  /**
+   * Find the {@link HelloWorld} service for the isolated app
+   * @return the service object, suitably proxied so that it can be actually used, or null if the service is not present
+   * @throws IllegalStateException if the isolated app is not installed
+   */
+  public static HelloWorld findHelloWorldService(BundleContext runtimeCtx, String appName) throws Exception
+  {
+    BundleContext appContext = IsolationTestUtils.findIsolatedAppBundleContext(runtimeCtx, appName);
+    
+    if (appContext != null) {  
+      // Dive into the context and pull out the composite bundle for the app
+      Filter osgiFilter = FrameworkUtil.createFilter("(" + Constants.OBJECTCLASS + "=" + HelloWorld.class.getName() + ")");
+      ServiceTracker tracker = new ServiceTracker(appContext, 
+          osgiFilter,
+          null);
+      
+      tracker.open();
+      final Object hw = tracker.waitForService(DEFAULT_TIMEOUT);
+      tracker.close();
+
+      if (hw != null) {
+        // proxy because the class space between the sample app and the test bundle is not consistent
+        return new HelloWorld() {
+          public String getMessage() {
+            try {
+              Method m = hw.getClass().getMethod("getMessage");
+              return (String) m.invoke(hw);
+            } catch (Exception e) {
+              throw new RuntimeException(e);
+            }
+          }
+        };
+      } else {
+        return null;
+      }
+
+    } else {
+      throw new IllegalStateException("Expected to find isolated app ctx, but didn't");
+    }
+  }
+}

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=992685&r1=992684&r2=992685&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 Sat Sep  4 21:35:00 2010
@@ -57,6 +57,7 @@ import org.apache.aries.application.mana
 import org.apache.aries.application.management.ManagementException;
 import org.apache.aries.application.management.ResolveConstraint;
 import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.management.internal.MessageUtil;
 import org.apache.aries.application.management.repository.ApplicationRepository;
 import org.apache.aries.application.utils.AppConstants;
@@ -287,7 +288,7 @@ public class AriesApplicationManagerImpl
     
     // Register an Application Repository for this application
     Dictionary dict = new Hashtable();
-    dict.put(ApplicationRepository.REPOSITORY_SCOPE, app.getApplicationMetadata().getApplicationScope());
+    dict.put(BundleRepository.REPOSITORY_SCOPE, app.getApplicationMetadata().getApplicationScope());
     _bundleContext.registerService(BundleRepository.class.getName(), 
         new ApplicationRepository(app), 
         dict);
@@ -353,4 +354,38 @@ public class AriesApplicationManagerImpl
     return mf;
   }
 
+  public AriesApplicationContext update(AriesApplication app, DeploymentMetadata depMf) throws UpdateException {
+    if (!(app instanceof AriesApplicationImpl)) throw new IllegalArgumentException("Argument is not AriesApplication created by this manager");
+    
+    if (!!!app.getApplicationMetadata().getApplicationSymbolicName().equals(depMf.getApplicationSymbolicName())
+        || !!!app.getApplicationMetadata().getApplicationVersion().equals(depMf.getApplicationVersion())) {
+      throw new IllegalArgumentException("The deployment metadata does not match the application.");
+    }
+    
+    DeploymentMetadata oldMetadata = app.getDeploymentMetadata();
+    
+    AriesApplicationContext foundCtx = null;
+    for (AriesApplicationContext ctx : _applicationContextManager.getApplicationContexts()) {
+      if (ctx.getApplication().equals(app)) {
+        foundCtx = ctx;
+        break;
+      }
+    }
+    
+    ((AriesApplicationImpl) app).setDeploymentMetadata(depMf);
+    
+    if (foundCtx != null) {
+      try {
+        return _applicationContextManager.update(app, oldMetadata);
+      } catch (UpdateException ue) {
+        if (ue.hasRolledBack()) {
+          ((AriesApplicationImpl) app).setDeploymentMetadata(oldMetadata);
+        }
+        
+        throw ue;
+      }
+    } else {
+      return null;
+    }
+  }
 }

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=992685&r1=992684&r2=992685&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 Sat Sep  4 21:35:00 2010
@@ -19,9 +19,7 @@
 
 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 static org.junit.Assert.*;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -30,6 +28,7 @@ import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -51,6 +50,8 @@ import org.apache.aries.application.impl
 import org.apache.aries.application.impl.DeploymentContentImpl;
 import org.apache.aries.application.impl.DeploymentMetadataFactoryImpl;
 import org.apache.aries.application.management.AriesApplication;
+import org.apache.aries.application.management.AriesApplicationContext;
+import org.apache.aries.application.management.AriesApplicationContextManager;
 import org.apache.aries.application.management.AriesApplicationResolver;
 import org.apache.aries.application.management.BundleConversion;
 import org.apache.aries.application.management.BundleConverter;
@@ -61,12 +62,15 @@ import org.apache.aries.application.mana
 import org.apache.aries.application.management.ManagementException;
 import org.apache.aries.application.management.ResolveConstraint;
 import org.apache.aries.application.management.ResolverException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.modelling.ModelledResource;
 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.management.SimpleBundleInfo;
 import org.apache.aries.application.utils.manifest.BundleManifest;
+import org.apache.aries.unittest.mocks.MethodCall;
+import org.apache.aries.unittest.mocks.Skeleton;
 import org.apache.aries.unittest.utils.EbaUnitTestUtils;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -375,6 +379,101 @@ public class AriesApplicationManagerImpl
     assertEquals (dm.getApplicationVersion(), app.getApplicationMetadata().getApplicationVersion());
   }
   
+  @Test
+  public void testUpdate() throws Exception {
+    AriesApplication app = createApplication(TEST_EBA);
+
+    DeploymentMetadata depMf = createUpdateDepMf();
+    
+    AriesApplicationContextManager ctxMgr = Skeleton.newMock(AriesApplicationContextManager.class);
+    _appMgr.setApplicationContextManager(ctxMgr);
+
+    _appMgr.update(app, depMf);
+    
+    assertTrue("Deployment.mf should have been updated", app.getDeploymentMetadata() == depMf);
+  }
+  
+  @Test(expected=IllegalArgumentException.class)
+  public void testUpdateWithIncorrectDepMf() throws Exception
+  {
+    AriesApplication app = createApplication(TEST_EBA);
+
+    DeploymentMetadata depMf = Skeleton.newMock(DeploymentMetadata.class);
+    Skeleton.getSkeleton(depMf).setReturnValue(new MethodCall(DeploymentMetadata.class, "getApplicationSymbolicName"), "random.app");
+    Skeleton.getSkeleton(depMf).setReturnValue(new MethodCall(DeploymentMetadata.class, "getApplicationVersion"), new Version("1.0.0"));
+    
+    AriesApplicationContextManager ctxMgr = Skeleton.newMock(AriesApplicationContextManager.class);
+    _appMgr.setApplicationContextManager(ctxMgr);
+
+    _appMgr.update(app, depMf);    
+  }
+  
+  @Test
+  public void testFailedUpdate() throws Exception {
+    AriesApplication app = createApplication(TEST_EBA);
+
+    DeploymentMetadata depMf = createUpdateDepMf();
+    
+    AriesApplicationContext ctx = Skeleton.newMock(AriesApplicationContext.class);
+    Skeleton.getSkeleton(ctx).setReturnValue(new MethodCall(AriesApplicationContext.class, "getApplication"), app);
+    
+    AriesApplicationContextManager ctxMgr = Skeleton.newMock(AriesApplicationContextManager.class);
+    Skeleton.getSkeleton(ctxMgr).setReturnValue(
+        new MethodCall(AriesApplicationContextManager.class, "getApplicationContexts"), 
+        Collections.singleton(ctx));    
+    
+    Skeleton.getSkeleton(ctxMgr).setThrows(
+        new MethodCall(AriesApplicationContextManager.class, "update", AriesApplication.class, DeploymentMetadata.class), 
+        new UpdateException("", null, false, null));
+    
+    _appMgr.setApplicationContextManager(ctxMgr);
+
+    try {
+      _appMgr.update(app, depMf);
+      fail("Update should have failed.");
+    } catch (UpdateException e) {
+      assertTrue("Deployment.mf should have been updated", app.getDeploymentMetadata() == depMf);
+    }
+  }
+  
+  @Test
+  public void testRolledbackUpdate() throws Exception {
+    AriesApplication app = createApplication(TEST_EBA);
+
+    DeploymentMetadata depMf = createUpdateDepMf();
+    DeploymentMetadata oldMf = app.getDeploymentMetadata();
+    
+    AriesApplicationContext ctx = Skeleton.newMock(AriesApplicationContext.class);
+    Skeleton.getSkeleton(ctx).setReturnValue(new MethodCall(AriesApplicationContext.class, "getApplication"), app);
+    
+    AriesApplicationContextManager ctxMgr = Skeleton.newMock(AriesApplicationContextManager.class);
+    Skeleton.getSkeleton(ctxMgr).setReturnValue(
+        new MethodCall(AriesApplicationContextManager.class, "getApplicationContexts"), 
+        Collections.singleton(ctx));    
+    
+    Skeleton.getSkeleton(ctxMgr).setThrows(
+        new MethodCall(AriesApplicationContextManager.class, "update", AriesApplication.class, DeploymentMetadata.class), 
+        new UpdateException("", null, true, null));
+    
+    _appMgr.setApplicationContextManager(ctxMgr);
+
+    try {
+      _appMgr.update(app, depMf);
+      fail("Update should have failed.");
+    } catch (UpdateException e) {
+      assertTrue("Deployment.mf should have been rolled back to the old", app.getDeploymentMetadata() == oldMf);
+    }
+  }
+  
+  private DeploymentMetadata createUpdateDepMf()
+  {
+    DeploymentMetadata depMf = Skeleton.newMock(DeploymentMetadata.class);
+    Skeleton.getSkeleton(depMf).setReturnValue(new MethodCall(DeploymentMetadata.class, "getApplicationSymbolicName"), "org.apache.aries.application.management.test");
+    Skeleton.getSkeleton(depMf).setReturnValue(new MethodCall(DeploymentMetadata.class, "getApplicationVersion"), new Version("1.0.0"));
+
+    return depMf;
+  }
+  
   private AriesApplication createApplication (String fileName) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException, ManagementException, ResolverException {
     // This next block is a very long winded way of constructing a BundleInfoImpl
     // against the existing (BundleManifest bm, String location) constructor. If we 

Modified: incubator/aries/trunk/application/application-runtime-framework-management/src/main/java/org/apache/aries/application/runtime/framework/management/BundleFrameworkManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-runtime-framework-management/src/main/java/org/apache/aries/application/runtime/framework/management/BundleFrameworkManagerImpl.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-runtime-framework-management/src/main/java/org/apache/aries/application/runtime/framework/management/BundleFrameworkManagerImpl.java (original)
+++ incubator/aries/trunk/application/application-runtime-framework-management/src/main/java/org/apache/aries/application/runtime/framework/management/BundleFrameworkManagerImpl.java Sat Sep  4 21:35:00 2010
@@ -25,19 +25,24 @@ import static org.apache.aries.applicati
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 
 import org.apache.aries.application.Content;
+import org.apache.aries.application.DeploymentContent;
 import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.BundleFramework;
 import org.apache.aries.application.management.BundleFrameworkFactory;
 import org.apache.aries.application.management.BundleFrameworkManager;
 import org.apache.aries.application.management.ContextException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
+import org.apache.aries.application.management.provider.UpdateStrategy;
 import org.apache.aries.application.utils.runtime.InstallUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -54,6 +59,13 @@ public class BundleFrameworkManagerImpl 
   BundleFramework _sharedBundleFramework;
   BundleFrameworkFactory _bundleFrameworkFactory;
   Map<Bundle, BundleFramework> _frameworks = new HashMap<Bundle, BundleFramework>();
+  Map<AriesApplication, BundleFramework> _frameworksByApp = new HashMap<AriesApplication, BundleFramework>();
+  private List<UpdateStrategy> _updateStrategies = Collections.emptyList();
+
+  public void setUpdateStrategies(List<UpdateStrategy> updateStrategies) 
+  {
+    _updateStrategies = updateStrategies;
+  }
 
   public void setBundleContext(BundleContext ctx)
   {
@@ -89,6 +101,7 @@ public class BundleFrameworkManagerImpl 
     BundleFramework isolatedFramework = isolatedInstall(bundlesToInstall, app);
 
     _frameworks.put(isolatedFramework.getFrameworkBundle(), isolatedFramework);
+    _frameworksByApp.put(app, isolatedFramework);
 
     return isolatedFramework.getFrameworkBundle();
   }
@@ -226,4 +239,79 @@ public class BundleFrameworkManagerImpl 
     }
     // Do not stop shared bundles
   }
+
+  public boolean allowsUpdate(DeploymentMetadata newMetadata, DeploymentMetadata oldMetadata) 
+  {
+    for (UpdateStrategy strategy : _updateStrategies) {
+      if (strategy.allowsUpdate(newMetadata, oldMetadata)) {
+        return true;
+      }
+    }
+    
+    return false;
+  }
+
+  public void updateBundles(
+      final DeploymentMetadata newMetadata, 
+      final DeploymentMetadata oldMetadata, 
+      final AriesApplication app, 
+      final BundleLocator locator,
+      final Set<Bundle> bundles,
+      final boolean startBundles) 
+    throws UpdateException 
+  {
+    UpdateStrategy strategy = null;
+    
+    for (UpdateStrategy us : _updateStrategies) {
+      if (us.allowsUpdate(newMetadata, oldMetadata)) {
+        strategy = us;
+        break;
+      }
+    }
+    
+    if (strategy == null) throw new IllegalArgumentException("No UpdateStrategy supports the supplied DeploymentMetadata changes.");
+    
+    final BundleFramework appFwk = _frameworksByApp.get(app);
+    
+    strategy.update(new UpdateStrategy.UpdateInfo() {
+      
+      public void register(Bundle bundle) {
+        bundles.add(bundle);
+      }
+      
+      public void unregister(Bundle bundle) {
+        bundles.remove(bundle);
+      }
+      
+      public Map<DeploymentContent, BundleSuggestion> suggestBundle(Collection<DeploymentContent> bundles) throws ContextException {
+        return locator.suggestBundle(bundles);
+      }
+      
+      public boolean startBundles() {
+        return startBundles;
+      }
+      
+      public BundleFramework getSharedFramework() {
+        return _sharedBundleFramework;
+      }
+      
+      public DeploymentMetadata getOldMetadata() {
+        return oldMetadata;
+      }
+      
+      public DeploymentMetadata getNewMetadata() {
+        return newMetadata;
+      }
+      
+      public AriesApplication getApplication() {
+        return app;
+      }
+      
+      public BundleFramework getAppFramework() {
+        return appFwk;
+      }
+    });
+  }
+  
+  
 }

Modified: incubator/aries/trunk/application/application-runtime-framework-management/src/main/resources/OSGI-INF/blueprint/bundle-framework-management.xml
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-runtime-framework-management/src/main/resources/OSGI-INF/blueprint/bundle-framework-management.xml?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-runtime-framework-management/src/main/resources/OSGI-INF/blueprint/bundle-framework-management.xml (original)
+++ incubator/aries/trunk/application/application-runtime-framework-management/src/main/resources/OSGI-INF/blueprint/bundle-framework-management.xml Sat Sep  4 21:35:00 2010
@@ -22,6 +22,7 @@
   <bean id="equinox-bundle-framework-manager" class="org.apache.aries.application.runtime.framework.management.BundleFrameworkManagerImpl" init-method="init">
       <property name="bundleFrameworkFactory" ref="bundle-framework-factory"/>
       <property name="bundleContext" ref="blueprintBundleContext"/>
+      <property name="updateStrategies" ref="strategies" />
   </bean>
 
   <service interface="org.apache.aries.application.management.BundleFrameworkManager"
@@ -30,4 +31,6 @@
             
   <reference id="bundle-framework-factory" interface="org.apache.aries.application.management.BundleFrameworkFactory"/>
 
+  <reference-list id="strategies" interface="org.apache.aries.application.management.provider.UpdateStrategy" availability="optional" />
+
 </blueprint>

Modified: incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextImpl.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextImpl.java (original)
+++ incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextImpl.java Sat Sep  4 21:35:00 2010
@@ -24,6 +24,7 @@ import static org.apache.aries.applicati
 import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -39,9 +40,9 @@ import org.apache.aries.application.mana
 import org.apache.aries.application.management.BundleRepositoryManager;
 import org.apache.aries.application.management.ContextException;
 import org.apache.aries.application.management.ManagementException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.management.BundleRepository.BundleSuggestion;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,12 +54,11 @@ public class ApplicationContextImpl impl
   private AriesApplication _application;
   private Set<Bundle> _bundles;
   private ApplicationState _state = ApplicationState.UNINSTALLED;
-  private BundleContext _bundleContext;
   private BundleRepositoryManager _bundleRepositoryManager;
   private BundleFrameworkManager _bundleFrameworkManager;
 
   /** deployment metadata associated with aries application */
-  private final DeploymentMetadata _deploymentMF;
+  private DeploymentMetadata _deploymentMF;
 
   public ApplicationContextImpl(AriesApplication app, ApplicationContextManagerImpl acm)
       throws BundleException, ManagementException
@@ -212,28 +212,28 @@ public class ApplicationContextImpl impl
        */
       Map<DeploymentContent, BundleSuggestion> bundlesToBeInstalled = new HashMap<DeploymentContent, BundleSuggestion>();
       try {
-        bundlesToBeInstalled = _bundleRepositoryManager.getBundleSuggestions(_application
-            .getApplicationMetadata().getApplicationSymbolicName(), _application
-            .getApplicationMetadata().getApplicationVersion().toString(), bundlesToFind);
+        bundlesToBeInstalled = findBundleSuggestions(bundlesToFind);
       } catch (ContextException e) {
         numException++;
         LOGGER.debug(LOG_EXCEPTION, e);
       }
 
-      /**
-       * Perform the install of the bundles
-       */
-      try {
-        if (shared) 
-          _bundles.addAll(_bundleFrameworkManager.installSharedBundles(
-            new ArrayList<BundleSuggestion>(bundlesToBeInstalled.values()), _application));
-        else 
-          _bundles.add(_bundleFrameworkManager.installIsolatedBundles(
-            new ArrayList<BundleSuggestion>(bundlesToBeInstalled.values()), _application));
-
-      } catch (BundleException e) {
-        numException++;
-        LOGGER.debug(LOG_EXCEPTION, e);
+      if (numException == 0) {
+        /**
+         * Perform the install of the bundles
+         */
+        try {
+          if (shared) 
+            _bundles.addAll(_bundleFrameworkManager.installSharedBundles(
+              new ArrayList<BundleSuggestion>(bundlesToBeInstalled.values()), _application));
+          else 
+            _bundles.add(_bundleFrameworkManager.installIsolatedBundles(
+              new ArrayList<BundleSuggestion>(bundlesToBeInstalled.values()), _application));
+  
+        } catch (BundleException e) {
+          numException++;
+          LOGGER.debug(LOG_EXCEPTION, e);
+        }
       }
     }
 
@@ -241,6 +241,14 @@ public class ApplicationContextImpl impl
 
     return (numException == 0);
   }
+  
+  private Map<DeploymentContent, BundleSuggestion> findBundleSuggestions(Collection<DeploymentContent> bundlesToFind)
+    throws ContextException
+  {
+    return _bundleRepositoryManager.getBundleSuggestions(_application
+        .getApplicationMetadata().getApplicationSymbolicName(), _application
+        .getApplicationMetadata().getApplicationVersion().toString(), bundlesToFind);
+  }
 
   public AriesApplication getApplication()
   {
@@ -323,4 +331,69 @@ public class ApplicationContextImpl impl
 
     LOGGER.debug(LOG_EXIT, "setState");
   }
+  
+  public void update(final DeploymentMetadata newMetadata, final DeploymentMetadata oldMetadata) 
+    throws UpdateException
+  {
+    final boolean toStart = getApplicationState() == ApplicationState.ACTIVE;
+    
+    if (_bundleFrameworkManager.allowsUpdate(newMetadata, oldMetadata)) {
+      _bundleFrameworkManager.updateBundles(
+          newMetadata, oldMetadata, 
+          _application, 
+          new BundleFrameworkManager.BundleLocator() {            
+            public Map<DeploymentContent, BundleSuggestion> suggestBundle(
+                Collection<DeploymentContent> bundles) throws ContextException {
+              return findBundleSuggestions(bundles);
+            }
+          },
+          _bundles, 
+          toStart);
+      
+    } else {
+      // fallback do a uninstall, followed by a reinstall
+      
+      boolean uninstallSuccess = uninstall();
+      
+      if (uninstallSuccess) {
+        _deploymentMF = newMetadata;
+        boolean reinstallSuccess = processContent();
+        Exception installException = null;
+        
+        if (reinstallSuccess) {
+          if (toStart) {
+            try {
+              start();
+            } catch (BundleException be) {
+              reinstallSuccess = false;
+              installException = be;              
+            }
+          }
+        }
+          
+        if (!!!reinstallSuccess) {
+          boolean rollbackSuccess = uninstall();
+          Exception rollbackException = null;
+          
+          if (rollbackSuccess) {
+            _deploymentMF = oldMetadata;
+            rollbackSuccess = processContent();
+            
+            if (rollbackSuccess && toStart) {
+              try {
+                start();
+              } catch (BundleException be) {
+                rollbackException = be;
+                rollbackSuccess = false;
+              }
+            }
+          }
+           
+          throw new UpdateException("Could not install updated application", installException, rollbackSuccess, rollbackException);
+        }
+      } else {
+        throw new UpdateException("Could not uninstall old bundles", null, false, null);
+      }
+    }
+  }
 }

Modified: incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextManagerImpl.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextManagerImpl.java (original)
+++ incubator/aries/trunk/application/application-runtime-isolated/src/main/java/org/apache/aries/application/runtime/isolated/impl/ApplicationContextManagerImpl.java Sat Sep  4 21:35:00 2010
@@ -21,7 +21,6 @@ package org.apache.aries.application.run
 
 import static org.apache.aries.application.utils.AppConstants.LOG_ENTRY;
 import static org.apache.aries.application.utils.AppConstants.LOG_EXIT;
-import static org.apache.aries.application.utils.AppConstants.LOG_EXCEPTION;
 
 import java.util.HashSet;
 import java.util.Iterator;
@@ -30,15 +29,15 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.AriesApplicationContext;
 import org.apache.aries.application.management.AriesApplicationContextManager;
-import org.apache.aries.application.management.BundleFramework;
 import org.apache.aries.application.management.BundleFrameworkManager;
 import org.apache.aries.application.management.BundleRepositoryManager;
 import org.apache.aries.application.management.ManagementException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.management.AriesApplicationContext.ApplicationState;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,7 +82,7 @@ public class ApplicationContextManagerIm
     
     return _bundleRepositoryManager;
   }
-
+  
   public synchronized AriesApplicationContext getApplicationContext(AriesApplication app)
       throws BundleException, ManagementException
   {
@@ -174,4 +173,18 @@ public class ApplicationContextManagerIm
     return _bundleFrameworkManager;
   }
 
+  public AriesApplicationContext update(AriesApplication app, DeploymentMetadata oldMetadata) throws UpdateException {
+    ApplicationContextImpl ctx = _appToContextMap.get(app);
+    
+    if (ctx == null) {
+      throw new IllegalArgumentException("AriesApplication "+
+          app.getApplicationMetadata().getApplicationSymbolicName() + "/" + app.getApplicationMetadata().getApplicationVersion() + 
+          " cannot be updated because it is not installed");
+    }
+    
+    ctx.update(app.getDeploymentMetadata(), oldMetadata);
+    
+    return ctx;
+  }
+
 }
\ No newline at end of file

Modified: incubator/aries/trunk/application/application-runtime/src/main/java/org/apache/aries/application/runtime/impl/ApplicationContextManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/application/application-runtime/src/main/java/org/apache/aries/application/runtime/impl/ApplicationContextManagerImpl.java?rev=992685&r1=992684&r2=992685&view=diff
==============================================================================
--- incubator/aries/trunk/application/application-runtime/src/main/java/org/apache/aries/application/runtime/impl/ApplicationContextManagerImpl.java (original)
+++ incubator/aries/trunk/application/application-runtime/src/main/java/org/apache/aries/application/runtime/impl/ApplicationContextManagerImpl.java Sat Sep  4 21:35:00 2010
@@ -26,10 +26,12 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import org.apache.aries.application.DeploymentMetadata;
 import org.apache.aries.application.management.AriesApplication;
 import org.apache.aries.application.management.AriesApplicationContext;
 import org.apache.aries.application.management.AriesApplicationContextManager;
 import org.apache.aries.application.management.ManagementException;
+import org.apache.aries.application.management.UpdateException;
 import org.apache.aries.application.management.AriesApplicationContext.ApplicationState;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -110,4 +112,28 @@ public class ApplicationContextManagerIm
     
     _appToContextMap.clear();
   }
+
+  public AriesApplicationContext update(AriesApplication app, DeploymentMetadata oldMetadata) throws UpdateException {
+    ApplicationContextImpl oldCtx = _appToContextMap.get(app);
+    
+    if (oldCtx == null) {
+      throw new IllegalArgumentException("AriesApplication "+
+          app.getApplicationMetadata().getApplicationSymbolicName() + "/" + app.getApplicationMetadata().getApplicationVersion() + 
+          " cannot be updated because it is not installed");
+    }
+    
+    uninstall(oldCtx);
+    try {
+      AriesApplicationContext newCtx = getApplicationContext(app);
+      if (oldCtx.getApplicationState() == ApplicationState.ACTIVE) {
+        newCtx.start();
+      }
+      
+      return newCtx;
+    } catch (BundleException e) {
+      throw new UpdateException("Update failed: "+e.getMessage(), e, false, null);
+    } catch (ManagementException e) {
+      throw new UpdateException("Update failed: "+e.getMessage(), e, false, null);
+    }
+  }
 }
\ No newline at end of file