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);
+}