? sandbox/META-INF
? sandbox/src/sandbox.iml
Index: sandbox/src/org/springframework/osgi/context/ContextLoaderListener.java
===================================================================
RCS file: sandbox/src/org/springframework/osgi/context/ContextLoaderListener.java
diff -N sandbox/src/org/springframework/osgi/context/ContextLoaderListener.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sandbox/src/org/springframework/osgi/context/ContextLoaderListener.java 22 Mar 2006 09:29:29 -0000
@@ -0,0 +1,196 @@
+package org.springframework.osgi.context;
+
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.ServiceReference;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.osgi.context.support.BundleDelegatingClassLoader;
+import org.springframework.osgi.context.support.DefaultOsgiBundleXmlApplicationContextFactory;
+import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext;
+import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContextFactory;
+import org.springframework.osgi.service.OsgiServiceUtils;
+import org.springframework.util.StringUtils;
+
+/**
+ * A BundlerListener that transparently activates Spring inside a bundle.
+ * Activation is based on the presence of a configuration file named
+ * <bundle symbolic name>-context.xml
+ *
+ * The service properties used when publishing the service are
+ * determined by the OsgiServicePropertiesResolver. The default
+ * implementation uses
+ *
+ * - BundleSymbolicName=<bundle symbolic name>
+ * - BundleVersion=<bundle version>
+ * - org.springframework.osgi.beanname="<bean name>
+ *
+ *
+ * @author OSGi Hackers
+ * @see ContextLoaderBundleActivator
+ * @since 2.0
+ */
+public class ContextLoaderListener implements BundleActivator, BundleListener {
+
+ private static final String CONTEXT_LOCATION_HEADER = "org.springframework.context";
+ // FIXME:
+ private static final String PARENT_CONTEXT_SERVICE_NAME_HEADER = "SpringParentContext";
+ //private static final String PARENT_CONTEXT_SERVICE_NAME_HEADER = "org.springframework.parent.context";
+ private static final String CONTEXT_LOCATION_DELIMITERS = ", ";
+ private static final String DEFAULT_CONTEXT_PREFIX = "/META-INF/";
+ private static final String DEFAULT_CONTEXT_POSTFIX = "-context.xml";
+
+ private OsgiBundleXmlApplicationContextFactory contextFactory = new DefaultOsgiBundleXmlApplicationContextFactory();
+ private ConfigurableApplicationContext applicationContext;
+ private ServiceReference parentServiceReference;
+
+ private HashMap managedBundles = new HashMap();
+
+ public void start(BundleContext context) throws Exception {
+ context.addBundleListener(this);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ }
+
+ public void bundleChanged(BundleEvent event) {
+ switch (event.getType()) {
+ case BundleEvent.STARTED:
+ startBundle(event.getBundle());
+ break;
+ case BundleEvent.STOPPED:
+ stopBundle(event.getBundle());
+ break;
+ }
+ }
+
+ private void startBundle(Bundle bundle) {
+ String[] applicationContextLocations = getApplicationContextLocations(bundle);
+ BundleContext bundleContext = getBundleContext(bundle);
+ ApplicationContext parent = getParentApplicationContext(bundleContext);
+
+ ClassLoader ccl =
+ new BundleDelegatingClassLoader(getClass().getClassLoader(), bundle);
+ ClassLoader savedCCL = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(ccl);
+
+ try {
+ try {
+ OsgiBundleXmlApplicationContext ctx =
+ contextFactory.createApplicationContext(parent, bundleContext,
+ applicationContextLocations);
+ managedBundles.put(bundle, ctx);
+ } catch (Throwable thr) {
+ thr.printStackTrace();
+ }
+ } finally {
+ Thread.currentThread().setContextClassLoader(savedCCL);
+ }
+ }
+
+ private void stopBundle(Bundle bundle) {
+ OsgiBundleXmlApplicationContext ctx = managedBundles.remove(bundle);
+ if (ctx != null) {
+ ctx.close();
+ }
+ }
+
+ protected ApplicationContext getParentApplicationContext(BundleContext context) {
+ String parentContextServiceName = (String) context.getBundle().getHeaders().get(PARENT_CONTEXT_SERVICE_NAME_HEADER);
+ if (parentContextServiceName == null) {
+ return null;
+ }
+ else {
+ // try to find the service
+ String filter = "(" + OsgiBundleXmlApplicationContext.APPLICATION_CONTEXT_SERVICE_NAME_HEADER +
+ "=" + parentContextServiceName + ")";
+ ServiceReference ref = OsgiServiceUtils.getService(context,ApplicationContext.class, filter);
+ ApplicationContext parent = (ApplicationContext) context.getService(ref);
+ // TODO: register as service listener..., probably in a proxy to the app context
+ // that we create here and return instead.
+
+ return parent;
+ }
+ }
+
+ /**
+ * Retrieves the org.springframework.context manifest header attribute
+ * and parses it to create a String[] of resource names for creating
+ * the application context.
+ *
+ * If the org.springframework.context header is not present, the
+ * default -context.xml file will be returned.
+ */
+ protected String[] getApplicationContextLocations(Bundle bundle) {
+ Dictionary manifestHeaders = bundle.getHeaders();
+ String contextLocationsHeader = (String) manifestHeaders.get(CONTEXT_LOCATION_HEADER);
+ if (contextLocationsHeader != null) {
+ String[] locs =
+ StringUtils.tokenizeToStringArray(contextLocationsHeader, CONTEXT_LOCATION_DELIMITERS);
+ List ret = new ArrayList();
+ for (String s : locs) {
+ if (bundle.getEntry(s) != null) {
+ ret.add(s);
+ }
+ }
+ if (ret.isEmpty()) return null;
+ else return addBundlePrefixTo((String[])ret.toArray());
+ }
+ else {
+ String defaultName = DEFAULT_CONTEXT_PREFIX + bundle.getSymbolicName() + DEFAULT_CONTEXT_POSTFIX;
+ if (bundle.getEntry(defaultName) != null)
+ return addBundlePrefixTo(new String[] {defaultName});
+ else return null;
+ }
+ }
+
+ /**
+ * add the "bundle:" prefix to the resource location paths in the given argument.
+ * This ensures that only this bundle will be searched for matching resources.
+ *
+ * Modifies the argument in place and returns it.
+ */
+ private String[] addBundlePrefixTo(String[] resourcePaths) {
+ for (int i = 0; i < resourcePaths.length; i++) {
+ resourcePaths[i] = OsgiBundleXmlApplicationContext.BUNDLE_URL_PREFIX + resourcePaths[i];
+ }
+ return resourcePaths;
+ }
+
+ // for testing...
+ protected void setApplicationContext(ConfigurableApplicationContext context) {
+ this.applicationContext = context;
+ }
+
+ // for testing...
+ protected void setParentServiceReference(ServiceReference ref) {
+ this.parentServiceReference = ref;
+ }
+
+ // for testing...
+ protected void setApplicationContextFactory(OsgiBundleXmlApplicationContextFactory factory) {
+ this.contextFactory = factory;
+ }
+
+ // FIXME:
+ private static BundleContext getBundleContext(Bundle bundle) {
+ try {
+ Method m = bundle.getClass().getDeclaredMethod("getContext");
+ m.setAccessible(true);
+ return (BundleContext) m.invoke(bundle);
+ } catch (Exception exc) {
+ throw new AssertionError(exc);
+ }
+ }
+
+}
Index: sandbox/src/org/springframework/osgi/context/MANIFEST.MF
===================================================================
RCS file: sandbox/src/org/springframework/osgi/context/MANIFEST.MF
diff -N sandbox/src/org/springframework/osgi/context/MANIFEST.MF
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sandbox/src/org/springframework/osgi/context/MANIFEST.MF 22 Mar 2006 09:29:30 -0000
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: SpringBundle
+Bundle-SymbolicName: SpringBundle
+Bundle-Version: 1.0.0
+Bundle-Activator: org.springframework.osgi.context.ContextLoaderListener
+Bundle-Localization: plugin
+Import-Package: org.osgi.framework;version="1.3.0"
+Bundle-ClassPath: bin/,
+ lib/spring.jar,
+ lib/commons-logging.jar,
+ lib/log4j-1.2.13.jar
Index: sandbox/src/org/springframework/osgi/context/support/BundleDelegatingClassLoader.java
===================================================================
RCS file: sandbox/src/org/springframework/osgi/context/support/BundleDelegatingClassLoader.java
diff -N sandbox/src/org/springframework/osgi/context/support/BundleDelegatingClassLoader.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sandbox/src/org/springframework/osgi/context/support/BundleDelegatingClassLoader.java 22 Mar 2006 09:29:30 -0000
@@ -0,0 +1,26 @@
+package org.springframework.osgi.context.support;
+
+import org.osgi.framework.Bundle;
+
+public class BundleDelegatingClassLoader extends ClassLoader
+{
+ private final ClassLoader springBundleClassLoader;
+ private final Bundle targetBundle;
+
+
+ public BundleDelegatingClassLoader(ClassLoader springBundleClassLoader,
+ Bundle targetBundle)
+ {
+ this.springBundleClassLoader = springBundleClassLoader;
+ this.targetBundle = targetBundle;
+ }
+
+ public Class> loadClass(String name) throws ClassNotFoundException {
+ if (name.startsWith("org.springframework") ||
+ name.startsWith("org.aopalliance"))
+ return springBundleClassLoader.loadClass(name);
+ else
+ return targetBundle.loadClass(name);
+ }
+
+}
Index: sandbox/src/org/springframework/osgi/context/support/OsgiBundleXmlApplicationContext.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/context/support/OsgiBundleXmlApplicationContext.java,v
retrieving revision 1.2
diff -u -r1.2 OsgiBundleXmlApplicationContext.java
--- sandbox/src/org/springframework/osgi/context/support/OsgiBundleXmlApplicationContext.java 21 Mar 2006 10:53:48 -0000 1.2
+++ sandbox/src/org/springframework/osgi/context/support/OsgiBundleXmlApplicationContext.java 22 Mar 2006 09:29:30 -0000
@@ -17,17 +17,19 @@
*/
package org.springframework.osgi.context.support;
-import java.io.IOException;
-import java.net.URL;
import java.util.Dictionary;
-import java.util.Enumeration;
import java.util.Properties;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.core.io.Resource;
@@ -89,10 +91,9 @@
this.configLocations = configLocations;
this.osgiBundleContext = aBundleContext;
this.osgiBundle = this.osgiBundleContext.getBundle();
- this.setClassLoader(createBundleClassLoader(this.osgiBundle));
refresh();
- publishContextAsOsgiService();
+ publishContextAsOsgiService();
}
protected String[] getConfigLocations() {
@@ -110,6 +111,7 @@
protected void publishContextAsOsgiService() {
Dictionary serviceProperties = new Properties();
serviceProperties.put(APPLICATION_CONTEXT_SERVICE_NAME_HEADER, getServiceName());
+
this.serviceRegistration =
this.osgiBundleContext.registerService(
new String[] {ApplicationContext.class.getName()},
@@ -118,9 +120,12 @@
}
public void close() {
- if (this.serviceRegistration != null) {
- this.serviceRegistration.unregister();
- }
+ try {
+ if (this.serviceRegistration != null) {
+ this.serviceRegistration.unregister();
+ }
+ } catch (IllegalStateException ignore) {
+ }
super.close();
}
@@ -195,29 +200,22 @@
beanFactory.addBeanPostProcessor(new BundleContextAwareProcessor(this.osgiBundleContext));
beanFactory.ignoreDependencyInterface(BundleContextAware.class);
}
-
- private ClassLoader createBundleClassLoader(Bundle bundle) {
- return new BundleClassLoader(bundle);
- }
-
- private static class BundleClassLoader extends ClassLoader {
-
- private Bundle backingBundle;
-
- public BundleClassLoader(Bundle aBundle) {
- this.backingBundle = aBundle;
- }
-
- protected Class findClass(String name) throws ClassNotFoundException {
- return this.backingBundle.loadClass(name);
- }
-
- protected URL findResource(String name) {
- return this.backingBundle.getResource(name);
- }
-
- protected Enumeration findResources(String name) throws IOException {
- return this.backingBundle.getResources(name);
- }
- }
+
+ protected DefaultListableBeanFactory createBeanFactory() {
+ return new DefaultListableBeanFactory() {
+ public BeanDefinition getBeanDefinition(String beanName)
+ throws NoSuchBeanDefinitionException
+ {
+ try {
+ return super.getBeanDefinition(beanName);
+ } catch (NoSuchBeanDefinitionException nsbd) {
+ System.err.println("BEAN DEFINITION NOT FOUND2: " + nsbd);
+
+ throw nsbd;
+ }
+ }
+ };
+ }
+
+
}
Index: sandbox/src/org/springframework/osgi/service/BeanNameServicePropertiesResolver.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/service/BeanNameServicePropertiesResolver.java,v
retrieving revision 1.1
diff -u -r1.1 BeanNameServicePropertiesResolver.java
--- sandbox/src/org/springframework/osgi/service/BeanNameServicePropertiesResolver.java 10 Mar 2006 16:40:11 -0000 1.1
+++ sandbox/src/org/springframework/osgi/service/BeanNameServicePropertiesResolver.java 22 Mar 2006 09:29:30 -0000
@@ -25,7 +25,7 @@
import org.springframework.osgi.context.BundleContextAware;
/**
- * OsgiServicePropertiesResolver that creats a service property set with
+ * OsgiServicePropertiesResolver that creates a service property set with
* the following properties:
*
* - Bundle-SymbolicName=<bundle symbolic name>
@@ -61,7 +61,7 @@
return (String) this.bundleContext.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
}
- private String getSymbolicName() {
+ private String getSymbolicName() {
return this.bundleContext.getBundle().getSymbolicName();
}
Index: sandbox/src/org/springframework/osgi/service/OsgiServiceExporter.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/service/OsgiServiceExporter.java,v
retrieving revision 1.1
diff -u -r1.1 OsgiServiceExporter.java
--- sandbox/src/org/springframework/osgi/service/OsgiServiceExporter.java 10 Mar 2006 16:40:11 -0000 1.1
+++ sandbox/src/org/springframework/osgi/service/OsgiServiceExporter.java 22 Mar 2006 09:29:30 -0000
@@ -93,6 +93,8 @@
public void setBundleContext(BundleContext context) {
this.bundleContext = context;
+ if (resolver instanceof BundleContextAware)
+ ((BundleContextAware)resolver).setBundleContext(this.bundleContext);
}
/**
@@ -107,6 +109,8 @@
*/
public void setResolver(OsgiServicePropertiesResolver resolver) {
this.resolver = resolver;
+ if (resolver instanceof BundleContextAware)
+ ((BundleContextAware)resolver).setBundleContext(this.bundleContext);
}
/* (non-Javadoc)
@@ -158,8 +162,14 @@
}
protected void publishBeanAsService(Object bean, Properties serviceProperties) {
+ // FIXME:
// TODO : what type should we publish the service as???
- ServiceRegistration sReg = this.bundleContext.registerService(bean.getClass().getName(), bean, serviceProperties);
+ Class[] interfaces = bean.getClass().getInterfaces();
+ ServiceRegistration sReg;
+ if (interfaces != null && interfaces.length > 0)
+ sReg = this.bundleContext.registerService(interfaces[0].getName(), bean, serviceProperties);
+ else
+ sReg = this.bundleContext.registerService(bean.getClass().getName(), bean, serviceProperties);
this.publishedServices.add(sReg);
}
Index: sandbox/src/org/springframework/osgi/service/OsgiServiceInterceptor.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/service/OsgiServiceInterceptor.java,v
retrieving revision 1.1
diff -u -r1.1 OsgiServiceInterceptor.java
--- sandbox/src/org/springframework/osgi/service/OsgiServiceInterceptor.java 10 Mar 2006 16:40:11 -0000 1.1
+++ sandbox/src/org/springframework/osgi/service/OsgiServiceInterceptor.java 22 Mar 2006 09:29:31 -0000
@@ -163,7 +163,7 @@
private synchronized boolean rebindToService() {
log.info("Attempting to rebind to OSGi service of type '" + this.serviceType +
"' using filter '" + this.lookupFilter + "'.");
- ServiceReference[] sRefs = OsgiServiceUtils.getServices(this.bundleContext, this.serviceType, this.lookupFilter);
+ ServiceReference[] sRefs = OsgiServiceUtils.getAllServices(this.bundleContext, this.serviceType, this.lookupFilter);
if (sRefs.length == 0) {
if (log.isInfoEnabled()) {
log.info("No target OSGi service of type '" + this.serviceType +
Index: sandbox/src/org/springframework/osgi/service/OsgiServicePropertiesResolver.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/service/OsgiServicePropertiesResolver.java,v
retrieving revision 1.1
diff -u -r1.1 OsgiServicePropertiesResolver.java
--- sandbox/src/org/springframework/osgi/service/OsgiServicePropertiesResolver.java 10 Mar 2006 16:40:11 -0000 1.1
+++ sandbox/src/org/springframework/osgi/service/OsgiServicePropertiesResolver.java 22 Mar 2006 09:29:31 -0000
@@ -25,7 +25,7 @@
* It is used as a collaborator of OsgiServiceExporter.
*
* @see OsgiServiceExporter
- * @see BeanNameOsgiPropertiesResolver
+ * @see BeanNameServicePropertiesResolver
*
* @author Adrian Colyer
* @since 2.0
Index: sandbox/src/org/springframework/osgi/service/OsgiServiceUtils.java
===================================================================
RCS file: /cvsroot/springframework/spring/sandbox/src/org/springframework/osgi/service/OsgiServiceUtils.java,v
retrieving revision 1.1
diff -u -r1.1 OsgiServiceUtils.java
--- sandbox/src/org/springframework/osgi/service/OsgiServiceUtils.java 10 Mar 2006 16:40:11 -0000 1.1
+++ sandbox/src/org/springframework/osgi/service/OsgiServiceUtils.java 22 Mar 2006 09:29:32 -0000
@@ -46,6 +46,8 @@
public static ServiceReference getService(BundleContext context, Class serviceClass, String filter)
throws NoSuchServiceException, AmbiguousServiceReferenceException, IllegalArgumentException
{
+ // System.err.println("SEARCHING FOR SERVICE: " + serviceClass);
+
try {
ServiceReference[] serviceReferences =
context.getServiceReferences(serviceClass.getName(),filter);
@@ -94,4 +96,26 @@
}
}
+ /**
+ * Return all of the service references for services of the given type and matching
+ * the given filter
+ * @param context
+ * @param serviceClass
+ * @param filter
+ * @return
+ *
+ * @throws IllegalArgumentException if the filter string is non-null and is not well-formed
+ */
+ public static ServiceReference[] getAllServices(BundleContext context, Class serviceClass, String filter)
+ throws IllegalArgumentException
+ {
+ try {
+ ServiceReference[] serviceReferences =
+ context.getAllServiceReferences(serviceClass.getName(),filter);
+ return serviceReferences;
+ }
+ catch (InvalidSyntaxException ex) {
+ throw new IllegalArgumentException(ex.getMessage(),ex);
+ }
+ }
}