You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mr...@apache.org on 2007/07/29 15:45:03 UTC

svn commit: r560720 - in /struts/sandbox/trunk/struts2-osgi-plugin: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/struts2/ src/main/java/org/apache/struts2/osgi/ src/main/resources/

Author: mrdon
Date: Sun Jul 29 06:45:02 2007
New Revision: 560720

URL: http://svn.apache.org/viewvc?view=rev&rev=560720
Log:
initial import

Added:
    struts/sandbox/trunk/struts2-osgi-plugin/
    struts/sandbox/trunk/struts2-osgi-plugin/pom.xml
    struts/sandbox/trunk/struts2-osgi-plugin/src/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleResourceLoader.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/
    struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/struts-plugin.xml

Added: struts/sandbox/trunk/struts2-osgi-plugin/pom.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/pom.xml?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/pom.xml (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/pom.xml Sun Jul 29 06:45:02 2007
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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.struts</groupId>
+        <artifactId>struts2-plugins</artifactId>
+        <version>2.0.9</version>
+    </parent>
+    <groupId>org.apache.struts</groupId>
+    <artifactId>struts2-osgi-plugin</artifactId>
+    <packaging>jar</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <name>Struts 2 OSGI Plugin</name>
+    
+    <scm>
+       <connection>scm:svn:http://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-osgi-plugin/</connection>
+       <developerConnection>scm:svn:https://svn.apache.org/repos/asf/struts/sandbox/trunk/struts2-osgi-plugin/</developerConnection>
+       <url>http://svn.apache.org/viewcvs.cgi/struts/sandbox/trunk/struts2-osgi-plugin/</url>
+    </scm>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.main</artifactId>
+            <version>0.9.0-incubator-SNAPSHOT</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.apache.struts</groupId>
+            <artifactId>struts2-core</artifactId>
+            <version>2.0.9</version>
+        </dependency>
+ 
+         <dependency>
+            <groupId>velocity-tools</groupId>
+            <artifactId>velocity-tools</artifactId>
+            <version>1.1</version>
+        </dependency>
+
+       
+        <dependency>
+            <groupId>velocity</groupId>
+            <artifactId>velocity</artifactId>
+            <version>1.4</version>
+        </dependency>
+        <dependency>
+            <groupId>velocity</groupId>
+            <artifactId>velocity-dep</artifactId>
+            <version>1.4</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+            <version>3.8.1</version>
+        </dependency>
+   </dependencies>
+</project>

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,17 @@
+package org.apache.struts2.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+public interface BundleAccessor {
+    
+    void setBundles(Map<String,Bundle> bundles);
+    Class loadClass(String name) throws ClassNotFoundException;
+    InputStream loadResourceAsStream(String name) throws IOException;
+    URL loadResource(String name);
+
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,84 @@
+package org.apache.struts2.osgi;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.config.impl.DefaultConfiguration;
+import com.opensymphony.xwork2.config.providers.XmlConfigurationProvider;
+import com.opensymphony.xwork2.util.location.Location;
+
+public class BundlePackageLoader implements PackageLoader {
+
+    public List<PackageConfig> loadPackages(Bundle bundle, ObjectFactory objectFactory, Map<String,PackageConfig> pkgConfigs) throws ConfigurationException {
+        BundleConfigurationProvider prov = new BundleConfigurationProvider("struts.xml", bundle);
+        Configuration config = new DefaultConfiguration("struts.xml");
+        for (PackageConfig pkg : pkgConfigs.values()) {
+            config.addPackageConfig(pkg.getName(), pkg);
+        }
+        prov.setObjectFactory(objectFactory);
+        prov.init(config);
+        prov.loadPackages();
+        return new ArrayList<PackageConfig>(config.getPackageConfigs().values());
+    }
+    
+    static class BundleConfigurationProvider extends XmlConfigurationProvider {
+        private Bundle bundle;
+
+        public BundleConfigurationProvider(String filename, Bundle bundle) { 
+            super(filename, true);
+            this.bundle = bundle;
+        }
+        public BundleConfigurationProvider(String filename) { super(filename); }
+
+        @Override
+        protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException {
+            Enumeration<URL> e = bundle.getResources("struts.xml");
+            Iterator<URL> iter = new EnumeratorIterator<URL>(e);
+            return iter;
+        }
+        @Override
+        protected boolean verifyAction(String className, String name,
+                Location loc) {
+            try {
+                Class cls = bundle.loadClass(className);
+                return cls != null;
+            } catch (ClassNotFoundException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+                return false;
+            }
+        }
+        
+        
+    }
+    
+    static class EnumeratorIterator<E> implements Iterator<E> {
+        Enumeration<E> e = null;
+        public EnumeratorIterator(Enumeration<E> e) {
+            this.e = e;
+        }
+        public boolean hasNext() {
+          return e.hasMoreElements();
+        }
+
+        public E next() {
+          return e.nextElement();
+        }
+
+        public void remove() {
+          throw new UnsupportedOperationException();
+        }
+      }
+
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleResourceLoader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleResourceLoader.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleResourceLoader.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/BundleResourceLoader.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,30 @@
+package org.apache.struts2.osgi;
+
+import java.io.InputStream;
+
+import org.apache.struts2.util.ClassLoaderUtils;
+import org.apache.struts2.views.velocity.StrutsResourceLoader;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
+
+import com.opensymphony.xwork2.inject.Inject;
+
+public class BundleResourceLoader extends ClasspathResourceLoader {
+
+    public synchronized InputStream getResourceStream(String name)
+            throws ResourceNotFoundException {
+        if ((name == null) || (name.length() == 0)) {
+            throw new ResourceNotFoundException("No template name provided");
+        }
+
+        if (name.startsWith("/")) {
+            name = name.substring(1);
+        }
+
+        try {
+            return DefaultBundleAccessor.getInstance().loadResourceAsStream(name);
+        } catch (Exception e) {
+            throw new ResourceNotFoundException(e.getMessage());
+        }
+    }
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,93 @@
+package org.apache.struts2.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+
+public class DefaultBundleAccessor implements BundleAccessor {
+
+    private static DefaultBundleAccessor self;
+    private static final Log LOG = LogFactory.getLog(DefaultBundleAccessor.class);
+    
+    private Map<String, Bundle> bundles = new HashMap<String, Bundle>();
+    private Map<String,String> classToBundle = new HashMap<String,String>();
+    
+    public DefaultBundleAccessor() {
+        self = this;
+    }
+    
+    // todo: this is crap
+    public static DefaultBundleAccessor getInstance() {
+        return self;
+    }
+    
+    public void setBundles(Map<String,Bundle> bundles) {
+        this.bundles = bundles;
+        classToBundle.clear();
+    }
+    
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        Class cls = null;
+        if (classToBundle.containsKey(name)) {
+            bundles.get(classToBundle.get(name)).loadClass(name);
+        } else {
+            for (Entry<String,Bundle> entry : bundles.entrySet()) {
+                try {
+                    cls = entry.getValue().loadClass(name);
+                    if (cls != null) {
+                        classToBundle.put(name, entry.getKey());
+                    }
+                } catch (ClassNotFoundException ex) {
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("class not found in bundle "+entry.getValue().getSymbolicName(), ex);
+                    }
+                }
+            }
+        }
+        
+        if (cls == null) {
+            throw new ClassNotFoundException("Unable to find class "+name+" in bundles");
+        }
+        return cls;
+    }
+    
+    public List<URL> loadResources(String name) throws IOException {
+        List<URL> resources = new ArrayList<URL>();
+        for (Entry<String,Bundle> entry : bundles.entrySet()) {
+            Enumeration e = entry.getValue().getResources(name);
+            while (e.hasMoreElements()) {
+                resources.add((URL) e.nextElement());
+            }
+        }
+        return resources;
+    }
+
+    public URL loadResource(String name) {
+        URL url = null;
+        for (Entry<String,Bundle> entry : bundles.entrySet()) {
+            url = entry.getValue().getResource(name);
+            if (url != null)
+                break;
+        }
+        return url;
+    }
+
+    public InputStream loadResourceAsStream(String name) throws IOException {
+        URL url = loadResource(name);
+        if (url != null) {
+            return url.openStream();
+        }
+        return null;
+    }
+    
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,40 @@
+package org.apache.struts2.osgi;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
+
+public class DelegatingObjectFactory extends ObjectFactory {
+    private ObjectFactory delegateObjectFactory;
+    private BundleAccessor bundleResourceLoader;
+    
+    @Inject
+    public DelegatingObjectFactory(@Inject Container container,
+                                   @Inject("struts.objectFactory.delegate") String delegate) {
+        
+        if (delegate == null) {
+            delegate = "struts";
+        }
+        delegateObjectFactory = container.getInstance(ObjectFactory.class, delegate);
+    }
+    
+    @Inject
+    public void setBundleResourceLoader(BundleAccessor rl) {
+        this.bundleResourceLoader = rl;
+    }
+    
+    
+    @Override
+    public Class getClassInstance(String className) throws ClassNotFoundException {
+        try
+        {
+            return delegateObjectFactory.getClassInstance(className);
+        }
+        catch (ClassNotFoundException cnfe)
+        {
+            return bundleResourceLoader.loadClass(className);
+        }
+    }
+    
+    
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,336 @@
+package org.apache.struts2.osgi;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import javax.servlet.ServletContext;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.cache.BundleCache;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.struts2.views.velocity.VelocityManager;
+import org.apache.velocity.app.Velocity;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ResolverUtil.Test;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+
+public class OsgiConfigurationProvider implements ConfigurationProvider {
+    
+    private static final Log log = LogFactory.getLog(OsgiConfigurationProvider.class);
+
+    private Felix felix;
+    private Map<String,Bundle> bundles = Collections.synchronizedMap(new HashMap<String,Bundle>());
+    private Configuration configuration;
+    private BundleContext bundleContext;
+    private ServletContext servletContext;
+    private boolean bundlesChanged = false;
+
+    private ObjectFactory objectFactory;
+
+    @Inject
+    public void setBundleAccessor(BundleAccessor acc) {
+        acc.setBundles(bundles);
+    }
+    
+    @Inject
+    public void setServletContext(ServletContext ctx) {
+        this.servletContext = ctx;
+    }
+    
+    @Inject
+    public void setObjectFactory(ObjectFactory factory) {
+        this.objectFactory = factory;
+    }
+    
+    @Inject
+    public void setVelocityManager(VelocityManager vm) {
+        Properties props = new Properties();
+        props.setProperty("osgi.resource.loader.description","OSGI bundle loader");
+        props.setProperty("osgi.resource.loader.class", BundleResourceLoader.class.getName());
+        props.setProperty(Velocity.RESOURCE_LOADER, "strutsclass,osgi");
+        vm.setVelocityProperties(props);
+    }
+    
+    public void destroy() {
+        try {
+            felix.stop();
+        } catch (BundleException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        bundles = null; 
+    }
+    
+    public void init(Configuration configuration) throws ConfigurationException {
+        loadOsgi();
+        this.configuration = configuration;
+    }
+
+    public synchronized void loadPackages() throws ConfigurationException {
+        ServiceReference[] refs;
+        try {
+            refs = bundleContext.getServiceReferences(PackageLoader.class.getName(), null);
+        } catch (InvalidSyntaxException e) {
+            throw new ConfigurationException(e);
+        }
+        Set bundleNames = new HashSet();
+        if (refs != null) {
+            for (ServiceReference ref : refs) {
+                if (!bundleNames.contains(ref.getBundle().getSymbolicName())) {
+                    bundleNames.add(ref.getBundle().getSymbolicName());
+                    log.info("Loading packages from bundle "+ref.getBundle().getSymbolicName());
+                    PackageLoader loader = (PackageLoader) bundleContext.getService(ref);
+                    for (PackageConfig pkg : loader.loadPackages(ref.getBundle(), objectFactory, configuration.getPackageConfigs())) {
+                        configuration.addPackageConfig(pkg.getName(), pkg);
+                    }
+                }
+            }
+        }
+        bundlesChanged = false;
+    }
+
+    public synchronized boolean needsReload() {
+        return bundlesChanged;
+    }
+
+    public void register(ContainerBuilder builder, LocatableProperties props)
+            throws ConfigurationException {
+    }
+    
+    protected void loadOsgi() {
+        Map configMap = new StringMap(false);
+        configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES,
+            "org.osgi.framework; version=1.4.0," +
+            "org.osgi.service.packageadmin; version=1.2.0," +
+            "org.osgi.service.startlevel; version=1.0.0," +
+            "org.osgi.service.url; version=1.0.0");
+
+        Set<String> bundlePaths = new HashSet<String>(findInPackage("bundles"));
+        log.info("Loading Struts bundles "+bundlePaths);
+        
+        StringBuilder sb = new StringBuilder();
+        for (String path : bundlePaths) {
+            sb.append(path).append(" ");
+        }
+        
+        configMap.put(FelixConstants.AUTO_START_PROP + ".1",
+            sb.toString());
+        configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, "/tmp/foo");//System.getProperty("tmp.dir"));
+        configMap.put(BundleCache.CACHE_DIR_PROP, "jim");
+        configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true");
+        configMap.put(FelixConstants.SERVICE_URLHANDLERS_PROP, "false");
+        configMap.put("org.osgi.framework.bootdelegation", "org.apache.*");
+        configMap.put("osgi.parentClassloader", "app");
+        configMap.put("felix.log.level", "4");
+        configMap.put(FelixConstants.BUNDLE_CLASSPATH, ".");
+
+        try {
+            List list = new ArrayList();
+            list.add(new BundleRegistration());
+            // Now create an instance of the framework.
+            felix = new Felix(configMap, list);
+            felix.start();
+        }
+        catch (Exception ex) {
+            throw new ConfigurationException("Couldn't start Felix (OSGi)", ex);
+        }
+        
+        // Wait for all bundles to load
+        while (bundles.size() < bundlePaths.size()) {
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        
+        
+    }
+    
+    class BundleRegistration implements BundleActivator, BundleListener {
+
+        public void start(BundleContext context) throws Exception {
+            context.addBundleListener(this);
+            bundleContext = context;
+        }
+
+        public void stop(BundleContext arg0) throws Exception {
+            // TODO Auto-generated method stub
+            
+        }
+
+        public void bundleChanged(BundleEvent evt) {
+            if (evt.getType() == evt.INSTALLED) {
+                log.debug("Installed bundle "+evt.getBundle().getSymbolicName());
+                bundles.put(evt.getBundle().getLocation(), evt.getBundle());
+                bundlesChanged = true;
+            }
+            
+            // Copy out all view files
+            /*if (evt.getType() == evt.STARTED) {
+                Enumeration e = evt.getBundle().findEntries("/view/", null, true);
+                while (e != null && e.hasMoreElements()) {
+                    URL url = (URL) e.nextElement();
+                    System.out.println("found view url: "+url);
+                }
+            }
+            */
+        }
+
+    }
+    
+    /**
+     * Scans for classes starting at the package provided and descending into subpackages.
+     * Each class is offered up to the Test as it is discovered, and if the Test returns
+     * true the class is retained.  Accumulated classes can be fetched by calling
+     * {@link #getClasses()}.
+     *
+     * @param test an instance of {@link Test} that will be used to filter classes
+     * @param packageName the name of the package from which to start scanning for
+     *        classes, e.g. {@code net.sourceforge.stripes}
+     */
+    public List<String> findInPackage(String packageName) {
+        packageName = packageName.replace('.', '/');
+        Enumeration<URL> urls;
+        List<String> paths = new ArrayList<String>();
+
+        try {
+            urls = Thread.currentThread().getContextClassLoader().getResources(packageName);
+        }
+        catch (IOException ioe) {
+            log.warn("Could not read package: " + packageName, ioe);
+            return paths;
+        }
+
+        while (urls.hasMoreElements()) {
+            try {
+                String urlPath = urls.nextElement().getFile();
+                urlPath = URLDecoder.decode(urlPath, "UTF-8");
+
+                // If it's a file in a directory, trim the stupid file: spec
+                if ( urlPath.startsWith("file:") ) {
+                    urlPath = urlPath.substring(5);
+                }
+
+                // Else it's in a JAR, grab the path to the jar
+                if (urlPath.indexOf('!') > 0) {
+                    urlPath = urlPath.substring(0, urlPath.indexOf('!'));
+                }
+
+                //log.info("Scanning for classes in [" + urlPath + "] matching criteria: " + test);
+                File file = new File(urlPath);
+                if ( file.isDirectory() ) {
+                    loadImplementationsInDirectory(paths, packageName, file);
+                }
+                else {
+                    loadImplementationsInJar(paths, packageName, file);
+                }
+            }
+            catch (IOException ioe) {
+                log.warn("could not read entries", ioe);
+            }
+        }
+        return paths;
+    }
+
+
+    /**
+     * Finds matches in a physical directory on a filesystem.  Examines all
+     * files within a directory - if the File object is not a directory, and ends with <i>.class</i>
+     * the file is loaded and tested to see if it is acceptable according to the Test.  Operates
+     * recursively to find classes within a folder structure matching the package structure.
+     *
+     * @param test a Test used to filter the classes that are discovered
+     * @param parent the package name up to this directory in the package hierarchy.  E.g. if
+     *        /classes is in the classpath and we wish to examine files in /classes/org/apache then
+     *        the values of <i>parent</i> would be <i>org/apache</i>
+     * @param location a File object representing a directory
+     */
+    private void loadImplementationsInDirectory(List<String> paths, String parent, File location) {
+        File[] files = location.listFiles();
+        StringBuilder builder = null;
+
+        for (File file : files) {
+            builder = new StringBuilder(100);
+            builder.append(parent).append("/").append(file.getName());
+            String packageOrClass = ( parent == null ? file.getName() : builder.toString() );
+
+            if (file.isDirectory()) {
+                loadImplementationsInDirectory(paths, packageOrClass, file);
+            }
+            else if (file.getName().endsWith(".jar")) {
+                try {
+                    paths.add(file.toURL().toString());
+                } catch (MalformedURLException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * Finds matching classes within a jar files that contains a folder structure
+     * matching the package structure.  If the File is not a JarFile or does not exist a warning
+     * will be logged, but no error will be raised.
+     *
+     * @param test a Test used to filter the classes that are discovered
+     * @param parent the parent package under which classes must be in order to be considered
+     * @param jarfile the jar file to be examined for classes
+     */
+    private void loadImplementationsInJar(List<String> paths, String parent, File jarfile) {
+
+        try {
+            JarEntry entry;
+            JarInputStream jarStream = new JarInputStream(new FileInputStream(jarfile));
+
+            while ( (entry = jarStream.getNextJarEntry() ) != null) {
+                String name = entry.getName();
+                if (!entry.isDirectory() && name.startsWith(parent) && name.endsWith(".jar")) {
+                    paths.add(jarfile.toURL()+"!"+entry.getName());
+                }
+            }
+        }
+        catch (IOException ioe) {
+            log.error("Could not search jar file '" + jarfile + "' due to an IOException", ioe);
+        }
+    }
+
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,14 @@
+package org.apache.struts2.osgi;
+
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+
+public interface PackageLoader {
+    List<PackageConfig> loadPackages(Bundle bundle, ObjectFactory objectFactory, Map<String,PackageConfig> map) throws ConfigurationException;
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java Sun Jul 29 06:45:02 2007
@@ -0,0 +1,19 @@
+package org.apache.struts2.osgi;
+
+import java.util.Properties;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+public class StrutsActivator implements BundleActivator {
+
+    public void start(final BundleContext ctx) throws Exception {
+        ctx.registerService(PackageLoader.class.getName(), new BundlePackageLoader(), new Properties());
+        ctx.getBundle().loadClass("org.apache.struts2.osgi.BundleAccessor");
+        ctx.getBundle().loadClass("org.twdata.osgitest.foo.FooAction");
+    }
+
+    public void stop(BundleContext ctx) throws Exception {
+    }
+
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/struts-plugin.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/struts-plugin.xml?view=auto&rev=560720
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/struts-plugin.xml (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/src/main/resources/struts-plugin.xml Sun Jul 29 06:45:02 2007
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
+    "http://struts.apache.org/dtds/struts-2.0.dtd">
+    
+<struts>
+    <bean type="org.apache.struts2.osgi.BundleAccessor" class="org.apache.struts2.osgi.DefaultBundleAccessor" />
+    <bean type="org.apache.struts2.osgi.PackageLoader" class="org.apache.struts2.osgi.BundlePackageLoader" />
+    <bean name="osgi" type="com.opensymphony.xwork2.ObjectFactory" class="org.apache.struts2.osgi.DelegatingObjectFactory" />
+    
+    <constant name="struts.objectFactory" value="osgi" />
+    <constant name="struts.objectFactory.delegate" value="struts" />
+    
+</struts>