You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2015/05/24 19:02:38 UTC
svn commit: r1681493 - in /chemistry/opencmis/trunk:
chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/
chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/c...
Author: fmui
Date: Sun May 24 17:02:37 2015
New Revision: 1681493
URL: http://svn.apache.org/r1681493
Log:
CMIS-878: loading classes from OSGi bundles
Modified:
chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/Activator.java
chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/ClassLoaderUtil.java
Modified: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/Activator.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/Activator.java?rev=1681493&r1=1681492&r2=1681493&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/Activator.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/osgi/Activator.java Sun May 24 17:02:37 2015
@@ -18,22 +18,52 @@
*/
package org.apache.chemistry.opencmis.client.osgi;
+import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Hashtable;
+import java.util.List;
import org.apache.chemistry.opencmis.client.api.SessionFactory;
import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
+import org.apache.chemistry.opencmis.commons.impl.ClassLoaderUtil;
+import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
import org.osgi.framework.Constants;
+import org.osgi.framework.SynchronousBundleListener;
+import org.osgi.framework.wiring.BundleWiring;
/**
* OSGi Bundle activator for the OpenCMIS client which registers an instance of
* the {@link SessionFactory} in the OSGi service registry.
*/
-public class Activator implements BundleActivator {
+public class Activator implements BundleActivator, SynchronousBundleListener {
+
+ /**
+ * Represents the manifest header indicating this bundle holds an OpenCMIS
+ * SPI implementation
+ */
+ private static final String OPENCMIS_SPI_HEADER = "OpenCMIS-SPI";
+
+ private BundleContext bundleContext;
+
+ @Override
+ public void start(final BundleContext context) {
+
+ this.bundleContext = context;
+
+ // add bundle listener
+ context.addBundleListener(this);
+
+ // check existing bundles in framework for chemistry SPIs
+ for (Bundle bundle : context.getBundles()) {
+ if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.STARTING
+ || bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STOPPING) {
+ register(bundle);
+ }
+ }
- public void start(BundleContext context) {
// register the MetaTypeService now, that we are ready
Dictionary<String, String> props = new Hashtable<String, String>();
props.put(Constants.SERVICE_DESCRIPTION, "Apache Chemistry OpenCMIS Client Session Factory");
@@ -43,7 +73,72 @@ public class Activator implements Bundle
context.registerService(SessionFactory.class.getName(), sessionFactory, props);
}
- public void stop(BundleContext context) {
+ @Override
+ public void stop(final BundleContext context) {
+ // remove bundle listener
+ context.removeBundleListener(this);
+
+ // forget our bundle context
+ bundleContext = null;
+
+ // unregister all classloaders
+ ClassLoaderUtil.unregisterAllBundleClassLoaders();
+
// The SessionFactory service will be unregistered automatically
}
+
+ @Override
+ public void bundleChanged(final BundleEvent event) {
+ // bundle context might not yet been initialized
+ synchronized (this) {
+ if (bundleContext == null) {
+ return;
+ }
+ }
+
+ if (event.getType() == BundleEvent.RESOLVED) {
+ register(event.getBundle());
+ } else if (event.getType() == BundleEvent.UNRESOLVED || event.getType() == BundleEvent.UNINSTALLED) {
+ unregister(event.getBundle().getBundleId());
+ }
+ }
+
+ private void register(final Bundle bundle) {
+ BundleWiring bundleWiring = bundle.adapt(BundleWiring.class);
+ if (bundleWiring == null) {
+ return;
+ }
+
+ ClassLoader classLoader = bundleWiring.getClassLoader();
+ if (classLoader == null) {
+ return;
+ }
+
+ List<String> classes = getOpenCmisSpiHeader(bundle);
+ if (classes != null) {
+ ClassLoaderUtil.registerBundleClassLoader(bundle.getBundleId(), classLoader, classes);
+ }
+ }
+
+ private void unregister(final long bundleId) {
+ ClassLoaderUtil.unregisterBundleClassLoader(bundleId);
+ }
+
+ private List<String> getOpenCmisSpiHeader(final Bundle bundle) {
+ String spiHeader = (String) bundle.getHeaders().get(OPENCMIS_SPI_HEADER);
+ if (spiHeader == null) {
+ return null;
+ }
+
+ List<String> headerValues = new ArrayList<String>();
+
+ String[] split = spiHeader.split(",");
+ for (String className : split) {
+ if (className != null && !className.trim().isEmpty()) {
+ headerValues.add(className.trim());
+ }
+ }
+
+ return headerValues;
+ }
}
Modified: chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/ClassLoaderUtil.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/ClassLoaderUtil.java?rev=1681493&r1=1681492&r2=1681493&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/ClassLoaderUtil.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-commons/chemistry-opencmis-commons-impl/src/main/java/org/apache/chemistry/opencmis/commons/impl/ClassLoaderUtil.java Sun May 24 17:02:37 2015
@@ -18,24 +18,126 @@
*/
package org.apache.chemistry.opencmis.commons.impl;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
public final class ClassLoaderUtil {
+ private static ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
+ private static Map<Long, Map<String, ClassLoader>> CLASSLOADER_MAP = null;
+
private ClassLoaderUtil() {
}
/**
+ * Registers a bundle classloader.
+ */
+ public static void registerBundleClassLoader(long bundleId, ClassLoader classLoader, List<String> classes) {
+ if (classLoader == null || classes == null || classes.isEmpty()) {
+ return;
+ }
+
+ Map<String, ClassLoader> bundleMap = new HashMap<String, ClassLoader>();
+
+ for (String clazz : classes) {
+ if (clazz != null && !clazz.isEmpty()) {
+ bundleMap.put(clazz, classLoader);
+ }
+ }
+
+ if (bundleMap.isEmpty()) {
+ return;
+ }
+
+ LOCK.writeLock().lock();
+ try {
+ if (CLASSLOADER_MAP == null) {
+ CLASSLOADER_MAP = new HashMap<Long, Map<String, ClassLoader>>();
+ }
+
+ CLASSLOADER_MAP.put(bundleId, bundleMap);
+ } finally {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Unregisters a bundle classloader.
+ */
+ public static void unregisterBundleClassLoader(long bundleId) {
+ LOCK.writeLock().lock();
+ try {
+ if (CLASSLOADER_MAP != null) {
+ CLASSLOADER_MAP.remove(bundleId);
+ }
+ } finally {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Unregisters all bundle classloaders.
+ */
+ public static void unregisterAllBundleClassLoaders() {
+ LOCK.writeLock().lock();
+ try {
+ CLASSLOADER_MAP = null;
+ } finally {
+ LOCK.writeLock().unlock();
+ }
+ }
+
+ /**
* Loads a class. If the context class loader is set, it is used.
*/
public static Class<?> loadClass(String className) throws ClassNotFoundException {
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == null) {
- return loadClass(className, null);
+ try {
+ return loadClass(className, null);
+ } catch (ClassNotFoundException cnf) {
+ return loadClassWithRegisteredClassLoaders(className);
+ }
}
try {
return loadClass(className, ccl);
} catch (ClassNotFoundException cnf) {
- return loadClass(className, null);
+ try {
+ return loadClass(className, null);
+ } catch (ClassNotFoundException cnf2) {
+ return loadClassWithRegisteredClassLoaders(className);
+ }
+ }
+ }
+
+ /**
+ * Loads a class with the reigistered class loaders.
+ */
+ private static Class<?> loadClassWithRegisteredClassLoaders(String className) throws ClassNotFoundException {
+ if (className == null) {
+ throw new ClassNotFoundException("Class name is null!");
+ }
+
+ LOCK.readLock().lock();
+ try {
+ if (CLASSLOADER_MAP == null) {
+ throw new ClassNotFoundException();
+ }
+
+ for (Map<String, ClassLoader> clm : CLASSLOADER_MAP.values()) {
+ for (Map.Entry<String, ClassLoader> cle : clm.entrySet()) {
+ if (cle.getKey().equals(className)) {
+ return loadClass(className, cle.getValue());
+ }
+ }
+ }
+
+ throw new ClassNotFoundException();
+ } finally {
+ LOCK.readLock().unlock();
}
}