Author: bdelacretaz
Date: Mon May  4 15:23:36 2009
New Revision: 771331

URL: http://svn.apache.org/viewvc?rev=771331&view=rev
Log:
SLING-904 - InstallableDataWrapper stores bundle data locally, in case 
InputStream is gone when installing

Added:
    
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
   (with props)
Modified:
    
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiController.java
    
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
    
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerTask.java
    
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/test/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessorTest.java

Modified: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiController.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiController.java?rev=771331&r1=771330&r2=771331&view=diff
==============================================================================
--- 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiController.java
 (original)
+++ 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/OsgiController.java
 Mon May  4 15:23:36 2009
@@ -41,7 +41,7 @@
      *  @param attributes metadata stored by the OsgiController, will be
      *      removed after calling this method
      */
-    void scheduleUninstall(String uri) throws JcrInstallException;
+    void scheduleUninstall(String uri) throws IOException, JcrInstallException;
     
     /** Return the list of uri for resources that have been installed 
      *  by this controller.

Added: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java?rev=771331&view=auto
==============================================================================
--- 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
 (added)
+++ 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
 Mon May  4 15:23:36 2009
@@ -0,0 +1,111 @@
+/*
+ * 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.sling.jcr.jcrinstall.osgi.impl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.sling.jcr.jcrinstall.osgi.InstallableData;
+import org.osgi.framework.BundleContext;
+
+/** Wraps InstallableData instances that provide an InputStream
+ *     so that their data comes from our BundleContext's storage.
+ * 
+ *     Needed as InstallableData will be provided by a separate bundle,
+ *  with InputStreams that might not be available anymore once
+ *  the data is actually installed, for example if that data comes
+ *  from a JCR repository that's deactivated due to bundle updates.
+ */
+class InstallableDataWrapper implements InstallableData {
+       
+       private InstallableData wrapped;
+       private final File dataFile;
+       private static int fileCounter;
+       
+       InstallableDataWrapper(InstallableData d, BundleContext bc) throws 
IOException {
+               wrapped = d;
+               
+               // If d adapts to an input stream, save its content in
+               // our BundleContext storage
+               final InputStream is = wrapped.adaptTo(InputStream.class);
+               if(is == null) {
+                       dataFile = null;
+               } else {
+                       OutputStream os = null;
+                       try {
+                               String filename = getClass().getName();
+                               synchronized (getClass()) {
+                                       filename += "." + (++fileCounter);
+                               }
+                               dataFile = bc.getDataFile(filename);
+                               
+                               os = new BufferedOutputStream(new 
FileOutputStream(dataFile));
+                               final byte[] buffer = new byte[16384];
+                               int count = 0;
+                               while((count = is.read(buffer, 0, 
buffer.length)) > 0) {
+                                       os.write(buffer, 0, count);
+                               }
+                               os.flush();
+                       } finally {
+                               is.close();
+                               if(os != null) {
+                                       os.close();
+                               }
+                       }
+               }
+       }
+
+       public int getBundleStartLevel() {
+               return wrapped.getBundleStartLevel();
+       }
+       
+       /** Adapt the underlying data to the provided type.
+        *      @return null if cannot be adapted */
+       @SuppressWarnings("unchecked")
+       public <AdapterType> AdapterType adaptTo(Class<AdapterType> type) {
+               // If we saved out content to a data file, use that
+               if(InputStream.class.equals(type) && dataFile != null) {
+                       try {
+                               return (AdapterType)(new 
BufferedInputStream(new FileInputStream(dataFile)));
+                       } catch(IOException ioe) {
+                               throw new IllegalStateException("Unable to open 
data file " + dataFile.getAbsolutePath());
+                       }
+               } else {
+                       return wrapped.adaptTo(type);
+               }
+       }
+
+       public String getDigest() {
+               return wrapped.getDigest();
+       }
+       
+       void cleanup() {
+               if(dataFile != null) {
+                       dataFile.delete();
+               }
+               wrapped = null;
+       }
+
+}

Propchange: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/InstallableDataWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java?rev=771331&r1=771330&r2=771331&view=diff
==============================================================================
--- 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
 (original)
+++ 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerImpl.java
 Mon May  4 15:23:36 2009
@@ -30,6 +30,7 @@
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiController;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor;
 import org.apache.sling.jcr.jcrinstall.osgi.ResourceOverrideRules;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.SynchronousBundleListener;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -54,6 +55,7 @@
 */
 public class OsgiControllerImpl implements OsgiController, 
SynchronousBundleListener {
 
+       private BundleContext bundleContext;
     private Storage storage;
     private OsgiResourceProcessorList processors;
     private final Logger log = LoggerFactory.getLogger(this.getClass());
@@ -79,11 +81,13 @@
     public static final long LAST_MODIFIED_NOT_FOUND = -1;
 
     protected void activate(ComponentContext context) throws IOException {
+       bundleContext = context.getBundleContext();
         processors = new OsgiResourceProcessorList(context.getBundleContext(), 
packageAdmin, startLevel, configAdmin);
         storage = new 
Storage(context.getBundleContext().getDataFile(STORAGE_FILENAME));
     }
 
     protected void deactivate(ComponentContext oldContext) {
+       bundleContext = null;
         if(storage != null) {
             try {
                 storage.saveToFile();
@@ -104,13 +108,13 @@
     
     public void scheduleInstallOrUpdate(String uri, InstallableData data) 
throws IOException, JcrInstallException {
        synchronized (tasks) {
-               tasks.add(new OsgiControllerTask(storage, processors, roRules, 
uri, data));
+               tasks.add(new OsgiControllerTask(storage, processors, roRules, 
uri, data, bundleContext));
                }
     }
 
-    public void scheduleUninstall(String uri) throws JcrInstallException {
+    public void scheduleUninstall(String uri) throws IOException, 
JcrInstallException {
        synchronized (tasks) {
-               tasks.add(new OsgiControllerTask(storage, processors, roRules, 
uri, null));
+               tasks.add(new OsgiControllerTask(storage, processors, roRules, 
uri, null, bundleContext));
        }
     }
 

Modified: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerTask.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerTask.java?rev=771331&r1=771330&r2=771331&view=diff
==============================================================================
--- 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerTask.java
 (original)
+++ 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/main/java/org/apache/sling/jcr/jcrinstall/osgi/impl/OsgiControllerTask.java
 Mon May  4 15:23:36 2009
@@ -28,6 +28,7 @@
 import org.apache.sling.jcr.jcrinstall.osgi.JcrInstallException;
 import org.apache.sling.jcr.jcrinstall.osgi.OsgiResourceProcessor;
 import org.apache.sling.jcr.jcrinstall.osgi.ResourceOverrideRules;
+import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,13 +53,14 @@
                        OsgiResourceProcessorList processors, 
                        ResourceOverrideRules roRules, 
                        String uri, 
-                       InstallableData data)
+                       InstallableData data,
+                       BundleContext bc) throws IOException
        {
                this.storage = storage;
                this.processors = processors;
                this.roRules = roRules;
                this.uri = uri;
-               this.data = data;
+               this.data = (data == null ? null : new 
InstallableDataWrapper(data, bc));
        }
        
        @Override
@@ -72,12 +74,18 @@
                ;
        }
        
-       public Object call() throws JcrInstallException, IOException {
+       public Object call() throws Exception {
                if(isInstallOrUpdate()) {
                        executeInstallOrUpdate();
                } else {
                        executeUninstall();
                }
+               
+               // Cleanup InstallableDataWrapper
+               if(data instanceof InstallableDataWrapper) {
+                       ((InstallableDataWrapper)data).cleanup();
+               }
+               
                return null;
        }
        
@@ -85,7 +93,7 @@
                return data != null;
        }
 
-       private void executeUninstall() throws JcrInstallException {
+       private void executeUninstall() throws Exception {
         // If a corresponding higher priority resource is installed, ignore 
this request
         if(roRules != null) {
             for(String r : roRules.getHigherPriorityResources(uri)) {
@@ -97,22 +105,17 @@
             }
         }
         
-        try {
-               // let each processor try to uninstall, one of them
-               // should know how that handle uri
-               for(OsgiResourceProcessor p : this.processors) {
-                       p.uninstall(uri, storage.getMap(uri));
-               }
-               
-               storage.remove(uri);
-               storage.saveToFile();
-               
-        } catch(Exception e) {
-            throw new JcrInstallException("Exception in uninstall (" + uri + 
")", e);
-        }
+        // let each processor try to uninstall, one of them
+       // should know how that handle uri
+       for(OsgiResourceProcessor p : this.processors) {
+                p.uninstall(uri, storage.getMap(uri));
+       }
+       
+        storage.remove(uri);
+        storage.saveToFile();
        }
 
-       private void executeInstallOrUpdate() throws JcrInstallException , 
IOException {
+       private void executeInstallOrUpdate() throws Exception {
         // If a corresponding higher priority resource is already installed, 
ignore this one
         if(roRules != null) {
             for(String r : roRules.getHigherPriorityResources(uri)) {
@@ -138,17 +141,11 @@
         // let suitable OsgiResourceProcessor process install
         final OsgiResourceProcessor p = processors.getProcessor(uri, data);
         if (p != null) {
-            try {
-                final Map<String, Object> map = storage.getMap(uri);
-                if(p.installOrUpdate(uri, map, data) != IGNORED) {
-                    map.put(OsgiControllerImpl.KEY_DIGEST, data.getDigest());
-                }
-                storage.saveToFile();
-            } catch(IOException ioe) {
-                throw ioe;
-            } catch(Exception e) {
-                throw new JcrInstallException("Exception in installOrUpdate (" 
+ uri + ")", e);
+            final Map<String, Object> map = storage.getMap(uri);
+            if(p.installOrUpdate(uri, map, data) != IGNORED) {
+                map.put(OsgiControllerImpl.KEY_DIGEST, data.getDigest());
             }
+            storage.saveToFile();
         }
         return;
                

Modified: 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/test/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessorTest.java
URL: 
http://svn.apache.org/viewvc/incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/test/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessorTest.java?rev=771331&r1=771330&r2=771331&view=diff
==============================================================================
--- 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/test/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessorTest.java
 (original)
+++ 
incubator/sling/trunk/contrib/extensions/jcrinstall/service/src/test/java/org/apache/sling/jcr/jcrinstall/osgi/impl/BundleResourceProcessorTest.java
 Mon May  4 15:23:36 2009
@@ -41,6 +41,7 @@
 
     private Mockery mockery;
     private Sequence sequence;
+    private static int counter;
 
     static class TestStorage extends Storage {
         int saveCounter;
@@ -65,6 +66,7 @@
 
         final OsgiControllerImpl c = new OsgiControllerImpl();
         final BundleContext bc = mockery.mock(BundleContext.class);
+        Utilities.setField(c, "bundleContext", bc);
         final PackageAdmin pa = mockery.mock(PackageAdmin.class);
         final TestStorage s = new TestStorage(Utilities.getTestFile());
         Utilities.setStorage(c, s);
@@ -72,7 +74,7 @@
         final Bundle [] bundles = { b };
         final long bundleId = 1234;
         final String uri = "/test/bundle.jar";
-        final MockInstallableData data = new MockInstallableData(uri);
+        final MockInstallableData data = new MockInstallableData(uri, "some 
data");
         final InputStream is = data.adaptTo(InputStream.class);
 
         // We'll try installing a bundle, re-installing to cause
@@ -93,8 +95,12 @@
             allowing(b).getLocation();
             will(returnValue(uri));
             
allowing(bc).addFrameworkListener(with(any(FrameworkListener.class)));
+            allowing(bc).getDataFile(with(any(String.class)));
+            will(returnValue(getDataFile()));
 
-            one(bc).installBundle(OsgiControllerImpl.getResourceLocation(uri), 
is);
+            one(bc).installBundle(
+                       
with(equal(OsgiControllerImpl.getResourceLocation(uri))), 
+                       with(any(InputStream.class)));
             inSequence(sequence);
             will(returnValue(b));
 
@@ -105,7 +111,7 @@
             one(b).stop();
             inSequence(sequence);
             
-            one(b).update(is);
+            one(b).update(with(any(InputStream.class)));
             inSequence(sequence);
 
             one(b).uninstall();
@@ -166,4 +172,8 @@
         mockery.assertIsSatisfied();
         t.active = false;
     }
+    
+    static File getDataFile() throws IOException {
+        return 
File.createTempFile(BundleResourceProcessor.class.getSimpleName() + 
(++counter),".tmp");
+    }
 }


Reply via email to