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); + } +}