You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/04/12 07:26:27 UTC

svn commit: r764282 - in /struts/sandbox/trunk/struts2-osgi-plugin: demo-bundle/ demo-bundle/src/main/java/actions/osgi/ demo-bundle/src/main/resources/ demo-bundle/src/main/resources/content/osgi/ plugin/ plugin/src/main/java/org/apache/struts2/osgi/ ...

Author: musachy
Date: Sun Apr 12 05:26:26 2009
New Revision: 764282

URL: http://svn.apache.org/viewvc?rev=764282&view=rev
Log:
Refactor Felix start up into a listener (now there is full support for Spring IoC). Remove activator

Added:
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsOsgiListener.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/beanRefContext.xml
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/OsgiInterceptorTest.java
Removed:
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsActivator.java
Modified:
    struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/pom.xml
    struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/java/actions/osgi/HelloWorldAction.java
    struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.ftl
    struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.vm
    struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/struts.xml
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/pom.xml
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/FelixOsgiHost.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiHost.java
    struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/struts-plugin.xml

Modified: struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/pom.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/pom.xml?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/pom.xml (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/pom.xml Sun Apr 12 05:26:26 2009
@@ -39,6 +39,12 @@
             <version>2.1.7-SNAPSHOT</version>
         </dependency>
 
+         <dependency>
+            <groupId>org.apache.struts</groupId>
+            <artifactId>struts2-osgi-plugin</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.struts</groupId>
             <artifactId>struts2-spring-plugin</artifactId>
@@ -56,15 +62,9 @@
                 <configuration>
                     <instructions>
                         <manifestLocation>META-INF</manifestLocation>
-                        <Import-Package>
-                            *,com.opensymphony.xwork2
-                        </Import-Package>
-                        <Bundle-Activator>
-                            org.apache.struts2.osgi.StrutsActivator
-                        </Bundle-Activator>
-                        <Spring-Context>
-                            *;create-asynchronously:=false
-                        </Spring-Context>
+                        <Import-Package>*,com.opensymphony.xwork2</Import-Package>
+                        <Spring-Context>*;create-asynchronously:=false</Spring-Context>
+                        <Struts2-Enabled>true</Struts2-Enabled>
                     </instructions>
                 </configuration>
             </plugin>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/java/actions/osgi/HelloWorldAction.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/java/actions/osgi/HelloWorldAction.java?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/java/actions/osgi/HelloWorldAction.java (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/java/actions/osgi/HelloWorldAction.java Sun Apr 12 05:26:26 2009
@@ -1,13 +1,19 @@
 package actions.osgi;
 
 import com.opensymphony.xwork2.ActionSupport;
-import org.apache.struts2.convention.annotation.ParentPackage;
-import org.apache.struts2.convention.annotation.ResultPath;
 import org.apache.struts2.convention.annotation.Action;
+import org.apache.struts2.convention.annotation.ResultPath;
+import org.apache.struts2.osgi.interceptor.BundleContextAware;
+import org.apache.struts2.osgi.interceptor.ServiceAware;
+import org.osgi.framework.BundleContext;
+import org.springframework.context.ApplicationContext;
+
+import java.util.List;
 
 @ResultPath("/content")
-public class HelloWorldAction extends ActionSupport {
+public class HelloWorldAction extends ActionSupport implements BundleContextAware, ServiceAware<ApplicationContext> {
     private Message message;
+    private BundleContext bundleContext;
 
     @Action("hello-convention")
     public String execute() {
@@ -32,4 +38,12 @@
         sb.append("}");
         return sb.toString();
     }
+
+    public void setBundleContext(BundleContext context) {
+        this.bundleContext = context;
+    }
+
+    public void setServices(List<ApplicationContext> service) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
 }
\ No newline at end of file

Modified: struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.ftl
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.ftl?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.ftl (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.ftl Sun Apr 12 05:26:26 2009
@@ -3,7 +3,7 @@
         <title>Action mapped by the XML configurationn</title>
     </head>
     <body>
-        This is an action mapped by XML configuration, using a FreeMarker result.
+        This is an action mapped by XML configuration, using a <b>FreeMarker</b> result.
         <br />
         Message from Action: ${message.text}
     </body>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.vm
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.vm?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.vm (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/content/osgi/hello.vm Sun Apr 12 05:26:26 2009
@@ -3,8 +3,7 @@
         <title>Action mapped by the XML configurationn</title>
     </head>
     <body>
-        This is an action mapped by XML configuration, using a Velocity result.
-        ->$top
+        This is an action mapped by XML configuration, using a <b>Velocity</b> result.
         <br />
         Message from Action: $message.text
     </body>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/struts.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/struts.xml?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/struts.xml (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/demo-bundle/src/main/resources/struts.xml Sun Apr 12 05:26:26 2009
@@ -4,7 +4,7 @@
     "http://struts.apache.org/dtds/struts-2.0.dtd">
 
 <struts>
-    <package name="bundle-demo" namespace="/osgi" extends="struts-default">
+    <package name="bundle-demo" namespace="/osgi" extends="osgi-default">
         <default-action-ref name="home" />
         <action name="hello-velocity" class="helloWorldAction">
             <result type="velocity">/content/osgi/hello.vm</result>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/pom.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/pom.xml?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/pom.xml (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/pom.xml Sun Apr 12 05:26:26 2009
@@ -84,5 +84,12 @@
             <scope>test</scope>
             <version>3.8.1</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+            <version>2.4</version>
+        </dependency>
     </dependencies>
 </project>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/FelixOsgiHost.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/FelixOsgiHost.java?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/FelixOsgiHost.java (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/FelixOsgiHost.java Sun Apr 12 05:26:26 2009
@@ -38,6 +38,9 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.Constants;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.BundleEvent;
 import org.osgi.util.tracker.ServiceTracker;
 
 import javax.servlet.ServletContext;
@@ -63,17 +66,13 @@
  * Apache felix implementation of an OsgiHost
  * See http://felix.apache.org/site/apache-felix-framework-launching-and-embedding.html
  */
-public class FelixOsgiHost implements OsgiHost {
+public class FelixOsgiHost implements OsgiHost, BundleListener {
     private static final Logger LOG = LoggerFactory.getLogger(FelixOsgiHost.class);
 
     private Felix felix;
     private Map<String, Bundle> bundles = Collections.synchronizedMap(new HashMap<String, Bundle>());
-    private List<? extends BundleActivator> extraBundleActivators;
-    private boolean cleanBundleCache;
     private static Pattern versionPattern = Pattern.compile("([\\d])+[\\.-]");
-    private String startRunLevel;
     private ServletContext servletContext;
-    private String logLevel;
 
     protected void startFelix() {
         //load properties from felix embedded file
@@ -96,7 +95,8 @@
         if (LOG.isDebugEnabled())
             LOG.debug("Storing bundle at [#0]", storageDir);
 
-        if (cleanBundleCache) {
+        String cleanBundleCache = getServletContextParam("struts.osgi.cleanBundleCache", "true");
+        if ("true".equalsIgnoreCase(cleanBundleCache)) {
             if (LOG.isDebugEnabled())
                 LOG.debug("Clearing bundle cache");
             configProps.put(FelixConstants.FRAMEWORK_STORAGE_CLEAN, FelixConstants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT);
@@ -104,15 +104,24 @@
 
         //other properties
         configProps.put(FelixConstants.SERVICE_URLHANDLERS_PROP, "false");
-        configProps.put(FelixConstants.LOG_LEVEL_PROP, logLevel);
+        configProps.put(FelixConstants.LOG_LEVEL_PROP, getServletContextParam("struts.osgi.logLevel", "1"));
         configProps.put(FelixConstants.BUNDLE_CLASSPATH, ".");
-        configProps.put(FelixConstants.FRAMEWORK_BEGINNING_STARTLEVEL, startRunLevel);
+        configProps.put(FelixConstants.FRAMEWORK_BEGINNING_STARTLEVEL, getServletContextParam("struts.osgi.runLevel", "3"));
 
         try {
             List<BundleActivator> list = new ArrayList<BundleActivator>();
-            if (extraBundleActivators != null)
-                list.addAll(extraBundleActivators);
             list.add(new AutoActivator(configProps));
+
+            //this activator just hooks this class as a BundleListener
+            list.add(new BundleActivator() {
+                public void start(BundleContext bundleContext) throws Exception {
+                    bundleContext.addBundleListener(FelixOsgiHost.this);
+                }
+
+                public void stop(BundleContext bundleContext) throws Exception {
+                }
+            });
+
             configProps.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list);
 
             felix = new Felix(configProps);
@@ -121,19 +130,23 @@
                 LOG.trace("Apache Felix is running");
         }
         catch (Exception ex) {
-            throw new ConfigurationException("Couldn't start Felix (OSGi)", ex);
-        }
-
-        // Wait for all bundles to load
-        while (bundles.size() < bundlePaths) {
-            try {
-                Thread.sleep(500);
-            } catch (InterruptedException e) {
-                LOG.error("An error occured while waiting for bundle activation", e);
-            }
+            throw new ConfigurationException("Couldn't start Apache Felix", ex);
         }
 
         addSpringOSGiSupport();
+
+        //add the bundle context to the ServletContext
+        servletContext.setAttribute(OSGI_BUNDLE_CONTEXT, felix.getBundleContext());
+    }
+
+    /**
+     * Gets a param from the ServletContext, returning the default value if the param is not set 
+     * @param paramName the name of the param to get from the ServletContext
+     * @param defaultValue value to return if the param is not set
+     * @return
+     */
+    private String getServletContextParam(String paramName, String defaultValue) {
+        return StringUtils.defaultString(this.servletContext.getInitParameter(paramName), defaultValue);
     }
 
     protected int addAutoStartBundles(Properties configProps) {
@@ -329,19 +342,12 @@
         }
     }
 
-    /**
-     * Bundle activators that will be added to the container
-     */
-    public void setExtraBundleActivators(List<? extends BundleActivator> extraBundleActivators) {
-        this.extraBundleActivators = extraBundleActivators;
-    }
-
     public Map<String, Bundle> getBundles() {
         return Collections.unmodifiableMap(bundles);
     }
 
-    public void addBundle(Bundle bundle) {
-        bundles.put(bundle.getSymbolicName(), bundle);
+    public BundleContext getBundleContext() {
+        return felix.getBundleContext();
     }
 
     public void destroy() throws Exception {
@@ -352,28 +358,18 @@
         }
     }
 
-    @Override
-    public void init() throws Exception {
-        startFelix();
-    }
-
-    @Inject("struts.osgi.clearBundleCache")
-    public void setCleanBundleCache(String cleanBundleCache) {
-        this.cleanBundleCache = "true".equalsIgnoreCase(cleanBundleCache);
-    }
-
-    @Inject("struts.osgi.startRunLevel")
-    public void setStartRunLevel(String startRunLevel) {
-        this.startRunLevel = startRunLevel;
-    }
-
-    @Inject
-    public void setServletContext(ServletContext servletContext) {
+    public void init(ServletContext servletContext) throws Exception {
         this.servletContext = servletContext;
+        startFelix();
     }
 
-    @Inject("struts.osgi.logLevel")
-    public void setLogLevel(String logLevel) {
-        this.logLevel = logLevel;
+    /**
+     * Listen to BundleEvent(s) and build a bundles list
+     */
+    public void bundleChanged(BundleEvent evt) {
+        Bundle bundle = evt.getBundle();
+        if (evt.getType() == BundleEvent.STARTED && bundle.getSymbolicName() != null) {
+            this.bundles.put(bundle.getSymbolicName(), bundle);            
+        }
     }
 }

Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiConfigurationProvider.java Sun Apr 12 05:26:26 2009
@@ -21,87 +21,58 @@
 
 package org.apache.struts2.osgi;
 
-import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.config.Configuration;
 import com.opensymphony.xwork2.config.ConfigurationException;
 import com.opensymphony.xwork2.config.PackageProvider;
 import com.opensymphony.xwork2.config.entities.PackageConfig;
-import com.opensymphony.xwork2.inject.Inject;
 import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
 import com.opensymphony.xwork2.util.logging.Logger;
 import com.opensymphony.xwork2.util.logging.LoggerFactory;
-import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
 import org.apache.struts2.osgi.loaders.VelocityBundleResourceLoader;
 import org.apache.struts2.views.velocity.VelocityManager;
 import org.apache.velocity.app.Velocity;
-import org.apache.commons.lang.xwork.StringUtils;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.BundleListener;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 
-import java.util.Arrays;
+import javax.servlet.ServletContext;
+import java.util.ArrayList;
 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.List;
-import java.util.ArrayList;
 
 /**
  * Struts package provider that starts the OSGi container and deelgates package loading
  */
 public class OsgiConfigurationProvider implements PackageProvider {
 
+    private static final String STRUTS_ENABLED = "Struts2-Enabled";
     private static final Logger LOG = LoggerFactory.getLogger(OsgiConfigurationProvider.class);
 
     private Configuration configuration;
     private ObjectFactory objectFactory;
-    private OsgiHost osgiHost;
 
+    private OsgiHost osgiHost;
     private BundleContext bundleContext;
     private BundleAccessor bundleAccessor;
     private boolean bundlesChanged = false;
-
-    public void destroy() {
-        try {
-            if (LOG.isTraceEnabled())
-                LOG.trace("Stopping OSGi container");
-            osgiHost.destroy();
-        } catch (Exception e) {
-            LOG.error("Failed to stop OSGi container", e);
-        }
-    }
+    private ServletContext servletContext;
 
     public void init(Configuration configuration) throws ConfigurationException {
-        if (LOG.isTraceEnabled())
-            LOG.trace("Starting OSGi container");
-        try {
-            osgiHost.setExtraBundleActivators(Arrays.asList(new BundleRegistrationListener()));
-            osgiHost.init();
-            bundleAccessor.setBundles(osgiHost.getBundles());
-        } catch (Exception e) {
-            if (LOG.isErrorEnabled())
-                LOG.error("Failed to start the OSGi container", e);
-            throw new ConfigurationException(e);
-        }
+        osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST);
+        bundleContext = osgiHost.getBundleContext();
+        bundleAccessor.setBundles(osgiHost.getBundles());
+        bundleAccessor.setBundleContext(bundleContext);
         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);
-        }
-
-
         //init action contect
         ActionContext ctx = ActionContext.getContext();
         if (ctx == null) {
@@ -111,26 +82,20 @@
 
         Map<String, String> packageToBundle = new HashMap<String, String>();
         Set<String> bundleNames = new HashSet<String>();
-        
-        if (refs != null) {
-            for (ServiceReference ref : refs) {
-                String bundleName = ref.getBundle().getSymbolicName();
-                if (!bundleNames.contains(bundleName)) {
-                    bundleNames.add(bundleName);
-
-                    if (LOG.isDebugEnabled())
-                        LOG.debug("Loading packages from bundle [#0]", bundleName);
-
-                    PackageLoader loader = (PackageLoader) bundleContext.getService(ref);
-                    try {
-                        ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, bundleName);
-                        for (PackageConfig pkg : loader.loadPackages(ref.getBundle(), bundleContext, objectFactory, configuration.getPackageConfigs())) {
-                            configuration.addPackageConfig(pkg.getName(), pkg);
-                            packageToBundle.put(pkg.getName(), bundleName);
-                        }
-                    } finally {
-                        ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null);                        
-                    }
+
+        //iterate over the bundles and load packages from them
+        for (Bundle bundle : osgiHost.getBundles().values()) {
+            String bundleName = bundle.getSymbolicName();
+            if (shouldProcessBundle(bundle) && !bundleNames.contains(bundleName)) {
+                bundleNames.add(bundleName);
+
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Loading packages from bundle [#0]", bundleName);
+
+                PackageLoader loader = new BundlePackageLoader();
+                for (PackageConfig pkg : loader.loadPackages(bundle, bundleContext, objectFactory, configuration.getPackageConfigs())) {
+                    configuration.addPackageConfig(pkg.getName(), pkg);
+                    packageToBundle.put(pkg.getName(), bundleName);
                 }
             }
         }
@@ -138,7 +103,7 @@
         //add the loaded packages to the BundleAccessor
         bundleAccessor.setPackageToBundle(packageToBundle);
 
-        //reload container that will load configuration based on bundles (like convention plugin)
+        //reload container, that will load configuration based on bundles (like convention plugin)
         reloadExtraProviders(configuration.getContainer());
 
         bundlesChanged = false;
@@ -151,26 +116,22 @@
         if (conventionPackageProvider != null)
             providers.add(conventionPackageProvider);
 
-        //init action context
-        ActionContext ctx = ActionContext.getContext();
-        if (ctx == null) {
-            ctx = new ActionContext(new HashMap());
-            ActionContext.setContext(ctx);
-        }
-
         //reload all providers by bundle
+        ActionContext ctx = ActionContext.getContext();
         for (Bundle bundle : osgiHost.getBundles().values()) {
-            try {
-                //the Convention plugin will use BundleClassLoaderInterface from the ActionContext to find resources
-                //and load classes
-                ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, new BundleClassLoaderInterface());
-                ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, bundle.getSymbolicName());
-                
-                Object bundleActivator = bundle.getHeaders().get("Bundle-Activator");
-                if (bundleActivator != null && StringUtils.equals(StrutsActivator.class.getName(), bundleActivator.toString())) {                   ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, bundle.getSymbolicName());
+            String bundleName = bundle.getSymbolicName();
+            if (shouldProcessBundle(bundle)) {
+                try {
+                    //the Convention plugin will use BundleClassLoaderInterface from the ActionContext to find resources
+                    //and load classes
+                    ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, new BundleClassLoaderInterface());
+                    ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, bundleName);
+
                     for (PackageProvider provider : providers) {
-                        if (LOG.isDebugEnabled())
-                            LOG.debug("Reloading provider [#0] for bundle [#1]", provider.getClass().getName(), bundle.getSymbolicName());
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Reloading provider [#0] for bundle [#1]", provider.getClass().getName(), bundleName);
+                        }
+
                         //get the existing packages before reloading the provider (se we can figure out what are the new packages)
                         Set<String> packagesBeforeLoading = new HashSet(configuration.getPackageConfigNames());
                         provider.loadPackages();
@@ -182,14 +143,23 @@
                                 bundleAccessor.addPackageFromBundle(bundle, packageName);
                         }
                     }
+                } finally {
+                    ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null);
+                    ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, null);
                 }
-            } finally {
-                ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null);
-                ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, null);
             }
         }
     }
 
+    /**
+     * Checks for "Struts2-Enabled" header in the bundle
+     */
+    protected boolean shouldProcessBundle(Bundle bundle) {
+        String strutsEnabled = (String) bundle.getHeaders().get(STRUTS_ENABLED);
+
+        return "true".equalsIgnoreCase(strutsEnabled);
+    }
+
     public synchronized boolean needsReload() {
         return bundlesChanged;
     }
@@ -218,28 +188,18 @@
         vm.setVelocityProperties(props);
     }
 
-    /**
-     * Listens to bundle events and adds bundles to the bundle list when one is activated
-     */
-    class BundleRegistrationListener implements BundleActivator, BundleListener {
-        public void start(BundleContext context) throws Exception {
-            context.addBundleListener(this);
-            bundleContext = context;
-            bundleAccessor.setBundleContext(bundleContext);
-        }
-
-        public void stop(BundleContext ctx) throws Exception {
-        }
-
-        public void bundleChanged(BundleEvent evt) {
-            if (evt.getType() == BundleEvent.STARTED && evt.getBundle().getSymbolicName() != null) {
-                if (LOG.isDebugEnabled())
-                    LOG.debug("Started bundle [#0]", evt.getBundle().getSymbolicName());
+    @Inject
+    public void setServletContext(ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
 
-                osgiHost.addBundle(evt.getBundle());
-                bundlesChanged = true;
-            }
+    public void destroy() {
+        try {
+            if (LOG.isTraceEnabled())
+                LOG.trace("Stopping OSGi container");
+            osgiHost.destroy();
+        } catch (Exception e) {
+            LOG.error("Failed to stop OSGi container", e);
         }
     }
-
 }

Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiHost.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiHost.java?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiHost.java (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/OsgiHost.java Sun Apr 12 05:26:26 2009
@@ -23,14 +23,21 @@
 
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 
+import javax.servlet.ServletContext;
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Implementations of this class start an OSGi container. They must also add the BundleContext to
+ * the ServletContext under the key  OsgiHost.OSGI_BUNDLE_CONTEXT;
+ */
 public interface OsgiHost {
+    String OSGI_BUNDLE_CONTEXT = "__struts_osgi_bundle_context"; 
+
     void destroy() throws Exception;
-    void init() throws Exception;
-    void setExtraBundleActivators(List<? extends BundleActivator> extraBundleActivators);
+    void init(ServletContext servletContext) throws Exception;
     Map<String, Bundle> getBundles();
-    void addBundle(Bundle bundle);
+    BundleContext getBundleContext();
 }

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsOsgiListener.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsOsgiListener.java?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsOsgiListener.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/StrutsOsgiListener.java Sun Apr 12 05:26:26 2009
@@ -0,0 +1,34 @@
+package org.apache.struts2.osgi;
+
+import org.apache.struts2.StrutsException;
+
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContext;
+
+/**
+ * ServletContextListener that starts Apache Felix
+ */
+public class StrutsOsgiListener implements ServletContextListener {
+    public static final String OSGI_HOST = "__struts_osgi_host";
+    private FelixOsgiHost osgiHost;
+
+    public void contextInitialized(ServletContextEvent sce) {
+        ServletContext servletContext = sce.getServletContext();
+        osgiHost = new FelixOsgiHost();
+        servletContext.setAttribute(OSGI_HOST, osgiHost);
+        try {
+            osgiHost.init(servletContext);
+        } catch (Exception e) {
+            throw new StrutsException("Apache Felix failed to start", e);
+        }
+    }
+
+    public void contextDestroyed(ServletContextEvent sce) {
+        try {
+            osgiHost.destroy();
+        } catch (Exception e) {
+            throw new StrutsException("Apache Felix failed to stop", e);
+        }
+    }
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java Sun Apr 12 05:26:26 2009
@@ -0,0 +1,11 @@
+package org.apache.struts2.osgi.interceptor;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Action implementing this interface will receive an instance of the BundleContext,
+ * the OsgiInterceptor must be applied to the action.
+ */
+public interface BundleContextAware {
+    void setBundleContext(BundleContext bundleContext);
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java Sun Apr 12 05:26:26 2009
@@ -0,0 +1,79 @@
+package org.apache.struts2.osgi.interceptor;
+
+import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
+import com.opensymphony.xwork2.ActionInvocation;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import com.opensymphony.xwork2.inject.Inject;
+
+import javax.servlet.ServletContext;
+
+import org.apache.struts2.osgi.OsgiHost;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+import java.lang.reflect.Type;
+import java.lang.reflect.ParameterizedType;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * If a class implements BundleContextAware, this interceptor will call the setBundleContext(BundleContext)
+ * method on it
+ */
+public class OsgiInterceptor extends AbstractInterceptor {
+    private static final Logger LOG = LoggerFactory.getLogger(OsgiInterceptor.class);
+
+    private BundleContext bundleContext;
+
+    public String intercept(ActionInvocation invocation) throws Exception {
+        if (bundleContext != null) {
+            Object action = invocation.getAction();
+
+            //inject BundleContext
+            if (action instanceof BundleContextAware)
+                ((BundleContextAware)action).setBundleContext(bundleContext);
+
+            //inject service implementations
+            if (action instanceof ServiceAware) {
+                Type[] types = action.getClass().getGenericInterfaces();
+                if (types != null) {
+                    for (Type type : types) {
+                        if (type instanceof ParameterizedType) {
+                            ParameterizedType parameterizedType = (ParameterizedType) type;
+                            if (parameterizedType.getRawType() instanceof Class) {
+                                Class clazz = (Class) parameterizedType.getRawType();
+                                if (ServiceAware.class.equals(clazz)) {
+                                    Class serviceClass = (Class) parameterizedType.getActualTypeArguments()[0];
+                                    ServiceReference[] refs = bundleContext.getAllServiceReferences(serviceClass.getName(), null);
+                                    //get the services
+                                    if (refs != null) {
+                                        List services = new ArrayList(refs.length);
+                                        for (ServiceReference ref : refs) {
+                                            Object service = bundleContext.getService(ref);
+                                            //wow, that's a lot of nested ifs
+                                            if (service != null)
+                                                services.add(service);
+                                        }
+
+                                        if (!services.isEmpty())
+                                            ((ServiceAware)action).setServices(services);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else if (LOG.isWarnEnabled()){
+            LOG.warn("The OSGi interceptor was not able to find the BundleContext in the ServletContext");          
+        }
+
+        return invocation.invoke();
+    }
+
+    @Inject
+    public void setServletContext(ServletContext servletContext) {
+        this.bundleContext = (BundleContext) servletContext.getAttribute(OsgiHost.OSGI_BUNDLE_CONTEXT);
+    }
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java Sun Apr 12 05:26:26 2009
@@ -0,0 +1,7 @@
+package org.apache.struts2.osgi.interceptor;
+
+import java.util.List;
+
+public interface ServiceAware<T> {
+    void setServices(List<T> service);
+}

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/beanRefContext.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/beanRefContext.xml?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/beanRefContext.xml (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/beanRefContext.xml Sun Apr 12 05:26:26 2009
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+<beans>
+    <bean id="parent-context-bean" class="org.springframework.context.support.ClassPathXmlApplicationContext">
+        <constructor-arg>
+            <list>
+                <value>classpath*:applicationContext.xml</value>
+            </list>
+        </constructor-arg>
+    </bean>
+</beans>

Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/struts-plugin.xml
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/struts-plugin.xml?rev=764282&r1=764281&r2=764282&view=diff
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/struts-plugin.xml (original)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/resources/struts-plugin.xml Sun Apr 12 05:26:26 2009
@@ -12,12 +12,6 @@
 
     <constant name="struts.convention.action.includeJars" value="jar:file:.*?/bundles/.*?\.jar(!/)?" />
 
-    <constant name="struts.osgi.clearBundleCache" value="true" />
-    <constant name="struts.osgi.startRunLevel" value="3" />
-
-    <!--1 = error, 2 = warning, 3 = information, and 4 = debug -->
-    <constant name="struts.osgi.logLevel" value="1" />
-
     <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" />
@@ -25,4 +19,17 @@
     <bean name="osgi" type="com.opensymphony.xwork2.config.PackageProvider" class="org.apache.struts2.osgi.OsgiConfigurationProvider" />
     <bean name="felix" type="org.apache.struts2.osgi.OsgiHost" class="org.apache.struts2.osgi.FelixOsgiHost" />
     <bean name="osgi" type="com.opensymphony.xwork2.util.finder.ClassLoaderInterface" class="org.apache.struts2.osgi.BundleClassLoaderInterface" />
+
+    <package name="osgi-default" extends="struts-default" abstract="yes">
+        <interceptors>
+            <interceptor name="osgi" class="org.apache.struts2.osgi.interceptor.OsgiInterceptor" />
+
+            <interceptor-stack name="osgiStack">
+                <interceptor-ref name="defaultStack"/>
+                <interceptor-ref name="osgi"/>
+            </interceptor-stack>
+        </interceptors>
+
+         <default-interceptor-ref name="osgiStack"/>
+    </package>
 </struts>

Added: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/OsgiInterceptorTest.java
URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/OsgiInterceptorTest.java?rev=764282&view=auto
==============================================================================
--- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/OsgiInterceptorTest.java (added)
+++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/test/java/org/apache/struts2/osgi/interceptor/OsgiInterceptorTest.java Sun Apr 12 05:26:26 2009
@@ -0,0 +1,53 @@
+package org.apache.struts2.osgi.interceptor;
+
+import org.easymock.EasyMock;
+import org.apache.struts2.osgi.OsgiHost;
+import org.osgi.framework.BundleContext;
+
+import javax.servlet.ServletContext;
+
+import com.opensymphony.xwork2.ActionInvocation;
+import junit.framework.TestCase;
+
+public class OsgiInterceptorTest extends TestCase {
+    public void testBundleContextAware() throws Exception {
+        ServletContext servletContext = EasyMock.createStrictMock(ServletContext.class);
+        BundleContext bundleContext = EasyMock.createStrictMock(BundleContext.class);
+        ActionInvocation actionInvocation = EasyMock.createStrictMock(ActionInvocation.class);
+        BundleContextAware bundleContextAware = EasyMock.createStrictMock(BundleContextAware.class);
+
+        EasyMock.expect(servletContext.getAttribute(OsgiHost.OSGI_BUNDLE_CONTEXT)).andReturn(bundleContext);
+        EasyMock.expect(actionInvocation.getAction()).andReturn(bundleContextAware);
+        bundleContextAware.setBundleContext(bundleContext);
+        EasyMock.expect(actionInvocation.invoke()).andReturn("");
+
+        EasyMock.replay(bundleContextAware);
+        EasyMock.replay(servletContext);
+        EasyMock.replay(actionInvocation);
+
+        OsgiInterceptor osgiInterceptor = new OsgiInterceptor();
+        osgiInterceptor.setServletContext(servletContext);
+        osgiInterceptor.intercept(actionInvocation);
+
+        EasyMock.verify(bundleContextAware);
+    }
+
+     public void testBundleContextAwareNegative() throws Exception {
+        ServletContext servletContext = EasyMock.createStrictMock(ServletContext.class);
+        ActionInvocation actionInvocation = EasyMock.createStrictMock(ActionInvocation.class);
+        BundleContextAware bundleContextAware = EasyMock.createStrictMock(BundleContextAware.class);
+
+        EasyMock.expect(servletContext.getAttribute(OsgiHost.OSGI_BUNDLE_CONTEXT)).andReturn(null);
+        EasyMock.expect(actionInvocation.invoke()).andReturn("");
+
+        EasyMock.replay(bundleContextAware);
+        EasyMock.replay(servletContext);
+        EasyMock.replay(actionInvocation);
+
+        OsgiInterceptor osgiInterceptor = new OsgiInterceptor();
+        osgiInterceptor.setServletContext(servletContext);
+        osgiInterceptor.intercept(actionInvocation);
+
+        EasyMock.verify(bundleContextAware);
+    }
+}