Return-Path: Delivered-To: apmail-activemq-commits-archive@www.apache.org Received: (qmail 80536 invoked from network); 18 Sep 2009 02:49:45 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 18 Sep 2009 02:49:45 -0000 Received: (qmail 70736 invoked by uid 500); 18 Sep 2009 02:49:45 -0000 Delivered-To: apmail-activemq-commits-archive@activemq.apache.org Received: (qmail 70665 invoked by uid 500); 18 Sep 2009 02:49:45 -0000 Mailing-List: contact commits-help@activemq.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@activemq.apache.org Delivered-To: mailing list commits@activemq.apache.org Received: (qmail 70656 invoked by uid 99); 18 Sep 2009 02:49:45 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 18 Sep 2009 02:49:45 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 18 Sep 2009 02:49:43 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id C2346238888E; Fri, 18 Sep 2009 02:49:22 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r816444 - in /activemq/trunk: ./ activemq-core/ activemq-core/src/main/java/org/apache/activemq/util/ activemq-core/src/main/java/org/apache/activemq/util/osgi/ Date: Fri, 18 Sep 2009 02:49:22 -0000 To: commits@activemq.apache.org From: chirino@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090918024922.C2346238888E@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: chirino Date: Fri Sep 18 02:49:21 2009 New Revision: 816444 URL: http://svn.apache.org/viewvc?rev=816444&view=rev Log: - refactored FactoryFinder so that it Implementation is pluggable. - made an OSGi friendly strategy for it using a BundleActivator (needs testing) Added: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/ - copied from r816369, servicemix/smx4/specs/trunk/locator/src/main/java/org/apache/servicemix/specs/locator/ Removed: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/OsgiLocator.java Modified: activemq/trunk/activemq-core/pom.xml activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/FactoryFinder.java activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/Activator.java activemq/trunk/pom.xml Modified: activemq/trunk/activemq-core/pom.xml URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/pom.xml?rev=816444&r1=816443&r2=816444&view=diff ============================================================================== --- activemq/trunk/activemq-core/pom.xml (original) +++ activemq/trunk/activemq-core/pom.xml Fri Sep 18 02:49:21 2009 @@ -83,11 +83,18 @@ org.apache.activemq.protobuf activemq-protobuf false - - + + + + + org.osgi + org.osgi.core + + + org.apache.activemq activemq-jaas Modified: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/FactoryFinder.java URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/FactoryFinder.java?rev=816444&r1=816443&r2=816444&view=diff ============================================================================== --- activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/FactoryFinder.java (original) +++ activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/FactoryFinder.java Fri Sep 18 02:49:21 2009 @@ -22,89 +22,129 @@ import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +/** + * + */ public class FactoryFinder { - private final String path; - private final ConcurrentHashMap classMap = new ConcurrentHashMap(); + /** + * The strategey that the FactoryFinder uses to find load and instanciate Objects + * can be chagned out by calling the + * {@link org.apache.activemq.util.FactoryFinder#setObjectFactory(org.apache.activemq.util.FactoryFinder.ObjectFactory)} + * method with a custom implemenation of ObjectFactory. + * + * The default ObjectFactory is typically changed out when running in a specialized container + * enviorment where service discovery needs to be done via the container system. For example, + * in an OSGi scenario. + */ + public interface ObjectFactory { + /** + * @param path the full service path + * @return + */ + public Object create(String path) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException; - public FactoryFinder(String path) { - this.path = path; } /** - * Creates a new instance of the given key - * - * @param key is the key to add to the path to find a text file containing - * the factory name - * @return a newly created instance + * The default implementation of Object factory which works well in standalone applications. */ - public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { - return newInstance(key, null); - } + protected static class StandaloneObjectFactory implements ObjectFactory { + final ConcurrentHashMap classMap = new ConcurrentHashMap(); - public Object newInstance(String key, String propertyPrefix) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { - if (propertyPrefix == null) { - propertyPrefix = ""; + public Object create(final String path) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException { + Class clazz = classMap.get(path); + if (clazz == null) { + clazz = loadClass(loadProperties(path)); + classMap.put(path, clazz); + } + return clazz.newInstance(); } - Class clazz = classMap.get(propertyPrefix + key); - if (clazz == null) { - clazz = newInstance(doFindFactoryProperies(key), propertyPrefix); - classMap.put(propertyPrefix + key, clazz); - } - return clazz.newInstance(); - } + static public Class loadClass(Properties properties) throws ClassNotFoundException, IOException { - private Class newInstance(Properties properties, String propertyPrefix) throws ClassNotFoundException, IOException { + String className = properties.getProperty("class"); + if (className == null) { + throw new IOException("Expected property is missing: class"); + } + Class clazz = null; + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + if (loader != null) { + try { + clazz = loader.loadClass(className); + } catch (ClassNotFoundException e) { + // ignore + } + } + if (clazz == null) { + clazz = FactoryFinder.class.getClassLoader().loadClass(className); + } - String className = properties.getProperty(propertyPrefix + "class"); - if (className == null) { - throw new IOException("Expected property is missing: " + propertyPrefix + "class"); + return clazz; } - Class clazz = null; - ClassLoader loader = Thread.currentThread().getContextClassLoader(); - if (loader != null) { + + static public Properties loadProperties(String uri) throws IOException { + // lets try the thread context class loader first + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + if (classLoader == null) { + classLoader = StandaloneObjectFactory.class.getClassLoader(); + } + InputStream in = classLoader.getResourceAsStream(uri); + if (in == null) { + in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri); + if (in == null) { + throw new IOException("Could not find factory class for resource: " + uri); + } + } + + // lets load the file + BufferedInputStream reader = null; try { - clazz = loader.loadClass(className); - } catch (ClassNotFoundException e) { - // ignore + reader = new BufferedInputStream(in); + Properties properties = new Properties(); + properties.load(reader); + return properties; + } finally { + try { + reader.close(); + } catch (Exception e) { + } } } - if (clazz == null) { - clazz = FactoryFinder.class.getClassLoader().loadClass(className); - } + } + + // ================================================================ + // Class methods and properties + // ================================================================ + private static ObjectFactory objectFactory = new StandaloneObjectFactory(); - return clazz; + public static ObjectFactory getObjectFactory() { + return objectFactory; } - private Properties doFindFactoryProperies(String key) throws IOException { - String uri = path + key; + public static void setObjectFactory(ObjectFactory objectFactory) { + FactoryFinder.objectFactory = objectFactory; + } - // lets try the thread context class loader first - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - if (classLoader == null) { - classLoader = getClass().getClassLoader(); - } - InputStream in = classLoader.getResourceAsStream(uri); - if (in == null) { - in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri); - if (in == null) { - throw new IOException("Could not find factory class for resource: " + uri); - } - } + // ================================================================ + // Instance methods and properties + // ================================================================ + private final String path; - // lets load the file - BufferedInputStream reader = null; - try { - reader = new BufferedInputStream(in); - Properties properties = new Properties(); - properties.load(reader); - return properties; - } finally { - try { - reader.close(); - } catch (Exception e) { - } - } + public FactoryFinder(String path) { + this.path = path; } + + /** + * Creates a new instance of the given key + * + * @param key is the key to add to the path to find a text file containing + * the factory name + * @return a newly created instance + */ + public Object newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { + return objectFactory.create(path+key); + } + + } Modified: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/Activator.java URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/Activator.java?rev=816444&r1=816369&r2=816444&view=diff ============================================================================== --- activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/Activator.java (original) +++ activemq/trunk/activemq-core/src/main/java/org/apache/activemq/util/osgi/Activator.java Fri Sep 18 02:49:21 2009 @@ -14,17 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.servicemix.specs.locator; +package org.apache.activemq.util.osgi; -import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Callable; +import java.io.BufferedReader; +import java.util.Properties; +import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.net.URL; + +import org.apache.activemq.util.FactoryFinder; +import org.apache.activemq.util.FactoryFinder.ObjectFactory; +import org.apache.commons.logging.LogFactory; +import org.apache.commons.logging.Log; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; @@ -32,57 +37,56 @@ import org.osgi.framework.BundleEvent; import org.osgi.framework.SynchronousBundleListener; -public class Activator implements BundleActivator, SynchronousBundleListener { - - private static boolean debug = false; +/** + * An OSGi bundle activator for ActiveMQ which adapts the {@link org.apache.activemq.util.FactoryFinder} + * to the OSGi enviorment. + * + */ +public class Activator implements BundleActivator, SynchronousBundleListener, ObjectFactory { - private ConcurrentMap>> factories = new ConcurrentHashMap>>(); + private static final Log LOG = LogFactory.getLog(Activator.class); + private final ConcurrentHashMap serviceCache = new ConcurrentHashMap(); + private final ConcurrentMap bundleWrappers = new ConcurrentHashMap(); private BundleContext bundleContext; - static { - try { - String prop = System.getProperty("org.apache.servicemix.specs.debug"); - debug = prop != null && !"false".equals(prop); - } catch (Throwable t) { } - } - - /** - *

Output debugging messages.

- * - * @param msg String to print to stderr. - */ - protected void debugPrintln(String msg) { - if (debug) { - System.err.println("Spec(" + bundleContext.getBundle().getBundleId() + "): " + msg); - } - } + // ================================================================ + // BundleActivator interface impl + // ================================================================ public synchronized void start(BundleContext bundleContext) throws Exception { + + // This is how we replace the default FactoryFinder strategy + // with one that is more compatible in an OSGi env. + FactoryFinder.setObjectFactory(this); + + debug("activating"); this.bundleContext = bundleContext; - debugPrintln("activating"); - debugPrintln("adding bundle listener"); - bundleContext.addBundleListener(this); - debugPrintln("checking existing bundles"); + debug("checking existing bundles"); for (Bundle bundle : bundleContext.getBundles()) { if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.STARTING || - bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STOPPING) { + bundle.getState() == Bundle.ACTIVE || bundle.getState() == Bundle.STOPPING) { register(bundle); } } - debugPrintln("activated"); + debug("activated"); } + public synchronized void stop(BundleContext bundleContext) throws Exception { - debugPrintln("deactivating"); + debug("deactivating"); bundleContext.removeBundleListener(this); - while (!factories.isEmpty()) { - unregister(factories.keySet().iterator().next()); + while (!bundleWrappers.isEmpty()) { + unregister(bundleWrappers.keySet().iterator().next()); } - debugPrintln("deactivated"); + debug("deactivated"); this.bundleContext = null; } + // ================================================================ + // SynchronousBundleListener interface impl + // ================================================================ + public void bundleChanged(BundleEvent event) { if (event.getType() == BundleEvent.RESOLVED) { register(event.getBundle()); @@ -92,87 +96,121 @@ } protected void register(final Bundle bundle) { - debugPrintln("checking bundle " + bundle.getBundleId()); - Map> map = factories.get(bundle.getBundleId()); - Enumeration e = bundle.findEntries("META-INF/services/", "*", false); - if (e != null) { - while (e.hasMoreElements()) { - final URL u = (URL) e.nextElement(); - final String url = u.toString(); - if (url.endsWith("/")) { - continue; - } - final String factoryId = url.substring(url.lastIndexOf("/") + 1); - if (map == null) { - map = new HashMap>(); - factories.put(bundle.getBundleId(), map); - } - map.put(factoryId, new BundleFactoryLoader(factoryId, u, bundle)); - } - } - if (map != null) { - for (Map.Entry> entry : map.entrySet()) { - debugPrintln("registering service for key " + entry.getKey() + "with value " + entry.getValue()); - OsgiLocator.register(entry.getKey(), entry.getValue()); - } + debug("checking bundle " + bundle.getBundleId()); + if( !isImportingUs(bundle) ) { + debug("The bundle does not import us: "+ bundle.getBundleId()); + return; } + bundleWrappers.put(bundle.getBundleId(), new BundleWrapper(bundle)); } + /** + * When bundles unload.. we remove them thier cached Class entries from the + * serviceCache. Future service lookups for the service will fail. + * + * TODO: consider a way to get the Broker release any references to + * instances of the service. + * + * @param bundleId + */ protected void unregister(long bundleId) { - Map> map = factories.remove(bundleId); - if (map != null) { - for (Map.Entry> entry : map.entrySet()) { - debugPrintln("unregistering service for key " + entry.getKey() + "with value " + entry.getValue()); - OsgiLocator.unregister(entry.getKey(), entry.getValue()); + BundleWrapper bundle = bundleWrappers.remove(bundleId); + if (bundle != null) { + for (String path : bundle.cachedServices) { + debug("unregistering service for key: " +path ); + serviceCache.remove(path); } } } - private class BundleFactoryLoader implements Callable { - private final String factoryId; - private final URL u; - private final Bundle bundle; + // ================================================================ + // ObjectFactory interface impl + // ================================================================ + + public Object create(String path) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { + Class clazz = serviceCache.get(path); + if (clazz == null) { + StringBuffer warnings = new StringBuffer(); + // We need to look for a bundle that has that class. + int wrrningCounter=1; + for (BundleWrapper wrapper : bundleWrappers.values()) { + URL resource = wrapper.bundle.getResource(path); + if( resource == null ) { + continue; + } - public BundleFactoryLoader(String factoryId, URL u, Bundle bundle) { - this.factoryId = factoryId; - this.u = u; - this.bundle = bundle; + Properties properties = loadProperties(resource); + + String className = properties.getProperty("class"); + if (className == null) { + warnings.append("("+(wrrningCounter++)+") Invalid sevice file in bundle "+wrapper+": 'class' property not defined."); + continue; + } + + try { + clazz = wrapper.bundle.loadClass(className); + } catch (ClassNotFoundException e) { + warnings.append("("+(wrrningCounter++)+") Bundle "+wrapper+" could not load "+className+": "+e); + continue; + } + + // Yay.. the class was found. Now cache it. + serviceCache.put(path, clazz); + wrapper.cachedServices.add(path); + break; + } + + if( clazz == null ) { + // Since OSGi is such a tricky enviorment to work in.. lets give folks the + // most information we can in the error message. + String msg = "Service not found: '" + path + "'"; + if (warnings.length()!= 0) { + msg += ", "+warnings; + } + throw new IOException(msg); + } } + return clazz.newInstance(); + } + + // ================================================================ + // Internal Helper Methods + // ================================================================ + + private void debug(Object msg) { + LOG.debug(msg); + } - public Class call() throws Exception { + private Properties loadProperties(URL resource) throws IOException { + InputStream in = resource.openStream(); + try { + BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); + Properties properties = new Properties(); + properties.load(in); + return properties; + } finally { try { - debugPrintln("creating factory for key: " + factoryId); - BufferedReader br = new BufferedReader(new InputStreamReader(u.openStream(), "UTF-8")); - String factoryClassName = br.readLine(); - br.close(); - debugPrintln("factory implementation: " + factoryClassName); - return bundle.loadClass(factoryClassName); + in.close(); } catch (Exception e) { - debugPrintln("exception caught while creating factory: " + e); - throw e; - } catch (Error e) { - debugPrintln("error caught while creating factory: " + e); - throw e; } } + } - @Override - public String toString() { - return u.toString(); - } - - @Override - public int hashCode() { - return u.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof BundleFactoryLoader) { - return u.equals(((BundleFactoryLoader) obj).u); - } else { - return false; - } + private boolean isImportingUs(Bundle bundle) { + try { + // If that bundle can load our classes.. then it must be importing us. + return bundle.loadClass(Activator.class.getName())==Activator.class; + } catch (ClassNotFoundException e) { + return false; + } + } + + private static class BundleWrapper { + private final Bundle bundle; + private final ArrayList cachedServices = new ArrayList(); + + public BundleWrapper(Bundle bundle) { + this.bundle = bundle; } } } Modified: activemq/trunk/pom.xml URL: http://svn.apache.org/viewvc/activemq/trunk/pom.xml?rev=816444&r1=816443&r2=816444&view=diff ============================================================================== --- activemq/trunk/pom.xml (original) +++ activemq/trunk/pom.xml Fri Sep 18 02:49:21 2009 @@ -401,6 +401,13 @@
+ org.osgi + org.osgi.core + 4.1.0 + provided + + + org.apache.hadoop.zookeeper zookeeper 3.0.0