You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2020/03/23 08:30:03 UTC
[camel-karaf] 01/05: Camel-Karaf: First commit
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git
commit 271a283d594f15f51a5ae32a6ae470b8b770265c
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Mon Mar 23 08:47:44 2020 +0100
Camel-Karaf: First commit
---
.gitignore | 27 +
core/camel-core-osgi/pom.xml | 107 +++
.../apache/camel/core/osgi/OsgiBeanRepository.java | 183 ++++
.../camel/core/osgi/OsgiCamelContextHelper.java | 53 ++
.../core/osgi/OsgiCamelContextNameStrategy.java | 63 ++
.../camel/core/osgi/OsgiCamelContextPublisher.java | 153 ++++
.../apache/camel/core/osgi/OsgiClassResolver.java | 186 +++++
.../camel/core/osgi/OsgiComponentResolver.java | 69 ++
.../camel/core/osgi/OsgiDataFormatResolver.java | 91 ++
.../camel/core/osgi/OsgiDefaultCamelContext.java | 60 ++
.../camel/core/osgi/OsgiEventAdminNotifier.java | 144 ++++
.../apache/camel/core/osgi/OsgiFactoryFinder.java | 126 +++
.../camel/core/osgi/OsgiFactoryFinderResolver.java | 37 +
.../camel/core/osgi/OsgiLanguageResolver.java | 98 +++
.../core/osgi/OsgiManagementNameStrategy.java | 73 ++
.../apache/camel/core/osgi/OsgiNamingHelper.java | 91 ++
.../core/osgi/OsgiPackageScanClassResolver.java | 115 +++
.../apache/camel/core/osgi/OsgiTypeConverter.java | 336 ++++++++
.../org/apache/camel/core/osgi/impl/Activator.java | 728 ++++++++++++++++
.../org/apache/camel/core/osgi/impl/package.html | 27 +
.../camel/core/osgi/utils/BundleContextUtils.java | 67 ++
.../osgi/utils/BundleDelegatingClassLoader.java | 99 +++
.../apache/camel/core/osgi/CamelMockBundle.java | 132 +++
.../camel/core/osgi/CamelMockBundleContext.java | 139 ++++
.../camel/core/osgi/CamelMockLanguageResolver.java | 33 +
.../camel/core/osgi/CamelOsgiTestSupport.java | 53 ++
.../camel/core/osgi/OsgiClassResolverTest.java | 40 +
.../camel/core/osgi/OsgiComponentResolverTest.java | 122 +++
.../core/osgi/OsgiDataFormatResolverTest.java | 88 ++
.../camel/core/osgi/OsgiFactoryFinderTest.java | 42 +
.../camel/core/osgi/OsgiLanguageResolverTest.java | 94 +++
.../osgi/OsgiPackageScanClassResolverTest.java | 79 ++
.../camel/core/osgi/ServiceRegistryTest.java | 58 ++
.../camel/core/osgi/other/MyOtherRouteBuilder.java | 28 +
.../core/osgi/other/MyOtherTypeConverter.java | 77 ++
.../core/osgi/test/MockTypeConverterRegistry.java | 141 ++++
.../camel/core/osgi/test/MyRouteBuilder.java | 28 +
.../org/apache/camel/core/osgi/test/MyService.java | 25 +
.../camel/core/osgi/test/MyTypeConverter.java | 77 ++
.../src/test/resources/META-INF/LICENSE.txt | 203 +++++
.../src/test/resources/META-INF/NOTICE.txt | 11 +
.../services/org/apache/camel/component/file_test | 19 +
.../services/org/apache/camel/component/timer_test | 18 +
.../services/org/apache/camel/language/bean_test | 18 +
.../services/org/apache/camel/language/file_test | 18 +
.../org/apache/camel/language/resolver/default | 18 +
.../resources/META-INF/spring/camel-context.xml | 66 ++
.../src/test/resources/log4j2.properties | 28 +
core/pom.xml | 37 +
pom.xml | 921 +++++++++++++++++++++
50 files changed, 5546 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5d69a55
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,27 @@
+target
+*.iml
+*.ipr
+*.iws
+.idea
+.DS_Store
+.classpath
+.ekstazi
+.project
+.settings
+.checkstyle
+*.log
+test-salesforce-login.properties
+dependency-reduced-pom.xml
+id_file
+components/camel-solr/data
+*.epoch
+.factorypath
+.pmd
+.sts4-cache
+log-camel-lsp.out
+.vscode
+*.code-workspace
+components/camel-cxf/activemq-data
+*.swp
+.flattened-pom.xml
+.java-version
diff --git a/core/camel-core-osgi/pom.xml b/core/camel-core-osgi/pom.xml
new file mode 100644
index 0000000..205ef0e
--- /dev/null
+++ b/core/camel-core-osgi/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel.karaf</groupId>
+ <artifactId>core-modules</artifactId>
+ <version>3.2.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>camel-core-osgi</artifactId>
+ <packaging>jar</packaging>
+
+ <name>Camel Karaf :: Core OSGi</name>
+ <description>Camel Karaf Core OSGi support</description>
+
+ <properties>
+ <camel.osgi.import>
+ org.osgi.service.event;resolution:=optional,
+ *
+ </camel.osgi.import>
+ <camel.osgi.provide.capability>
+ osgi.extender; osgi.extender="org.apache.camel"; uses:="org.apache.camel.core.osgi.impl";
+ version:Version="$(version;==;${camel.osgi.version.clean})"
+ </camel.osgi.provide.capability>
+ <camel.osgi.activator>
+ org.apache.camel.core.osgi.impl.Activator
+ </camel.osgi.activator>
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-core-engine</artifactId>
+ </dependency>
+
+ <!-- osgi -->
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.cmpn</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- for testing -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-core-languages</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-file</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-mock</artifactId>
+ <version>1.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-api</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-slf4j-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+</project>
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiBeanRepository.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiBeanRepository.java
new file mode 100644
index 0000000..dcec057
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiBeanRepository.java
@@ -0,0 +1,183 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.Service;
+import org.apache.camel.spi.BeanRepository;
+import org.apache.camel.support.LifecycleStrategySupport;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The OSGi {@link BeanRepository} support to lookup beans from the OSGi service registry from its bundle context.
+ */
+public class OsgiBeanRepository extends LifecycleStrategySupport implements BeanRepository, Service, ServiceListener {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiBeanRepository.class);
+ private final BundleContext bundleContext;
+ private final Map<ServiceReference<?>, AtomicLong> serviceReferenceUsageMap = new ConcurrentHashMap<>();
+
+ public OsgiBeanRepository(BundleContext bc) {
+ bundleContext = bc;
+ bundleContext.addServiceListener(this);
+ }
+
+ /**
+ * Support to lookup the Object with filter with the (name=NAME) and class type
+ */
+ @Override
+ public <T> T lookupByNameAndType(String name, Class<T> type) {
+ Object service = null;
+ ServiceReference<?> sr;
+ try {
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences(type.getName(), "(name=" + name + ")");
+ if (refs != null && refs.length > 0) {
+ // just return the first one
+ sr = refs[0];
+ incrementServiceUsage(sr);
+ service = bundleContext.getService(sr);
+ }
+ } catch (Exception ex) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(ex);
+ }
+ service = unwrap(service);
+ return type.cast(service);
+ }
+
+ /**
+ * It's only support to look up the ServiceReference with Class name or service PID
+ */
+ @Override
+ public Object lookupByName(String name) {
+ Object service = null;
+ ServiceReference<?> sr = bundleContext.getServiceReference(name);
+ if (sr == null) {
+ // trying to lookup service by PID if not found by name
+ String filterExpression = "(" + Constants.SERVICE_PID + "=" + name + ")";
+ try {
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences((String)null, filterExpression);
+ if (refs != null && refs.length > 0) {
+ // just return the first one
+ sr = refs[0];
+ }
+ } catch (InvalidSyntaxException ex) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Invalid OSGi service reference filter, skipped lookup by service.pid. Filter expression: {}", filterExpression, ex);
+ }
+ }
+ }
+ if (sr != null) {
+ incrementServiceUsage(sr);
+ service = bundleContext.getService(sr);
+ }
+ service = unwrap(service);
+ return service;
+ }
+
+ @Override
+ public <T> Map<String, T> findByTypeWithName(Class<T> type) {
+ Map<String, T> result = new HashMap<>();
+ int count = 0;
+ try {
+ ServiceReference<?>[] refs = bundleContext.getAllServiceReferences(type.getName(), null);
+ if (refs != null) {
+ for (ServiceReference<?> sr : refs) {
+ if (sr != null) {
+ Object service = bundleContext.getService(sr);
+ incrementServiceUsage(sr);
+ if (service != null) {
+ String name = (String)sr.getProperty("name");
+ service = unwrap(service);
+ if (name != null) {
+ result.put(name, type.cast(service));
+ } else {
+ // generate a unique name for it
+ result.put(type.getSimpleName() + count, type.cast(service));
+ count++;
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception ex) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(ex);
+ }
+ return result;
+ }
+
+ @Override
+ public <T> Set<T> findByType(Class<T> type) {
+ Map<String, T> map = findByTypeWithName(type);
+ return new HashSet<>(map.values());
+ }
+
+ @Override
+ public void start() {
+ // noop
+ }
+
+ @Override
+ public void stop() {
+ // Unget the OSGi service as OSGi uses reference counting
+ // and we should do this as one of the last actions when stopping Camel
+ this.serviceReferenceUsageMap.forEach(this::drainServiceUsage);
+ this.serviceReferenceUsageMap.clear();
+ }
+
+ private void drainServiceUsage(ServiceReference<?> serviceReference, AtomicLong serviceUsageCount) {
+ if (serviceUsageCount != null && serviceReference != null) {
+ while (serviceUsageCount.decrementAndGet() >= 0) {
+ this.bundleContext.ungetService(serviceReference);
+ }
+ }
+ }
+
+ private void incrementServiceUsage(ServiceReference<?> sr) {
+ AtomicLong serviceUsageCount = this.serviceReferenceUsageMap.get(sr);
+ if (serviceUsageCount != null) {
+ serviceUsageCount.incrementAndGet();
+ } else {
+ this.serviceReferenceUsageMap.merge(sr, new AtomicLong(1),
+ (existingServiceUsageCount, newServiceUsageCount) -> {
+ existingServiceUsageCount.getAndAdd(newServiceUsageCount.get());
+ return existingServiceUsageCount;
+ });
+ }
+ }
+
+ @Override
+ public void serviceChanged(ServiceEvent event) {
+ if (event.getType() == ServiceEvent.UNREGISTERING) {
+ ServiceReference<?> serviceReference = event.getServiceReference();
+ AtomicLong serviceUsageCount = this.serviceReferenceUsageMap.remove(serviceReference);
+ drainServiceUsage(serviceReference, serviceUsageCount);
+ }
+ }
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java
new file mode 100644
index 0000000..aeda372
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextHelper.java
@@ -0,0 +1,53 @@
+/*
+ * 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.impl.DefaultCamelContext;
+import org.apache.camel.util.ObjectHelper;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class OsgiCamelContextHelper {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiCamelContextHelper.class);
+
+ private OsgiCamelContextHelper() {
+ // helper class
+ }
+
+ public static void osgiUpdate(DefaultCamelContext camelContext, BundleContext bundleContext) {
+ ObjectHelper.notNull(bundleContext, "BundleContext");
+
+ LOG.debug("Using OsgiCamelContextNameStrategy");
+ camelContext.setNameStrategy(new OsgiCamelContextNameStrategy(bundleContext));
+ LOG.debug("Using OsgiManagementNameStrategy");
+ camelContext.setManagementNameStrategy(new OsgiManagementNameStrategy(camelContext, bundleContext));
+ LOG.debug("Using OsgiClassResolver");
+ camelContext.setClassResolver(new OsgiClassResolver(camelContext, bundleContext));
+ LOG.debug("Using OsgiFactoryFinderResolver");
+ camelContext.setFactoryFinderResolver(new OsgiFactoryFinderResolver(bundleContext));
+ LOG.debug("Using OsgiPackageScanClassResolver");
+ camelContext.setPackageScanClassResolver(new OsgiPackageScanClassResolver(bundleContext));
+ LOG.debug("Using OsgiComponentResolver");
+ camelContext.setComponentResolver(new OsgiComponentResolver(bundleContext));
+ LOG.debug("Using OsgiLanguageResolver");
+ camelContext.setLanguageResolver(new OsgiLanguageResolver(bundleContext));
+ LOG.debug("Using OsgiDataFormatResolver");
+ camelContext.setDataFormatResolver(new OsgiDataFormatResolver(bundleContext));
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java
new file mode 100644
index 0000000..965d11c
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextNameStrategy.java
@@ -0,0 +1,63 @@
+/*
+ * 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.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.spi.CamelContextNameStrategy;
+import org.osgi.framework.BundleContext;
+
+import static org.apache.camel.core.osgi.OsgiCamelContextPublisher.CONTEXT_NAME_PROPERTY;
+
+/**
+ * In OSGi we want to use a {@link CamelContextNameStrategy} that finds a free name in the
+ * OSGi Service Registry to be used for auto assigned names.
+ * <p/>
+ * If there is a name clash in the OSGi registry, then a new candidate name is used by appending
+ * a unique counter.
+ */
+public class OsgiCamelContextNameStrategy implements CamelContextNameStrategy {
+
+ private static final AtomicInteger CONTEXT_COUNTER = new AtomicInteger(0);
+ private final BundleContext context;
+ private final String prefix = "camel";
+ private volatile String name;
+
+ public OsgiCamelContextNameStrategy(BundleContext context) {
+ this.context = context;
+ }
+
+ @Override
+ public String getName() {
+ if (name == null) {
+ name = getNextName();
+ }
+ return name;
+ }
+
+ @Override
+ public synchronized String getNextName() {
+ // false = do no check fist, but add the counter asap, so we have camel-1
+ return OsgiNamingHelper.findFreeCamelContextName(context, prefix, CONTEXT_NAME_PROPERTY, CONTEXT_COUNTER, false);
+ }
+
+ @Override
+ public boolean isFixedName() {
+ return false;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java
new file mode 100644
index 0000000..ab0976d
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java
@@ -0,0 +1,153 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.spi.CamelEvent.CamelContextEvent;
+import org.apache.camel.spi.CamelEvent.Type;
+import org.apache.camel.support.EventNotifierSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This {@link org.apache.camel.spi.EventNotifier} is in charge of registering
+ * {@link CamelContext} in the OSGi registry
+ */
+public class OsgiCamelContextPublisher extends EventNotifierSupport {
+
+ public static final String CONTEXT_SYMBOLIC_NAME_PROPERTY = "camel.context.symbolicname";
+ public static final String CONTEXT_VERSION_PROPERTY = "camel.context.version";
+ public static final String CONTEXT_NAME_PROPERTY = "camel.context.name";
+ public static final String CONTEXT_MANAGEMENT_NAME_PROPERTY = "camel.context.managementname";
+
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiCamelContextPublisher.class);
+
+ private final BundleContext bundleContext;
+ private final Map<CamelContext, ServiceRegistration<?>> registrations
+ = new ConcurrentHashMap<>();
+
+ public OsgiCamelContextPublisher(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public void notify(CamelEvent event) throws Exception {
+ if (event.getType() == Type.CamelContextStarted) {
+ CamelContext context = ((CamelContextEvent) event).getContext();
+ registerCamelContext(context);
+ } else if (event.getType() == Type.CamelContextStopping) {
+ CamelContext context = ((CamelContextEvent) event).getContext();
+ ServiceRegistration<?> reg = registrations.remove(context);
+ if (reg != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unregistering CamelContext [{}] from OSGi registry", context.getName());
+ }
+ try {
+ reg.unregister();
+ } catch (Exception e) {
+ LOG.warn("Error unregistering CamelContext [" + context.getName() + "] from OSGi registry. This exception will be ignored.", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isEnabled(CamelEvent event) {
+ return event.getType() == Type.CamelContextStarted || event.getType() == Type.CamelContextStopping;
+ }
+
+ @Override
+ protected void doShutdown() throws Exception {
+ // clear and unregister any left-over registration (which should not happen)
+ if (!registrations.isEmpty()) {
+ LOG.warn("On shutdown there are {} registrations which was supposed to have been unregistered already. Will unregister these now.", registrations.size());
+ for (ServiceRegistration<?> reg : registrations.values()) {
+ try {
+ reg.unregister();
+ } catch (Exception e) {
+ LOG.warn("Error unregistering from OSGi registry. This exception will be ignored.", e);
+ }
+ }
+ }
+ registrations.clear();
+ }
+
+ public ServiceRegistration<?> registerCamelContext(CamelContext camelContext) throws InvalidSyntaxException {
+ // avoid registering the same service again
+ // we must include unique camel management name so the symbolic name becomes unique,
+ // in case the bundle has more than one CamelContext
+ String name = camelContext.getName();
+ String managementName = camelContext.getManagementName();
+ String symbolicName = bundleContext.getBundle().getSymbolicName();
+
+ if (!lookupCamelContext(bundleContext, symbolicName, name)) {
+ Version bundleVersion = getBundleVersion(bundleContext.getBundle());
+
+ Dictionary<String, Object > props = new Hashtable<>();
+ props.put(CONTEXT_SYMBOLIC_NAME_PROPERTY, symbolicName);
+ props.put(CONTEXT_VERSION_PROPERTY, bundleVersion);
+ props.put(CONTEXT_NAME_PROPERTY, name);
+ if (managementName != null) {
+ props.put(CONTEXT_MANAGEMENT_NAME_PROPERTY, managementName);
+ }
+
+ LOG.debug("Registering CamelContext [{}] in OSGi registry", name);
+
+ ServiceRegistration<?> reg = bundleContext.registerService(CamelContext.class.getName(), camelContext, props);
+ if (reg != null) {
+ registrations.put(camelContext, reg);
+ }
+ return reg;
+ } else {
+ return null;
+ }
+ }
+
+ public static Version getBundleVersion(Bundle bundle) {
+ Dictionary<?, ?> headers = bundle.getHeaders();
+ String version = (String) headers.get(Constants.BUNDLE_VERSION);
+ return (version != null) ? Version.parseVersion(version) : Version.emptyVersion;
+ }
+
+ /**
+ * Lookup in the OSGi Service Registry whether a {@link org.apache.camel.CamelContext} is already registered with the given symbolic name.
+ *
+ * @return <tt>true</tt> if exists, <tt>false</tt> otherwise
+ */
+ public static boolean lookupCamelContext(BundleContext bundleContext, String symbolicName, String contextName) throws InvalidSyntaxException {
+ Version bundleVersion = getBundleVersion(bundleContext.getBundle());
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences(CamelContext.class.getName(),
+ "(&(" + CONTEXT_SYMBOLIC_NAME_PROPERTY + "=" + symbolicName + ")"
+ + "(" + CONTEXT_NAME_PROPERTY + "=" + contextName + ")"
+ + "(" + CONTEXT_VERSION_PROPERTY + "=" + bundleVersion + "))");
+ return refs != null && refs.length > 0;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java
new file mode 100644
index 0000000..0d9e059
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiClassResolver.java
@@ -0,0 +1,186 @@
+/*
+ * 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 java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.engine.DefaultClassResolver;
+import org.apache.camel.util.CastUtils;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/* Using the bundle of CamelContext to load the class */
+public class OsgiClassResolver extends DefaultClassResolver {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiClassResolver.class);
+
+ private final CamelContext camelContext;
+ private final BundleContext bundleContext;
+
+ public OsgiClassResolver(CamelContext camelContext, BundleContext context) {
+ super(camelContext);
+ this.camelContext = camelContext;
+ this.bundleContext = context;
+ }
+
+ @Override
+ public Class<?> resolveClass(String name) {
+ LOG.trace("Resolve class {}", name);
+ name = StringHelper.normalizeClassName(name);
+ if (ObjectHelper.isEmpty(name)) {
+ return null;
+ }
+ // we need to avoid the NPE issue of loading the class
+ Class<?> clazz = ObjectHelper.loadSimpleType(name);
+ if (clazz == null) {
+ clazz = doLoadClass(name, bundleContext.getBundle());
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Loading class {} using BundleContext {} -> {}", name, bundleContext.getBundle(), clazz);
+ }
+ }
+ if (clazz == null && camelContext != null) {
+ // fallback and load class using the application context classloader
+ clazz = super.loadClass(name, camelContext.getApplicationContextClassLoader());
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Loading class {} using CamelContext {} -> {}", name, camelContext, clazz);
+ }
+ }
+ return clazz;
+ }
+
+ @Override
+ public <T> Class<T> resolveClass(String name, Class<T> type) {
+ return CastUtils.cast(resolveClass(name));
+ }
+
+ @Override
+ public InputStream loadResourceAsStream(String uri) {
+ StringHelper.notEmpty(uri, "uri");
+
+ String resolvedName = resolveUriPath(uri);
+ URL url = loadResourceAsURL(resolvedName);
+ InputStream answer = null;
+ if (url != null) {
+ try {
+ answer = url.openStream();
+ } catch (IOException ex) {
+ throw new RuntimeException("Cannot load resource: " + uri, ex);
+ }
+ }
+
+ // fallback to default as OSGi may have issues loading resources
+ if (answer == null) {
+ answer = super.loadResourceAsStream(uri);
+ }
+ return answer;
+ }
+
+ @Override
+ public URL loadResourceAsURL(String uri) {
+ StringHelper.notEmpty(uri, "uri");
+ String resolvedName = resolveUriPath(uri);
+ URL answer = bundleContext.getBundle().getResource(resolvedName);
+
+ // fallback to default as OSGi may have issues loading resources
+ if (answer == null) {
+ answer = super.loadResourceAsURL(uri);
+ }
+ return answer;
+ }
+
+ @Override
+ public Enumeration<URL> loadResourcesAsURL(String uri) {
+ StringHelper.notEmpty(uri, "uri");
+ try {
+ String resolvedName = resolveUriPath(uri);
+ return bundleContext.getBundle().getResources(resolvedName);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot load resource: " + uri, e);
+ }
+ }
+
+ @Override
+ public Enumeration<URL> loadAllResourcesAsURL(String uri) {
+ StringHelper.notEmpty(uri, "uri");
+ Vector<URL> answer = new Vector<>();
+
+ try {
+ String resolvedName = resolveUriPath(uri);
+
+ Enumeration<URL> e = bundleContext.getBundle().getResources(resolvedName);
+ while (e != null && e.hasMoreElements()) {
+ answer.add(e.nextElement());
+ }
+
+ String path = FileUtil.onlyPath(uri);
+ String name = FileUtil.stripPath(uri);
+ if (path != null && name != null) {
+ for (Bundle bundle : bundleContext.getBundles()) {
+ LOG.trace("Finding all entries in path: {} with pattern: {}", path, name);
+ e = bundle.findEntries(path, name, false);
+ while (e != null && e.hasMoreElements()) {
+ answer.add(e.nextElement());
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot load resource: " + uri, e);
+ }
+
+ return answer.elements();
+ }
+
+ protected Class<?> doLoadClass(String name, Bundle loader) {
+ StringHelper.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 + ". This exception will be ignored.", e);
+ }
+ }
+ }
+ return answer;
+ }
+
+ /**
+ * Helper operation used to remove relative path notation from
+ * resources. Most critical for resources on the Classpath
+ * as resource loaders will not resolve the relative paths correctly.
+ *
+ * @param name the name of the resource to load
+ * @return the modified or unmodified string if there were no changes
+ */
+ private static String resolveUriPath(String name) {
+ // compact the path and use / as separator as that's used for loading resources on the classpath
+ return FileUtil.compactPath(name, '/');
+ }
+
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java
new file mode 100644
index 0000000..f87ad7a
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiComponentResolver.java
@@ -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.RuntimeCamelException;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.support.ResolverHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OsgiComponentResolver implements ComponentResolver {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiComponentResolver.class);
+
+ private final BundleContext bundleContext;
+
+ public OsgiComponentResolver(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public Component resolveComponent(String name, CamelContext context) throws Exception {
+ Component componentReg = ResolverHelper.lookupComponentInRegistryWithFallback(context, name);
+ if (componentReg != null) {
+ return componentReg;
+ }
+
+ // Check in OSGi bundles
+ return getComponent(name, context);
+ }
+
+ protected Component getComponent(String name, CamelContext context) throws Exception {
+ LOG.trace("Finding Component: {}", name);
+ try {
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences(ComponentResolver.class.getName(), "(component=" + name + ")");
+ if (refs != null) {
+ for (ServiceReference<?> ref : refs) {
+ Object service = bundleContext.getService(ref);
+ if (ComponentResolver.class.isAssignableFrom(service.getClass())) {
+ ComponentResolver resolver = (ComponentResolver) service;
+ return resolver.resolveComponent(name, context);
+ }
+ }
+ }
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDataFormatResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDataFormatResolver.java
new file mode 100644
index 0000000..417fba0
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDataFormatResolver.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataFormatFactory;
+import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.support.ResolverHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OsgiDataFormatResolver implements DataFormatResolver {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiDataFormatResolver.class);
+
+ private final BundleContext bundleContext;
+
+ public OsgiDataFormatResolver(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public DataFormat resolveDataFormat(String name, CamelContext context) {
+ // lookup in registry first
+ DataFormat dataFormat = ResolverHelper.lookupDataFormatInRegistryWithFallback(context, name);
+ if (dataFormat == null) {
+ dataFormat = getDataFormat(name, context, false);
+ }
+
+ if (dataFormat == null) {
+ dataFormat = createDataFormat(name, context);
+ }
+
+ return dataFormat;
+ }
+
+ @Override
+ public DataFormat createDataFormat(String name, CamelContext context) {
+ DataFormat dataFormat = null;
+
+ // lookup in registry first
+ DataFormatFactory dataFormatFactory = ResolverHelper.lookupDataFormatFactoryInRegistryWithFallback(context, name);
+ if (dataFormatFactory != null) {
+ dataFormat = dataFormatFactory.newInstance();
+ }
+
+ if (dataFormat == null) {
+ dataFormat = getDataFormat(name, context, true);
+ }
+
+ return dataFormat;
+ }
+
+ private DataFormat getDataFormat(String name, CamelContext context, boolean create) {
+ LOG.trace("Finding DataFormat: {}", name);
+ try {
+ Collection<ServiceReference<DataFormatResolver>> refs = bundleContext.getServiceReferences(DataFormatResolver.class, "(dataformat=" + name + ")");
+ if (refs != null) {
+ for (ServiceReference<DataFormatResolver> ref : refs) {
+ return create
+ ? bundleContext.getService(ref).createDataFormat(name, context)
+ : bundleContext.getService(ref).resolveDataFormat(name, context);
+ }
+ }
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java
new file mode 100644
index 0000000..9f85f73
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiDefaultCamelContext.java
@@ -0,0 +1,60 @@
+/*
+ * 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.core.osgi.utils.BundleContextUtils;
+import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.support.DefaultRegistry;
+import org.osgi.framework.BundleContext;
+
+public class OsgiDefaultCamelContext extends DefaultCamelContext {
+
+ private final BundleContext bundleContext;
+
+ public OsgiDefaultCamelContext(BundleContext bundleContext) {
+ super(false);
+ this.bundleContext = bundleContext;
+
+ // inject common osgi
+ OsgiCamelContextHelper.osgiUpdate(this, bundleContext);
+
+ // and these are blueprint specific
+ OsgiBeanRepository repo1 = new OsgiBeanRepository(bundleContext);
+ setRegistry(new DefaultRegistry(repo1));
+ // Need to clean up the OSGi service when camel context is closed.
+ addLifecycleStrategy(repo1);
+ // setup the application context classloader with the bundle classloader
+ setApplicationContextClassLoader(new BundleDelegatingClassLoader(bundleContext.getBundle()));
+
+ init();
+ }
+
+ @Override
+ protected TypeConverter createTypeConverter() {
+ // CAMEL-3614: make sure we use a bundle context which imports org.apache.camel.impl.converter package
+ BundleContext ctx = BundleContextUtils.getBundleContext(getClass());
+ if (ctx == null) {
+ ctx = bundleContext;
+ }
+ FactoryFinder finder = new OsgiFactoryFinderResolver(bundleContext).resolveDefaultFactoryFinder(getClassResolver());
+ return new OsgiTypeConverter(ctx, this, getInjector(), finder);
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java
new file mode 100644
index 0000000..2f12900
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java
@@ -0,0 +1,144 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.camel.spi.CamelEvent;
+import org.apache.camel.support.EventNotifierSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * This {@link org.apache.camel.spi.EventNotifier} is in charge of propagating events
+ * to OSGi {@link EventAdmin} if present.
+ */
+public class OsgiEventAdminNotifier extends EventNotifierSupport {
+
+ public static final String TYPE = "type";
+ public static final String EVENT = "event";
+ public static final String TIMESTAMP = "timestamp";
+ public static final String BUNDLE = "bundle";
+ public static final String BUNDLE_ID = "bundle.id";
+ public static final String BUNDLE_SYMBOLICNAME = "bundle.symbolicName";
+ public static final String BUNDLE_VERSION = "bundle.version";
+ public static final String CAUSE = "cause";
+
+ public static final String TOPIC_CAMEL_EVENTS = "org/apache/camel/";
+ public static final String TOPIC_CAMEL_CONTEXT_EVENTS = TOPIC_CAMEL_EVENTS + "context/";
+ public static final String TOPIC_CAMEL_EXCHANGE_EVENTS = TOPIC_CAMEL_EVENTS + "exchange/";
+ public static final String TOPIC_CAMEL_SERVICE_EVENTS = TOPIC_CAMEL_EVENTS + "service/";
+ public static final String TOPIC_CAMEL_ROUTE_EVENTS = TOPIC_CAMEL_EVENTS + "route/";
+
+ private final BundleContext bundleContext;
+ private final ServiceTracker<EventAdmin, EventAdmin> tracker;
+
+ public OsgiEventAdminNotifier(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ this.tracker = new ServiceTracker<>(bundleContext, EventAdmin.class.getName(), null);
+ setIgnoreExchangeEvents(true);
+ }
+
+ @Override
+ public void notify(CamelEvent event) throws Exception {
+ EventAdmin eventAdmin = tracker.getService();
+ if (eventAdmin == null) {
+ return;
+ }
+
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put(TYPE, getType(event));
+ props.put(EVENT, event);
+ props.put(TIMESTAMP, System.currentTimeMillis());
+ props.put(BUNDLE, bundleContext.getBundle());
+ props.put(BUNDLE_SYMBOLICNAME, bundleContext.getBundle().getSymbolicName());
+ props.put(BUNDLE_ID, bundleContext.getBundle().getBundleId());
+ props.put(BUNDLE_VERSION, getBundleVersion(bundleContext.getBundle()));
+ try {
+ props.put(CAUSE, event.getClass().getMethod("getCause").invoke(event));
+ } catch (Throwable t) {
+ // ignore
+ }
+ eventAdmin.postEvent(new Event(getTopic(event), props));
+ }
+
+ @Override
+ public boolean isEnabled(CamelEvent event) {
+ return true;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ tracker.open();
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ tracker.close();
+ }
+
+ public static String toUpper(String text) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ if (Character.isUpperCase(c) && sb.length() > 0) {
+ sb.append('_');
+ }
+ sb.append(Character.toUpperCase(c));
+ }
+ return sb.toString();
+ }
+
+ public static String getType(CamelEvent event) {
+ return event.getType().name();
+ }
+
+ public static String getTopic(CamelEvent event) {
+ String topic;
+ String type = getType(event);
+ if (type.startsWith("CamelContext")) {
+ topic = TOPIC_CAMEL_CONTEXT_EVENTS;
+ type = type.substring("CamelContext".length());
+ } else if (type.startsWith("Exchange")) {
+ topic = TOPIC_CAMEL_EXCHANGE_EVENTS;
+ type = type.substring("Exchange".length());
+ } else if (type.startsWith("Route")) {
+ topic = TOPIC_CAMEL_ROUTE_EVENTS;
+ type = type.substring("Route".length());
+ } else if (type.startsWith("Service")) {
+ topic = TOPIC_CAMEL_SERVICE_EVENTS;
+ type = type.substring("Service".length());
+ } else {
+ topic = TOPIC_CAMEL_EVENTS + "unknown/";
+ }
+ topic += toUpper(type);
+ return topic;
+ }
+
+ public static Version getBundleVersion(Bundle bundle) {
+ Dictionary<?, ?> headers = bundle.getHeaders();
+ String version = (String)headers.get(Constants.BUNDLE_VERSION);
+ return (version != null) ? Version.parseVersion(version) : Version.emptyVersion;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
new file mode 100644
index 0000000..ca6adb7
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinder.java
@@ -0,0 +1,126 @@
+/*
+ * 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.Optional;
+import java.util.Properties;
+
+import org.apache.camel.impl.engine.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 {
+ private BundleContext bundleContext;
+
+ public OsgiFactoryFinder(BundleContext bundleContext, ClassResolver classResolver, String resourcePath) {
+ super(classResolver, resourcePath);
+ this.bundleContext = bundleContext;
+ }
+
+ private static class BundleEntry {
+ URL url;
+ Bundle bundle;
+ }
+
+ @Override
+ public Optional<Class<?>> findClass(String key, String propertyPrefix, Class<?> checkClass) {
+ final String prefix = propertyPrefix != null ? propertyPrefix : "";
+ final String classKey = propertyPrefix + key;
+
+ Class<?> answer = addToClassMap(classKey, () -> {
+ BundleEntry entry = getResource(key, checkClass);
+ if (entry != null) {
+ URL url = entry.url;
+ InputStream in = url.openStream();
+ // lets load the file
+ BufferedInputStream reader = null;
+ try {
+ reader = IOHelper.buffered(in);
+ Properties properties = new Properties();
+ properties.load(reader);
+ String className = properties.getProperty(prefix + "class");
+ if (className == null) {
+ throw new IOException("Expected property is missing: " + prefix + "class");
+ }
+ return entry.bundle.loadClass(className);
+ } finally {
+ IOHelper.close(reader, key, null);
+ IOHelper.close(in, key, null);
+ }
+ } else {
+ return null;
+ }
+ });
+
+ return Optional.ofNullable(answer);
+ }
+
+ @Override
+ public Optional<Class<?>> findClass(String key, String propertyPrefix) {
+ return findClass(key, propertyPrefix, null);
+ }
+
+ // As the META-INF of the Factory could not be export,
+ // we need to go through the bundles to look for it
+ // NOTE, the first found factory will be return
+ public BundleEntry getResource(String name) {
+ return getResource(name, null);
+ }
+
+ // The clazz can make sure we get right version of class that we need
+ public BundleEntry getResource(String name, Class<?> clazz) {
+ BundleEntry entry = null;
+ Bundle[] bundles;
+
+ bundles = bundleContext.getBundles();
+
+ URL url;
+ for (Bundle bundle : bundles) {
+ url = bundle.getEntry(getResourcePath() + name);
+ if (url != null && checkCompatibility(bundle, clazz)) {
+ entry = new BundleEntry();
+ entry.url = url;
+ entry.bundle = bundle;
+ break;
+ }
+ }
+
+ return entry;
+ }
+
+ private boolean checkCompatibility(Bundle bundle, Class<?> clazz) {
+ if (clazz == null) {
+ return true;
+ }
+ // Check bundle compatibility
+ try {
+ if (bundle.loadClass(clazz.getName()) != clazz) {
+ return false;
+ }
+ } catch (Throwable t) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java
new file mode 100644
index 0000000..631c190
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiFactoryFinderResolver.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+import org.osgi.framework.BundleContext;
+
+public class OsgiFactoryFinderResolver implements FactoryFinderResolver {
+
+ private final BundleContext bundleContext;
+
+ public OsgiFactoryFinderResolver(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public FactoryFinder resolveFactoryFinder(ClassResolver classResolver, String resourcePath) {
+ return new OsgiFactoryFinder(bundleContext, classResolver, resourcePath);
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java
new file mode 100644
index 0000000..c2197dc
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiLanguageResolver.java
@@ -0,0 +1,98 @@
+/*
+ * 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.NoSuchLanguageException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.support.ResolverHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OsgiLanguageResolver implements LanguageResolver {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiLanguageResolver.class);
+
+ private final BundleContext bundleContext;
+
+ public OsgiLanguageResolver(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ public Language resolveLanguage(String name, CamelContext context) {
+ // lookup in registry first
+ Language lang = ResolverHelper.lookupLanguageInRegistryWithFallback(context, name);
+ if (lang != null) {
+ return lang;
+ }
+
+ lang = getLanguage(name, context);
+ if (lang != null) {
+ return lang;
+ }
+ LanguageResolver resolver = getLanguageResolver("default", context);
+ if (resolver != null) {
+ return resolver.resolveLanguage(name, context);
+ }
+ throw new NoSuchLanguageException(name);
+ }
+
+ protected Language getLanguage(String name, CamelContext context) {
+ LOG.trace("Finding Language: {}", name);
+ try {
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences(LanguageResolver.class.getName(), "(language=" + name + ")");
+ if (refs != null) {
+ for (ServiceReference<?> ref : refs) {
+ Object service = bundleContext.getService(ref);
+ if (LanguageResolver.class.isAssignableFrom(service.getClass())) {
+ LanguageResolver resolver = (LanguageResolver) service;
+ return resolver.resolveLanguage(name, context);
+ }
+ }
+ }
+
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
+
+ protected LanguageResolver getLanguageResolver(String name, CamelContext context) {
+ LOG.trace("Finding LanguageResolver: {}", name);
+ try {
+ ServiceReference<?>[] refs = bundleContext.getServiceReferences(LanguageResolver.class.getName(), "(resolver=" + name + ")");
+ if (refs != null) {
+ for (ServiceReference<?> ref : refs) {
+ Object service = bundleContext.getService(ref);
+ if (LanguageResolver.class.isAssignableFrom(service.getClass())) {
+ LanguageResolver resolver = (LanguageResolver) service;
+ return resolver;
+ }
+ }
+ }
+ return null;
+ } catch (InvalidSyntaxException e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java
new file mode 100644
index 0000000..ed16568
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiManagementNameStrategy.java
@@ -0,0 +1,73 @@
+/*
+ * 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.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.engine.DefaultManagementNameStrategy;
+import org.apache.camel.util.StringHelper;
+import org.osgi.framework.BundleContext;
+
+/**
+ * OSGi enhanced {@link org.apache.camel.spi.ManagementNameStrategy}.
+ * <p/>
+ * This {@link org.apache.camel.spi.ManagementNameStrategy} supports the default
+ * tokens (see {@link DefaultManagementNameStrategy}) and the following additional OSGi specific tokens
+ * <ul>
+ * <li>#bundleId# - The bundle id</li>
+ * <li>#version# - The bundle version</li>
+ * <li>#symbolicName# - The bundle symbolic name</li>
+ * </ul>
+ * <p/>
+ * This implementation will by default use a name pattern as <tt>#symbolicName#</tt> and in case
+ * of a clash (such as multiple versions of the same symbolicName),
+ * then the pattern will fallback to append an unique counter <tt>#symbolicName#-#counter#</tt>.
+ *
+ * @see DefaultManagementNameStrategy
+ */
+public class OsgiManagementNameStrategy extends DefaultManagementNameStrategy {
+
+ private static final AtomicInteger CONTEXT_COUNTER = new AtomicInteger(0);
+ private final BundleContext bundleContext;
+
+ public OsgiManagementNameStrategy(CamelContext camelContext, BundleContext bundleContext) {
+ super(camelContext, "#symbolicName#-#name#", "#symbolicName#-#name#-#counter#");
+ this.bundleContext = bundleContext;
+ }
+
+ @Override
+ protected String customResolveManagementName(String pattern, String answer) {
+ String bundleId = "" + bundleContext.getBundle().getBundleId();
+ String symbolicName = bundleContext.getBundle().getSymbolicName();
+ if (symbolicName == null) {
+ symbolicName = "";
+ }
+ String version = bundleContext.getBundle().getVersion().toString();
+
+ answer = StringHelper.replaceAll(answer, "#bundleId#", bundleId);
+ answer = StringHelper.replaceAll(answer, "#symbolicName#", symbolicName);
+ answer = StringHelper.replaceAll(answer, "#version#", version);
+
+ // we got a candidate then find a free name
+ // true = check fist if the candidate as-is is free, if not then use the counter
+ answer = OsgiNamingHelper.findFreeCamelContextName(bundleContext, answer, OsgiCamelContextPublisher.CONTEXT_MANAGEMENT_NAME_PROPERTY, CONTEXT_COUNTER, true);
+
+ return answer;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiNamingHelper.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiNamingHelper.java
new file mode 100644
index 0000000..5391887
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiNamingHelper.java
@@ -0,0 +1,91 @@
+/*
+ * 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.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.CamelContext;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A helper to find free names in the OSGi service registry.
+ */
+public final class OsgiNamingHelper {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiNamingHelper.class);
+
+ private OsgiNamingHelper() {
+ }
+
+ /**
+ * Checks the OSGi service registry for a free name (uses the counter if there is a clash to find next free name)
+ *
+ * @param context the bundle context
+ * @param prefix the prefix for the name
+ * @param key the key to use in the OSGi filter; either {@link OsgiCamelContextPublisher#CONTEXT_NAME_PROPERTY}
+ * or {@link OsgiCamelContextPublisher#CONTEXT_MANAGEMENT_NAME_PROPERTY}.
+ * @param counter the counter
+ * @param checkFirst <tt>true</tt> to check the prefix name as-is before using the counter, <tt>false</tt> the counter is used immediately
+ * @return the free name, is never <tt>null</tt>
+ */
+ public static String findFreeCamelContextName(BundleContext context, String prefix, String key, AtomicInteger counter, boolean checkFirst) {
+ String candidate = null;
+ boolean clash = false;
+
+ do {
+ try {
+ clash = false;
+
+ if (candidate == null && checkFirst) {
+ // try candidate as-is
+ candidate = prefix;
+ } else {
+ // generate new candidate
+ candidate = prefix + "-" + getNextCounter(counter);
+ }
+ LOG.trace("Checking OSGi Service Registry for existence of existing CamelContext with name: {}", candidate);
+
+ ServiceReference<?>[] refs = context.getServiceReferences(CamelContext.class.getName(), "(" + key + "=" + candidate + ")");
+ if (refs != null && refs.length > 0) {
+ for (ServiceReference<?> ref : refs) {
+ Object id = ref.getProperty(key);
+ if (id != null && candidate.equals(id)) {
+ clash = true;
+ break;
+ }
+ }
+ }
+ } catch (InvalidSyntaxException e) {
+ LOG.debug("Error finding free Camel name in OSGi Service Registry due " + e.getMessage() + ". This exception is ignored.", e);
+ break;
+ }
+ } while (clash);
+
+ LOG.debug("Generated free name for bundle id: {}, clash: {} -> {}", context.getBundle().getBundleId(), clash, candidate);
+ return candidate;
+ }
+
+ public static int getNextCounter(AtomicInteger counter) {
+ // we want to start counting from 1, so increment first
+ return counter.incrementAndGet();
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java
new file mode 100644
index 0000000..a973b54
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolver.java
@@ -0,0 +1,115 @@
+/*
+ * 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.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
+import org.apache.camel.impl.engine.DefaultPackageScanClassResolver;
+import org.apache.camel.spi.PackageScanFilter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+public class OsgiPackageScanClassResolver extends DefaultPackageScanClassResolver {
+
+ private final Bundle bundle;
+
+ public OsgiPackageScanClassResolver(BundleContext context) {
+ this(context.getBundle());
+ }
+
+ public OsgiPackageScanClassResolver(Bundle bundle) {
+ this.bundle = bundle;
+ // add the BundleDelegatingClassLoader to the class loaders
+ addClassLoader(new BundleDelegatingClassLoader(bundle));
+ }
+
+ @Override
+ public void find(PackageScanFilter test, String packageName, Set<Class<?>> classes) {
+ packageName = packageName.replace('.', '/');
+ // remember the number of classes found so far
+ int classesSize = classes.size();
+ // look in osgi bundles
+ loadImplementationsInBundle(test, packageName, classes);
+ // if we did not find any new, then fallback to use regular non bundle class loading
+ if (classes.size() == classesSize) {
+ // Using the non-OSGi classloaders as a fallback
+ // this is necessary when use JBI packaging for servicemix-camel SU
+ // so that we get chance to use SU classloader to scan packages in the SU
+ log.trace("Cannot find any classes in bundles, not trying regular classloaders scanning: {}", packageName);
+ for (ClassLoader classLoader : super.getClassLoaders()) {
+ if (!isOsgiClassloader(classLoader)) {
+ find(test, packageName, classLoader, classes);
+ }
+ }
+ }
+ }
+
+ 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, Set<Class<?>> classes) {
+ Set<String> urls = getImplementationsInBundle(test, packageName);
+ if (urls != null) {
+ for (String url : urls) {
+ // substring to avoid leading slashes
+ addIfMatching(test, url, classes);
+ }
+ }
+ }
+
+ private Set<String> getImplementationsInBundle(PackageScanFilter test, String packageName) {
+ Bundle[] bundles;
+ if (bundle.getBundleContext() != null) {
+ bundles = bundle.getBundleContext().getBundles();
+ } else {
+ bundles = new Bundle[]{bundle};
+ }
+ Set<String> urls = new LinkedHashSet<>();
+ for (Bundle bd : bundles) {
+ log.trace("Searching in bundle: {}", bd);
+ try {
+ 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);
+ log.trace("Added url: {}", urlString);
+ }
+ } catch (Throwable t) {
+ log.warn("Cannot search in bundle: " + bundle + " for classes matching criteria: " + test + " due: "
+ + t.getMessage() + ". This exception will be ignored.", t);
+ }
+ }
+ return urls;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiTypeConverter.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiTypeConverter.java
new file mode 100644
index 0000000..6354cf7
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiTypeConverter.java
@@ -0,0 +1,336 @@
+/*
+ * 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.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.TypeConverterExists;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.converter.DefaultTypeConverter;
+import org.apache.camel.impl.engine.DefaultPackageScanClassResolver;
+import org.apache.camel.spi.FactoryFinder;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.TypeConverterLoader;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.support.SimpleTypeConverter;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.support.service.ServiceSupport;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OsgiTypeConverter extends ServiceSupport implements TypeConverter, TypeConverterRegistry,
+ ServiceTrackerCustomizer<TypeConverterLoader, Object> {
+ private static final Logger LOG = LoggerFactory.getLogger(OsgiTypeConverter.class);
+
+ private final BundleContext bundleContext;
+ private CamelContext camelContext;
+ private final Injector injector;
+ private final FactoryFinder factoryFinder;
+ private final ServiceTracker<TypeConverterLoader, Object> tracker;
+ private volatile DefaultTypeConverter delegate;
+
+ public OsgiTypeConverter(BundleContext bundleContext, CamelContext camelContext, Injector injector, FactoryFinder factoryFinder) {
+ this.bundleContext = bundleContext;
+ this.camelContext = camelContext;
+ this.injector = injector;
+ this.factoryFinder = factoryFinder;
+ this.tracker = new ServiceTracker<>(bundleContext, TypeConverterLoader.class.getName(), this);
+ }
+
+ @Override
+ public Object addingService(ServiceReference<TypeConverterLoader> serviceReference) {
+ LOG.trace("AddingService: {}, Bundle: {}", serviceReference, serviceReference.getBundle());
+ TypeConverterLoader loader = bundleContext.getService(serviceReference);
+ try {
+ LOG.debug("loading type converter from bundle: {}", serviceReference.getBundle().getSymbolicName());
+ if (delegate != null) {
+ ServiceHelper.startService(this.delegate);
+ loader.load(delegate);
+ }
+ } catch (Throwable t) {
+ throw new RuntimeCamelException("Error loading type converters from service: " + serviceReference + " due: " + t.getMessage(), t);
+ }
+
+ return loader;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<TypeConverterLoader> serviceReference, Object o) {
+ }
+
+ @Override
+ public void removedService(ServiceReference<TypeConverterLoader> serviceReference, Object o) {
+ LOG.trace("RemovedService: {}, Bundle: {}", serviceReference, serviceReference.getBundle());
+ try {
+ ServiceHelper.stopService(this.delegate);
+ } catch (Exception e) {
+ // ignore
+ LOG.debug("Error stopping service due: " + e.getMessage() + ". This exception will be ignored.", e);
+ }
+ // It can force camel to reload the type converter again
+ this.delegate = null;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ this.tracker.open();
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ this.tracker.close();
+ ServiceHelper.stopService(this.delegate);
+ this.delegate = null;
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+ @Override
+ public boolean allowNull() {
+ return getDelegate().allowNull();
+ }
+
+ @Override
+ public <T> T convertTo(Class<T> type, Object value) {
+ return getDelegate().convertTo(type, value);
+ }
+
+ @Override
+ public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
+ return getDelegate().convertTo(type, exchange, value);
+ }
+
+ @Override
+ public <T> T mandatoryConvertTo(Class<T> type, Object value) throws NoTypeConversionAvailableException {
+ return getDelegate().mandatoryConvertTo(type, value);
+ }
+
+ @Override
+ public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) throws NoTypeConversionAvailableException {
+ return getDelegate().mandatoryConvertTo(type, exchange, value);
+ }
+
+ @Override
+ public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
+ return getDelegate().tryConvertTo(type, exchange, value);
+ }
+
+ @Override
+ public <T> T tryConvertTo(Class<T> type, Object value) {
+ return getDelegate().tryConvertTo(type, value);
+ }
+
+ @Override
+ public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
+ getDelegate().addTypeConverter(toType, fromType, typeConverter);
+ }
+
+ @Override
+ public void addTypeConverters(TypeConverters typeConverters) {
+ getDelegate().addTypeConverters(typeConverters);
+ }
+
+ @Override
+ public boolean removeTypeConverter(Class<?> toType, Class<?> fromType) {
+ return getDelegate().removeTypeConverter(toType, fromType);
+ }
+
+ @Override
+ public void addFallbackTypeConverter(TypeConverter typeConverter, boolean canPromote) {
+ getDelegate().addFallbackTypeConverter(typeConverter, canPromote);
+ }
+
+ @Override
+ public TypeConverter lookup(Class<?> toType, Class<?> fromType) {
+ return getDelegate().lookup(toType, fromType);
+ }
+
+ @Override
+ public List<Class<?>[]> listAllTypeConvertersFromTo() {
+ return getDelegate().listAllTypeConvertersFromTo();
+ }
+
+ @Override
+ public void setInjector(Injector injector) {
+ getDelegate().setInjector(injector);
+ }
+
+ @Override
+ public Injector getInjector() {
+ return getDelegate().getInjector();
+ }
+
+ @Override
+ public Statistics getStatistics() {
+ return getDelegate().getStatistics();
+ }
+
+ @Override
+ public int size() {
+ return getDelegate().size();
+ }
+
+ @Override
+ public LoggingLevel getTypeConverterExistsLoggingLevel() {
+ return getDelegate().getTypeConverterExistsLoggingLevel();
+ }
+
+ @Override
+ public void setTypeConverterExistsLoggingLevel(LoggingLevel loggingLevel) {
+ getDelegate().setTypeConverterExistsLoggingLevel(loggingLevel);
+ }
+
+ @Override
+ public TypeConverterExists getTypeConverterExists() {
+ return getDelegate().getTypeConverterExists();
+ }
+
+ @Override
+ public void setTypeConverterExists(TypeConverterExists typeConverterExists) {
+ getDelegate().setTypeConverterExists(typeConverterExists);
+ }
+
+ public synchronized DefaultTypeConverter getDelegate() {
+ if (delegate == null) {
+ delegate = createRegistry();
+ }
+ return delegate;
+ }
+
+ protected DefaultTypeConverter createRegistry() {
+ // base the osgi type converter on the default type converter
+ DefaultTypeConverter answer = new OsgiDefaultTypeConverter(new DefaultPackageScanClassResolver() {
+ @Override
+ public Set<ClassLoader> getClassLoaders() {
+ // we only need classloaders for loading core TypeConverterLoaders
+ return new HashSet<>(Arrays.asList(
+ DefaultTypeConverter.class.getClassLoader(),
+ DefaultCamelContext.class.getClassLoader()));
+ }
+ }, injector, factoryFinder, false);
+
+ // inject CamelContext
+ answer.setCamelContext(camelContext);
+
+
+ try {
+ // init before loading core converters
+ answer.init();
+ // only load the core type converters, as OSGi activator will keep track on bundles
+ // being installed/uninstalled and load type converters as part of that process
+ answer.loadCoreAndFastTypeConverters();
+ } catch (Exception e) {
+ throw new RuntimeCamelException("Error loading CoreTypeConverter due: " + e.getMessage(), e);
+ }
+
+ // Load the type converters the tracker has been tracking
+ // Here we need to use the ServiceReference to check the ranking
+ ServiceReference<TypeConverterLoader>[] serviceReferences = this.tracker.getServiceReferences();
+ if (serviceReferences != null) {
+ ArrayList<ServiceReference<TypeConverterLoader>> servicesList =
+ new ArrayList<>(Arrays.asList(serviceReferences));
+ // Just make sure we install the high ranking fallback converter at last
+ Collections.sort(servicesList);
+ for (ServiceReference<TypeConverterLoader> sr : servicesList) {
+ try {
+ LOG.debug("loading type converter from bundle: {}", sr.getBundle().getSymbolicName());
+ ((TypeConverterLoader)this.tracker.getService(sr)).load(answer);
+ } catch (Throwable t) {
+ throw new RuntimeCamelException("Error loading type converters from service: " + sr + " due: " + t.getMessage(), t);
+ }
+ }
+ }
+
+ LOG.trace("Created TypeConverter: {}", answer);
+ return answer;
+ }
+
+ public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
+ return StreamSupport.stream(
+ Spliterators.spliteratorUnknownSize(
+ new Iterator<T>() {
+ public T next() {
+ return e.nextElement();
+ }
+ public boolean hasNext() {
+ return e.hasMoreElements();
+ }
+ public void forEachRemaining(Consumer<? super T> action) {
+ while (e.hasMoreElements()) {
+ action.accept(e.nextElement());
+ }
+ }
+ },
+ Spliterator.ORDERED), false);
+ }
+
+ private class OsgiDefaultTypeConverter extends DefaultTypeConverter {
+
+ public OsgiDefaultTypeConverter(PackageScanClassResolver resolver, Injector injector, FactoryFinder factoryFinder, boolean loadTypeConverters) {
+ super(resolver, injector, factoryFinder, loadTypeConverters);
+ }
+
+ @Override
+ public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
+ // favour keeping the converter that was loaded via TypeConverterLoader META-INF file
+ // as OSGi loads these first and then gets triggered again later when there is both a META-INF/TypeConverter and META-INF/TypeConverterLoaded file
+ // for the same set of type converters and we get duplicates (so this is a way of filtering out duplicates)
+ TypeConverter converter = typeMappings.get(toType, fromType);
+ if (converter != null && converter != typeConverter) {
+ // the converter is already there which we want to keep (optimized via SimpleTypeConverter)
+ if (converter instanceof SimpleTypeConverter) {
+ // okay keep this one
+ return;
+ }
+ }
+ super.addTypeConverter(toType, fromType, typeConverter);
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/Activator.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/Activator.java
new file mode 100644
index 0000000..6443411
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/Activator.java
@@ -0,0 +1,728 @@
+/*
+ * 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.impl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashSet;
+import java.util.List;
+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.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.Converter;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.TypeConverterLoaderException;
+import org.apache.camel.impl.converter.AnnotationTypeConverterLoader;
+import org.apache.camel.impl.scan.AnnotatedWithPackageScanFilter;
+import org.apache.camel.model.DataFormatDefinition;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.spi.ConfigurerResolver;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataFormatResolver;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.spi.PackageScanFilter;
+import org.apache.camel.spi.TypeConverterLoader;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleWire;
+import org.osgi.framework.wiring.BundleWiring;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.osgi.framework.wiring.BundleRevision.PACKAGE_NAMESPACE;
+
+public class Activator implements BundleActivator, BundleTrackerCustomizer<Object> {
+
+ public static final String META_INF_CONFIGURER = "META-INF/services/org/apache/camel/configurer/";
+ 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/";
+ public static final String META_INF_DATAFORMAT = "META-INF/services/org/apache/camel/dataformat/";
+ public static final String META_INF_TYPE_CONVERTER = "META-INF/services/org/apache/camel/TypeConverter";
+ public static final String META_INF_TYPE_CONVERTER_LOADER = "META-INF/services/org/apache/camel/TypeConverterLoader";
+ public static final String META_INF_FALLBACK_TYPE_CONVERTER = "META-INF/services/org/apache/camel/FallbackTypeConverter";
+ public static final String EXTENDER_NAMESPACE = "osgi.extender";
+ public static final String CAMEL_EXTENDER = "org.apache.camel";
+
+ private static final Logger LOG = LoggerFactory.getLogger(Activator.class);
+
+ private BundleTracker<?> tracker;
+ private final Map<Long, List<BaseService>> resolvers = new ConcurrentHashMap<>();
+ private long bundleId;
+
+ // Map from package name to the capability we export for this package
+ private final Map<String, BundleCapability> packageCapabilities = new HashMap<>();
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ LOG.info("Camel activator starting");
+ cachePackageCapabilities(context);
+ bundleId = context.getBundle().getBundleId();
+ BundleContext systemBundleContext = context.getBundle(0).getBundleContext();
+ tracker = new BundleTracker<>(systemBundleContext, Bundle.ACTIVE, this);
+ tracker.open();
+ LOG.info("Camel activator started");
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ LOG.info("Camel activator stopping");
+ tracker.close();
+ packageCapabilities.clear();
+ LOG.info("Camel activator stopped");
+ }
+
+ /**
+ * Caches the package capabilities that are needed for a set of interface classes
+ */
+ private void cachePackageCapabilities(BundleContext context) {
+ BundleWiring ourWiring = context.getBundle().adapt(BundleWiring.class);
+ List<BundleCapability> ourExports = ourWiring.getCapabilities(PACKAGE_NAMESPACE);
+ for (BundleCapability ourExport : ourExports) {
+ String ourPkgName = (String) ourExport.getAttributes().get(PACKAGE_NAMESPACE);
+ packageCapabilities.put(ourPkgName, ourExport);
+ }
+ for (BundleWire w : ourWiring.getRequiredWires(PACKAGE_NAMESPACE)) {
+ BundleCapability cap = w.getCapability();
+ String ourPkgName = (String) cap.getAttributes().get(PACKAGE_NAMESPACE);
+ packageCapabilities.put(ourPkgName, cap);
+ }
+ }
+
+ @Override
+ public Object addingBundle(Bundle bundle, BundleEvent event) {
+ LOG.debug("Bundle started: {}", bundle.getSymbolicName());
+ if (extenderCapabilityWired(bundle)) {
+ List<BaseService> r = new ArrayList<>();
+ registerConfigurers(bundle, r);
+ registerComponents(bundle, r);
+ registerLanguages(bundle, r);
+ registerDataFormats(bundle, r);
+ registerTypeConverterLoader(bundle, r);
+ for (BaseService service : r) {
+ service.register();
+ }
+ resolvers.put(bundle.getBundleId(), r);
+ }
+
+ return bundle;
+ }
+
+ private boolean extenderCapabilityWired(Bundle bundle) {
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ if (wiring == null) {
+ return true;
+ }
+ List<BundleWire> requiredWires = wiring.getRequiredWires(EXTENDER_NAMESPACE);
+ for (BundleWire requiredWire : requiredWires) {
+ if (CAMEL_EXTENDER.equals(requiredWire.getCapability().getAttributes().get(EXTENDER_NAMESPACE))) {
+ if (this.bundleId == requiredWire.getProviderWiring().getBundle().getBundleId()) {
+ LOG.debug("Camel extender requirement of bundle {} correctly wired to this implementation", bundle.getBundleId());
+ return true;
+ } else {
+ LOG.info("Not processing bundle {} as it requires a camel extender but is not wired to the this implementation", bundle.getBundleId());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+ }
+
+ @Override
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+ LOG.debug("Bundle stopped: {}", bundle.getSymbolicName());
+ List<BaseService> r = resolvers.remove(bundle.getBundleId());
+ if (r != null) {
+ for (BaseService service : r) {
+ service.unregister();
+ }
+ }
+ }
+
+ protected void registerConfigurers(Bundle bundle, List<BaseService> resolvers) {
+ if (canSee(bundle, GeneratedPropertyConfigurer.class)) {
+ Map<String, String> configurers = new HashMap<>();
+ for (Enumeration<?> e = bundle.getEntryPaths(META_INF_CONFIGURER); e != null && e.hasMoreElements();) {
+ String path = (String) e.nextElement();
+ LOG.debug("Found configureer: {} in bundle {}", path, bundle.getSymbolicName());
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ configurers.put(name, path);
+ }
+ if (!configurers.isEmpty()) {
+ resolvers.add(new BundleConfigurerResolver(bundle, configurers));
+ }
+ }
+ }
+
+ protected void registerComponents(Bundle bundle, List<BaseService> resolvers) {
+ if (canSee(bundle, Component.class)) {
+ Map<String, String> components = new HashMap<>();
+ for (Enumeration<?> e = bundle.getEntryPaths(META_INF_COMPONENT); e != null && e.hasMoreElements();) {
+ String path = (String) e.nextElement();
+ LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName());
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ components.put(name, path);
+ }
+ if (!components.isEmpty()) {
+ resolvers.add(new BundleComponentResolver(bundle, components));
+ }
+ }
+ }
+
+ protected void registerLanguages(Bundle bundle, List<BaseService> resolvers) {
+ if (canSee(bundle, Language.class)) {
+ Map<String, String> languages = new HashMap<>();
+ for (Enumeration<?> e = bundle.getEntryPaths(META_INF_LANGUAGE); e != null && e.hasMoreElements();) {
+ String path = (String) e.nextElement();
+ LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName());
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ languages.put(name, path);
+ }
+ if (!languages.isEmpty()) {
+ resolvers.add(new BundleLanguageResolver(bundle, languages));
+ }
+ for (Enumeration<?> e = bundle.getEntryPaths(META_INF_LANGUAGE_RESOLVER); e != null && e.hasMoreElements();) {
+ String path = (String) e.nextElement();
+ LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName());
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ resolvers.add(new BundleMetaLanguageResolver(bundle, name, path));
+ }
+ }
+ }
+
+ protected void registerDataFormats(Bundle bundle, List<BaseService> resolvers) {
+ if (canSee(bundle, DataFormat.class)) {
+ Map<String, String> dataformats = new HashMap<>();
+ for (Enumeration<?> e = bundle.getEntryPaths(META_INF_DATAFORMAT); e != null && e.hasMoreElements();) {
+ String path = (String) e.nextElement();
+ LOG.debug("Found entry: {} in bundle {}", path, bundle.getSymbolicName());
+ String name = path.substring(path.lastIndexOf("/") + 1);
+ dataformats.put(name, path);
+ }
+ if (!dataformats.isEmpty()) {
+ resolvers.add(new BundleDataFormatResolver(bundle, dataformats));
+ }
+ }
+ }
+
+ protected void registerTypeConverterLoader(Bundle bundle, List<BaseService> resolvers) {
+ if (canSee(bundle, TypeConverter.class)) {
+ URL url1 = bundle.getEntry(META_INF_TYPE_CONVERTER);
+ URL url2 = bundle.getEntry(META_INF_TYPE_CONVERTER_LOADER);
+ URL url3 = bundle.getEntry(META_INF_FALLBACK_TYPE_CONVERTER);
+ if (url2 != null) {
+ LOG.debug("Found TypeConverterLoader in bundle {}", bundle.getSymbolicName());
+ Set<String> packages = getConverterPackages(bundle.getEntry(META_INF_TYPE_CONVERTER_LOADER));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Found {} {} packages: {}", packages.size(), META_INF_TYPE_CONVERTER_LOADER, packages);
+ }
+ for (String pkg : packages) {
+
+ if (StringHelper.isClassName(pkg)) {
+ // its a FQN class name so load it directly
+ LOG.trace("Loading {} class", pkg);
+ try {
+ Class<?> clazz = bundle.loadClass(pkg);
+ BundleTypeConverterLoader bundleTypeConverterLoader =
+ new BundleTypeConverterLoader(bundle, url3 != null);
+ bundleTypeConverterLoader.setTypeConverterLoader((TypeConverterLoader)clazz.getDeclaredConstructor().newInstance());
+ resolvers.add(bundleTypeConverterLoader);
+ BundleTypeConverterLoader fallBackBundleTypeConverterLoader =
+ new BundleTypeConverterLoader(bundle, url3 != null);
+ // the class could be found and loaded so continue to next
+ resolvers.add(fallBackBundleTypeConverterLoader);
+ continue;
+ } catch (Throwable t) {
+ // Ignore
+ LOG.trace("Failed to load " + pkg + " class due " + t.getMessage() + ". This exception will be ignored.", t);
+ }
+ }
+ }
+
+ } else if (url1 != null || url3 != null) {
+ LOG.debug("Found TypeConverter in bundle {}", bundle.getSymbolicName());
+ resolvers.add(new BundleTypeConverterLoader(bundle, url3 != null));
+ }
+ }
+ }
+
+ /**
+ * Check if bundle can see the given class
+ */
+ protected boolean canSee(Bundle bundle, Class<?> clazz) {
+ if (bundle.getBundleId() == bundleId) {
+ // Need extra handling of camel core as it does not import the api
+ return true;
+ }
+ BundleCapability packageCap = packageCapabilities.get(clazz.getPackage().getName());
+ if (packageCap != null) {
+ BundleWiring wiring = bundle.adapt(BundleWiring.class);
+ List<BundleWire> imports = wiring.getRequiredWires(PACKAGE_NAMESPACE);
+ for (BundleWire importWire : imports) {
+ if (packageCap.equals(importWire.getCapability())) {
+ return true;
+ }
+ }
+ }
+
+ // it may be running outside real OSGi container such as when unit testing with camel-test-blueprint
+ // then we need to use a different canSee algorithm that works outside real OSGi
+ if (bundle.getBundleId() >= 0) {
+ Bundle root = bundle.getBundleContext().getBundle(0);
+ if (root != null && "org.apache.felix.connect".equals(root.getSymbolicName())) {
+ return checkCompat(bundle, clazz);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if bundle can see the given class used by camel-test-blueprint
+ */
+ protected static boolean checkCompat(Bundle bundle, Class<?> clazz) {
+ // Check bundle compatibility
+ try {
+ if (bundle.loadClass(clazz.getName()) != clazz) {
+ return false;
+ }
+ } catch (Throwable t) {
+ return false;
+ }
+ return true;
+ }
+
+ protected static class BundleComponentResolver extends BaseResolver<Component> implements ComponentResolver {
+
+ private final Map<String, String> components;
+
+ public BundleComponentResolver(Bundle bundle, Map<String, String> components) {
+ super(bundle, Component.class);
+ this.components = components;
+ }
+
+ @Override
+ public Component resolveComponent(String name, CamelContext context) throws Exception {
+ return createInstance(name, components.get(name), context);
+ }
+
+ @Override
+ public void register() {
+ doRegister(ComponentResolver.class, "component", components.keySet());
+ }
+ }
+
+ protected static class BundleConfigurerResolver extends BaseResolver<GeneratedPropertyConfigurer> implements ConfigurerResolver {
+
+ private final Map<String, String> configurers;
+
+ public BundleConfigurerResolver(Bundle bundle, Map<String, String> configurers) {
+ super(bundle, GeneratedPropertyConfigurer.class);
+ this.configurers = configurers;
+ }
+
+ @Override
+ public GeneratedPropertyConfigurer resolvePropertyConfigurer(String name, CamelContext context) {
+ return createInstance(name, configurers.get(name), context);
+ }
+
+ @Override
+ public void register() {
+ doRegister(ConfigurerResolver.class, "configurer", configurers.keySet());
+ }
+ }
+
+ protected static class BundleLanguageResolver extends BaseResolver<Language> implements LanguageResolver {
+
+ private final Map<String, String> languages;
+
+ public BundleLanguageResolver(Bundle bundle, Map<String, String> languages) {
+ super(bundle, Language.class);
+ this.languages = languages;
+ }
+
+ @Override
+ public Language resolveLanguage(String name, CamelContext context) {
+ return createInstance(name, languages.get(name), context);
+ }
+
+ @Override
+ public void register() {
+ doRegister(LanguageResolver.class, "language", languages.keySet());
+ }
+ }
+
+ protected static class BundleMetaLanguageResolver extends BaseResolver<LanguageResolver> implements LanguageResolver {
+
+ private final String name;
+ private final String path;
+
+ public BundleMetaLanguageResolver(Bundle bundle, String name, String path) {
+ super(bundle, LanguageResolver.class);
+ this.name = name;
+ this.path = path;
+ }
+
+ @Override
+ public Language resolveLanguage(String name, CamelContext context) {
+ LanguageResolver resolver = createInstance(this.name, path, context);
+ return resolver.resolveLanguage(name, context);
+ }
+
+ @Override
+ public void register() {
+ doRegister(LanguageResolver.class, "resolver", name);
+ }
+ }
+
+ protected static class BundleDataFormatResolver extends BaseResolver<DataFormat> implements DataFormatResolver {
+
+ private final Map<String, String> dataformats;
+
+ public BundleDataFormatResolver(Bundle bundle, Map<String, String> dataformats) {
+ super(bundle, DataFormat.class);
+ this.dataformats = dataformats;
+ }
+
+ @Override
+ public DataFormat resolveDataFormat(String name, CamelContext context) {
+ DataFormat dataFormat = createInstance(name, dataformats.get(name), context);
+ if (dataFormat == null) {
+ dataFormat = createDataFormat(name, context);
+ }
+
+ return dataFormat;
+ }
+
+ @Override
+ public DataFormat createDataFormat(String name, CamelContext context) {
+ return createInstance(name, dataformats.get(name), context);
+ }
+
+ public DataFormatDefinition resolveDataFormatDefinition(String name, CamelContext context) {
+ return null;
+ }
+
+ @Override
+ public void register() {
+ doRegister(DataFormatResolver.class, "dataformat", dataformats.keySet());
+ }
+ }
+
+ protected static class BundleTypeConverterLoader extends BaseResolver<TypeConverter> implements TypeConverterLoader {
+
+ private TypeConverterLoader loader = new Loader();
+ private final Bundle bundle;
+ private final boolean hasFallbackTypeConverter;
+
+ public BundleTypeConverterLoader(Bundle bundle, boolean hasFallbackTypeConverter) {
+ super(bundle, TypeConverter.class);
+ ObjectHelper.notNull(bundle, "bundle");
+ this.bundle = bundle;
+ this.hasFallbackTypeConverter = hasFallbackTypeConverter;
+ }
+
+ public void setTypeConverterLoader(TypeConverterLoader typeConverterloader) {
+ this.loader = typeConverterloader;
+ }
+
+ @Override
+ public synchronized void load(TypeConverterRegistry registry) throws TypeConverterLoaderException {
+ // must be synchronized to ensure we don't load type converters concurrently
+ // which cause Camel apps to fails in OSGi thereafter
+ try {
+ loader.load(registry);
+ } catch (Exception e) {
+ throw new TypeConverterLoaderException("Cannot load type converters using OSGi bundle: " + bundle.getBundleId(), e);
+ }
+ }
+
+ @Override
+ public void register() {
+ if (hasFallbackTypeConverter) {
+ // The FallbackTypeConverter should have a higher ranking
+ doRegister(TypeConverterLoader.class, Constants.SERVICE_RANKING, 100);
+ } else {
+ // The default service ranking is Integer(0);
+ doRegister(TypeConverterLoader.class);
+ }
+ }
+
+ class Loader extends AnnotationTypeConverterLoader {
+
+ Loader() {
+ super(null);
+ }
+
+ @Override
+ public void load(TypeConverterRegistry registry) throws TypeConverterLoaderException {
+ PackageScanFilter test = new AnnotatedWithPackageScanFilter(Converter.class, true);
+ Set<Class<?>> classes = new LinkedHashSet<>();
+ Set<String> packages = getConverterPackages(bundle.getEntry(META_INF_TYPE_CONVERTER));
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Found {} {} packages: {}", packages.size(), META_INF_TYPE_CONVERTER, packages);
+ }
+ // if we only have camel-core on the classpath then we have already pre-loaded all its type converters
+ // but we exposed the "org.apache.camel.core" package in camel-core. This ensures there is at least one
+ // packageName to scan, which triggers the scanning process. That allows us to ensure that we look for
+ // META-INF/services in all the JARs.
+ if (packages.size() == 1 && "org.apache.camel.core".equals(packages.iterator().next())) {
+ LOG.debug("No additional package names found in classpath for annotated type converters.");
+ // no additional package names found to load type converters so break out
+ return;
+ }
+
+ // now filter out org.apache.camel.core as its not needed anymore (it was just a dummy)
+ packages.remove("org.apache.camel.core");
+
+ for (String pkg : packages) {
+
+ if (StringHelper.isClassName(pkg)) {
+ // its a FQN class name so load it directly
+ LOG.trace("Loading {} class", pkg);
+ try {
+ Class<?> clazz = bundle.loadClass(pkg);
+ classes.add(clazz);
+ // the class could be found and loaded so continue to next
+ continue;
+ } catch (Throwable t) {
+ // Ignore
+ LOG.trace("Failed to load " + pkg + " class due " + t.getMessage() + ". This exception will be ignored.", t);
+ }
+ }
+
+ // its not a FQN but a package name so scan for classes in the bundle
+ Enumeration<URL> e = bundle.findEntries("/" + pkg.replace('.', '/'), "*.class", true);
+ while (e != null && e.hasMoreElements()) {
+ String path = e.nextElement().getPath();
+ String externalName = path.substring(path.charAt(0) == '/' ? 1 : 0, path.indexOf('.')).replace('/', '.');
+ LOG.trace("Loading {} class", externalName);
+ try {
+ Class<?> clazz = bundle.loadClass(externalName);
+ if (test.matches(clazz)) {
+ classes.add(clazz);
+ }
+ } catch (Throwable t) {
+ // Ignore
+ LOG.trace("Failed to load " + externalName + " class due " + t.getMessage() + ". This exception will be ignored.", t);
+ }
+ }
+ }
+
+ // load the classes into type converter registry
+ LOG.debug("Found {} @Converter classes to load", classes.size());
+ for (Class<?> type : classes) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Loading converter class: {}", ObjectHelper.name(type));
+ }
+ loadConverterMethods(registry, type);
+ }
+
+ // register fallback converters
+ URL fallbackUrl = bundle.getEntry(META_INF_FALLBACK_TYPE_CONVERTER);
+ if (fallbackUrl != null) {
+ LOG.debug("Found {} to load the FallbackTypeConverter", META_INF_FALLBACK_TYPE_CONVERTER);
+ TypeConverter tc = createInstance("FallbackTypeConverter", fallbackUrl, registry.getInjector());
+ registry.addFallbackTypeConverter(tc, false);
+ }
+
+ // now clear the maps so we do not hold references
+ visitedClasses.clear();
+ visitedURIs.clear();
+ }
+ }
+
+ }
+
+ protected abstract static class BaseResolver<T> extends BaseService {
+
+ private final Class<T> type;
+
+ public BaseResolver(Bundle bundle, Class<T> type) {
+ super(bundle);
+ this.type = type;
+ }
+
+ protected T createInstance(String name, String path, CamelContext context) {
+ if (path == null) {
+ return null;
+ }
+ URL url = bundle.getEntry(path);
+ LOG.trace("The entry {}'s url is {}", name, url);
+ //Setup the TCCL with Camel context application class loader
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ ClassLoader newClassLoader = context.getApplicationContextClassLoader();
+ if (newClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(newClassLoader);
+ }
+ T answer = createInstance(name, url, context.getInjector());
+ if (answer != null) {
+ initBundleContext(answer);
+ }
+ return answer;
+ } finally {
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+ }
+
+ private void initBundleContext(T answer) {
+ try {
+ Method method = answer.getClass().getMethod("setBundleContext", BundleContext.class);
+ if (method != null) {
+ method.invoke(answer, bundle.getBundleContext());
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected T createInstance(String name, URL url, Injector injector) {
+ try {
+ Properties properties = loadProperties(url);
+ String classname = (String) properties.get("class");
+ Class type = bundle.loadClass(classname);
+ if (!this.type.isAssignableFrom(type)) {
+ throw new IllegalArgumentException("Type is not a " + this.type.getName() + " implementation. Found: " + type.getName());
+ }
+ return (T) injector.newInstance(type, false);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalArgumentException("Invalid URI, no " + this.type.getName() + " registered for scheme : " + name, e);
+ }
+ }
+
+ }
+
+ protected abstract static class BaseService {
+
+ protected final Bundle bundle;
+ private ServiceRegistration<?> reg;
+
+ protected BaseService(Bundle bundle) {
+ this.bundle = bundle;
+ }
+
+ public abstract void register();
+
+ protected void doRegister(Class<?> type, String key, Collection<String> value) {
+ doRegister(type, key, value.toArray(new String[value.size()]));
+ }
+
+ protected void doRegister(Class<?> type, String key, Object value) {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put(key, value);
+ doRegister(type, props);
+ }
+
+ protected void doRegister(Class<?> type) {
+ doRegister(type, null);
+ }
+
+ protected void doRegister(Class<?> type, Dictionary<String, ?> props) {
+ reg = bundle.getBundleContext().registerService(type.getName(), this, props);
+ }
+
+ public void unregister() {
+ reg.unregister();
+ }
+ }
+
+ protected static Properties loadProperties(URL url) {
+ Properties properties = new Properties();
+ BufferedInputStream reader = null;
+ try {
+ reader = IOHelper.buffered(url.openStream());
+ properties.load(reader);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ } finally {
+ IOHelper.close(reader, "properties", LOG);
+ }
+ return properties;
+ }
+
+ protected static Set<String> getConverterPackages(URL resource) {
+ Set<String> packages = new LinkedHashSet<>();
+ if (resource != null) {
+ BufferedReader reader = null;
+ try {
+ reader = IOHelper.buffered(new InputStreamReader(resource.openStream()));
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ line = line.trim();
+ if (line.startsWith("#") || line.length() == 0) {
+ continue;
+ }
+ StringTokenizer iter = new StringTokenizer(line, ",");
+ while (iter.hasMoreTokens()) {
+ String name = iter.nextToken().trim();
+ if (name.length() > 0) {
+ packages.add(name);
+ }
+ }
+ }
+ } catch (Exception ignore) {
+ // Do nothing here
+ } finally {
+ IOHelper.close(reader, null, LOG);
+ }
+ }
+ return packages;
+ }
+
+}
+
+
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/package.html b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/package.html
new file mode 100644
index 0000000..aef59c0
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/impl/package.html
@@ -0,0 +1,27 @@
+<!--
+
+ 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.
+
+-->
+<html>
+<head>
+</head>
+<body>
+
+Camel OSGi Activator.
+
+</body>
+</html>
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleContextUtils.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleContextUtils.java
new file mode 100644
index 0000000..781c98a
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleContextUtils.java
@@ -0,0 +1,67 @@
+/*
+ * 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.utils;
+
+import java.lang.reflect.Method;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Helper class
+ */
+public final class BundleContextUtils {
+
+ private BundleContextUtils() {
+ }
+
+ /**
+ * Retrieve the BundleContext that the given class has been loaded from.
+ *
+ * @param clazz the class to find the bundle context from
+ * @return the bundle context or <code>null</code> if it can't be found
+ */
+ public static BundleContext getBundleContext(Class<?> clazz) {
+
+ // Ideally we should use FrameworkUtil.getBundle(clazz).getBundleContext()
+ // but that does not exist in OSGi 4.1, so until we upgrade, we keep that one
+
+ try {
+ ClassLoader cl = clazz.getClassLoader();
+ Class<?> clClazz = cl.getClass();
+ Method mth = null;
+ while (clClazz != null) {
+ try {
+ mth = clClazz.getDeclaredMethod("getBundle");
+ break;
+ } catch (NoSuchMethodException e) {
+ // Ignore
+ }
+ clClazz = clClazz.getSuperclass();
+ }
+ if (mth != null) {
+ mth.setAccessible(true);
+ return ((Bundle) mth.invoke(cl)).getBundleContext();
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+
+ return null;
+ }
+
+}
diff --git a/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleDelegatingClassLoader.java b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleDelegatingClassLoader.java
new file mode 100644
index 0000000..f0da831
--- /dev/null
+++ b/core/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/utils/BundleDelegatingClassLoader.java
@@ -0,0 +1,99 @@
+/*
+ * 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.utils;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+
+import org.osgi.framework.Bundle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A ClassLoader delegating to a given OSGi bundle.
+ *
+ */
+public class BundleDelegatingClassLoader extends ClassLoader {
+ private static final Logger LOG = LoggerFactory.getLogger(BundleDelegatingClassLoader.class);
+ private final Bundle bundle;
+ private final ClassLoader classLoader;
+
+ public BundleDelegatingClassLoader(Bundle bundle) {
+ this(bundle, null);
+ }
+
+ public BundleDelegatingClassLoader(Bundle bundle, ClassLoader classLoader) {
+ this.bundle = bundle;
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ LOG.trace("FindClass: {}", name);
+ return bundle.loadClass(name);
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ LOG.trace("FindResource: {}", name);
+ URL resource = bundle.getResource(name);
+ if (classLoader != null && resource == null) {
+ resource = classLoader.getResource(name);
+ }
+ return resource;
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ protected Enumeration findResources(String name) throws IOException {
+ LOG.trace("FindResource: {}", name);
+ return bundle.getResources(name);
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ LOG.trace("LoadClass: {}, resolve: {}", name, resolve);
+ Class<?> clazz;
+ try {
+ clazz = findClass(name);
+ } catch (ClassNotFoundException cnfe) {
+ if (classLoader != null) {
+ try {
+ clazz = classLoader.loadClass(name);
+ } catch (ClassNotFoundException e) {
+ throw new ClassNotFoundException(name + " from bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", cnfe);
+ }
+ } else {
+ throw new ClassNotFoundException(name + " from bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", cnfe);
+ }
+ }
+ if (resolve) {
+ resolveClass(clazz);
+ }
+ return clazz;
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("BundleDelegatingClassLoader(%s)", bundle);
+ }
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundle.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundle.java
new file mode 100644
index 0000000..f0cf522
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundle.java
@@ -0,0 +1,132 @@
+/*
+ * 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.net.URL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.util.CastUtils;
+import org.osgi.framework.Version;
+import org.springframework.osgi.mock.MockBundle;
+
+/**
+ * The mock bundle will make up a normal camel-components bundle
+ */
+public class CamelMockBundle extends MockBundle {
+
+ 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/";
+ public static final String META_INF_DATAFORMAT = "META-INF/services/org/apache/camel/dataformat/";
+
+ private static class ListEnumeration<E> implements Enumeration<E> {
+ private final List<E> list;
+ private int index;
+
+ ListEnumeration(List<E> list) {
+ this.list = list;
+ }
+
+ @Override
+ public boolean hasMoreElements() {
+ return list != null && index < list.size();
+ }
+
+ @Override
+ public E nextElement() {
+ E result = null;
+ if (list != null) {
+ result = list.get(index);
+ index++;
+ }
+ return result;
+ }
+
+ }
+
+ public CamelMockBundle() {
+ setClassLoader(getClass().getClassLoader());
+ }
+
+ private Enumeration<String> getListEnumeration(String prefix, String entrys[]) {
+ List<String> list = new ArrayList<>();
+ for (String entry : entrys) {
+ list.add(prefix + entry);
+ }
+ return new ListEnumeration<>(list);
+ }
+
+ @Override
+ public Enumeration<String> getEntryPaths(String path) {
+ Enumeration<String> result = null;
+ if (META_INF_COMPONENT.equals(path)) {
+ String[] entries = new String[] {"timer_test", "file_test"};
+ result = getListEnumeration(META_INF_COMPONENT, entries);
+ }
+ if (META_INF_LANGUAGE.equals(path)) {
+ String[] entries = new String[] {"bean_test", "file_test"};
+ result = getListEnumeration(META_INF_LANGUAGE, entries);
+ }
+ if (META_INF_LANGUAGE_RESOLVER.equals(path)) {
+ String[] entries = new String[] {"default"};
+ result = getListEnumeration(META_INF_LANGUAGE_RESOLVER, entries);
+ }
+
+ return result;
+ }
+
+ @Override
+ public Enumeration<URL> findEntries(String path, String filePattern, boolean recurse) {
+ if (path.equals("/org/apache/camel/core/osgi/test") && filePattern.equals("*.class")) {
+ List<URL> urls = new ArrayList<>();
+ URL url = getClass().getClassLoader().getResource("org/apache/camel/core/osgi/test/MyTypeConverter.class");
+ urls.add(url);
+ url = getClass().getClassLoader().getResource("org/apache/camel/core/osgi/test/MyRouteBuilder.class");
+ urls.add(url);
+ return new ListEnumeration<>(urls);
+ } else {
+ return CastUtils.cast(super.findEntries(path, filePattern, recurse));
+ }
+ }
+
+ @Override
+ public Map<X509Certificate, List<X509Certificate>> getSignerCertificates(int signersType) {
+ return null;
+ }
+
+ @Override
+ public Version getVersion() {
+ return Version.parseVersion("1.0.0");
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ if (isLoadableClass(name)) {
+ return super.loadClass(name);
+ } else {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ protected boolean isLoadableClass(String name) {
+ return !name.startsWith("org.apache.camel.core.osgi.other");
+ }
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundleContext.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundleContext.java
new file mode 100644
index 0000000..a1c61fa
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockBundleContext.java
@@ -0,0 +1,139 @@
+/*
+ * 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.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.component.file.FileComponent;
+import org.apache.camel.core.osgi.test.MyService;
+import org.apache.camel.language.simple.SimpleLanguage;
+import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.springframework.osgi.mock.MockBundleContext;
+import org.springframework.osgi.mock.MockServiceReference;
+
+public class CamelMockBundleContext extends MockBundleContext {
+
+ public static final String SERVICE_PID_PREFIX = "test.";
+
+ public CamelMockBundleContext(Bundle bundle) {
+ super(bundle);
+ }
+
+ @Override
+ public Object getService(@SuppressWarnings("rawtypes") ServiceReference reference) {
+ String[] classNames = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+ String classNames0 = classNames != null ? classNames[0] : null;
+ String pid = (String)reference.getProperty(Constants.SERVICE_PID);
+ if (classNames0 != null && classNames0.equals("org.apache.camel.core.osgi.test.MyService")) {
+ return new MyService();
+ } else if (pid != null && pid.equals(SERVICE_PID_PREFIX + "org.apache.camel.core.osgi.test.MyService")) {
+ return new MyService();
+ } else if (classNames0 != null && classNames0.equals(ComponentResolver.class.getName())) {
+ return new ComponentResolver() {
+ public Component resolveComponent(String name, CamelContext context) throws Exception {
+ if (name.equals("file_test")) {
+ return new FileComponent();
+ }
+ return null;
+ }
+ };
+ } else if (classNames0 != null && classNames0.equals(LanguageResolver.class.getName())) {
+ return new LanguageResolver() {
+ public Language resolveLanguage(String name, CamelContext context) {
+ if (name.equals("simple")) {
+ return new SimpleLanguage();
+ }
+ return null;
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ServiceReference getServiceReference(String clazz) {
+ // lookup Java class if clazz contains dot (.) symbol
+ if (clazz.contains(".")) {
+ try {
+ Class.forName(clazz);
+ return super.getServiceReference(clazz);
+ } catch (ClassNotFoundException ex) {
+ return null; // class not found so no service reference is returned
+ }
+ } else {
+ return super.getServiceReference(clazz);
+ }
+ }
+
+ private static void addServicePID(ServiceReference[] srs, String filter) {
+ for (ServiceReference sr : srs) {
+ if (sr instanceof MockServiceReference) {
+ Dictionary properties = new Hashtable();
+ String pid = filter.replace("(" + Constants.SERVICE_PID + "=", "").replace(")", "");
+ properties.put(Constants.SERVICE_PID, pid);
+ for (String key : sr.getPropertyKeys()) {
+ if (properties.get(key) == null) {
+ properties.put(key, sr.getProperty(key));
+ }
+ }
+ ((MockServiceReference)sr).setProperties(properties);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ public ServiceReference[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ // just simulate when the bundle context doesn't have right service reference
+ if (filter != null && filter.indexOf("name=test") > 0) {
+ return null;
+ } else {
+ ServiceReference[] srs = super.getServiceReferences(clazz, filter);
+
+ // set service.pid property by filter
+ if (filter != null && filter.indexOf(Constants.SERVICE_PID + "=") > 0) {
+ addServicePID(srs, filter);
+ }
+ return srs;
+ }
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public ServiceReference[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException {
+ // just simulate when the bundle context doesn't have right service reference
+ if (filter != null && filter.indexOf("name=test") > 0) {
+ return null;
+ }
+ MockServiceReference reference = new MockServiceReference(getBundle(), new String[] {clazz});
+ // setup the name property with the class name
+ Dictionary properties = new Hashtable();
+ properties.put("name", clazz);
+ reference.setProperties(properties);
+ return new ServiceReference[] {reference};
+ }
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockLanguageResolver.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockLanguageResolver.java
new file mode 100644
index 0000000..6b5e04b
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelMockLanguageResolver.java
@@ -0,0 +1,33 @@
+/*
+ * 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.engine.DefaultLanguageResolver;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.LanguageResolver;
+
+public class CamelMockLanguageResolver implements LanguageResolver {
+ // Delegate to the DefaultLanguageResolver
+ private LanguageResolver delegate = new DefaultLanguageResolver();
+
+ @Override
+ public Language resolveLanguage(String name, CamelContext context) {
+ return delegate.resolveLanguage(name, context);
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelOsgiTestSupport.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelOsgiTestSupport.java
new file mode 100644
index 0000000..3fba2c5
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/CamelOsgiTestSupport.java
@@ -0,0 +1,53 @@
+/*
+ * 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.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.osgi.framework.BundleContext;
+import org.springframework.osgi.mock.MockBundle;
+import org.springframework.osgi.mock.MockBundleContext;
+
+public class CamelOsgiTestSupport extends Assert {
+ private MockBundle bundle = new CamelMockBundle();
+ private MockBundleContext bundleContext = new CamelMockBundleContext(bundle);
+ private OsgiPackageScanClassResolver packageScanClassResolver = new OsgiPackageScanClassResolver(bundleContext);
+ private ClassResolver classResolver = new OsgiClassResolver(null, bundleContext);
+
+ @Before
+ public void setUp() throws Exception {
+ bundleContext.setBundle(bundle);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public OsgiPackageScanClassResolver getPackageScanClassResolver() {
+ return packageScanClassResolver;
+ }
+
+ public ClassResolver getClassResolver() {
+ return classResolver;
+ }
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiClassResolverTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiClassResolverTest.java
new file mode 100644
index 0000000..928ae79
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiClassResolverTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.InputStream;
+
+import org.apache.camel.spi.ClassResolver;
+import org.junit.Test;
+
+public class OsgiClassResolverTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testResolveClass() {
+ ClassResolver classResolver = getClassResolver();
+ Class<?> routeBuilder = classResolver.resolveClass("org.apache.camel.core.osgi.test.MyRouteBuilder");
+ assertNotNull("The class of routeBuilder should not be null.", routeBuilder);
+ }
+
+ @Test
+ public void testResolverResource() {
+ ClassResolver classResolver = getClassResolver();
+ InputStream is = classResolver.loadResourceAsStream("META-INF/services/org/apache/camel/TypeConverterLoader");
+ assertNotNull("The InputStream should not be null.", is);
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiComponentResolverTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiComponentResolverTest.java
new file mode 100644
index 0000000..1a12a13
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiComponentResolverTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.file.FileComponent;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.support.DefaultRegistry;
+import org.apache.camel.support.service.ServiceSupport;
+import org.junit.Test;
+
+public class OsgiComponentResolverTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testOsgiResolverFindComponentTest() throws Exception {
+ CamelContext camelContext = new DefaultCamelContext();
+ OsgiComponentResolver resolver = new OsgiComponentResolver(getBundleContext());
+ Component component = resolver.resolveComponent("file_test", camelContext);
+ assertNotNull("We should find file_test component", component);
+ assertTrue("We should get the file component here", component instanceof FileComponent);
+ }
+
+ @Test
+ public void testOsgiResolverFindComponentFallbackTest() throws Exception {
+ Registry registry = new DefaultRegistry();
+ registry.bind("allstar-component", new SampleComponent(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiComponentResolver resolver = new OsgiComponentResolver(getBundleContext());
+ Component component = resolver.resolveComponent("allstar", camelContext);
+ assertNotNull("We should find the super component", component);
+ assertTrue("We should get the super component here", component instanceof SampleComponent);
+ }
+
+ @Test
+ public void testOsgiResolverFindLanguageDoubleFallbackTest() throws Exception {
+ Registry registry = new DefaultRegistry();
+ registry.bind("allstar", new SampleComponent(false));
+ registry.bind("allstar-component", new SampleComponent(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiComponentResolver resolver = new OsgiComponentResolver(getBundleContext());
+ Component component = resolver.resolveComponent("allstar", camelContext);
+ assertNotNull("We should find the super component", component);
+ assertTrue("We should get the super component here", component instanceof SampleComponent);
+ assertFalse("We should NOT find the fallback component", ((SampleComponent) component).isFallback());
+ }
+
+ private static class SampleComponent extends ServiceSupport implements Component {
+
+ private boolean fallback;
+
+ SampleComponent(boolean fallback) {
+ this.fallback = fallback;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public Endpoint createEndpoint(String uri) throws Exception {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public Endpoint createEndpoint(String uri, Map<String, Object> parameters) throws Exception {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public boolean useRawUri() {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ public boolean isFallback() {
+ return fallback;
+ }
+
+ public void setFallback(boolean fallback) {
+ this.fallback = fallback;
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ // noop
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ // noop
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiDataFormatResolverTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiDataFormatResolverTest.java
new file mode 100644
index 0000000..dab6602
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiDataFormatResolverTest.java
@@ -0,0 +1,88 @@
+/*
+ * 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.InputStream;
+import java.io.OutputStream;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.support.DefaultDataFormat;
+import org.apache.camel.support.DefaultRegistry;
+import org.junit.Test;
+
+public class OsgiDataFormatResolverTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testOsgiResolverFindDataFormatFallbackTest() throws Exception {
+ Registry registry = new DefaultRegistry();
+ registry.bind("allstar-dataformat", new SampleDataFormat(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiDataFormatResolver resolver = new OsgiDataFormatResolver(getBundleContext());
+ DataFormat dataformat = resolver.resolveDataFormat("allstar", camelContext);
+ assertNotNull("We should find the super dataformat", dataformat);
+ assertTrue("We should get the super dataformat here", dataformat instanceof SampleDataFormat);
+ }
+
+ @Test
+ public void testOsgiResolverFindLanguageDoubleFallbackTest() throws Exception {
+ Registry registry = new DefaultRegistry();
+ registry.bind("allstar", new SampleDataFormat(false));
+ registry.bind("allstar-dataformat", new SampleDataFormat(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiDataFormatResolver resolver = new OsgiDataFormatResolver(getBundleContext());
+ DataFormat dataformat = resolver.resolveDataFormat("allstar", camelContext);
+ assertNotNull("We should find the super dataformat", dataformat);
+ assertTrue("We should get the super dataformat here", dataformat instanceof SampleDataFormat);
+ assertFalse("We should NOT find the fallback dataformat", ((SampleDataFormat) dataformat).isFallback());
+ }
+
+ private static class SampleDataFormat extends DefaultDataFormat {
+
+ private boolean fallback;
+
+ SampleDataFormat(boolean fallback) {
+ this.fallback = fallback;
+ }
+
+ @Override
+ public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ public boolean isFallback() {
+ return fallback;
+ }
+
+ public void setFallback(boolean fallback) {
+ this.fallback = fallback;
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiFactoryFinderTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiFactoryFinderTest.java
new file mode 100644
index 0000000..383a717
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiFactoryFinderTest.java
@@ -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 java.io.IOException;
+
+import org.apache.camel.impl.engine.DefaultClassResolver;
+import org.junit.Test;
+
+public class OsgiFactoryFinderTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testFindClass() throws Exception {
+ OsgiFactoryFinder finder = new OsgiFactoryFinder(getBundleContext(), new DefaultClassResolver(), "META-INF/services/org/apache/camel/component/");
+ Class<?> clazz = finder.findClass("file_test", "strategy.factory.").orElse(null);
+ assertNotNull("We should get the file strategy factory here", clazz);
+
+ assertFalse(finder.findClass("nofile", "strategy.factory.").isPresent());
+
+ try {
+ finder.findClass("file_test", "nostrategy.factory.");
+ fail("We should get exception here");
+ } catch (Exception ex) {
+ assertTrue("Should get IOException", ex.getCause() instanceof IOException);
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiLanguageResolverTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiLanguageResolverTest.java
new file mode 100644
index 0000000..6e160f2
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiLanguageResolverTest.java
@@ -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.io.IOException;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.spi.Language;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.support.DefaultRegistry;
+import org.junit.Test;
+
+public class OsgiLanguageResolverTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testOsgiResolverFindLanguageTest() throws IOException {
+ CamelContext camelContext = new DefaultCamelContext();
+ OsgiLanguageResolver resolver = new OsgiLanguageResolver(getBundleContext());
+ Language language = resolver.resolveLanguage("simple", camelContext);
+ assertNotNull("We should find simple language", language);
+ }
+
+ @Test
+ public void testOsgiResolverFindLanguageFallbackTest() throws IOException {
+ Registry registry = new DefaultRegistry();
+ registry.bind("fuffy-language", new SampleLanguage(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiLanguageResolver resolver = new OsgiLanguageResolver(getBundleContext());
+ Language language = resolver.resolveLanguage("fuffy", camelContext);
+ assertNotNull("We should find fuffy language", language);
+ assertTrue("We should find the fallback language", ((SampleLanguage) language).isFallback());
+ }
+
+ @Test
+ public void testOsgiResolverFindLanguageDoubleFallbackTest() throws IOException {
+ Registry registry = new DefaultRegistry();
+ registry.bind("fuffy", new SampleLanguage(false));
+ registry.bind("fuffy-language", new SampleLanguage(true));
+
+ CamelContext camelContext = new DefaultCamelContext(registry);
+
+ OsgiLanguageResolver resolver = new OsgiLanguageResolver(getBundleContext());
+ Language language = resolver.resolveLanguage("fuffy", camelContext);
+ assertNotNull("We should find fuffy language", language);
+ assertFalse("We should NOT find the fallback language", ((SampleLanguage) language).isFallback());
+ }
+
+ private static class SampleLanguage implements Language {
+
+ private boolean fallback;
+
+ SampleLanguage(boolean fallback) {
+ this.fallback = fallback;
+ }
+
+ @Override
+ public Predicate createPredicate(String expression) {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ @Override
+ public Expression createExpression(String expression) {
+ throw new UnsupportedOperationException("Should not be called");
+ }
+
+ public boolean isFallback() {
+ return fallback;
+ }
+
+ public void setFallback(boolean fallback) {
+ this.fallback = fallback;
+ }
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolverTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolverTest.java
new file mode 100644
index 0000000..eed874c
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/OsgiPackageScanClassResolverTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util.Set;
+
+import org.apache.camel.Converter;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.core.osgi.other.MyOtherRouteBuilder;
+import org.apache.camel.core.osgi.other.MyOtherTypeConverter;
+import org.apache.camel.core.osgi.test.MyRouteBuilder;
+import org.apache.camel.core.osgi.test.MyTypeConverter;
+import org.junit.Test;
+import org.osgi.framework.BundleContext;
+
+public class OsgiPackageScanClassResolverTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void testOsgiResolverFindAnnotatedTest() throws IOException {
+ BundleContext context = getBundleContext();
+ assertNotNull("The BundleContext should not be null", context);
+ OsgiPackageScanClassResolver resolver = new OsgiPackageScanClassResolver(context);
+
+ String[] packageNames = {"org.apache.camel.core.osgi.test"};
+ Set<Class<?>> classes = resolver.findAnnotated(Converter.class, packageNames);
+ assertEquals("There should find a class", classes.size(), 1);
+ assertTrue("Find a wrong class", classes.contains(MyTypeConverter.class));
+ }
+
+ @Test
+ public void testOsgiResolverFindImplementationTest() {
+ BundleContext context = getBundleContext();
+ assertNotNull("The BundleContext should not be null", context);
+ OsgiPackageScanClassResolver resolver = new OsgiPackageScanClassResolver(context);
+ String[] packageNames = {"org.apache.camel.core.osgi.test"};
+ Set<Class<?>> classes = resolver.findImplementations(RoutesBuilder.class, packageNames);
+ assertEquals("There should find a class", classes.size(), 1);
+ assertTrue("Find a wrong class", classes.contains(MyRouteBuilder.class));
+ }
+
+ @Test
+ public void testOsgiResolverFindAnnotatedWithFallbackClassLoaderTest() throws IOException {
+ BundleContext context = getBundleContext();
+ assertNotNull("The BundleContext should not be null", context);
+ OsgiPackageScanClassResolver resolver = new OsgiPackageScanClassResolver(context);
+
+ String[] packageNames = {"org.apache.camel.core.osgi.other"};
+ Set<Class<?>> classes = resolver.findAnnotated(Converter.class, packageNames);
+ assertEquals("There should find a class", classes.size(), 1);
+ assertTrue("Find a wrong class", classes.contains(MyOtherTypeConverter.class));
+ }
+
+ @Test
+ public void testOsgiResolverFindImplementationWithFallbackClassLoaderTest() {
+ BundleContext context = getBundleContext();
+ assertNotNull("The BundleContext should not be null", context);
+ OsgiPackageScanClassResolver resolver = new OsgiPackageScanClassResolver(context);
+ String[] packageNames = {"org.apache.camel.core.osgi.other"};
+ Set<Class<?>> classes = resolver.findImplementations(RoutesBuilder.class, packageNames);
+ assertEquals("There should find a class", classes.size(), 1);
+ assertTrue("Find a wrong class", classes.contains(MyOtherRouteBuilder.class));
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/ServiceRegistryTest.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/ServiceRegistryTest.java
new file mode 100644
index 0000000..e56fb40
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/ServiceRegistryTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.Map;
+import java.util.Set;
+
+import org.apache.camel.core.osgi.test.MyService;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.junit.Test;
+
+public class ServiceRegistryTest extends CamelOsgiTestSupport {
+
+ @Test
+ public void camelContextFactoryServiceRegistryTest() throws Exception {
+ DefaultCamelContext context = new OsgiDefaultCamelContext(getBundleContext());
+ context.start();
+
+ MyService myService = context.getRegistry().lookupByNameAndType(MyService.class.getName(), MyService.class);
+ assertNotNull("MyService should not be null", myService);
+
+ myService = context.getRegistry().lookupByNameAndType("test", MyService.class);
+ assertNull("We should not get the MyService Object here", myService);
+
+ Object service = context.getRegistry().lookupByName(MyService.class.getName());
+ assertNotNull("MyService should not be null", service);
+ assertTrue("It should be the instance of MyService ", service instanceof MyService);
+
+ Object serviceByPid = context.getRegistry().lookupByName(CamelMockBundleContext.SERVICE_PID_PREFIX + MyService.class.getName());
+ assertNotNull("MyService should not be null", serviceByPid);
+ assertTrue("It should be the instance of MyService ", serviceByPid instanceof MyService);
+
+ Map<String, MyService> collection = context.getRegistry().findByTypeWithName(MyService.class);
+ assertNotNull("MyService should not be null", collection);
+ assertNotNull("There should have one MyService.", collection.get(MyService.class.getName()));
+
+ Set<MyService> collection2 = context.getRegistry().findByType(MyService.class);
+ assertNotNull("MyService should not be null", collection2);
+ assertEquals(1, collection2.size());
+
+ context.stop();
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherRouteBuilder.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherRouteBuilder.java
new file mode 100644
index 0000000..1779087
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherRouteBuilder.java
@@ -0,0 +1,28 @@
+/*
+ * 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.other;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyOtherRouteBuilder extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ // Do nothing here
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherTypeConverter.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherTypeConverter.java
new file mode 100644
index 0000000..445a653
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/other/MyOtherTypeConverter.java
@@ -0,0 +1,77 @@
+/*
+ * 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.other;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.file.GenericFile;
+import org.apache.camel.spi.TypeConverterRegistry;
+
+@Converter
+public final class MyOtherTypeConverter {
+
+ /**
+ * Utility classes should not have a public constructor.
+ */
+ private MyOtherTypeConverter() {
+ }
+
+ /**
+ * Converts the given value to a boolean, handling strings or Boolean
+ * objects; otherwise returning false if the value could not be converted to
+ * a boolean
+ */
+ @Converter
+ public static boolean toBool(Object value) {
+ Boolean answer = null;
+ if (value instanceof String) {
+ answer = Boolean.valueOf((String)value);
+ }
+ if (value instanceof Boolean) {
+ answer = (Boolean) value;
+ }
+ if (answer != null) {
+ return answer.booleanValue();
+ }
+ return false;
+ }
+
+ @Converter(fallback = true)
+ public static Object convertTo(Class<?> type, Exchange exchange, Object value, TypeConverterRegistry registry) {
+ // use a fallback type converter so we can convert the embedded body if the value is GenericFile
+ if (GenericFile.class.isAssignableFrom(value.getClass())) {
+ GenericFile<?> file = (GenericFile<?>) value;
+ Class<?> from = file.getBody().getClass();
+
+ // maybe from is already the type we want
+ if (from.isAssignableFrom(type)) {
+ return file.getBody();
+ }
+ // no then try to lookup a type converter
+ TypeConverter tc = registry.lookup(type, from);
+ if (tc != null) {
+ Object body = file.getBody();
+ return tc.convertTo(type, exchange, body);
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MockTypeConverterRegistry.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MockTypeConverterRegistry.java
new file mode 100644
index 0000000..26c7c7f
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MockTypeConverterRegistry.java
@@ -0,0 +1,141 @@
+/*
+ * 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.test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.TypeConverterExists;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.spi.Injector;
+import org.apache.camel.spi.TypeConverterRegistry;
+
+public class MockTypeConverterRegistry implements TypeConverterRegistry {
+ private List<TypeConverter> typeConverters = new ArrayList<>();
+ private List<TypeConverter> fallbackTypeConverters = new ArrayList<>();
+
+ public List<TypeConverter> getTypeConverters() {
+ return typeConverters;
+ }
+
+ public List<TypeConverter> getFallbackTypeConverters() {
+ return fallbackTypeConverters;
+ }
+
+ @Override
+ public void addTypeConverter(Class<?> toType, Class<?> fromType, TypeConverter typeConverter) {
+ typeConverters.add(typeConverter);
+ }
+
+ @Override
+ public void addTypeConverters(TypeConverters typeConverters) {
+ // noop
+ }
+
+ @Override
+ public boolean removeTypeConverter(Class<?> toType, Class<?> fromType) {
+ // noop
+ return true;
+ }
+
+ @Override
+ public void addFallbackTypeConverter(TypeConverter typeConverter, boolean canPromote) {
+ fallbackTypeConverters.add(typeConverter);
+ }
+
+ @Override
+ public TypeConverter lookup(Class<?> toType, Class<?> fromType) {
+ return null;
+ }
+
+ @Override
+ public List<Class<?>[]> listAllTypeConvertersFromTo() {
+ return null;
+ }
+
+ @Override
+ public void setInjector(Injector injector) {
+ // do nothing
+ }
+
+ @Override
+ public Injector getInjector() {
+ return null;
+ }
+
+ @Override
+ public Statistics getStatistics() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return typeConverters.size();
+ }
+
+ @Override
+ public LoggingLevel getTypeConverterExistsLoggingLevel() {
+ return LoggingLevel.WARN;
+ }
+
+ @Override
+ public void setTypeConverterExistsLoggingLevel(LoggingLevel loggingLevel) {
+ // noop
+ }
+
+ @Override
+ public TypeConverterExists getTypeConverterExists() {
+ return TypeConverterExists.Override;
+ }
+
+ @Override
+ public void setTypeConverterExists(TypeConverterExists typeConverterExists) {
+ // noop
+ }
+
+ public boolean isAnnotationScanning() {
+ return false;
+ }
+
+ public void setAnnotationScanning(boolean annotationScanning) {
+ // noop
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ // noop
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return null;
+ }
+
+ @Override
+ public void start() {
+ // noop
+ }
+
+ @Override
+ public void stop() {
+ // noop
+ }
+}
+
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyRouteBuilder.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyRouteBuilder.java
new file mode 100644
index 0000000..90e8624
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyRouteBuilder.java
@@ -0,0 +1,28 @@
+/*
+ * 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.test;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class MyRouteBuilder extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ // Do nothing here
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyService.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyService.java
new file mode 100644
index 0000000..637949f
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyService.java
@@ -0,0 +1,25 @@
+/*
+ * 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.test;
+
+public class MyService {
+
+ public String sayHi() {
+ return "Hello";
+ }
+
+}
diff --git a/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyTypeConverter.java b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyTypeConverter.java
new file mode 100644
index 0000000..9c71f15
--- /dev/null
+++ b/core/camel-core-osgi/src/test/java/org/apache/camel/core/osgi/test/MyTypeConverter.java
@@ -0,0 +1,77 @@
+/*
+ * 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.test;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.component.file.GenericFile;
+import org.apache.camel.spi.TypeConverterRegistry;
+
+@Converter
+public final class MyTypeConverter {
+
+ /**
+ * Utility classes should not have a public constructor.
+ */
+ private MyTypeConverter() {
+ }
+
+ /**
+ * Converts the given value to a boolean, handling strings or Boolean
+ * objects; otherwise returning false if the value could not be converted to
+ * a boolean
+ */
+ @Converter
+ public static boolean toBool(Object value) {
+ Boolean answer = null;
+ if (value instanceof String) {
+ answer = Boolean.valueOf((String)value);
+ }
+ if (value instanceof Boolean) {
+ answer = (Boolean) value;
+ }
+ if (answer != null) {
+ return answer.booleanValue();
+ }
+ return false;
+ }
+
+ @Converter(fallback = true)
+ public static Object convertTo(Class<?> type, Exchange exchange, Object value, TypeConverterRegistry registry) {
+ // use a fallback type converter so we can convert the embedded body if the value is GenericFile
+ if (GenericFile.class.isAssignableFrom(value.getClass())) {
+ GenericFile<?> file = (GenericFile<?>) value;
+ Class<?> from = file.getBody().getClass();
+
+ // maybe from is already the type we want
+ if (from.isAssignableFrom(type)) {
+ return file.getBody();
+ }
+ // no then try to lookup a type converter
+ TypeConverter tc = registry.lookup(type, from);
+ if (tc != null) {
+ Object body = file.getBody();
+ return tc.convertTo(type, exchange, body);
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/LICENSE.txt b/core/camel-core-osgi/src/test/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/NOTICE.txt b/core/camel-core-osgi/src/test/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Apache Camel distribution. ==
+ =========================================================================
+
+ This product includes software developed by
+ The Apache Software Foundation (http://www.apache.org/).
+
+ Please read the different LICENSE files present in the licenses directory of
+ this distribution.
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/file_test b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/file_test
new file mode 100644
index 0000000..2172240
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/file_test
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.file.FileComponent
+strategy.factory.class=org.apache.camel.component.file.strategy.FileProcessStrategyFactory
\ No newline at end of file
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/timer_test b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/timer_test
new file mode 100644
index 0000000..87adb9a
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/component/timer_test
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.timer.TimerComponent
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/bean_test b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/bean_test
new file mode 100644
index 0000000..028e2cb
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/bean_test
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.language.bean.BeanLanguage
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/file_test b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/file_test
new file mode 100644
index 0000000..c907df9
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/file_test
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.language.simple.FileLanguage
\ No newline at end of file
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/resolver/default b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/resolver/default
new file mode 100644
index 0000000..b6a8d70
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/services/org/apache/camel/language/resolver/default
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.core.osgi.CamelMockLanguageResolver
\ No newline at end of file
diff --git a/core/camel-core-osgi/src/test/resources/META-INF/spring/camel-context.xml b/core/camel-core-osgi/src/test/resources/META-INF/spring/camel-context.xml
new file mode 100644
index 0000000..440ef69
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/META-INF/spring/camel-context.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<!--
+
+ The default Application Context used by the org.apache.camel.spring.Main if there
+ is no /META-INF/sprint.xml
+
+ -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+ <route>
+ <from uri="direct:a.start"/>
+ <choice>
+ <when>
+ <xpath>$foo = 'bar'</xpath>
+ <to uri="mock:x"/>
+ </when>
+ <when>
+ <xpath>$foo = 'cheese'</xpath>
+ <to uri="mock:y"/>
+ </when>
+ <otherwise>
+ <to uri="mock:z"/>
+ </otherwise>
+ </choice>
+ </route>
+ <route>
+ <from uri="direct:b.start"/>
+ <filter>
+ <xpath>/person[@name='James']</xpath>
+ <to uri="mock:b.end"/>
+ </filter>
+ </route>
+ <route>
+ <from uri="direct:c.start"/>
+ <resequence>
+ <simple>body</simple>
+ <to uri="mock:c.end"/>
+ </resequence>
+ </route>
+ </camelContext>
+
+</beans>
diff --git a/core/camel-core-osgi/src/test/resources/log4j2.properties b/core/camel-core-osgi/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..2b6df8b
--- /dev/null
+++ b/core/camel-core-osgi/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-core-osgi-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..fb91603
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.camel.karaf</groupId>
+ <artifactId>karaf</artifactId>
+ <version>3.2.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <groupId>org.apache.camel.karaf</groupId>
+ <artifactId>core-modules</artifactId>
+ <name>Camel Karaf :: Core Modules</name>
+ <description>Camel Karaf Core Modules</description>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>camel-core-osgi</module>
+ </modules>
+
+</project>
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..61931ab
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,921 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>21</version>
+ </parent>
+
+ <groupId>org.apache.camel.karaf</groupId>
+ <artifactId>karaf</artifactId>
+ <version>3.2.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <name>Camel Karaf</name>
+ <description>Camel Karaf Root POM</description>
+ <url>https://camel.apache.org</url>
+ <inceptionYear>2007</inceptionYear>
+
+ <developers>
+ <developer>
+ <name>The Apache Camel Team</name>
+ <email>dev@camel.apache.org</email>
+ <url>https://camel.apache.org</url>
+ <organization>Apache Software Foundation</organization>
+ <organizationUrl>http://apache.org/</organizationUrl>
+ </developer>
+ </developers>
+
+ <mailingLists>
+ <mailingList>
+ <name>Development List</name>
+ <subscribe>dev-subscribe@camel.apache.org</subscribe>
+ <unsubscribe>dev-unsubscribe@camel.apache.org</unsubscribe>
+ <post>dev@camel.apache.org</post>
+ </mailingList>
+ <mailingList>
+ <name>User List</name>
+ <subscribe>users-subscribe@camel.apache.org</subscribe>
+ <unsubscribe>users-unsubscribe@camel.apache.org</unsubscribe>
+ <post>users@camel.apache.org</post>
+ </mailingList>
+ <mailingList>
+ <name>Commits List</name>
+ <subscribe>commits-subscribe@camel.apache.org</subscribe>
+ <unsubscribe>commits-unsubscribe@camel.apache.org</unsubscribe>
+ <post>commits@camel.apache.org</post>
+ </mailingList>
+ </mailingLists>
+
+ <prerequisites>
+ <maven>3.5.0</maven>
+ </prerequisites>
+
+ <modules>
+ <!--<module>tooling</module>-->
+ <module>core</module>
+ <!--<module>components-starter</module>
+ <module>catalog</module>
+ <module>tests</module>
+ <module>examples</module>
+ <module>docs</module>-->
+ </modules>
+
+ <scm>
+ <connection>scm:git:http://gitbox.apache.org/repos/asf/camel-karaf.git</connection>
+ <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/camel-karaf.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=camel-karaf.git;a=summary</url>
+ <tag>HEAD</tag>
+ </scm>
+ <issueManagement>
+ <system>jira</system>
+ <url>https://issues.apache.org/jira/browse/CAMEL</url>
+ </issueManagement>
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <url>${site-repo-url}</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+
+ <!-- unify the encoding for all the modules -->
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+ <site-repo-url>scpexe://people.apache.org/www/camel.apache.org/maven/</site-repo-url>
+ <jdk.version>1.8</jdk.version>
+ <compiler.fork>false</compiler.fork>
+
+ <!-- Spring-Boot target version -->
+ <spring-boot-version>2.2.5.RELEASE</spring-boot-version>
+
+ <!-- Camel target version -->
+ <camel-version>3.2.0-SNAPSHOT</camel-version>
+
+ <!-- versions -->
+ <aether-version>1.0.2.v20150114</aether-version>
+ <arquillian-container-se-managed-version>1.0.2.Final</arquillian-container-se-managed-version>
+ <arquillian-version>1.5.0.Final</arquillian-version>
+ <asciidoctorj-version>2.1.0</asciidoctorj-version>
+ <atomix-version>1.0.8</atomix-version>
+ <avro-version>1.8.1</avro-version>
+ <cassandra-driver-guava-version>19.0</cassandra-driver-guava-version>
+ <cdi-api-2.0-version>2.0</cdi-api-2.0-version>
+ <curator-version>4.3.0</curator-version>
+ <deltaspike-version>1.9.0</deltaspike-version>
+ <egit-github-core-version>2.1.5</egit-github-core-version>
+ <exec-maven-plugin-version>1.6.0</exec-maven-plugin-version>
+ <freemarker-version>2.3.29</freemarker-version>
+ <geronimo-ws-metadata-spec-version>1.1.3</geronimo-ws-metadata-spec-version>
+ <glassfish-jaxb-runtime-version>${jakarta-jaxb-version}</glassfish-jaxb-runtime-version>
+ <google-guava-version>19.0</google-guava-version>
+ <groovy-version>3.0.2</groovy-version>
+ <grpc-guava-version>28.1-jre</grpc-guava-version>
+ <grpc-version>1.27.0</grpc-version>
+ <gson-version>2.8.5</gson-version>
+ <hadoop2-version>2.7.4</hadoop2-version>
+ <hibernate-validator-version>6.1.2.Final</hibernate-validator-version>
+ <hibernate-version>5.4.12.Final</hibernate-version>
+ <infinispan-spring-boot-version>2.2.3.Final</infinispan-spring-boot-version>
+ <jackson-version>1.9.12</jackson-version>
+ <jakarta-jaxb-version>2.3.2</jakarta-jaxb-version>
+ <jandex-version>2.1.1.Final</jandex-version>
+ <javax-annotation-api-version>1.3.2</javax-annotation-api-version>
+ <jaxb-version>2.3.0</jaxb-version>
+ <jetty9-version>9.4.20.v20190813</jetty9-version>
+ <jolokia-version>1.6.2</jolokia-version>
+ <junit-jupiter-version>5.6.0</junit-jupiter-version>
+ <kafka-avro-serializer-version>5.2.2</kafka-avro-serializer-version>
+ <log4j2-version>2.13.1</log4j2-version>
+ <lucene3-version>3.6.0</lucene3-version>
+ <maven-checkstyle-plugin-version>3.1.0</maven-checkstyle-plugin-version>
+ <maven-checkstyle-version>8.26</maven-checkstyle-version>
+ <maven-compiler-plugin-version>3.8.1</maven-compiler-plugin-version>
+ <maven-javadoc-plugin-version>3.0.1</maven-javadoc-plugin-version>
+ <maven-resources-plugin-version>3.1.0</maven-resources-plugin-version>
+ <maven-surefire-plugin-version>3.0.0-M4</maven-surefire-plugin-version>
+ <mvel-version>2.4.5.Final</mvel-version>
+ <mycila-license-version>3.0</mycila-license-version>
+ <openjpa-version>3.1.1</openjpa-version>
+ <opentracing-version>0.33.0</opentracing-version>
+ <os-maven-plugin-version>1.6.0</os-maven-plugin-version>
+ <protobuf-maven-plugin-version>0.6.1</protobuf-maven-plugin-version>
+ <protobuf-version>3.11.1</protobuf-version>
+ <reactor-version>3.2.15.RELEASE</reactor-version>
+ <roaster-version>2.20.1.Final</roaster-version>
+ <rxjava-version>1.3.8</rxjava-version>
+ <shrinkwrap-resolver-version>3.1.3</shrinkwrap-resolver-version>
+ <shrinkwrap-version>1.2.6</shrinkwrap-version>
+ <spring-cloud-commons-version>2.2.2.RELEASE</spring-cloud-commons-version>
+ <spring-cloud-consul-version>2.2.2.RELEASE</spring-cloud-consul-version>
+ <spring-cloud-netflix-version>2.2.2.RELEASE</spring-cloud-netflix-version>
+ <spring-cloud-zookeeper-version>2.2.1.RELEASE</spring-cloud-zookeeper-version>
+ <surefire.version>${maven-surefire-plugin-version}</surefire.version>
+ <testcontainers-version>1.13.0</testcontainers-version>
+ <tomcat-version>9.0.31</tomcat-version>
+ <undertow-version>2.0.30.Final</undertow-version>
+ <weld3-version>3.0.5.RELEASE</weld3-version>
+ </properties>
+
+
+ <!-- Comment out the snapshot repositories as we don't need them now -->
+ <repositories>
+ <repository>
+ <id>apache.snapshots</id>
+ <url>https://repository.apache.org/snapshots/</url>
+ <name>Apache Snapshot Repo</name>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>apache.snapshots</id>
+ <url>https://repository.apache.org/snapshots/</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-parent</artifactId>
+ <version>${camel-version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${maven-compiler-plugin-version}</version>
+ <configuration>
+ <source>${jdk.version}</source>
+ <target>${jdk.version}</target>
+ <maxmem>512M</maxmem>
+ <fork>${compiler.fork}</fork>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <attach>true</attach>
+ <source>${jdk.version}</source>
+ <quiet>true</quiet>
+ <bottom>Apache Camel</bottom>
+ <detectOfflineLinks>false</detectOfflineLinks>
+ <javadocVersion>1.8.0</javadocVersion>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <configuration>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ </plugins>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>${maven-javadoc-plugin-version}</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.10</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-buildtools</artifactId>
+ <version>${camel-version}</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <downloadSources>true</downloadSources>
+ <downloadJavadocs>false</downloadJavadocs>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludeSubProjects>false</excludeSubProjects>
+ <excludes>
+ <exclude>**/*.mvel</exclude>
+ <exclude>**/catalog/*.properties</exclude>
+ <exclude>**/*.json</exclude>
+ <exclude>**/README</exclude>
+ <exclude>**/README.txt</exclude>
+ <exclude>**/README.md</exclude>
+ <exclude>**/ReadMe.md</exclude>
+ <exclude>**/resources/**/*.xsd</exclude>
+ <exclude>**/webapp/js/**/*</exclude>
+ <exclude>**/test/resources/**/*</exclude>
+ <exclude>**/test/data*/**/*</exclude>
+ <exclude>.gitignore</exclude>
+ <exclude>.git/**/*</exclude>
+ <exclude>**/*.adoc</exclude>
+ <exclude>**/*.adoc.template</exclude>
+ <exclude>**/*.md</exclude>
+ <exclude>**/*.sh</exclude>
+ <exclude>**/*.bat</exclude>
+ <exclude>**/java9-maven-settings</exclude>
+ <exclude>**/*.pfx</exclude>
+ <!-- tooling json-simple parser -->
+ <exclude>**/src/main/java/org/json/simple/**</exclude>
+ <!-- tooling/camel-manual/src/styles/print.css use a different license -->
+ <exclude>**/src/styles/print.css</exclude>
+ <!-- tooling for component docs -->
+ <exclude>**/component-header.mvel</exclude>
+ <exclude>**/component-options.mvel</exclude>
+ <exclude>**/endpoint-options.mvel</exclude>
+ <exclude>**/dataformat-options.mvel</exclude>
+ <exclude>**/eip-options.mvel</exclude>
+ <exclude>**/language-options.mvel</exclude>
+ <exclude>**/website-components-list.mvel</exclude>
+ <exclude>**/website-languages-list.mvel</exclude>
+ <exclude>**/website-others-list.mvel</exclude>
+ <exclude>**/website-dataformats-list.mvel</exclude>
+ <exclude>**/readme-examples.mvel</exclude>
+ <exclude>**/spring-boot-auto-configure-options.mvel</exclude>
+ <exclude>**/camel-NOTICE.txt</exclude>
+ <exclude>**/spring-boot-starter-NOTICE.txt</exclude>
+ <!-- cxf does not handle comments here -->
+ <exclude>**/src/main/resources/META-INF/cxf/cxf.extension</exclude>
+ <exclude>**/src/main/resources/META-INF/cxf/bus-extensions.txt</exclude>
+ <!-- ignore the api signatures files -->
+ <exclude>**/src/signatures/*.txt</exclude>
+ <!-- camel-salesforce BSD license from salesforce developers -->
+ <exclude>**/CometDReplayExtension.java</exclude>
+ <exclude>**/LICENSE-SALESFORCE.txt</exclude>
+ <!-- camel-as2 -->
+ <exclude>**/mdnDescription.vm</exclude>
+ <!-- camel-jbpm -->
+ <exclude>**/src/main/resources/*.wid</exclude>
+ <!-- camel website and user-manual -->
+ <exclude>**/node/**</exclude>
+ <exclude>**/node_modules/**</exclude>
+ <exclude>**/user-manual/**</exclude>
+ <exclude>**/yarn.lock</exclude>
+ <!-- examples -->
+ <exclude>**/fabric8/*.yaml</exclude>
+ <exclude>**/src/main/data/*.patient</exclude>
+ <exclude>**/src/main/data/*.csv</exclude>
+ <exclude>**/src/main/resources/avro/*.avsc</exclude>
+ <!-- generated files -->
+ <exclude>**/target/**/*</exclude>
+ <exclude>**/eclipse-classes/**/*</exclude>
+ <exclude>**/.*</exclude>
+ <exclude>**/.settings/**/*</exclude>
+ <exclude>**/*.iml</exclude>
+ <exclude>**/.idea/**/*</exclude>
+ <exclude>**/avro/**/*.avpr</exclude>
+ <exclude>**/OSGI-INF/bundle.info</exclude>
+ <exclude>**/test_rsa*</exclude>
+ <exclude>**/data*/**/*.xml</exclude>
+ <exlucde>**/*.log</exlucde>
+ <exclude>**/id_file</exclude>
+ <exclude>**/dependency-reduced-pom.xml</exclude>
+ <exclude>**/Dropbox_API_Terms_and_Conditions.txt</exclude>
+ <exclude>**/MerchandiseRestResource.apxc</exclude>
+ <exclude>**/file-sig-api.txt</exclude>
+ <exclude>**/Tasks__c.java</exclude>
+ <exclude>**/*.proto</exclude>
+ <exclude>
+ **/src/main/resources/META-INF/services/org.kie.server.services.api.KieServerExtension
+ </exclude>
+ <!-- Maven Wrapper -->
+ <exclude>.mvn/**/*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <!-- see https://issues.apache.org/jira/browse/MRELEASE-812 -->
+ <version>2.4.2</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-provider-gitexe</artifactId>
+ <version>1.9</version>
+ </dependency>
+ </dependencies>
+ <configuration>
+ <localCheckout>true</localCheckout>
+ <pushChanges>true</pushChanges>
+ <tagNameFormat>@{project.artifactId}-@{project.version}</tagNameFormat>
+ <useReleaseProfile>false</useReleaseProfile>
+ <preparationGoals>clean install</preparationGoals>
+ <goals>deploy</goals>
+ <!-- The profile we want to use when doing the release -->
+ <arguments>-Prelease,apache-release,sourcecheck</arguments>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-remote-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>process-resource-bundles</id>
+ <phase>disabled</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>flatten-maven-plugin</artifactId>
+ <version>1.1.0</version>
+ <executions>
+ <execution>
+ <id>default-cli</id>
+ <phase>process-resources</phase>
+ <goals>
+ <goal>flatten</goal>
+ </goals>
+ <configuration>
+ <updatePomFile>true</updatePomFile>
+ <pomElements>
+ <build>keep</build>
+ <dependencyManagement>keep</dependencyManagement>
+ <description>keep</description>
+ <name>keep</name>
+ <parent>expand</parent>
+ <pluginManagement>keep</pluginManagement>
+ <profiles>remove</profiles>
+ <properties>keep</properties>
+ </pomElements>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <configuration>
+ <skipInstallation>${invoker.skip}</skipInstallation>
+ <skipInvocation>${invoker.skip}</skipInvocation>
+ <mavenOpts>-Xmx64m -XshowSettings</mavenOpts>
+ <showVersion>true</showVersion>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>${exec-maven-plugin-version}</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${maven-surefire-plugin-version}</version>
+ <configuration>
+ <!--forkMode>pertest</forkMode -->
+ <forkedProcessTimeoutInSeconds>300</forkedProcessTimeoutInSeconds>
+ <childDelegation>false</childDelegation>
+ <useFile>true</useFile>
+ <failIfNoTests>false</failIfNoTests>
+ <runOrder>alphabetical</runOrder>
+ <!-- lets re-run the failed test one more time, just to be sure -->
+ <rerunFailingTestsCount>2</rerunFailingTestsCount>
+ <systemPropertyVariables>
+ <javax.xml.accessExternalSchema>file,http,https</javax.xml.accessExternalSchema>
+ <javax.xml.accessExternalDTD>file,http</javax.xml.accessExternalDTD>
+ <derby.stream.error.file>target/derby.log</derby.stream.error.file>
+ <java.awt.headless>${java.awt.headless}</java.awt.headless>
+ <java.util.logging.config.file>${basedir}/target/test-classes/logging.properties
+ </java.util.logging.config.file>
+ <org.apache.activemq.default.directory.prefix>target/
+ </org.apache.activemq.default.directory.prefix>
+ </systemPropertyVariables>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/*IntegrationTest.java</exclude>
+ <exclude>**/*XXXTest.*</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>dev</id>
+ <properties>
+ <camel-version>3.2.0-SNAPSHOT</camel-version>
+ </properties>
+ </profile>
+
+ <profile>
+ <id>fastinstall</id>
+ <activation>
+ <property>
+ <name>fastinstall</name>
+ </property>
+ </activation>
+ <properties>
+ <maven.test.skip.exec>true</maven.test.skip.exec>
+ <assembly.skipAssembly>true</assembly.skipAssembly>
+ <fastinstall>true</fastinstall>
+ <noassembly>true</noassembly>
+ </properties>
+ </profile>
+
+ <profile>
+ <id>setup.eclipse</id>
+ <!-- set up the eclipse workspace and generate the .classpath and .project
+ files for modules -->
+ <properties>
+ <eclipse.workspace.dir>${basedir}/../workspace</eclipse.workspace.dir>
+ <maven.test.skip.exec>true</maven.test.skip.exec>
+ </properties>
+ <build>
+ <defaultGoal>package</defaultGoal>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${maven-compiler-plugin-version}</version>
+ <configuration>
+ <source>${jdk.version}</source>
+ <target>${jdk.version}</target>
+ <maxmem>512M</maxmem>
+ <fork>${compiler.fork}</fork>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <inherited>false</inherited>
+ <executions>
+ <execution>
+ <id>setup.eclipse.workspace</id>
+ <phase>process-test-sources</phase>
+ <goals>
+ <goal>configure-workspace</goal>
+ </goals>
+ <configuration>
+ <workspace>${eclipse.workspace.dir}</workspace>
+ <workspaceCodeStylesURL>file:etc/eclipse/CamelCodeFormatter.xml
+ </workspaceCodeStylesURL>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <inherited>false</inherited>
+ <executions>
+ <execution>
+ <id>setup.workspace</id>
+ <phase>validate</phase>
+ <configuration>
+ <target>
+ <path id="ecp.ws.path" location="${eclipse.workspace.dir}" />
+ <property name="full.eclipse.workspace" refid="ecp.ws.path" />
+ <path path="${basedir}/etc" id="etc.path" />
+
+ <path id="buildtools.classpath">
+ <fileset dir="${basedir}/buildingtools/target" includes="*.jar" />
+ <pathelement location="${basedir}/buildingtools/target/classes" />
+ <pathelement location="${basedir}/buildingtools/src/main/resources" />
+ </path>
+
+ <whichresource resource="/camel-eclipse-pmd" property="pmd.url" classpathref="buildtools.classpath" />
+ <whichresource resource="/camel-pmd-ruleset.xml" property="pmdruleset.url" classpathref="buildtools.classpath" />
+ <whichresource resource="/camel-eclipse-checkstyle" property="eclipse.checkstyle.url" classpathref="buildtools.classpath" />
+ <whichresource resource="/camel-checkstyle.xml" property="checkstyle.url" classpathref="buildtools.classpath" />
+
+ <mkdir dir="${full.eclipse.workspace}/.metadata/.plugins/org.eclipse.core.runtime/.settings" />
+ <mkdir dir="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core" />
+ <mkdir dir="${full.eclipse.workspace}/.metadata/.plugins/net.sourceforge.pmd.eclipse" />
+
+ <get src="${checkstyle.url}" dest="${full.eclipse.workspace}/camel-checkstyle.xml" />
+
+ <!-- Add checkstyle config -->
+ <copy file="${basedir}/etc/eclipse/template.checkstyle-config.xml" tofile="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core/checkstyle-config.xml" overwrite="no">
+ <filterset>
+ <filter token="CHECKSTYLE_CONFIG_FILE" value="${full.eclipse.workspace}/camel-checkstyle.xml" />
+ <filter token="APACHE_HEADER_FILE" value="${full.eclipse.workspace}/apache-header.txt" />
+ </filterset>
+ </copy>
+
+ <xslt style="${basedir}/etc/eclipse/addcheckstyle.xsl" in="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core/checkstyle-config.xml" out="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core/checkstyle-config.xml.new">
+ <param name="checkstyleconfig" expression="${full.eclipse.workspace}/camel-checkstyle.xml" />
+ </xslt>
+ <copy file="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core/checkstyle-config.xml.new" tofile="${full.eclipse.workspace}/.metadata/.plugins/net.sf.eclipsecs.core/checkstyle-config.xml" overwrite="yes" />
+
+ <!-- Add code format rules -->
+ <concat destfile="${full.eclipse.workspace}/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.core.prefs" append="true" fixlastline="true">
+ <filelist dir="${basedir}/etc/eclipse" files="org.eclipse.jdt.core.prefs" />
+ </concat>
+ <loadfile property="eclipse.code.format" srcFile="${basedir}/etc/eclipse/CamelCodeFormatter.xml" />
+ <loadfile property="eclipse.code.templates" srcFile="${basedir}/etc/eclipse/codetemplates.xml" />
+ <loadfile property="eclipse.camel.java.code.templates" srcFile="${basedir}/etc/eclipse/camel_java_templates.xml" />
+ <loadfile property="eclipse.camel.xml.code.templates" srcFile="${basedir}/etc/eclipse/camel_xml_templates.xml" />
+ <propertyfile file="${full.eclipse.workspace}/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.jdt.ui.prefs">
+ <entry key="formatter_profile" value="Camel Java Conventions" />
+ <entry key="org.eclipse.jdt.ui.formatterprofiles" value="${eclipse.code.format}" />
+ <entry key="org.eclipse.jdt.ui.text.custom_code_templates" value="${eclipse.code.templates}" />
+
+ <!-- Add Camel templates for Java DSL -->
+ <entry key="org.eclipse.jdt.ui.text.custom_templates" value="${eclipse.camel.java.code.templates}" />
+
+ <!-- Add import order -->
+ <entry key="org.eclipse.jdt.ui.importorder" value="java;javax;org.w3c;org.xml;w3c;" />
+ <!-- Sort order -->
+ <entry key="org.eclipse.jdt.ui.visibility.order" value="B,R,D,V," />
+ <entry key="outlinesortoption" value="T,SF,F,SI,I,C,SM,M," />
+ <entry key="org.eclipse.jdt.ui.enable.visibility.order" value="true" />
+ </propertyfile>
+ <propertyfile file="${full.eclipse.workspace}/.metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.wst.xml.ui.prefs">
+ <entry key="eclipse.preferences.version" value="1" />
+ <!-- Add Camel templates for Spring DSL -->
+ <entry key="org.eclipse.wst.sse.ui.custom_templates" value="${eclipse.camel.xml.code.templates}" />
+ </propertyfile>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <!-- When not on the Mac, we need to add tools.jar to the antrun plugin
+ for schemagen to work -->
+ <id>not-mac</id>
+ <activation>
+ <os>
+ <family>!mac</family>
+ </os>
+ </activation>
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-core</artifactId>
+ <version>${jaxb-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-impl</artifactId>
+ <version>${jaxb-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-jxc</artifactId>
+ <version>${jaxb-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.11.0</version>
+ </dependency>
+ <dependency>
+ <groupId>ant-contrib</groupId>
+ <artifactId>ant-contrib</artifactId>
+ <version>1.0b3</version>
+ <exclusions>
+ <exclusion>
+ <groupId>ant</groupId>
+ <artifactId>ant</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant-trax</artifactId>
+ <version>1.8.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant-nodeps</artifactId>
+ <version>1.8.1</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+ </profile>
+
+ <profile>
+ <id>jdk8-build</id>
+ <activation>
+ <jdk>(,1.9)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ <version>1.5.0</version>
+ <scope>system</scope>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>deploy</id>
+ <build>
+ <defaultGoal>deploy</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ <configuration>
+ <additionalOptions>${javadoc.opts}</additionalOptions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>source-jar</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>release</id>
+ <activation>
+ <property>
+ <name>release</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <!-- We want to deploy the artifact to a staging location for perusal -->
+ <plugin>
+ <inherited>true</inherited>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <updateReleaseInfo>true</updateReleaseInfo>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <additionalOptions>${javadoc.opts}</additionalOptions>
+ </configuration>
+ </plugin>
+ <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <configuration>
+ <passphrase>${gpg.passphrase}</passphrase>
+ <useAgent>${gpg.useagent}</useAgent>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>doclint-java8-disable</id>
+ <activation>
+ <jdk>[1.8,)</jdk>
+ </activation>
+ <properties>
+ <javadoc.opts>-Xdoclint:none</javadoc.opts>
+ </properties>
+ </profile>
+
+ <profile>
+ <id>cleanrepo</id>
+ <build>
+ <defaultGoal>build-helper:remove-project-artifact</defaultGoal>
+ </build>
+ </profile>
+
+ <profile>
+ <id>license</id>
+ <build>
+ <defaultGoal>license:format</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>com.mycila</groupId>
+ <artifactId>license-maven-plugin</artifactId>
+ <version>${mycila-license-version}</version>
+ <configuration>
+ <header>header.txt</header>
+ <excludes>
+ <exclude>KEYS</exclude>
+ <exclude>**/NOTICE</exclude>
+ <exclude>**/LICENSE</exclude>
+ <exclude>**/NOTICE.txt</exclude>
+ <exclude>**/LICENSE.txt</exclude>
+ <exclude>doap.rdf</exclude>
+ <exclude>**/README</exclude>
+ <exclude>**/*.adoc</exclude>
+ <exclude>**/node_modules/**</exclude>
+ <exclude>**/cacerts</exclude>
+ <exclude>**/*.p12</exclude>
+ <exclude>**/*.txt</exclude>
+ <exclude>.mvn/**</exclude>
+ <exclude>mvnw*</exclude>
+ <exclude>**/META-INF/persistence*.xsd</exclude>
+ </excludes>
+ <mapping>
+ <java>SLASHSTAR_STYLE</java>
+ <properties>CAMEL_PROPERTIES_STYLE</properties>
+ <spring.factories>CAMEL_PROPERTIES_STYLE</spring.factories>
+ <spring.provides>CAMEL_PROPERTIES_STYLE</spring.provides>
+ </mapping>
+ <headerDefinitions>
+ <headerDefinition>license-properties-headerdefinition.xml</headerDefinition>
+ </headerDefinitions>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-buildtools</artifactId>
+ <version>${camel-version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+</project>