You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2010/05/28 09:52:36 UTC
svn commit: r949127 [2/5] - in /camel/trunk: components/
components/camel-blueprint/
components/camel-blueprint/src/main/java/org/apache/camel/blueprint/
components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/
components/camel-blue...
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/Activator.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/Activator.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/Activator.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/Activator.java Fri May 28 07:52:33 2010
@@ -0,0 +1,306 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.camel.Component;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.core.osgi.tracker.BundleTracker;
+import org.apache.camel.core.osgi.tracker.BundleTrackerCustomizer;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.util.IOHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+
+public class Activator implements BundleActivator, BundleTrackerCustomizer {
+ public static final String META_INF_TYPE_CONVERTER = "META-INF/services/org/apache/camel/TypeConverter";
+ public static final String META_INF_COMPONENT = "META-INF/services/org/apache/camel/component/";
+ public static final String META_INF_LANGUAGE = "META-INF/services/org/apache/camel/language/";
+ public static final String META_INF_LANGUAGE_RESOLVER = "META-INF/services/org/apache/camel/language/resolver/";
+
+ private static final transient Log LOG = LogFactory.getLog(Activator.class);
+ private static final Map<String, ComponentEntry> COMPONENTS = new ConcurrentHashMap<String, ComponentEntry>();
+ private static final Map<URL, TypeConverterEntry> TYPE_CONVERTERS = new ConcurrentHashMap<URL, TypeConverterEntry>();
+ private static final Map<String, ComponentEntry> LANGUAGES = new ConcurrentHashMap<String, ComponentEntry>();
+ private static final Map<String, ComponentEntry> LANGUAGE_RESOLVERS = new ConcurrentHashMap<String, ComponentEntry>();
+ private static Bundle bundle;
+
+ private BundleTracker tracker;
+
+ private class ComponentEntry {
+ Bundle bundle;
+ String path;
+ String name;
+ Class type;
+ }
+
+ public class TypeConverterEntry {
+ Bundle bundle;
+ URL resource;
+ Set<String> converterPackages;
+ }
+
+ public Object addingBundle(Bundle bundle, BundleEvent event) {
+ modifiedBundle(bundle, event, null);
+ return bundle;
+ }
+
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Bundle started: " + bundle.getSymbolicName());
+ }
+ mayBeAddComponentAndLanguageFor(bundle);
+ mayBeAddTypeConverterFor(bundle);
+ }
+
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Bundle stopped: " + bundle.getSymbolicName());
+ }
+ mayBeRemoveComponentAndLanguageFor(bundle);
+ mayBeRemoveTypeConverterFor(bundle);
+ }
+
+ protected void addComponentEntry(String entryPath, Bundle bundle, Map<String, ComponentEntry> entries, Class clazz) {
+ // Check bundle compatibility
+ try {
+ if (bundle.loadClass(clazz.getName()) != clazz) {
+ return;
+ }
+ } catch (Throwable t) {
+ return;
+ }
+ Enumeration e = bundle.getEntryPaths(entryPath);
+ if (e != null) {
+ while (e.hasMoreElements()) {
+ String path = (String)e.nextElement();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found entry: " + path + " in bundle " + bundle.getSymbolicName());
+ }
+ ComponentEntry entry = new ComponentEntry();
+ entry.bundle = bundle;
+ entry.path = path;
+ entry.name = path.substring(path.lastIndexOf("/") + 1);
+ entries.put(entry.name, entry);
+ }
+ }
+
+ }
+
+ protected void mayBeAddComponentAndLanguageFor(Bundle bundle) {
+ addComponentEntry(META_INF_COMPONENT, bundle, COMPONENTS, Component.class);
+ addComponentEntry(META_INF_LANGUAGE, bundle, LANGUAGES, Language.class);
+ addComponentEntry(META_INF_LANGUAGE_RESOLVER, bundle, LANGUAGE_RESOLVERS, LanguageResolver.class);
+ }
+
+ protected void mayBeAddTypeConverterFor(Bundle bundle) {
+ // Check bundle compatibility
+ try {
+ Class clazz = TypeConverter.class;
+ if (bundle.loadClass(clazz.getName()) != clazz) {
+ return;
+ }
+ } catch (Throwable t) {
+ return;
+ }
+ try {
+ Enumeration e = bundle.getResources(META_INF_TYPE_CONVERTER);
+ if (e != null) {
+ while (e.hasMoreElements()) {
+ URL resource = (URL)e.nextElement();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found entry: " + resource + " in bundle " + bundle.getSymbolicName());
+ }
+ TypeConverterEntry entry = new TypeConverterEntry();
+ entry.bundle = bundle;
+ entry.resource = resource;
+ entry.converterPackages = getConverterPackages(resource);
+ TYPE_CONVERTERS.put(resource, entry);
+ }
+ }
+ } catch (IOException ignore) {
+ // can't find the resource
+ }
+ }
+
+ protected void mayBeRemoveComponentAndLanguageFor(Bundle bundle) {
+ removeComponentEntry(bundle, COMPONENTS);
+ removeComponentEntry(bundle, LANGUAGES);
+ removeComponentEntry(bundle, LANGUAGE_RESOLVERS);
+ }
+
+ protected void removeComponentEntry(Bundle bundle, Map<String, ComponentEntry> entries) {
+ ComponentEntry[] entriesArray = entries.values().toArray(new ComponentEntry[0]);
+ for (ComponentEntry entry : entriesArray) {
+ if (entry.bundle == bundle) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Removing entry: " + entry.path + " in bundle " + bundle.getSymbolicName());
+ }
+ entries.remove(entry.name);
+ }
+ }
+ }
+
+ protected void mayBeRemoveTypeConverterFor(Bundle bundle) {
+ TypeConverterEntry[] entriesArray = TYPE_CONVERTERS.values().toArray(new TypeConverterEntry[0]);
+ for (TypeConverterEntry entry : entriesArray) {
+ if (entry.bundle == bundle) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Removing entry: " + entry.resource + " in bundle " + bundle.getSymbolicName());
+ }
+ COMPONENTS.remove(entry.resource);
+ }
+ }
+ }
+
+ public void start(BundleContext context) throws Exception {
+ LOG.info("Camel activator starting");
+
+ bundle = context.getBundle();
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using bundle: " + bundle);
+ }
+
+ tracker = new BundleTracker(context, Bundle.ACTIVE, this);
+ tracker.open();
+ LOG.info("Camel activator started");
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ LOG.info("Camel activator stopping");
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Removing Camel bundles");
+ }
+ tracker.close();
+ LOG.info("Camel activator stopped");
+ }
+
+ protected Set<String> getConverterPackages(URL resource) {
+ Set<String> packages = new HashSet<String>();
+ if (resource != null) {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(resource.openStream()));
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ line = line.trim();
+ if (line.startsWith("#") || line.length() == 0) {
+ continue;
+ }
+ tokenize(packages, line);
+ }
+ } catch (Exception ignore) {
+ // Do nothing here
+ } finally {
+ if (reader != null) {
+ IOHelper.close(reader, null, LOG);
+ }
+ }
+ }
+ return packages;
+ }
+
+ protected void tokenize(Set<String> packages, String line) {
+ StringTokenizer iter = new StringTokenizer(line, ",");
+ while (iter.hasMoreTokens()) {
+ String name = iter.nextToken().trim();
+ if (name.length() > 0) {
+ packages.add(name);
+ }
+ }
+ }
+
+ protected static Bundle getBundle() {
+ return bundle;
+ }
+
+ protected static TypeConverterEntry[] getTypeConverterEntries() {
+ Collection<TypeConverterEntry> entries = TYPE_CONVERTERS.values();
+ return entries.toArray(new TypeConverterEntry[entries.size()]);
+ }
+
+ public static Class getComponent(String name) throws Exception {
+ LOG.trace("Finding Component: " + name);
+ return getClassFromEntries(name, COMPONENTS);
+ }
+
+ public static Class getLanguage(String name) throws Exception {
+ LOG.trace("Finding Language: " + name);
+ return getClassFromEntries(name, LANGUAGES);
+ }
+
+ public static Class getLanguageResolver(String name) throws Exception {
+ LOG.trace("Finding LanguageResolver: " + name);
+ return getClassFromEntries(name, LANGUAGE_RESOLVERS);
+ }
+
+ protected static Class getClassFromEntries(String name, Map<String, ComponentEntry> entries) throws Exception {
+ ComponentEntry entry = entries.get(name);
+ if (entry == null) {
+ return null;
+ }
+ if (entry.type == null) {
+ URL url = entry.bundle.getEntry(entry.path);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("The entry " + name + "'s url is" + url);
+ }
+ // lets load the file
+ Properties properties = new Properties();
+ BufferedInputStream reader = null;
+ try {
+ reader = new BufferedInputStream(url.openStream());
+ properties.load(reader);
+ } finally {
+ try {
+ if (reader != null) {
+ reader.close();
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ String classname = (String)properties.get("class");
+ entry.type = entry.bundle.loadClass(classname);
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found entry: " + name + " via type: " + entry.type.getName());
+ }
+ return entry.type;
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/CompositeRegistry.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/CompositeRegistry.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/CompositeRegistry.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/CompositeRegistry.java Fri May 28 07:52:33 2010
@@ -0,0 +1,78 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.spi.Registry;
+
+/**
+ * This registry will look up the object with the sequence of the registry list until it finds the Object.
+ */
+public class CompositeRegistry implements Registry {
+ private List<Registry> registryList;
+
+ public CompositeRegistry() {
+ registryList = new ArrayList<Registry>();
+ }
+
+ public CompositeRegistry(List<Registry> registries) {
+ registryList = registries;
+ }
+
+ public void addRegistry(Registry registry) {
+ registryList.add(registry);
+ }
+
+ public <T> T lookup(String name, Class<T> type) {
+ T answer = null;
+ for (Registry registry : registryList) {
+ answer = registry.lookup(name, type);
+ if (answer != null) {
+ break;
+ }
+ }
+ return answer;
+ }
+
+ public Object lookup(String name) {
+ Object answer = null;
+ for (Registry registry : registryList) {
+ answer = registry.lookup(name);
+ if (answer != null) {
+ break;
+ }
+ }
+ return answer;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> Map<String, T> lookupByType(Class<T> type) {
+ Map<String, T> answer = Collections.EMPTY_MAP;
+ for (Registry registry : registryList) {
+ answer = registry.lookupByType(type);
+ if (answer != Collections.EMPTY_MAP) {
+ break;
+ }
+ }
+ return answer;
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiAnnotationTypeConverterLoader.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiAnnotationTypeConverterLoader.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiAnnotationTypeConverterLoader.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiAnnotationTypeConverterLoader.java Fri May 28 07:52:33 2010
@@ -0,0 +1,52 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.util.Set;
+
+import org.apache.camel.Converter;
+import org.apache.camel.impl.converter.AnnotationTypeConverterLoader;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class OsgiAnnotationTypeConverterLoader extends AnnotationTypeConverterLoader {
+
+ private static final transient Log LOG = LogFactory.getLog(OsgiAnnotationTypeConverterLoader.class);
+
+ public OsgiAnnotationTypeConverterLoader(PackageScanClassResolver packageScanClassResolver) {
+ super(packageScanClassResolver);
+ }
+
+ @Override
+ public void load(TypeConverterRegistry registry) throws Exception {
+ for (Activator.TypeConverterEntry entry : Activator.getTypeConverterEntries()) {
+ OsgiPackageScanClassResolver resolver = new OsgiPackageScanClassResolver(entry.bundle);
+ String[] packages = entry.converterPackages.toArray(new String[entry.converterPackages.size()]);
+ Set<Class<?>> classes = resolver.findAnnotated(Converter.class, packages);
+ for (Class<?> type : classes) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Loading converter class: " + ObjectHelper.name(type));
+ }
+ loadConverterMethods(registry, type);
+ }
+ }
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java Fri May 28 07:52:33 2010
@@ -0,0 +1,94 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.util.List;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.converter.AnnotationTypeConverterLoader;
+import org.apache.camel.impl.converter.DefaultTypeConverter;
+import org.apache.camel.impl.converter.TypeConverterLoader;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.BundleContext;
+
+public final class OsgiCamelContextHelper {
+ private static final transient Log LOG = LogFactory.getLog(OsgiCamelContextHelper.class);
+
+ private OsgiCamelContextHelper() {
+ // helper class
+ }
+
+ public static DefaultTypeConverter createTypeConverter(DefaultCamelContext context) {
+
+ DefaultTypeConverter answer = new DefaultTypeConverter(context.getPackageScanClassResolver(), context.getInjector(), context.getDefaultFactoryFinder());
+ List<TypeConverterLoader> typeConverterLoaders = answer.getTypeConverterLoaders();
+
+ // Remove the AnnotationTypeConverterLoader
+ TypeConverterLoader atLoader = null;
+ for (TypeConverterLoader loader : typeConverterLoaders) {
+ if (loader instanceof AnnotationTypeConverterLoader) {
+ atLoader = loader;
+ break;
+ }
+ }
+ if (atLoader != null) {
+ typeConverterLoaders.remove(atLoader);
+ }
+
+ // add our osgi annotation loader
+ typeConverterLoaders.add(new OsgiAnnotationTypeConverterLoader(context.getPackageScanClassResolver()));
+ context.setTypeConverterRegistry(answer);
+ return answer;
+ }
+
+ public static void osgiUpdate(DefaultCamelContext camelContext, BundleContext bundleContext) {
+ if (bundleContext != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Using OSGi resolvers");
+ }
+ updateRegistry(camelContext, bundleContext);
+ LOG.debug("Using the OsgiClassResolver");
+ camelContext.setClassResolver(new OsgiClassResolver(bundleContext));
+ LOG.debug("Using OsgiFactoryFinderResolver");
+ camelContext.setFactoryFinderResolver(new OsgiFactoryFinderResolver());
+ LOG.debug("Using OsgiPackageScanClassResolver");
+ camelContext.setPackageScanClassResolver(new OsgiPackageScanClassResolver(bundleContext));
+ LOG.debug("Using OsgiComponentResolver");
+ camelContext.setComponentResolver(new OsgiComponentResolver());
+ LOG.debug("Using OsgiLanguageResolver");
+ camelContext.setLanguageResolver(new OsgiLanguageResolver());
+ } else {
+ // TODO: should we not thrown an exception to not allow it to startup
+ LOG.warn("BundleContext not set, cannot run in OSGI container");
+ }
+ }
+
+ public static void updateRegistry(DefaultCamelContext camelContext, BundleContext bundleContext) {
+ ObjectHelper.notNull(bundleContext, "BundleContext");
+ LOG.debug("Setting the OSGi ServiceRegistry");
+ OsgiServiceRegistry osgiServiceRegistry = new OsgiServiceRegistry(bundleContext);
+ // Need to clean up the OSGi service when camel context is closed.
+ camelContext.addLifecycleStrategy(osgiServiceRegistry);
+ CompositeRegistry compositeRegistry = new CompositeRegistry();
+ compositeRegistry.addRegistry(osgiServiceRegistry);
+ compositeRegistry.addRegistry(camelContext.getRegistry());
+ camelContext.setRegistry(compositeRegistry);
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java Fri May 28 07:52:33 2010
@@ -0,0 +1,104 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.camel.impl.DefaultClassResolver;
+import org.apache.camel.util.CastUtils;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/* Using the bundle of CamelContext to load the class */
+public class OsgiClassResolver extends DefaultClassResolver {
+ private static final transient Log LOG = LogFactory.getLog(OsgiClassResolver.class);
+
+ public BundleContext bundleContext;
+
+ public OsgiClassResolver(BundleContext context) {
+ this.bundleContext = context;
+ }
+
+ public Class<?> resolveClass(String name) {
+ return loadClass(name, bundleContext.getBundle());
+ }
+
+ public <T> Class<T> resolveClass(String name, Class<T> type) {
+ return CastUtils.cast(resolveClass(name));
+ }
+
+ public InputStream loadResourceAsStream(String uri) {
+ ObjectHelper.notEmpty(uri, "uri");
+ URL url = loadResourceAsURL(uri);
+ InputStream answer = null;
+ if (url != null) {
+ try {
+ answer = url.openStream();
+ } catch (IOException ex) {
+ LOG.error("Cannot load resource: " + uri, ex);
+ }
+ }
+ return answer;
+ }
+
+ public URL loadResourceAsURL(String uri) {
+ ObjectHelper.notEmpty(uri, "uri");
+ URL url = null;
+ for (Bundle bundle : bundleContext.getBundles()) {
+ url = bundle.getEntry(uri);
+ if (url != null) {
+ break;
+ }
+ }
+ return url;
+ }
+
+ protected Class<?> loadClass(String name, Bundle loader) {
+ ObjectHelper.notEmpty(name, "name");
+ Class<?> answer = null;
+ // Try to use the camel context's bundle's classloader to load the class
+ if (loader != null) {
+ try {
+ answer = loader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Cannot load class: " + name + " using classloader: " + loader, e);
+ }
+ }
+ }
+ // Load the class with bundle, if there are more than one version of the class the first one will be load
+ if (answer == null) {
+ for (Bundle bundle : bundleContext.getBundles()) {
+ try {
+ answer = bundle.loadClass(name);
+ if (answer != null) {
+ break;
+ }
+ } catch (Exception e) {
+ // do nothing here
+ }
+ }
+ }
+ return answer;
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java Fri May 28 07:52:33 2010
@@ -0,0 +1,69 @@
+/**
+ * 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.camel.core.osgi;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class OsgiComponentResolver implements ComponentResolver {
+
+ private static final transient Log LOG = LogFactory.getLog(OsgiComponentResolver.class);
+
+ @SuppressWarnings("unchecked")
+ public Component resolveComponent(String name, CamelContext context) throws Exception {
+ Object bean = null;
+ try {
+ bean = context.getRegistry().lookup(name);
+ if (bean != null && LOG.isDebugEnabled()) {
+ LOG.debug("Found component: " + name + " in registry: " + bean);
+ }
+ } catch (Exception e) {
+ LOG.debug("Ignored error looking up bean: " + name + ". Error: " + e);
+ }
+ if (bean != null) {
+ if (bean instanceof Component) {
+ return (Component)bean;
+ }
+ // we do not throw the exception here and try to auto create a component
+ }
+
+ // Check in OSGi bundles
+ Class type;
+ try {
+ type = getComponent(name);
+ } catch (Throwable e) {
+ throw new IllegalArgumentException("Invalid URI, no Component registered for scheme : " + name, e);
+ }
+ if (type == null) {
+ return null;
+ }
+
+ if (Component.class.isAssignableFrom(type)) {
+ return (Component)context.getInjector().newInstance(type);
+ } else {
+ throw new IllegalArgumentException("Type is not a Component implementation. Found: " + type.getName());
+ }
+ }
+
+ protected Class getComponent(String name) throws Exception {
+ return Activator.getComponent(name);
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java Fri May 28 07:52:33 2010
@@ -0,0 +1,35 @@
+/**
+ * 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.camel.core.osgi;
+
+import org.apache.camel.TypeConverter;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.osgi.framework.BundleContext;
+
+public class OsgiDefaultCamelContext extends DefaultCamelContext {
+
+ public OsgiDefaultCamelContext(BundleContext bundleContext) {
+ super();
+ OsgiCamelContextHelper.osgiUpdate(this, bundleContext);
+ }
+
+ @Override
+ protected TypeConverter createTypeConverter() {
+ return OsgiCamelContextHelper.createTypeConverter(this);
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java Fri May 28 07:52:33 2010
@@ -0,0 +1,106 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Properties;
+
+import org.apache.camel.NoFactoryAvailableException;
+import org.apache.camel.impl.DefaultFactoryFinder;
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.util.IOHelper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class OsgiFactoryFinder extends DefaultFactoryFinder {
+
+ public OsgiFactoryFinder(ClassResolver classResolver, String resourcePath) {
+ super(classResolver, resourcePath);
+ }
+
+ private class BundleEntry {
+ URL url;
+ Bundle bundle;
+ }
+
+ @Override
+ public Class<?> findClass(String key, String propertyPrefix) throws ClassNotFoundException, IOException {
+ if (propertyPrefix == null) {
+ propertyPrefix = "";
+ }
+
+ Class clazz = classMap.get(propertyPrefix + key);
+ if (clazz == null) {
+ BundleEntry entry = getResource(key);
+ if (entry != null) {
+ URL url = entry.url;
+ InputStream in = url.openStream();
+ // lets load the file
+ BufferedInputStream reader = null;
+ try {
+ reader = new BufferedInputStream(in);
+ Properties properties = new Properties();
+ properties.load(reader);
+ String className = properties.getProperty(propertyPrefix + "class");
+ if (className == null) {
+ throw new IOException("Expected property is missing: " + propertyPrefix + "class");
+ }
+ clazz = entry.bundle.loadClass(className);
+ classMap.put(propertyPrefix + key, clazz);
+ } finally {
+ IOHelper.close(reader, key, null);
+ IOHelper.close(in, key, null);
+ }
+ } else {
+ throw new NoFactoryAvailableException(propertyPrefix + key);
+ }
+ }
+
+ return clazz;
+ }
+
+
+ public BundleEntry getResource(String name) {
+ BundleEntry entry = null;
+ Bundle[] bundles = null;
+ BundleContext bundleContext = Activator.getBundle().getBundleContext();
+ if (bundleContext == null) {
+ // Bundle is not in STARTING|ACTIVE|STOPPING state
+ // (See OSGi 4.1 spec, section 4.3.17)
+ bundles = new Bundle[] {Activator.getBundle()};
+ } else {
+ bundles = bundleContext.getBundles();
+ }
+
+ URL url;
+ for (Bundle bundle : bundles) {
+ url = bundle.getEntry(getResourcePath() + name);
+ if (url != null) {
+ entry = new BundleEntry();
+ entry.url = url;
+ entry.bundle = bundle;
+ break;
+ }
+ }
+
+ return entry;
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java Fri May 28 07:52:33 2010
@@ -0,0 +1,36 @@
+/**
+ * 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.camel.core.osgi;
+
+import org.apache.camel.spi.ClassResolver;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.FactoryFinderResolver;
+
+/**
+ * @version $Revision: 785599 $
+ */
+public class OsgiFactoryFinderResolver implements FactoryFinderResolver {
+
+ public FactoryFinder resolveDefaultFactoryFinder(ClassResolver classResolver) {
+ return resolveFactoryFinder(classResolver, "META-INF/services/org/apache/camel/");
+ }
+
+ public FactoryFinder resolveFactoryFinder(ClassResolver classResolver, String resourcePath) {
+ return new OsgiFactoryFinder(classResolver, resourcePath);
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java Fri May 28 07:52:33 2010
@@ -0,0 +1,42 @@
+/**
+ * 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.camel.core.osgi;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultLanguageResolver;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class OsgiLanguageResolver extends DefaultLanguageResolver {
+ private static final transient Log LOG = LogFactory.getLog(OsgiLanguageResolver.class);
+
+ @Override
+ protected Log getLog() {
+ return LOG;
+ }
+
+ @Override
+ protected Class<?> findLanguage(String name, CamelContext context) throws Exception {
+ return Activator.getLanguage(name);
+ }
+
+ @Override
+ protected Class<?> findLanguageResolver(String name, CamelContext context) throws Exception {
+ return Activator.getLanguageResolver(name);
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java Fri May 28 07:52:33 2010
@@ -0,0 +1,174 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.camel.impl.DefaultPackageScanClassResolver;
+import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
+import org.apache.camel.spi.PackageScanFilter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class OsgiPackageScanClassResolver extends DefaultPackageScanClassResolver {
+ private Bundle bundle;
+
+ public OsgiPackageScanClassResolver(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public OsgiPackageScanClassResolver(BundleContext context) {
+ bundle = context.getBundle();
+ }
+
+ public Set<ClassLoader> getClassLoaders() {
+ Set<ClassLoader> classLoaders = super.getClassLoaders();
+ // Using the Activator's bundle to make up a class loader
+ ClassLoader osgiLoader = new BundleDelegatingClassLoader(bundle);
+ classLoaders.add(osgiLoader);
+ return classLoaders;
+ }
+
+ public void find(PackageScanFilter test, String packageName, Set<Class<?>> classes) {
+ packageName = packageName.replace('.', '/');
+ Set<ClassLoader> set = getClassLoaders();
+ ClassLoader osgiClassLoader = getOsgiClassLoader(set);
+ int classesSize = classes.size();
+ if (osgiClassLoader != null) {
+ // if we have an osgi bundle loader use this one first
+ log.debug("Using only osgi bundle classloader");
+ findInOsgiClassLoader(test, packageName, osgiClassLoader, classes);
+ }
+
+ if (classes.size() == classesSize) {
+ // Using the regular classloaders as a fallback
+ log.debug("Using only regular classloaders");
+ for (ClassLoader classLoader : set.toArray(new ClassLoader[set.size()])) {
+ if (!isOsgiClassloader(classLoader)) {
+ find(test, packageName, classLoader, classes);
+ }
+ }
+ }
+ }
+
+ private void findInOsgiClassLoader(PackageScanFilter test, String packageName, ClassLoader osgiClassLoader, Set<Class<?>> classes) {
+ try {
+ Method mth = osgiClassLoader.getClass().getMethod("getBundle", new Class<?>[]{});
+ if (mth != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Loading from osgi bundle using classloader: " + osgiClassLoader);
+ }
+ loadImplementationsInBundle(test, packageName, osgiClassLoader, mth, classes);
+ }
+ } catch (NoSuchMethodException e) {
+ log.warn("It's not an osgi bundle classloader: " + osgiClassLoader);
+ }
+ }
+
+ /**
+ * Gets the osgi classloader if any in the given set
+ */
+ private static ClassLoader getOsgiClassLoader(Set<ClassLoader> set) {
+ for (ClassLoader loader : set) {
+ if (isOsgiClassloader(loader)) {
+ return loader;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Is it an osgi classloader
+ */
+ private static boolean isOsgiClassloader(ClassLoader loader) {
+ try {
+ Method mth = loader.getClass().getMethod("getBundle", new Class[]{});
+ if (mth != null) {
+ return true;
+ }
+ } catch (NoSuchMethodException e) {
+ // ignore its not an osgi loader
+ }
+ return false;
+ }
+
+ private void loadImplementationsInBundle(PackageScanFilter test, String packageName, ClassLoader loader, Method mth, Set<Class<?>> classes) {
+ // Use an inner class to avoid a NoClassDefFoundError when used in a non-osgi env
+ Set<String> urls = OsgiUtil.getImplementationsInBundle(test, packageName, loader, mth);
+ if (urls != null) {
+ for (String url : urls) {
+ // substring to avoid leading slashes
+ addIfMatching(test, url, classes);
+ }
+ }
+ }
+
+ private static final class OsgiUtil {
+
+ private static final transient Log LOG = LogFactory.getLog(OsgiUtil.class);
+
+ private OsgiUtil() {
+ // Helper class
+ }
+ @SuppressWarnings("unchecked")
+ static Set<String> getImplementationsInBundle(PackageScanFilter test, String packageName, ClassLoader loader, Method mth) {
+ try {
+ Bundle bundle = (Bundle) mth.invoke(loader);
+ Bundle[] bundles = null;
+
+ BundleContext bundleContext = bundle.getBundleContext();
+
+ if (bundleContext == null) {
+ // Bundle is not in STARTING|ACTIVE|STOPPING state
+ // (See OSGi 4.1 spec, section 4.3.17)
+ bundles = new Bundle[] {bundle};
+ } else {
+ bundles = bundleContext.getBundles();
+ }
+
+ Set<String> urls = new HashSet<String>();
+ for (Bundle bd : bundles) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Searching in bundle:" + bd);
+ }
+ Enumeration<URL> paths = bd.findEntries("/" + packageName, "*.class", true);
+ while (paths != null && paths.hasMoreElements()) {
+ URL path = paths.nextElement();
+ String pathString = path.getPath();
+ String urlString = pathString.substring(pathString.indexOf(packageName));
+ urls.add(urlString);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Added url: " + urlString);
+ }
+ }
+ }
+ return urls;
+ } catch (Throwable t) {
+ LOG.error("Could not search osgi bundles for classes matching criteria: " + test
+ + "due to an Exception: " + t.getMessage());
+ return null;
+ }
+ }
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiServiceRegistry.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiServiceRegistry.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiServiceRegistry.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiServiceRegistry.java Fri May 28 07:52:33 2010
@@ -0,0 +1,138 @@
+/**
+ * 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.camel.core.osgi;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.Route;
+import org.apache.camel.Service;
+import org.apache.camel.builder.ErrorHandlerBuilder;
+import org.apache.camel.spi.LifecycleStrategy;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.RouteContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * The OsgiServiceRegistry support to get the service object from the bundle context
+ */
+public class OsgiServiceRegistry implements Registry, LifecycleStrategy {
+ private BundleContext bundleContext;
+ private Map<String, Object> serviceCacheMap = new ConcurrentHashMap<String, Object>();
+ private ConcurrentLinkedQueue<ServiceReference> serviceReferenceQueue = new ConcurrentLinkedQueue<ServiceReference>();
+
+ public OsgiServiceRegistry(BundleContext bc) {
+ bundleContext = bc;
+ }
+
+ public <T> T lookup(String name, Class<T> type) {
+ Object service = lookup(name);
+ return type.cast(service);
+ }
+
+ public Object lookup(String name) {
+ Object service = serviceCacheMap.get(name);
+ if (service == null) {
+ ServiceReference sr = bundleContext.getServiceReference(name);
+ if (sr != null) {
+ // Need to keep the track of Service
+ // and call ungetService when the camel context is closed
+ serviceReferenceQueue.add(sr);
+ service = bundleContext.getService(sr);
+ if (service != null) {
+ serviceCacheMap.put(name, service);
+ }
+ }
+ }
+ return service;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> Map<String, T> lookupByType(Class<T> type) {
+ // not implemented so we return an empty map
+ return Collections.EMPTY_MAP;
+ }
+
+ public void onComponentAdd(String name, Component component) {
+ // Do nothing here
+ }
+
+ public void onComponentRemove(String name, Component component) {
+ // Do nothing here
+ }
+
+ public void onContextStart(CamelContext context) {
+ // Do nothing here
+ }
+
+ public void onContextStop(CamelContext context) {
+ // Unget the OSGi service
+ ServiceReference sr = serviceReferenceQueue.poll();
+ while (sr != null) {
+ bundleContext.ungetService(sr);
+ sr = serviceReferenceQueue.poll();
+ }
+ // Clean up the OSGi Service Cache
+ serviceCacheMap.clear();
+ }
+
+ public void onEndpointAdd(Endpoint endpoint) {
+ // Do nothing here
+ }
+
+ public void onEndpointRemove(Endpoint endpoint) {
+ // Do nothing here
+ }
+
+ public void onRouteContextCreate(RouteContext routeContext) {
+ // Do nothing here
+ }
+
+ public void onRoutesAdd(Collection<Route> routes) {
+ // Do nothing here
+ }
+
+ public void onRoutesRemove(Collection<Route> routes) {
+ // Do nothing here
+ }
+
+ public void onServiceAdd(CamelContext context, Service service, Route route) {
+ // Do nothing here
+ }
+
+ public void onServiceRemove(CamelContext context, Service service, Route route) {
+ // Do nothing here
+ }
+
+ public void onErrorHandlerAdd(RouteContext routeContext, Processor processor, ErrorHandlerBuilder errorHandlerBuilder) {
+ // Do nothing here
+ }
+
+ public void onThreadPoolAdd(CamelContext camelContext, ThreadPoolExecutor threadPool) {
+ // Do nothing here
+ }
+
+}
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/tracker/AbstractTracked.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/tracker/AbstractTracked.java?rev=949127&view=auto
==============================================================================
--- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/tracker/AbstractTracked.java (added)
+++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/tracker/AbstractTracked.java Fri May 28 07:52:33 2010
@@ -0,0 +1,444 @@
+/**
+ * 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.
+ */
+
+/*
+ * Copyright (c) OSGi Alliance (2007, 2008). All Rights Reserved.
+ *
+ * Licensed 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.camel.core.osgi.tracker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Abstract class to track items. If a Tracker is reused (closed then reopened),
+ * then a new AbstractTracked object is used. This class acts a map of tracked
+ * item -> customized object. Subclasses of this class will act as the listener
+ * object for the tracker. This class is used to synchronize access to the
+ * tracked items. This is not a public class. It is only for use by the
+ * implementation of the Tracker class.
+ *
+ * @ThreadSafe
+ * @version $Revision: 938753 $
+ * @since 1.4
+ */
+abstract class AbstractTracked {
+ /* set this to true to compile in debug messages */
+ static final boolean DEBUG = false;
+
+ /**
+ * true if the tracked object is closed. This field is volatile because it
+ * is set by one thread and read by another.
+ */
+ volatile boolean closed;
+
+ /**
+ * Map of tracked items to customized objects.
+ *
+ * @GuardedBy this
+ */
+ private final Map tracked;
+
+ /**
+ * Modification count. This field is initialized to zero and incremented by
+ * modified.
+ *
+ * @GuardedBy this
+ */
+ private int trackingCount;
+
+ /**
+ * List of items in the process of being added. This is used to deal with
+ * nesting of events. Since events may be synchronously delivered, events
+ * can be nested. For example, when processing the adding of a service and
+ * the customizer causes the service to be unregistered, notification to the
+ * nested call to untrack that the service was unregistered can be made to
+ * the track method. Since the ArrayList implementation is not synchronized,
+ * all access to this list must be protected by the same synchronized object
+ * for thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final List adding;
+
+ /**
+ * Initial list of items for the tracker. This is used to correctly process
+ * the initial items which could be modified before they are tracked. This
+ * is necessary since the initial set of tracked items are not "announced"
+ * by events and therefore the event which makes the item untracked could be
+ * delivered before we track the item. An item must not be in both the
+ * initial and adding lists at the same time. An item must be moved from the
+ * initial list to the adding list "atomically" before we begin tracking it.
+ * Since the LinkedList implementation is not synchronized, all access to
+ * this list must be protected by the same synchronized object for
+ * thread-safety.
+ *
+ * @GuardedBy this
+ */
+ private final LinkedList initial;
+
+ /**
+ * AbstractTracked constructor.
+ */
+ AbstractTracked() {
+ tracked = new HashMap();
+ trackingCount = 0;
+ adding = new ArrayList(6);
+ initial = new LinkedList();
+ closed = false;
+ }
+
+ /**
+ * Set initial list of items into tracker before events begin to be
+ * received. This method must be called from Tracker's open method while
+ * synchronized on this object in the same synchronized block as the add
+ * listener call.
+ *
+ * @param list The initial list of items to be tracked. <code>null</code>
+ * entries in the list are ignored.
+ * @GuardedBy this
+ */
+ @SuppressWarnings("unchecked")
+ void setInitial(Object[] list) {
+ if (list == null) {
+ return;
+ }
+ int size = list.length;
+ for (int i = 0; i < size; i++) {
+ Object item = list[i];
+ if (item == null) {
+ continue;
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.setInitial: " + item); //$NON-NLS-1$
+ }
+ initial.add(item);
+ }
+ }
+
+ /**
+ * Track the initial list of items. This is called after events can begin to
+ * be received. This method must be called from Tracker's open method while
+ * not synchronized on this object after the add listener call.
+ */
+ @SuppressWarnings("unchecked")
+ void trackInitial() {
+ while (true) {
+ Object item;
+ synchronized (this) {
+ if (closed || (initial.size() == 0)) {
+ /*
+ * if there are no more initial items
+ */
+ return; /* we are done */
+ }
+ /*
+ * move the first item from the initial list to the adding list
+ * within this synchronized block.
+ */
+ item = initial.removeFirst();
+ if (tracked.get(item) != null) {
+ /* if we are already tracking this item */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial[already tracked]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ if (adding.contains(item)) {
+ /*
+ * if this item is already in the process of being added.
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial[already adding]: " + item); //$NON-NLS-1$
+ }
+ continue; /* skip this item */
+ }
+ adding.add(item);
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackInitial: " + item); //$NON-NLS-1$
+ }
+ trackAdding(item, null); /*
+ * Begin tracking it. We call trackAdding
+ * since we have already put the item in
+ * the adding list.
+ */
+ }
+ }
+
+ /**
+ * Called by the owning Tracker object when it is closed.
+ */
+ void close() {
+ closed = true;
+ }
+
+ /**
+ * Begin to track an item.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ @SuppressWarnings("unchecked")
+ void track(final Object item, final Object related) {
+ final Object object;
+ synchronized (this) {
+ if (closed) {
+ return;
+ }
+ object = tracked.get(item);
+ if (object == null) { /* we are not tracking the item */
+ if (adding.contains(item)) {
+ /* if this item is already in the process of being added. */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.track[already adding]: " + item); //$NON-NLS-1$
+ }
+ return;
+ }
+ adding.add(item); /* mark this item is being added */
+ } else { /* we are currently tracking this item */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.track[modified]: " + item); //$NON-NLS-1$
+ }
+ modified(); /* increment modification count */
+ }
+ }
+
+ if (object == null) { /* we are not tracking the item */
+ trackAdding(item, related);
+ } else {
+ /* Call customizer outside of synchronized region */
+ customizerModified(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Common logic to add an item to the tracker used by track and
+ * trackInitial. The specified item must have been placed in the adding list
+ * before calling this method.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ */
+ @SuppressWarnings("unchecked")
+ private void trackAdding(final Object item, final Object related) {
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackAdding: " + item); //$NON-NLS-1$
+ }
+ Object object = null;
+ boolean becameUntracked = false;
+ /* Call customizer outside of synchronized region */
+ try {
+ object = customizerAdding(item, related);
+ /*
+ * If the customizer throws an unchecked exception, it will
+ * propagate after the finally
+ */
+ } finally {
+ synchronized (this) {
+ if (adding.remove(item) && !closed) {
+ /*
+ * if the item was not untracked during the customizer
+ * callback
+ */
+ if (object != null) {
+ tracked.put(item, object);
+ modified(); /* increment modification count */
+ notifyAll(); /* notify any waiters */
+ }
+ } else {
+ becameUntracked = true;
+ }
+ }
+ }
+ /*
+ * The item became untracked during the customizer callback.
+ */
+ if (becameUntracked && (object != null)) {
+ if (DEBUG) {
+ System.out.println("AbstractTracked.trackAdding[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to
+ * let it propagate
+ */
+ }
+ }
+
+ /**
+ * Discontinue tracking the item.
+ *
+ * @param item Item to be untracked.
+ * @param related Action related object.
+ */
+ void untrack(final Object item, final Object related) {
+ final Object object;
+ synchronized (this) {
+ if (initial.remove(item)) { /*
+ * if this item is already in the list
+ * of initial references to process
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[removed from initial]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * we have removed it from the list and it will not be
+ * processed
+ */
+ }
+
+ if (adding.remove(item)) { /*
+ * if the item is in the process of being
+ * added
+ */
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[being added]: " + item); //$NON-NLS-1$
+ }
+ return; /*
+ * in case the item is untracked while in the process of
+ * adding
+ */
+ }
+ object = tracked.remove(item); /*
+ * must remove from tracker before
+ * calling customizer callback
+ */
+ if (object == null) { /* are we actually tracking the item */
+ return;
+ }
+ modified(); /* increment modification count */
+ }
+ if (DEBUG) {
+ System.out.println("AbstractTracked.untrack[removed]: " + item); //$NON-NLS-1$
+ }
+ /* Call customizer outside of synchronized region */
+ customizerRemoved(item, related, object);
+ /*
+ * If the customizer throws an unchecked exception, it is safe to let it
+ * propagate
+ */
+ }
+
+ /**
+ * Returns the number of tracked items.
+ *
+ * @return The number of tracked items.
+ * @GuardedBy this
+ */
+ int size() {
+ return tracked.size();
+ }
+
+ /**
+ * Return the customized object for the specified item
+ *
+ * @param item The item to lookup in the map
+ * @return The customized object for the specified item.
+ * @GuardedBy this
+ */
+ Object getCustomizedObject(final Object item) {
+ return tracked.get(item);
+ }
+
+ /**
+ * Return the list of tracked items.
+ *
+ * @param list An array to contain the tracked items.
+ * @return The specified list if it is large enough to hold the tracked
+ * items or a new array large enough to hold the tracked items.
+ * @GuardedBy this
+ */
+ @SuppressWarnings("unchecked")
+ Object[] getTracked(final Object[] list) {
+ return tracked.keySet().toArray(list);
+ }
+
+ /**
+ * Increment the modification count. If this method is overridden, the
+ * overriding method MUST call this method to increment the tracking count.
+ *
+ * @GuardedBy this
+ */
+ void modified() {
+ trackingCount++;
+ }
+
+ /**
+ * Returns the tracking count for this <code>ServiceTracker</code> object.
+ * The tracking count is initialized to 0 when this object is opened. Every
+ * time an item is added, modified or removed from this object the tracking
+ * count is incremented.
+ *
+ * @GuardedBy this
+ * @return The tracking count for this object.
+ */
+ int getTrackingCount() {
+ return trackingCount;
+ }
+
+ /**
+ * Call the specific customizer adding method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Item to be tracked.
+ * @param related Action related object.
+ * @return Customized object for the tracked item or <code>null</code> if
+ * the item is not to be tracked.
+ */
+ abstract Object customizerAdding(final Object item, final Object related);
+
+ /**
+ * Call the specific customizer modified method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerModified(final Object item, final Object related, final Object object);
+
+ /**
+ * Call the specific customizer removed method. This method must not be
+ * called while synchronized on this object.
+ *
+ * @param item Tracked item.
+ * @param related Action related object.
+ * @param object Customized object for the tracked item.
+ */
+ abstract void customizerRemoved(final Object item, final Object related, final Object object);
+}