Author: musachy Date: Mon Apr 13 01:55:02 2009 New Revision: 764348 URL: http://svn.apache.org/viewvc?rev=764348&view=rev Log: Add support for loading/unloading configuration when bundles are started/stopped
Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleFreemarkerManager.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java 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/PackageLoader.java 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/struts-plugin.xml Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/pom.xml Mon Apr 13 01:55:02 2009 @@ -14,6 +14,12 @@ <artifactId>struts2-osgi-plugin</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <version>2.4</version> + <scope>provided</scope> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> @@ -36,21 +42,26 @@ <configuration> <instructions> <manifestLocation>META-INF</manifestLocation> - <Import-Package> - *,com.opensymphony.xwork2 - </Import-Package> - <Export-Package> - org.apache.struts2.osgi.admin* - </Export-Package> - <Bundle-Activator> - org.apache.struts2.osgi.StrutsActivator - </Bundle-Activator> - <Spring-Context> - *;create-asynchronously:=false - </Spring-Context> + <Struts2-Enabled>true</Struts2-Enabled> + <Import-Package>*,com.opensymphony.xwork2</Import-Package> + <Export-Package>org.apache.struts2.osgi.admin*</Export-Package> + <Spring-Context>*;create-asynchronously:=false</Spring-Context> </instructions> </configuration> </plugin> + <plugin> + <inherited>true</inherited> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> </plugins> <pluginManagement> <plugins> @@ -64,5 +75,4 @@ </plugins> </pluginManagement> </build> - </project> Modified: struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/admin-bundle/src/main/java/org/apache/struts2/osgi/admin/actions/BundlesAction.java Mon Apr 13 01:55:02 2009 @@ -21,23 +21,24 @@ package org.apache.struts2.osgi.admin.actions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import org.apache.struts2.dispatcher.DefaultActionSupport; +import com.opensymphony.xwork2.ActionSupport; +import com.opensymphony.xwork2.config.Configuration; +import com.opensymphony.xwork2.config.entities.PackageConfig; +import com.opensymphony.xwork2.inject.Inject; import org.apache.struts2.osgi.BundleAccessor; -import org.apache.struts2.osgi.DefaultBundleAccessor; import org.apache.struts2.osgi.OsgiHost; +import org.apache.struts2.osgi.StrutsOsgiListener; +import org.apache.struts2.util.ServletContextAware; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import com.opensymphony.xwork2.config.Configuration; -import com.opensymphony.xwork2.config.entities.PackageConfig; -import com.opensymphony.xwork2.inject.Inject; +import javax.servlet.ServletContext; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; -public class BundlesAction extends DefaultActionSupport { +public class BundlesAction extends ActionSupport implements ServletContextAware { private String id; @@ -46,7 +47,6 @@ private OsgiHost osgiHost; public BundlesAction() { - this.bundleAccessor = DefaultBundleAccessor.getInstance(); } public String index() { @@ -61,6 +61,11 @@ Bundle bundle = osgiHost.getBundles().get(id); try { bundle.start(); + + //start fires the BundleEvent.STARTED, which load the config + //we need to wait until the config is loaded from that bundle + //there no easy way/elegant way to know if the bundle is being processed + Thread.sleep(1000); } catch (Exception e) { addActionError(e.toString()); } @@ -105,8 +110,12 @@ public List<PackageConfig> getPackages() { List<PackageConfig> pkgs = new ArrayList<PackageConfig>(); Bundle bundle = getBundle(); - for (String name : bundleAccessor.getPackagesByBundle(bundle)) { - pkgs.add(configuration.getPackageConfig(name)); + if (bundle.getState() == Bundle.ACTIVE) { + for (String name : bundleAccessor.getPackagesByBundle(bundle)) { + PackageConfig packageConfig = configuration.getPackageConfig(name); + if (packageConfig != null) + pkgs.add(packageConfig); + } } return pkgs; } @@ -161,7 +170,11 @@ } @Inject - public void setOsgiHost(OsgiHost osgiHost) { - this.osgiHost = osgiHost; + public void setBundleAccessor(BundleAccessor bundleAccessor) { + this.bundleAccessor = bundleAccessor; + } + + public void setServletContext(ServletContext servletContext) { + osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST); } } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleAccessor.java Mon Apr 13 01:55:02 2009 @@ -36,8 +36,6 @@ String CURRENT_BUNDLE_NAME = "__bundle_name__"; - void setPackageToBundle(Map<String, String> packageToBundle); - Class loadClass(String name) throws ClassNotFoundException; InputStream loadResourceAsStream(String name) throws IOException; Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleFreemarkerManager.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleFreemarkerManager.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleFreemarkerManager.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundleFreemarkerManager.java Mon Apr 13 01:55:02 2009 @@ -44,7 +44,7 @@ */ public class BundleFreemarkerManager extends FreemarkerManager { private static final Logger LOG = LoggerFactory.getLogger(BundleFreemarkerManager.class); - + @Override protected TemplateLoader getTemplateLoader(ServletContext servletContext) { // construct a FileTemplateLoader for the init-param 'TemplatePath' @@ -59,7 +59,8 @@ try { templatePathLoader = new FileTemplateLoader(new File(templatePath)); } catch (IOException e) { - LOG.error("Invalid template path specified: #1",e, e.getMessage()); + if (LOG.isErrorEnabled()) + LOG.error("Invalid template path specified: [#0]", e, e.getMessage()); } } @@ -73,10 +74,10 @@ new FreeMarkerBundleResourceLoader() }) : new MultiTemplateLoader(new TemplateLoader[]{ - new WebappTemplateLoader(servletContext), - new StrutsClassTemplateLoader(), - new FreeMarkerBundleResourceLoader() - }); + new WebappTemplateLoader(servletContext), + new StrutsClassTemplateLoader(), + new FreeMarkerBundleResourceLoader() + }); } - + } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/BundlePackageLoader.java Mon Apr 13 01:55:02 2009 @@ -41,48 +41,41 @@ import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; +/** + * Package loader implementation that loads resources from a bundle + */ public class BundlePackageLoader implements PackageLoader { private static final Logger LOG = LoggerFactory.getLogger(BundlePackageLoader.class); - public List<PackageConfig> loadPackages(Bundle bundle, BundleContext bundleContext, ObjectFactory objectFactory, Map<String,PackageConfig> pkgConfigs) throws ConfigurationException { + public List<PackageConfig> loadPackages(Bundle bundle, BundleContext bundleContext, ObjectFactory objectFactory, Map<String, PackageConfig> pkgConfigs) throws ConfigurationException { Configuration config = new DefaultConfiguration("struts.xml"); - ActionContext ctx = ActionContext.getContext(); - if (ctx == null) { - ctx = new ActionContext(new HashMap()); - ActionContext.setContext(ctx); - } - - try { - // Ensure all requested classes and resources will be resolved using the current bundle - ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, bundle.getSymbolicName()); - - BundleConfigurationProvider prov = new BundleConfigurationProvider("struts.xml", bundle, bundleContext); - for (PackageConfig pkg : pkgConfigs.values()) { - config.addPackageConfig(pkg.getName(), pkg); - } - prov.setObjectFactory(objectFactory); - prov.init(config); - prov.loadPackages(); - } finally { - ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null); - } + BundleConfigurationProvider prov = new BundleConfigurationProvider("struts.xml", bundle, bundleContext); + for (PackageConfig pkg : pkgConfigs.values()) { + config.addPackageConfig(pkg.getName(), pkg); + } + prov.setObjectFactory(objectFactory); + prov.init(config); + prov.loadPackages(); List<PackageConfig> list = new ArrayList<PackageConfig>(config.getPackageConfigs().values()); list.removeAll(pkgConfigs.values()); - + return list; } - + static class BundleConfigurationProvider extends XmlConfigurationProvider { private Bundle bundle; private BundleContext bundleContext; - public BundleConfigurationProvider(String filename, Bundle bundle, BundleContext bundleContext) { + public BundleConfigurationProvider(String filename, Bundle bundle, BundleContext bundleContext) { super(filename, false); this.bundle = bundle; this.bundleContext = bundleContext; } - public BundleConfigurationProvider(String filename) { super(filename); } + + public BundleConfigurationProvider(String filename) { + super(filename); + } @Override protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException { @@ -90,23 +83,25 @@ return e.hasMoreElements() ? new EnumeratorIterator<URL>(e) : null; } } - + 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(); + return e.hasMoreElements(); } public E next() { - return e.nextElement(); + return e.nextElement(); } public void remove() { - throw new UnsupportedOperationException(); + throw new UnsupportedOperationException(); } - } + } } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DefaultBundleAccessor.java Mon Apr 13 01:55:02 2009 @@ -50,8 +50,8 @@ private static final Logger LOG = LoggerFactory.getLogger(DefaultBundleAccessor.class); private BundleContext bundleContext; - private Map<String, String> packageToBundle; - private Map<Bundle, Set<String>> packagesByBundle; + private Map<String, String> packageToBundle = new HashMap<String, String>(); + private Map<Bundle, Set<String>> packagesByBundle = new HashMap<Bundle, Set<String>>(); private OsgiHost osgiHost; public DefaultBundleAccessor() { @@ -88,15 +88,6 @@ return bundleContext != null ? bundleContext.getServiceReferences(className, params) : null; } - public void setPackageToBundle(Map<String, String> packageToBundle) { - this.packageToBundle = packageToBundle; - this.packagesByBundle = new HashMap<Bundle, Set<String>>(); - for (Map.Entry<String, String> entry : packageToBundle.entrySet()) { - Bundle bundle = osgiHost.getActiveBundles().get(entry.getValue()); - addPackageFromBundle(bundle, entry.getKey()); - } - } - /** * Add as Bundle -> Package mapping * @param bundle the bundle where the package was loaded from @@ -117,7 +108,7 @@ if (bundle != null) { Class cls = bundle.loadClass(className); if (LOG.isTraceEnabled()) - LOG.debug("Located class [#0] in bundle [#1]", className, bundle.getSymbolicName()); + LOG.trace("Located class [#0] in bundle [#1]", className, bundle.getSymbolicName()); return cls; } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/DelegatingObjectFactory.java Mon Apr 13 01:55:02 2009 @@ -61,7 +61,10 @@ try { return delegateObjectFactory.buildBean(className, extraContext, injectInternal); } catch (Exception e) { - return bundleResourceLoader.loadClass(className).newInstance(); + Object object = bundleResourceLoader.loadClass(className).newInstance(); + if (injectInternal) + injectInternalBeans(object); + return object; } } 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=764348&r1=764347&r2=764348&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 Mon Apr 13 01:55:02 2009 @@ -71,11 +71,10 @@ * <p>struts.osgi.logLevel: Defaults to "1". Felix log level. 1 = error, 2 = warning, 3 = information, and 4 = debug </p> * <p>struts.osgi.runLevel: Defaults to "3". Run level to start the container.</p> */ -public class FelixOsgiHost implements OsgiHost, BundleListener { +public class FelixOsgiHost implements OsgiHost { private static final Logger LOG = LoggerFactory.getLogger(FelixOsgiHost.class); private Felix felix; - private Map<String, Bundle> bundles = Collections.synchronizedMap(new HashMap<String, Bundle>()); private static final Pattern versionPattern = Pattern.compile("([\\d])+[\\.-]"); private ServletContext servletContext; @@ -98,7 +97,7 @@ String storageDir = System.getProperty("java.io.tmpdir") + ".felix-cache"; configProps.setProperty(Constants.FRAMEWORK_STORAGE, storageDir); if (LOG.isDebugEnabled()) - LOG.debug("Storing bundle at [#0]", storageDir); + LOG.debug("Storing bundles at [#0]", storageDir); String cleanBundleCache = getServletContextParam("struts.osgi.clearBundleCache", "true"); if ("true".equalsIgnoreCase(cleanBundleCache)) { @@ -116,17 +115,6 @@ try { List<BundleActivator> list = new ArrayList<BundleActivator>(); 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); @@ -145,8 +133,9 @@ } /** - * 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 + * 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 */ @@ -352,17 +341,22 @@ * Use getActiveBundles() for active bundles */ public Map<String, Bundle> getBundles() { + Map<String, Bundle> bundles = new HashMap<String, Bundle>(); + for (Bundle bundle : felix.getBundleContext().getBundles()) { + bundles.put(bundle.getSymbolicName(), bundle); + } + return Collections.unmodifiableMap(bundles); } public Map<String, Bundle> getActiveBundles() { - Map<String, Bundle> activeBundleMap = new HashMap<String, Bundle>(); - for (Map.Entry<String, Bundle> entry : bundles.entrySet()) { - if (entry.getValue().getState() == Bundle.ACTIVE) - activeBundleMap.put(entry.getKey(), entry.getValue()); + Map<String, Bundle> bundles = new HashMap<String, Bundle>(); + for (Bundle bundle : felix.getBundleContext().getBundles()) { + if (bundle.getState() == Bundle.ACTIVE) + bundles.put(bundle.getSymbolicName(), bundle); } - return activeBundleMap; + return Collections.unmodifiableMap(bundles); } public BundleContext getBundleContext() { @@ -370,30 +364,13 @@ } public void destroy() throws Exception { - try { - felix.stop(); - } finally { - bundles = null; - } + felix.stop(); + if (LOG.isTraceEnabled()) + LOG.trace("Apache Felix has stopped"); } public void init(ServletContext servletContext) { this.servletContext = servletContext; startFelix(); } - - /** - * Listen to BundleEvent(s) and build a bundles list - */ - public void bundleChanged(BundleEvent evt) { - Bundle bundle = evt.getBundle(); - String bundleName = bundle.getSymbolicName(); - if (bundleName != null) { - switch (evt.getType()) { - case BundleEvent.STARTED: - this.bundles.put(bundleName, bundle); - break; - } - } - } } 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=764348&r1=764347&r2=764348&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 Mon Apr 13 01:55:02 2009 @@ -35,8 +35,11 @@ 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.Bundle; import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleListener; +import org.osgi.framework.BundleEvent; import javax.servlet.ServletContext; import java.util.ArrayList; @@ -50,7 +53,7 @@ /** * Struts package provider that starts the OSGi container and deelgates package loading */ -public class OsgiConfigurationProvider implements PackageProvider { +public class OsgiConfigurationProvider implements PackageProvider, BundleListener { private static final String STRUTS_ENABLED = "Struts2-Enabled"; private static final Logger LOG = LoggerFactory.getLogger(OsgiConfigurationProvider.class); @@ -68,13 +71,14 @@ osgiHost = (OsgiHost) servletContext.getAttribute(StrutsOsgiListener.OSGI_HOST); bundleContext = osgiHost.getBundleContext(); bundleAccessor.setBundleContext(bundleContext); - // I can't figure out why BundleAccessor doesn't get the OsgiHost injected - //for reason it always gets a new instace...weird bundleAccessor.setOsgiHost(osgiHost); this.configuration = configuration; } public synchronized void loadPackages() throws ConfigurationException { + if (LOG.isTraceEnabled()) + LOG.trace("Loading packages from XML and Convention on startup"); + //init action contect ActionContext ctx = ActionContext.getContext(); if (ctx == null) { @@ -82,7 +86,6 @@ ActionContext.setContext(ctx); } - Map<String, String> packageToBundle = new HashMap<String, String>(); Set<String> bundleNames = new HashSet<String>(); //iterate over the bundles and load packages from them @@ -90,66 +93,74 @@ 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); - } + //load XML and COnvention config + loadConfigFromBundle(bundle); } } - //add the loaded packages to the BundleAccessor - bundleAccessor.setPackageToBundle(packageToBundle); - - //reload container, that will load configuration based on bundles (like convention plugin) - reloadExtraProviders(configuration.getContainer()); - bundlesChanged = false; + bundleContext.addBundleListener(this); } - protected void reloadExtraProviders(Container container) { - //these providers will be reloaded for each bundle - List<PackageProvider> providers = new ArrayList<PackageProvider>(); - PackageProvider conventionPackageProvider = container.getInstance(PackageProvider.class, "convention.packageProvider"); - if (conventionPackageProvider != null) - providers.add(conventionPackageProvider); + /** + * Loads XML config as well as Convention config from a bundle + * Limitation: Constants and Beans are ignored on XML config + */ + protected void loadConfigFromBundle(Bundle bundle) { + String bundleName = bundle.getSymbolicName(); + if (LOG.isDebugEnabled()) + LOG.debug("Loading packages from bundle [#0]", bundleName); - //reload all providers by bundle + //init action context ActionContext ctx = ActionContext.getContext(); - for (Bundle bundle : osgiHost.getBundles().values()) { - 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(), 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(); - Set<String> packagesAfterLoading = new HashSet(configuration.getPackageConfigNames()); - packagesAfterLoading.removeAll(packagesBeforeLoading); - if (!packagesAfterLoading.isEmpty()) { - //add the new packages to the map of bundle -> package - for (String packageName : packagesAfterLoading) - bundleAccessor.addPackageFromBundle(bundle, packageName); - } - } - } finally { - ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null); - ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, null); - } + if (ctx == null) { + ctx = new ActionContext(new HashMap()); + ActionContext.setContext(ctx); + } + + 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); + + if (LOG.isTraceEnabled()) + LOG.trace("Loading XML config from bundle [#0]", bundleName); + + //XML config + PackageLoader loader = new BundlePackageLoader(); + for (PackageConfig pkg : loader.loadPackages(bundle, bundleContext, objectFactory, configuration.getPackageConfigs())) { + configuration.addPackageConfig(pkg.getName(), pkg); + bundleAccessor.addPackageFromBundle(bundle, pkg.getName()); + } + + //Convention + //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()); + + PackageProvider conventionPackageProvider = configuration.getContainer().getInstance(PackageProvider.class, "convention.packageProvider"); + if (conventionPackageProvider != null) { + if (LOG.isTraceEnabled()) + LOG.trace("Loading Convention config from bundle [#0]", bundleName); + conventionPackageProvider.loadPackages(); } + + Set<String> packagesAfterLoading = new HashSet(configuration.getPackageConfigNames()); + packagesAfterLoading.removeAll(packagesBeforeLoading); + if (!packagesAfterLoading.isEmpty()) { + //add the new packages to the map of bundle -> package + for (String packageName : packagesAfterLoading) + bundleAccessor.addPackageFromBundle(bundle, packageName); + } + + if (this.configuration.getRuntimeConfiguration() != null) { + //if there is a runtime config, it meas that this method was called froma bundle start event + //instead of the initial load, in that case, reload the config + this.configuration.rebuildRuntimeConfiguration(); + } + } finally { + ctx.put(BundleAccessor.CURRENT_BUNDLE_NAME, null); + ctx.put(ClassLoaderInterface.CLASS_LOADER_INTERFACE, null); } } @@ -171,11 +182,6 @@ this.objectFactory = factory; } - @Inject("felix") - public void setOsgiHost(OsgiHost osgiHost) { - this.osgiHost = osgiHost; - } - @Inject public void setBundleAccessor(BundleAccessor acc) { this.bundleAccessor = acc; @@ -197,11 +203,45 @@ 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); + if (LOG.isErrorEnabled()) + LOG.error("Failed to stop OSGi container", e); + } + } + + /** + * Listens to bundle event to load/unload config + */ + public void bundleChanged(BundleEvent bundleEvent) { + Bundle bundle = bundleEvent.getBundle(); + String bundleName = bundle.getSymbolicName(); + if (bundleName != null && shouldProcessBundle(bundle)) { + switch (bundleEvent.getType()) { + case BundleEvent.STARTED: + if (LOG.isTraceEnabled()) + LOG.trace("The bundlde [#0] has been activated and will be scanned for struts configuration", bundleName); + loadConfigFromBundle(bundle); + break; + case BundleEvent.STOPPED: + onBundleStopped(bundle); + break; + } + } + } + + /** + * This method is called when a bundle is stopped, so the config that is related to it is removed + * + * @param bundle the bundle that stopped + */ + protected void onBundleStopped(Bundle bundle) { + Set<String> packages = bundleAccessor.getPackagesByBundle(bundle); + if (!packages.isEmpty()) { + if (LOG.isTraceEnabled()) + LOG.trace("The bundle [#0] has been stopped. The packages [#1] will be disabled", bundle.getSymbolicName(), StringUtils.join(packages, ",")); + for (String packageName : packages) + configuration.removePackageConfig(packageName); } } } Modified: struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java?rev=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/PackageLoader.java Mon Apr 13 01:55:02 2009 @@ -32,6 +32,9 @@ import com.opensymphony.xwork2.config.PackageProvider; import com.opensymphony.xwork2.config.entities.PackageConfig; +/** + * Implementations of this interface can load packages from a Bundle + */ public interface PackageLoader { List<PackageConfig> loadPackages(Bundle bundle, BundleContext bundleContext, ObjectFactory objectFactory, Map<String, PackageConfig> map) throws ConfigurationException; } Modified: 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=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/BundleContextAware.java Mon Apr 13 01:55:02 2009 @@ -1,3 +1,23 @@ +/* + * $Id$ + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.struts2.osgi.interceptor; import org.osgi.framework.BundleContext; Modified: 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=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/OsgiInterceptor.java Mon Apr 13 01:55:02 2009 @@ -1,3 +1,23 @@ +/* + * $Id$ + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.struts2.osgi.interceptor; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; Modified: 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=764348&r1=764347&r2=764348&view=diff ============================================================================== --- struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java (original) +++ struts/sandbox/trunk/struts2-osgi-plugin/plugin/src/main/java/org/apache/struts2/osgi/interceptor/ServiceAware.java Mon Apr 13 01:55:02 2009 @@ -1,3 +1,23 @@ +/* + * $Id$ + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ package org.apache.struts2.osgi.interceptor; import java.util.List; 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=764348&r1=764347&r2=764348&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 Mon Apr 13 01:55:02 2009 @@ -14,10 +14,10 @@ <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" /> <bean name="springOsgi" type="com.opensymphony.xwork2.ObjectFactory" class="org.apache.struts2.osgi.SpringOsgiObjectFactory" /> <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">