Repository: camel Updated Branches: refs/heads/master a770bbb24 -> cdee7809b
[CAMEL-8000] Add global notion of CamelContextRegistry Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/ab750c95 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/ab750c95 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/ab750c95 Branch: refs/heads/master Commit: ab750c951cb4ec6d0aab5e56e862396f2b076049 Parents: a770bbb Author: Thomas Diesler <thomas.dies...@jboss.com> Authored: Fri Nov 7 10:48:15 2014 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Fri Nov 7 17:16:37 2014 +0100 ---------------------------------------------------------------------- .../apache/camel/impl/DefaultCamelContext.java | 16 ++- .../camel/impl/DefaultCamelContextRegistry.java | 123 +++++++++++++++++++ .../apache/camel/spi/CamelContextRegistry.java | 80 ++++++++++++ .../java/org/apache/camel/spi/Container.java | 3 + .../camel/spi/CamelContextRegistryTest.java | 68 ++++++++++ 5 files changed, 289 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/ab750c95/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java index 1ca5e19..b3f6ff3 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContext.java @@ -93,6 +93,7 @@ import org.apache.camel.processor.interceptor.HandleFault; import org.apache.camel.processor.interceptor.StreamCaching; import org.apache.camel.processor.interceptor.Tracer; import org.apache.camel.spi.CamelContextNameStrategy; +import org.apache.camel.spi.CamelContextRegistry; import org.apache.camel.spi.ClassResolver; import org.apache.camel.spi.ComponentResolver; import org.apache.camel.spi.Container; @@ -267,9 +268,14 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon this.managementStrategy = createManagementStrategy(); this.managementMBeanAssembler = createManagementMBeanAssembler(); + // Register this context with the registry + // Note, this may register a partially constructed object + ((DefaultCamelContextRegistry) CamelContextRegistry.INSTANCE).afterCreate(this); + + // [TODO] Remove in 3.0 Container.Instance.manage(this); } - + /** * Creates the {@link CamelContext} using the given JNDI context as the registry * @@ -1934,6 +1940,10 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon setApplicationContextClassLoader(cl); } + // We register the context again just before start. This ensures that is is registered on restart + // Listeners should only see one call to Listener.contextAdded(CamelContext) + ((DefaultCamelContextRegistry) CamelContextRegistry.INSTANCE).beforeStart(this); + if (log.isDebugEnabled()) { log.debug("Using ClassResolver={}, PackageScanClassResolver={}, ApplicationContextClassLoader={}", new Object[]{getClassResolver(), getPackageScanClassResolver(), getApplicationContextClassLoader()}); @@ -2184,7 +2194,11 @@ public class DefaultCamelContext extends ServiceSupport implements ModelCamelCon // and clear start date startDate = null; + // [TODO] Remove in 3.0 Container.Instance.unmanage(this); + + // Unregister this context from the registry + ((DefaultCamelContextRegistry) CamelContextRegistry.INSTANCE).afterStop(this); } /** http://git-wip-us.apache.org/repos/asf/camel/blob/ab750c95/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextRegistry.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextRegistry.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextRegistry.java new file mode 100644 index 0000000..9413050 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultCamelContextRegistry.java @@ -0,0 +1,123 @@ +/** + * 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.impl; + +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.CamelContextRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The default {@link CamelContextRegistry} + */ +public final class DefaultCamelContextRegistry implements CamelContextRegistry { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultCamelContextRegistry.class); + + private final Set<CamelContext> contexts = new LinkedHashSet<CamelContext>(); + private final Set<Listener> listeners = new LinkedHashSet<Listener>(); + + synchronized void afterCreate(CamelContext camelContext) { + registerContext(camelContext); + } + + synchronized void beforeStart(CamelContext camelContext) { + if (!contexts.contains(camelContext)) { + registerContext(camelContext); + } + } + + synchronized void afterStop(CamelContext camelContext) { + unregisterContext(camelContext); + } + + private void registerContext(CamelContext camelContext) { + contexts.add(camelContext); + for (Listener listener : listeners) { + try { + listener.contextAdded(camelContext); + } catch (Throwable th) { + LOG.error("Error calling registry listener", th); + } + } + } + + private void unregisterContext(CamelContext camelContext) { + contexts.remove(camelContext); + for (Listener listener : listeners) { + try { + listener.contextRemoved(camelContext); + } catch (Throwable th) { + LOG.error("Error calling registry listener", th); + } + } + } + + @Override + public synchronized void addListener(Listener listener, boolean withCallback) { + if (withCallback) { + for (CamelContext ctx : contexts) { + listener.contextAdded(ctx); + } + } + listeners.add(listener); + } + + @Override + public synchronized void removeListener(Listener listener, boolean withCallback) { + listeners.add(listener); + if (withCallback) { + for (CamelContext ctx : contexts) { + listener.contextAdded(ctx); + } + } + } + + @Override + public synchronized Set<CamelContext> getContexts() { + return new LinkedHashSet<CamelContext>(contexts); + } + + @Override + public synchronized Set<CamelContext> getContexts(String name) { + Set<CamelContext> result = new LinkedHashSet<CamelContext>(); + for (CamelContext ctx : contexts) { + if (ctx.getName().equals(name)) { + result.add(ctx); + } + } + return result; + } + + @Override + public synchronized CamelContext getRequiredContext(String name) { + Iterator<CamelContext> itctx = getContexts(name).iterator(); + if (!itctx.hasNext()) + throw new IllegalStateException("Cannot obtain context for name: " + name); + return itctx.next(); + } + + @Override + public synchronized CamelContext getContext(String name) { + Iterator<CamelContext> itctx = getContexts(name).iterator(); + return itctx.hasNext() ? itctx.next() : null; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/ab750c95/camel-core/src/main/java/org/apache/camel/spi/CamelContextRegistry.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/CamelContextRegistry.java b/camel-core/src/main/java/org/apache/camel/spi/CamelContextRegistry.java new file mode 100644 index 0000000..a27ca35 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/spi/CamelContextRegistry.java @@ -0,0 +1,80 @@ +package org.apache.camel.spi; + +import java.util.Set; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.DefaultCamelContextRegistry; + +/** + * A global registry for camel contexts. + * + * The runtime registeres all contexts that derive from {@link DefaultCamelContext} automatically. + */ +public interface CamelContextRegistry { + + /** + * The registry singleton + */ + static final CamelContextRegistry INSTANCE = new DefaultCamelContextRegistry(); + + /** + * A listener that can be registered witht he registry + */ + public class Listener { + + /** + * Called when a context is added to the registry + */ + public void contextAdded(CamelContext camelContext) { + } + + /** + * Called when a context is removed from the registry + */ + public void contextRemoved(CamelContext camelContext) { + } + } + + /** + * Add the given listener to the registry + * @param withCallback If true, the given listener is called with the set of already registered contexts + */ + void addListener(Listener listener, boolean withCallback); + + /** + * Remove the given listener from the registry + * @param withCallback If true, the given listener is called with the set of already registered contexts + */ + void removeListener(Listener listener, boolean withCallback); + + /** + * Get the set of registerd contexts + */ + Set<CamelContext> getContexts(); + + /** + * Get the set of registered contexts for the given name. + * + * Because the camel context name property is neither unique nor immutable + * the returned set may vary for the same name. + */ + Set<CamelContext> getContexts(String name); + + /** + * Get the registered context for the given name. + * + * @return The first context in the set + * @throws IllegalStateException when there is no registered context for the given name + * @see CamelContextRegistry#getContexts(String) + */ + CamelContext getRequiredContext(String name); + + /** + * Get the registered context for the given name. + * + * @return The first context in the set or null + * @see CamelContextRegistry#getContexts(String) + */ + CamelContext getContext(String name); +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/ab750c95/camel-core/src/main/java/org/apache/camel/spi/Container.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/spi/Container.java b/camel-core/src/main/java/org/apache/camel/spi/Container.java index bcfc2da..ba0a258 100644 --- a/camel-core/src/main/java/org/apache/camel/spi/Container.java +++ b/camel-core/src/main/java/org/apache/camel/spi/Container.java @@ -34,7 +34,10 @@ import org.slf4j.LoggerFactory; * This implementation is <b>not</b> thread-safe. The {@link #manage(org.apache.camel.CamelContext)} method * may be invoked concurrently if multiple Camel applications is being started concurrently, such as from * application servers that may start deployments concurrently. + * + * @deprecated use {@link CamelContextRegistry} */ +// [TODO] Remove in 3.0 public interface Container { /** http://git-wip-us.apache.org/repos/asf/camel/blob/ab750c95/camel-core/src/test/java/org/apache/camel/spi/CamelContextRegistryTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/spi/CamelContextRegistryTest.java b/camel-core/src/test/java/org/apache/camel/spi/CamelContextRegistryTest.java new file mode 100644 index 0000000..d64ca8f --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/spi/CamelContextRegistryTest.java @@ -0,0 +1,68 @@ +/** + * 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.spi; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; +import org.apache.camel.CamelContext; +import org.apache.camel.impl.DefaultCamelContext; + +public class CamelContextRegistryTest extends TestCase { + + private final class MyListener extends CamelContextRegistry.Listener { + + private List<String> names = new ArrayList<String>(); + + @Override + public void contextAdded(CamelContext camelContext) { + names.add(camelContext.getName()); + } + + @Override + public void contextRemoved(CamelContext camelContext) { + names.remove(camelContext.getName()); + } + } + + public void testContainerSet() throws Exception { + MyListener listener = new MyListener(); + + CamelContext camel1 = new DefaultCamelContext(); + CamelContext camel2 = new DefaultCamelContext(); + + assertEquals(0, listener.names.size()); + + CamelContextRegistry.INSTANCE.addListener(listener, true); + + // after we set, then we should manage the 2 pending contexts + assertEquals(2, listener.names.size()); + + CamelContext camel3 = new DefaultCamelContext(); + assertEquals(3, listener.names.size()); + assertEquals(camel1.getName(), listener.names.get(0)); + assertEquals(camel2.getName(), listener.names.get(1)); + assertEquals(camel3.getName(), listener.names.get(2)); + + camel1.stop(); + camel2.stop(); + camel3.stop(); + + assertEquals(0, listener.names.size()); + } +}