| /* |
| * 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; |
| |
| /** |
| * 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 final BundleContext bundleContext; |
| private final Map<CamelContext, ServiceRegistration<?>> registrations |
| = new ConcurrentHashMap<>(); |
| |
| public OsgiCamelContextPublisher(BundleContext bundleContext) { |
| this.bundleContext = bundleContext; |
| } |
| |
| 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); |
| } |
| } |
| } |
| } |
| |
| 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; |
| } |
| |
| } |