You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by da...@apache.org on 2011/03/23 15:39:58 UTC

svn commit: r1084603 - in /aries/trunk/spi-fly: ./ spi-fly-core/src/main/java/org/apache/aries/spifly/ spi-fly-core/src/test/java/org/apache/aries/spifly/ spi-fly-dynamic-bundle/ spi-fly-dynamic-bundle/src/ spi-fly-dynamic-bundle/src/main/ spi-fly-dyna...

Author: davidb
Date: Wed Mar 23 14:39:56 2011
New Revision: 1084603

URL: http://svn.apache.org/viewvc?rev=1084603&view=rev
Log:
First step of major SPI-Fly refactoring.

It introduces a dynamic bundle (which uses weaving hooks) and two static modules, a static weaver and a runtime support bundle for it.
Tests are broken - will work on those soon. Hudson should not be affected since spifly is currently not part of the overall build.

Added:
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/BaseActivator.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ClientWeavingHookTest.java.todo
      - copied unchanged from r1084567, aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ClientWeavingHookTest.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java.todo
      - copied, changed from r1084567, aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UnaffectedTestClient.java.todo
      - copied unchanged from r1084567, aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UnaffectedTestClient.java
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/ClientWeavingHook.java
    aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/DynamicWeavingActivator.java
    aries/trunk/spi-fly/spi-fly-static-bundle/
    aries/trunk/spi-fly/spi-fly-static-bundle/pom.xml
    aries/trunk/spi-fly/spi-fly-static-bundle/src/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/
    aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/StaticWeavingActivator.java
    aries/trunk/spi-fly/spi-fly-static-tool/
    aries/trunk/spi-fly/spi-fly-static-tool/pom.xml
    aries/trunk/spi-fly/spi-fly-static-tool/src/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/DirTree.java
    aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/MainTest.java
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/resources/
    aries/trunk/spi-fly/spi-fly-static-tool/src/test/resources/testjar.jar   (with props)
Removed:
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Activator.java
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ClientWeavingHook.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ClientWeavingHookTest.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java
    aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UnaffectedTestClient.java
    aries/trunk/spi-fly/spi-fly-static/
    aries/trunk/spi-fly/spi-fly-static-support-bundle/
Modified:
    aries/trunk/spi-fly/pom.xml
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/TCCLSetterVisitor.java
    aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java

Modified: aries/trunk/spi-fly/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/pom.xml?rev=1084603&r1=1084602&r2=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/pom.xml (original)
+++ aries/trunk/spi-fly/pom.xml Wed Mar 23 14:39:56 2011
@@ -56,7 +56,8 @@
     <modules>
         <module>spi-fly-deps</module>
         <module>spi-fly-core</module>
-        <module>spi-fly-static</module>
-        <module>spi-fly-static-support-bundle</module>
+        <module>spi-fly-dynamic-bundle</module>
+        <module>spi-fly-static-tool</module>
+        <module>spi-fly-static-bundle</module>
     </modules>
 </project>

Added: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/BaseActivator.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/BaseActivator.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/BaseActivator.java (added)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/BaseActivator.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,238 @@
+/**
+ * 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.spifly;
+
+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.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.aries.spifly.api.SpiFlyConstants;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.ServiceTracker;
+
+public abstract class BaseActivator implements BundleActivator {
+    private static final Set<WeavingData> NON_WOVEN_BUNDLE = Collections.emptySet();
+    
+    // Static access to the activator used by the woven code, therefore 
+    // this bundle must be a singleton.
+    // TODO see if we can get rid of the static access.
+    static BaseActivator activator;
+    
+    private BundleContext bundleContext;
+    private LogServiceTracker logServiceTracker;
+    private List<LogService> logServices = new CopyOnWriteArrayList<LogService>();
+    private BundleTracker<Object> consumerBundleTracker; 
+    private BundleTracker<List<ServiceRegistration<?>>> providerBundleTracker;
+
+    private final ConcurrentMap<Bundle, Set<WeavingData>> bundleWeavingData = 
+        new ConcurrentHashMap<Bundle, Set<WeavingData>>();
+
+    private final ConcurrentMap<String, SortedMap<Long, Bundle>> registeredProviders = 
+            new ConcurrentHashMap<String, SortedMap<Long, Bundle>>();
+
+    private final ConcurrentMap<Bundle, Map<ConsumerRestriction, List<BundleDescriptor>>> consumerRestrictions = 
+            new ConcurrentHashMap<Bundle, Map<ConsumerRestriction, List<BundleDescriptor>>>();
+    
+    public synchronized void start(BundleContext context, final String consumerHeaderName) throws Exception {
+        bundleContext = context;
+        
+        logServiceTracker = new LogServiceTracker(context);
+        logServiceTracker.open();
+
+        providerBundleTracker = new BundleTracker<List<ServiceRegistration<?>>>(context,
+                Bundle.ACTIVE, new ProviderBundleTrackerCustomizer(this, context.getBundle()));
+        providerBundleTracker.open();
+        
+        consumerBundleTracker = new BundleTracker<Object>(context, Bundle.INSTALLED, null) {
+            @Override
+            public Object addingBundle(Bundle bundle, BundleEvent event) {
+                processBundle(bundle, consumerHeaderName);                    
+                
+                return super.addingBundle(bundle, event);
+            }
+
+            @Override
+            public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+                removedBundle(bundle, event, object);
+                addingBundle(bundle, event);
+            }
+
+            @Override
+            public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+                bundleWeavingData.remove(bundle);
+            }
+        };
+        consumerBundleTracker.open();
+        
+        for (Bundle bundle : context.getBundles()) {
+            processBundle(bundle, consumerHeaderName);
+        }
+        
+        activator = this;
+    }
+
+    private void processBundle(Bundle bundle, String consumerHeaderName) {
+        if (bundleWeavingData.containsKey(bundle)) {
+            // This bundle was already processed
+            return;
+        }
+        
+        String consumerHeader = bundle.getHeaders().get(consumerHeaderName);
+        if (consumerHeader != null) {
+            Set<WeavingData> wd = ConsumerHeaderProcessor.processHeader(consumerHeader);
+            bundleWeavingData.put(bundle, Collections.unmodifiableSet(wd));
+            
+            for (WeavingData w : wd) {
+                registerConsumerBundle(bundle, w.getArgRestrictions(), w.getAllowedBundles());
+            }
+        } else {
+            bundleWeavingData.put(bundle, NON_WOVEN_BUNDLE);
+        }
+    }
+
+    @Override
+    public synchronized void stop(BundleContext context) throws Exception {
+        activator = null;
+        
+        consumerBundleTracker.close();
+        providerBundleTracker.close();
+        logServiceTracker.close();
+    }
+
+    public void log(int level, String message) {
+        synchronized (logServices) {
+            for (LogService log : logServices) {
+                log.log(level, message);
+            }
+        }
+    }
+
+    public void log(int level, String message, Throwable th) {
+        synchronized (logServices) {
+            for (LogService log : logServices) {
+                log.log(level, message, th);
+            }
+        }
+    }
+    
+    public Set<WeavingData> getWeavingData(Bundle b) {
+        // Simply return the value as it's already an unmovable set.
+        Set<WeavingData> wd = bundleWeavingData.get(b);
+        if (wd == null) 
+            return null;
+        
+        if (wd.size() == 0) 
+            return null;
+        
+        return wd;
+    }
+
+    public void registerProviderBundle(String registrationClassName, Bundle bundle) {        
+        registeredProviders.putIfAbsent(registrationClassName, Collections.synchronizedSortedMap(new TreeMap<Long, Bundle>()));
+        SortedMap<Long, Bundle> map = registeredProviders.get(registrationClassName);
+        map.put(bundle.getBundleId(), bundle);
+    }
+
+    public Collection<Bundle> findProviderBundles(String name) {
+        SortedMap<Long, Bundle> map = registeredProviders.get(name);
+        return map == null ? Collections.<Bundle>emptyList() : map.values();
+    }
+    
+    // TODO unRegisterProviderBundle();
+    public void registerConsumerBundle( Bundle consumerBundle,
+            Set<ConsumerRestriction> restrictions, List<BundleDescriptor> allowedBundles) {
+        consumerRestrictions.putIfAbsent(consumerBundle, new HashMap<ConsumerRestriction, List<BundleDescriptor>>());
+        Map<ConsumerRestriction, List<BundleDescriptor>> map = consumerRestrictions.get(consumerBundle);
+        for (ConsumerRestriction restriction : restrictions) {
+            map.put(restriction, allowedBundles);
+        }
+    }
+
+    public Collection<Bundle> findConsumerRestrictions(Bundle consumer, String className, String methodName,
+            Map<Pair<Integer, String>, String> args) {
+        Map<ConsumerRestriction, List<BundleDescriptor>> restrictions = consumerRestrictions.get(consumer);
+        if (restrictions == null) {
+            // Null means: no restrictions
+            return null;
+        }
+        
+        for (Map.Entry<ConsumerRestriction, List<BundleDescriptor>> entry : restrictions.entrySet()) {
+            if (entry.getKey().matches(className, methodName, args)) {
+                return getBundles(entry.getValue());
+            }
+        }
+        
+        // Empty collection: nothing matches
+        return Collections.emptySet();
+    }
+
+    private Collection<Bundle> getBundles(List<BundleDescriptor> descriptors) {
+        if (descriptors == null) {
+            return null;
+        }
+        
+        List<Bundle> bundles = new ArrayList<Bundle>();
+        for (Bundle b : bundleContext.getBundles()) {
+            for (BundleDescriptor desc : descriptors) {
+                if (b.getSymbolicName().equals(desc.getSymbolicName())) {
+                    if (desc.getVersion() == null || b.getVersion().equals(desc.getVersion())) {
+                        bundles.add(b);
+                    }
+                }
+            }
+        }
+        return bundles;
+    }
+
+    // TODO unRegisterConsumerBundle();
+    
+    private class LogServiceTracker extends ServiceTracker<LogService, LogService> {
+        public LogServiceTracker(BundleContext context) {
+            super(context, LogService.class, null);
+        }
+
+        public LogService addingService(ServiceReference<LogService> reference) {
+            LogService svc = super.addingService(reference);
+            if (svc != null)
+                logServices.add(svc);
+            return svc;
+        }
+
+        @Override
+        public void removedService(ServiceReference<LogService> reference, LogService service) {
+            logServices.remove(service);
+        }        
+    }
+}

Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java?rev=1084603&r1=1084602&r2=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ConsumerHeaderProcessor.java Wed Mar 23 14:39:56 2011
@@ -56,7 +56,7 @@ public class ConsumerHeaderProcessor {
      * @param consumerHeader the <tt>SPI-Consumer</tt> header.
      * @return an instance of the {@link WeavingData} class.
      */
-    public static WeavingData[] processHeader(/* Bundle consumerBundle, */String consumerHeader) {
+    public static Set<WeavingData> processHeader(/* Bundle consumerBundle, */String consumerHeader) {
         Set<WeavingData> weavingData = new HashSet<WeavingData>();
         
         for (PathElement element : HeaderParser.parseHeader(consumerHeader)) {
@@ -169,6 +169,6 @@ public class ConsumerHeaderProcessor {
             weavingData.add(new WeavingData(className, methodName, argClasses, restrictions, 
                     allowedBundles.size() == 0 ? null : allowedBundles));
         }
-        return weavingData.toArray(new WeavingData [weavingData.size()]);
+        return weavingData;
     }
 }

Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java?rev=1084603&r1=1084602&r2=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizer.java Wed Mar 23 14:39:56 2011
@@ -37,10 +37,10 @@ import org.osgi.util.tracker.BundleTrack
  * Listens for new bundles being installed and registers them as service providers if applicable.
  */
 public class ProviderBundleTrackerCustomizer implements BundleTrackerCustomizer<List<ServiceRegistration<?>>> {
-    final Activator activator;
+    final BaseActivator activator;
     final Bundle spiBundle;
 
-    public ProviderBundleTrackerCustomizer(Activator a, Bundle b) {
+    public ProviderBundleTrackerCustomizer(BaseActivator a, Bundle b) {
         activator = a;
         spiBundle = b;
                 

Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/TCCLSetterVisitor.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/TCCLSetterVisitor.java?rev=1084603&r1=1084602&r2=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/TCCLSetterVisitor.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/TCCLSetterVisitor.java Wed Mar 23 14:39:56 2011
@@ -20,6 +20,7 @@ package org.apache.aries.spifly;
 
 import java.util.Arrays;
 import java.util.ServiceLoader;
+import java.util.Set;
 
 import org.objectweb.asm.ClassAdapter;
 import org.objectweb.asm.ClassVisitor;
@@ -39,13 +40,13 @@ public class TCCLSetterVisitor extends C
     private static final String VOID_RETURN_TYPE = "()V";
     
     private final String targetClass;
-    private final WeavingData [] weavingData;
+    private final Set<WeavingData> weavingData;
 
     // Set to true when the weaving code has changed the client such that an additional import 
     // (to the Util.class.getPackage()) is needed.
     private boolean additionalImportRequired = false;
 
-    public TCCLSetterVisitor(ClassVisitor cv, String className, WeavingData [] weavingData) {
+    public TCCLSetterVisitor(ClassVisitor cv, String className, Set<WeavingData> weavingData) {
         super(cv);
         this.targetClass = className.replace('.', '/');
         this.weavingData = weavingData;

Modified: aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java?rev=1084603&r1=1084602&r2=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java Wed Mar 23 14:39:56 2011
@@ -49,7 +49,7 @@ public class Util {
         
     public static void fixContextClassloader(String cls, String method, Class<?> clsArg, ClassLoader bundleLoader) {
         if (!(bundleLoader instanceof BundleReference)) {
-            Activator.activator.log(LogService.LOG_WARNING, "Classloader of consuming bundle doesn't implement BundleReference: " + bundleLoader);
+            BaseActivator.activator.log(LogService.LOG_WARNING, "Classloader of consuming bundle doesn't implement BundleReference: " + bundleLoader);
             return;
         }
 
@@ -58,15 +58,15 @@ public class Util {
         
         ClassLoader cl = findContextClassloader(br.getBundle(), cls, method, clsArg);
         if (cl != null) {
-            Activator.activator.log(LogService.LOG_INFO, "Temporarily setting Thread Context Classloader to: " + cl);
+            BaseActivator.activator.log(LogService.LOG_INFO, "Temporarily setting Thread Context Classloader to: " + cl);
             Thread.currentThread().setContextClassLoader(cl);
         } else {
-            Activator.activator.log(LogService.LOG_WARNING, "No classloader found for " + cls + ":" + method + "(" + clsArg + ")");
+            BaseActivator.activator.log(LogService.LOG_WARNING, "No classloader found for " + cls + ":" + method + "(" + clsArg + ")");
         }
     }
     
     private static ClassLoader findContextClassloader(Bundle consumerBundle, String className, String methodName, Class<?> clsArg) {
-        Activator activator = Activator.activator;
+        BaseActivator activator = BaseActivator.activator;
         
         String requestedClass;
         Map<Pair<Integer, String>, String> args;

Copied: aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java.todo (from r1084567, aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java)
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java.todo?p2=aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java.todo&p1=aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java&r1=1084567&r2=1084603&rev=1084603&view=diff
==============================================================================
--- aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java (original)
+++ aries/trunk/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerTest.java.todo Wed Mar 23 14:39:56 2011
@@ -40,7 +40,7 @@ public class ProviderBundleTrackerCustom
     public void testAddingRemovedBundle() throws Exception {        
         Bundle spiBundle = EasyMock.createMock(Bundle.class);
         EasyMock.replay(spiBundle);
-        Activator a = new Activator();        
+        BaseActivator a = new BaseActivator();        
         
         ProviderBundleTrackerCustomizer customizer = new ProviderBundleTrackerCustomizer(a, spiBundle);
         

Added: aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/ClientWeavingHook.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/ClientWeavingHook.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/ClientWeavingHook.java (added)
+++ aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/ClientWeavingHook.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,68 @@
+/**
+ * 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.spifly.dynamic;
+
+import java.util.Set;
+
+import org.apache.aries.spifly.TCCLSetterVisitor;
+import org.apache.aries.spifly.Util;
+import org.apache.aries.spifly.WeavingData;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.hooks.weaving.WeavingHook;
+import org.osgi.framework.hooks.weaving.WovenClass;
+import org.osgi.service.log.LogService;
+
+public class ClientWeavingHook implements WeavingHook {
+    private final String addedImport;
+    private final DynamicWeavingActivator activator;
+    
+    ClientWeavingHook(BundleContext context, DynamicWeavingActivator dwActivator) {
+        activator = dwActivator;
+        
+        Bundle b = context.getBundle();
+        String bver = b.getVersion().toString();
+        String bsn = b.getSymbolicName();
+        
+        addedImport = Util.class.getPackage().getName() + 
+            ";bundle-symbolic-name=" + bsn + 
+            ";bundle-version=" + bver;
+    }
+    
+	@Override
+	public void weave(WovenClass wovenClass) {
+	    Bundle consumerBundle = wovenClass.getBundleWiring().getBundle();
+        Set<WeavingData> wd = activator.getWeavingData(consumerBundle);
+        if (wd != null) {
+	        activator.log(LogService.LOG_DEBUG, "Weaving class " + wovenClass.getClassName());            
+            
+//            WeavingData[] wd = ConsumerHeaderProcessor.processHeader(consumerBundle, consumerHeader);
+	        
+	        ClassReader cr = new ClassReader(wovenClass.getBytes());
+	        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+	        TCCLSetterVisitor tsv = new TCCLSetterVisitor(cw, wovenClass.getClassName(), wd);
+	        cr.accept(tsv, 0);	        
+	        wovenClass.setBytes(cw.toByteArray());
+	        if (tsv.additionalImportRequired())
+	            wovenClass.getDynamicImports().add(addedImport);
+	    }			
+	}
+}

Added: aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/DynamicWeavingActivator.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/DynamicWeavingActivator.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/DynamicWeavingActivator.java (added)
+++ aries/trunk/spi-fly/spi-fly-dynamic-bundle/src/main/java/org/apache/aries/spifly/dynamic/DynamicWeavingActivator.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,27 @@
+package org.apache.aries.spifly.dynamic;
+
+import org.apache.aries.spifly.BaseActivator;
+import org.apache.aries.spifly.api.SpiFlyConstants;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.hooks.weaving.WeavingHook;
+
+public class DynamicWeavingActivator extends BaseActivator implements BundleActivator {
+    private ServiceRegistration<WeavingHook> weavingHookService;
+
+    @Override
+    public synchronized void start(BundleContext context) throws Exception {
+        WeavingHook wh = new ClientWeavingHook(context, this);
+        weavingHookService = context.registerService(WeavingHook.class, wh, null);
+        
+        super.start(context, SpiFlyConstants.SPI_CONSUMER_HEADER);
+    }
+
+    @Override
+    public synchronized void stop(BundleContext context) throws Exception {
+        weavingHookService.unregister();
+        
+        super.stop(context);
+    }
+}

Added: aries/trunk/spi-fly/spi-fly-static-bundle/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-bundle/pom.xml?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-bundle/pom.xml (added)
+++ aries/trunk/spi-fly/spi-fly-static-bundle/pom.xml Wed Mar 23 14:39:56 2011
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+    <!--
+ 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.
+    -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.spifly</groupId>
+        <artifactId>spifly</artifactId>
+        <version>0.4-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.spifly.static.bundle</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Aries SPI Fly Static Weaving Bundle</name>
+    <description>
+        This bundle contains support classes used at runtime by bundles
+        woven using the static weaving done through the org.apache.aries.spifly.static
+        component.
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.spifly</groupId>
+            <artifactId>org.apache.aries.spifly.core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>        
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            *
+                        </Import-Package>
+                        <Export-Package>
+                            org.apache.aries.spifly;version=${project.version},
+                            org.apache.aries.spifly.api;version=${project.version}
+                        </Export-Package>
+                        <Private-Package>
+                            org.apache.aries.spifly.staticbundle
+                        </Private-Package>
+                        <Bundle-Activator>org.apache.aries.spifly.staticbundle.StaticWeavingActivator</Bundle-Activator>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

Added: aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/StaticWeavingActivator.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/StaticWeavingActivator.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/StaticWeavingActivator.java (added)
+++ aries/trunk/spi-fly/spi-fly-static-bundle/src/main/java/org/apache/aries/spifly/staticbundle/StaticWeavingActivator.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,18 @@
+package org.apache.aries.spifly.staticbundle;
+
+import org.apache.aries.spifly.BaseActivator;
+import org.apache.aries.spifly.api.SpiFlyConstants;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class StaticWeavingActivator extends BaseActivator implements BundleActivator {
+    @Override
+    public synchronized void start(BundleContext context) throws Exception {
+        super.start(context, SpiFlyConstants.PROCESSED_SPI_CONSUMER_HEADER);
+    }
+
+    @Override
+    public synchronized void stop(BundleContext context) throws Exception {
+        super.stop(context);
+    }
+}

Added: aries/trunk/spi-fly/spi-fly-static-tool/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool/pom.xml?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-tool/pom.xml (added)
+++ aries/trunk/spi-fly/spi-fly-static-tool/pom.xml Wed Mar 23 14:39:56 2011
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+    <!--
+ 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.
+    -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries.spifly</groupId>
+        <artifactId>spifly</artifactId>
+        <version>0.4-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.aries.spifly.static.tool</artifactId>
+    <packaging>jar</packaging>
+    <name>Apache Aries SPI Fly Static Weaving Tool</name>
+    <description>
+        This tool does the weaving to support SPI ServiceLoader statically.
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>asm</groupId>
+            <artifactId>asm-all</artifactId>
+            <version>3.3.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.aries.spifly</groupId>
+            <artifactId>org.apache.aries.spifly.core</artifactId>
+            <version>${pom.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <mainClass>org.apache.aries.spifly.statictool.Main</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

Added: aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/DirTree.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/DirTree.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/DirTree.java (added)
+++ aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/DirTree.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,51 @@
+/**
+ * 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.spifly.statictool;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DirTree {
+    List<File> fileList = new ArrayList<File>();
+
+    public DirTree(File f) {
+        String[] names = f.list();
+
+        if (names == null) {
+            fileList.add(f);
+            return;
+        }
+
+        for (String name : names) {
+            File curFile = new File(f, name);
+
+            if (curFile.isDirectory()) {
+                fileList.addAll(new DirTree(curFile).getFiles());
+            } else {
+                fileList.add(curFile);
+            }
+        }
+        fileList.add(f);
+    }
+
+    public List<File> getFiles() {
+        return fileList;
+    }
+}

Added: aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java (added)
+++ aries/trunk/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,282 @@
+/**
+ * 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.spifly.statictool;
+
+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 java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.aries.spifly.ConsumerHeaderProcessor;
+import org.apache.aries.spifly.Streams;
+import org.apache.aries.spifly.TCCLSetterVisitor;
+import org.apache.aries.spifly.Util;
+import org.apache.aries.spifly.WeavingData;
+import org.apache.aries.spifly.api.SpiFlyConstants;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+public class Main {
+    private static final String IMPORT_PACKAGE = "Import-Package";
+
+    public static void usage() {
+        System.err.println();
+        System.err.println("Usage: java " + Main.class.getName() + " bundle1.jar bundle2.jar ...");
+        System.exit(-1);
+    }
+    
+    public static void main(String ... args) throws Exception {
+        for (String arg : args) {
+            weaveJar(arg);
+        }
+    }
+
+    private static void weaveJar(String jarPath) throws IOException {
+        String spiFlyVersion = getMyVersion();
+        
+        File jarFile = new File(jarPath);
+        File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis());        
+        Manifest manifest = unJar(jarFile, tempDir);
+        String consumerHeader = manifest.getMainAttributes().getValue(SpiFlyConstants.SPI_CONSUMER_HEADER);
+        if (consumerHeader != null) {
+            weaveDir(tempDir, consumerHeader);
+
+            manifest.getMainAttributes().remove(new Attributes.Name(SpiFlyConstants.SPI_CONSUMER_HEADER));
+            manifest.getMainAttributes().putValue(SpiFlyConstants.PROCESSED_SPI_CONSUMER_HEADER, consumerHeader);
+            // TODO if new packages needed then...
+            extendImportPackage(spiFlyVersion, manifest);
+            
+            File newJar = getNewJarFile(jarFile);
+            jar(newJar, tempDir, manifest);
+        }
+        delTree(tempDir);
+    }
+
+    private static void extendImportPackage(String spiFlyVersion, Manifest manifest) {
+        String ip = manifest.getMainAttributes().getValue(IMPORT_PACKAGE);            
+        StringBuilder sb = new StringBuilder(ip);
+        sb.append(",");
+        sb.append(Util.class.getPackage().getName());
+        sb.append(";version=\"[");
+        sb.append(spiFlyVersion);
+        sb.append(",");
+        sb.append(spiFlyVersion);
+        sb.append("]\"");
+        manifest.getMainAttributes().putValue(IMPORT_PACKAGE, sb.toString());
+    }
+
+    private static String getMyVersion() throws IOException {
+        // Should be able to leverage the aries.osgi.version file that appears in the target directory here. 
+        // Need to figure that out...
+        return "0.4.0.SNAPSHOT";
+        
+//        String classResource = "/" + Main.class.getName().replace(".", "/") + ".class";
+//        URL jarUrl = Main.class.getResource(classResource);
+//        if (jarUrl != null) {
+//            String jarLoc = jarUrl.toExternalForm();
+//            Manifest mf = null;
+//            if (jarLoc.startsWith("jar:")) {
+//                jarLoc.substring("jar:".length());
+//                int idx = jarLoc.indexOf("!/");
+//                if (idx >= 0) {
+//                    jarLoc = jarLoc.substring(0, idx);
+//                }
+//                
+//                JarFile jr = new JarFile(jarLoc);
+//                mf = jr.getManifest();
+//            } else if (jarLoc.startsWith("file:") && jarLoc.endsWith(classResource)) {
+//                String rootDir = jarLoc.substring(0, jarLoc.length() - classResource.length());
+//                File manifestFile = new File(rootDir + "/META-INF/MANIFEST.MF");
+//                if (manifestFile.exists()) {
+//                    mf = new Manifest(new FileInputStream(manifestFile));
+//                }
+//            }
+//            
+//            if (mf != null) {
+//                String version = mf.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+//                if (version == null)
+//                    throw new IOException("Could not obtain the implementation version of this jar file from the manifest");
+//                return version.trim();
+//            }
+//        }
+//        throw new IOException("This class can only be executed from inside a jar or an exploded jar file."); 
+    }
+
+    private static File getNewJarFile(File jarFile) {
+        String s = jarFile.getAbsolutePath();
+        int idx = s.lastIndexOf('.');
+        s = s.substring(0, idx);
+        s += "_spifly.jar";
+        return new File(s);
+    }
+
+    private static void weaveDir(File dir, String consumerHeader) throws IOException {
+        String dirName = dir.getAbsolutePath();
+        
+        DirTree dt = new DirTree(dir);
+        for (File f : dt.getFiles()) {
+            if (!f.getName().endsWith(".class"))
+                continue;
+            
+            String className = f.getAbsolutePath().substring(dirName.length());
+            if (className.startsWith(File.separator)) 
+                className = className.substring(1);
+            className = className.substring(0, className.length() - ".class".length());
+            className = className.replace(File.separator, ".");
+            
+            Set<WeavingData> wd = ConsumerHeaderProcessor.processHeader(consumerHeader);
+            InputStream is = new FileInputStream(f);
+            byte[] b;
+            try {
+                ClassReader cr = new ClassReader(is);
+                ClassWriter cw = new ClassWriter(0);                
+                ClassVisitor cv = new TCCLSetterVisitor(cw, className, wd); 
+                cr.accept(cv, 0);
+                b = cw.toByteArray();
+            } finally {
+                is.close();
+            }
+            
+            OutputStream os = new FileOutputStream(f);
+            try {
+                os.write(b);                
+            } finally {
+                os.close();
+            }
+        }
+    }
+
+    static Manifest unJar(File jarFile, File tempDir) throws IOException {
+        ensureDirectory(tempDir);
+
+        JarInputStream jis = new JarInputStream(new FileInputStream(jarFile));
+        JarEntry je = null;
+        while((je = jis.getNextJarEntry()) != null) {
+            if (je.isDirectory()) {
+                File outDir = new File(tempDir, je.getName());
+                ensureDirectory(outDir);
+                
+                continue;
+            }
+            
+            File outFile = new File(tempDir, je.getName());
+            File outDir = outFile.getParentFile();
+            ensureDirectory(outDir); 
+            
+            OutputStream out = new FileOutputStream(outFile);
+            try {
+                Streams.pump(jis, out);
+            } finally {
+                out.flush();
+                out.close();
+                jis.closeEntry();
+            }
+            outFile.setLastModified(je.getTime());
+        }
+        
+        Manifest manifest = jis.getManifest();
+        if (manifest != null) {
+            File mf = new File(tempDir, "META-INF/MANIFEST.MF");
+            File mfDir = mf.getParentFile();
+            ensureDirectory(mfDir);
+
+            OutputStream out = new FileOutputStream(mf);
+            try {
+                manifest.write(out);
+            } finally {
+                out.flush();
+                out.close();                
+            }
+        }
+        
+        jis.close();
+        return manifest;
+    }
+    
+    static void jar(File jarFile, File rootFile, Manifest manifest) throws IOException {
+        JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest);
+        try {
+            addToJarRecursively(jos, rootFile.getAbsoluteFile(), rootFile.getAbsolutePath());
+        } finally {
+            jos.close();
+        }
+    }
+
+    static void addToJarRecursively(JarOutputStream jar, File source, String rootDirectory) throws IOException {                
+        String sourceName = source.getAbsolutePath().replace("\\", "/");
+        sourceName = sourceName.substring(rootDirectory.length());
+        
+        if (sourceName.startsWith("/")) {
+            sourceName = sourceName.substring(1);
+        }
+        
+        if ("META-INF/MANIFEST.MF".equals(sourceName))
+            return;
+        
+        if (source.isDirectory()) {
+            /* Is there any point in adding a directory beyond just taking up space? 
+            if (!sourceName.isEmpty()) {
+                if (!sourceName.endsWith("/")) {
+                    sourceName += "/";                        
+                }
+                JarEntry entry = new JarEntry(sourceName);
+                jar.putNextEntry(entry);
+                jar.closeEntry();
+            }
+            */
+            for (File nested : source.listFiles()) {
+                addToJarRecursively(jar, nested, rootDirectory);
+            }
+            return;
+        }
+        
+        JarEntry entry = new JarEntry(sourceName);
+        jar.putNextEntry(entry);
+        InputStream is = new FileInputStream(source);
+        try {
+            Streams.pump(is, jar);
+        } finally {
+            jar.closeEntry();
+            is.close();
+        }
+    }
+
+    static void delTree(File tempDir) throws IOException {
+        for (File f : new DirTree(tempDir).getFiles()) {
+            if (!f.delete())
+                throw new IOException("Problem deleting file: " + tempDir.getAbsolutePath());
+        }
+    }
+
+    private static void ensureDirectory(File outDir) throws IOException {
+        if (!outDir.isDirectory())
+            if (!outDir.mkdirs())
+                throw new IOException("Unable to create directory " + outDir.getAbsolutePath());
+    }
+}
+

Added: aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/MainTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/MainTest.java?rev=1084603&view=auto
==============================================================================
--- aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/MainTest.java (added)
+++ aries/trunk/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/MainTest.java Wed Mar 23 14:39:56 2011
@@ -0,0 +1,120 @@
+/**
+ * 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.spifly.statictool;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.Manifest;
+
+import org.apache.aries.spifly.Streams;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.internal.ArrayComparisonFailure;
+
+public class MainTest {
+    @Test
+    public void testUnJarReJar() throws Exception {
+        URL jarURL = getClass().getResource("/testjar.jar");
+        File jarFile = new File(jarURL.getFile());
+        File tempDir = new File(System.getProperty("java.io.tmpdir") + "/testjar_" + System.currentTimeMillis());
+        
+        try {
+            Manifest manifest = Main.unJar(jarFile, tempDir);
+            
+            assertStreams(new File(tempDir, "META-INF/MANIFEST.MF"), 
+                    "jar:" + jarURL + "!/META-INF/MANIFEST.MF");
+            
+            assertStreams(new File(tempDir, "A text File with no content"),
+                    "jar:" + jarURL + "!/A text File with no content");
+            assertStreams(new File(tempDir, "dir/Main.class"),
+                    "jar:" + jarURL + "!/dir/Main.class");
+            assertStreams(new File(tempDir, "dir/dir 2/a.txt"), 
+                    "jar:" + jarURL + "!/dir/dir 2/a.txt");
+            assertStreams(new File(tempDir, "dir/dir 2/b.txt"), 
+                    "jar:" + jarURL + "!/dir/dir 2/b.txt");
+                        
+            Assert.assertTrue(new File(tempDir, "dir/dir.3").exists());
+            
+            // Create a second jar from the exploded directory
+            File copiedFile = new File(jarFile.getAbsolutePath() + ".copy");            
+            Main.jar(copiedFile, tempDir, manifest);
+            URL copyURL = copiedFile.toURI().toURL();
+            
+            assertStreams("jar:" + copyURL + "!/META-INF/MANIFEST.MF", 
+                    "jar:" + jarURL + "!/META-INF/MANIFEST.MF");
+            
+            assertStreams("jar:" + copyURL + "!/A text File with no content",
+                    "jar:" + jarURL + "!/A text File with no content");
+            assertStreams("jar:" + copyURL + "!/dir/Main.class",
+                    "jar:" + jarURL + "!/dir/Main.class");
+            assertStreams("jar:" + copyURL + "!/dir/dir 2/a.txt", 
+                    "jar:" + jarURL + "!/dir/dir 2/a.txt");
+            assertStreams("jar:" + copyURL + "!/dir/dir 2/b.txt", 
+                    "jar:" + jarURL + "!/dir/dir 2/b.txt");
+        } finally {
+            Main.delTree(tempDir);
+        }
+    }
+
+    @Test
+    public void testDelTree() throws IOException {
+        URL jarURL = getClass().getResource("/testjar.jar");
+        File jarFile = new File(jarURL.getFile());
+        File tempDir = new File(System.getProperty("java.io.tmpdir") + "/testjar_" + System.currentTimeMillis());
+        
+        assertFalse("Precondition", tempDir.exists());
+        Main.unJar(jarFile, tempDir);
+        assertTrue(tempDir.exists());
+        
+        Main.delTree(tempDir);                
+        assertFalse(tempDir.exists());
+    }
+    
+    private void assertStreams(String url1, String url2) throws Exception {
+        InputStream is1 = new URL(url1).openStream();
+        InputStream is2 = new URL(url2).openStream();
+        assertStreams(is1, is2);
+    }
+    
+    private void assertStreams(File file, String url) throws Exception {
+        InputStream is1 = new FileInputStream(file);
+        InputStream is2 = new URL(url).openStream();
+        assertStreams(is1, is2);
+    }
+
+    private void assertStreams(InputStream is1, InputStream is2)
+            throws IOException, ArrayComparisonFailure {
+        try {
+            byte[] bytes1 = Streams.suck(is1);
+            byte[] bytes2 = Streams.suck(is2);
+            Assert.assertArrayEquals("Files not equal", bytes1, bytes2);
+        } finally {
+            is1.close();
+            is2.close();
+        }
+    }
+}
+
+

Added: aries/trunk/spi-fly/spi-fly-static-tool/src/test/resources/testjar.jar
URL: http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool/src/test/resources/testjar.jar?rev=1084603&view=auto
==============================================================================
Binary file - no diff available.

Propchange: aries/trunk/spi-fly/spi-fly-static-tool/src/test/resources/testjar.jar
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream