Author: gnodet Date: Mon Dec 6 12:58:27 2010 New Revision: 1042612 URL: http://svn.apache.org/viewvc?rev=1042612&view=rev Log: [CAMEL-3381][CAMEL-3382] Publish the CamelContext as an OSGi service and propagate camel events as EventAdmin events
Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java Modified: camel/trunk/components/camel-blueprint/pom.xml camel/trunk/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java camel/trunk/components/camel-spring/pom.xml camel/trunk/components/camel-spring/src/main/java/org/apache/camel/osgi/CamelContextFactoryBean.java Modified: camel/trunk/components/camel-blueprint/pom.xml URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-blueprint/pom.xml?rev=1042612&r1=1042611&r2=1042612&view=diff ============================================================================== --- camel/trunk/components/camel-blueprint/pom.xml (original) +++ camel/trunk/components/camel-blueprint/pom.xml Mon Dec 6 12:58:27 2010 @@ -35,6 +35,7 @@ <camel.osgi.import> !org.apache.camel.blueprint.*, org.apache.camel.*;${camel.osgi.import.strict.version}, + org.osgi.service.event*;resolution:=optional, * </camel.osgi.import> <camel.osgi.export> Modified: camel/trunk/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java?rev=1042612&r1=1042611&r2=1042612&view=diff ============================================================================== --- camel/trunk/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java (original) +++ camel/trunk/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java Mon Dec 6 12:58:27 2010 @@ -31,6 +31,8 @@ import org.apache.camel.RoutesBuilder; import org.apache.camel.ShutdownRoute; import org.apache.camel.ShutdownRunningTask; import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.core.osgi.OsgiCamelContextPublisher; +import org.apache.camel.core.osgi.OsgiEventAdminNotifier; import org.apache.camel.core.xml.AbstractCamelContextFactoryBean; import org.apache.camel.core.xml.CamelJMXAgentDefinition; import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition; @@ -50,6 +52,8 @@ import org.apache.camel.model.ThreadPool import org.apache.camel.model.config.PropertiesDefinition; import org.apache.camel.model.dataformat.DataFormatsDefinition; import org.apache.camel.spi.PackageScanFilter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.osgi.framework.BundleContext; import org.osgi.service.blueprint.container.BlueprintContainer; @@ -64,6 +68,7 @@ import org.osgi.service.blueprint.contai @XmlRootElement(name = "camelContext") @XmlAccessorType(XmlAccessType.FIELD) public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<BlueprintCamelContext> { + private static final Log LOG = LogFactory.getLog(CamelContextFactoryBean.class); @XmlAttribute(name = "depends-on", required = false) private String dependsOn; @@ -198,6 +203,19 @@ public class CamelContextFactoryBean ext protected void findRouteBuildersByContextScan(PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception { } + @Override + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + getContext().getManagementStrategy().addEventNotifier(new OsgiCamelContextPublisher(bundleContext)); + try { + getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin"); + getContext().getManagementStrategy().addEventNotifier(new OsgiEventAdminNotifier(bundleContext)); + } catch (Throwable t) { + // Ignore, if the EventAdmin package is not available, just don't use it + LOG.debug("EventAdmin package is not available, just don't use it"); + } + } + public String getDependsOn() { return dependsOn; } Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java?rev=1042612&view=auto ============================================================================== --- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java (added) +++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiCamelContextPublisher.java Mon Dec 6 12:58:27 2010 @@ -0,0 +1,90 @@ +/** + * 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.management.EventNotifierSupport; +import org.apache.camel.management.event.CamelContextStartedEvent; +import org.apache.camel.management.event.CamelContextStoppingEvent; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.Version; + +import java.util.Dictionary; +import java.util.EventObject; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This EventNotifier is in charge of registerting 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"; + + private final BundleContext bundleContext; + private final Map<CamelContext, ServiceRegistration> registrations = new ConcurrentHashMap<CamelContext, ServiceRegistration>(); + + public OsgiCamelContextPublisher(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void notify(EventObject event) throws Exception { + if (event instanceof CamelContextStartedEvent) { + CamelContext context = ((CamelContextStartedEvent) event).getContext(); + Properties props = new Properties(); + props.put(CONTEXT_SYMBOLIC_NAME_PROPERTY, + bundleContext.getBundle().getSymbolicName()); + props.put(CONTEXT_VERSION_PROPERTY, + getBundleVersion(bundleContext.getBundle())); + ServiceRegistration reg = bundleContext.registerService( + CamelContext.class.getName(), + context, + props); + registrations.put( context, reg ); + } else if (event instanceof CamelContextStoppingEvent) { + CamelContext context = ((CamelContextStoppingEvent) event).getContext(); + ServiceRegistration reg = registrations.get( context ); + if (reg != null) { + reg.unregister(); + } + } + } + + public boolean isEnabled(EventObject event) { + return true; + } + + @Override + protected void doStart() throws Exception { + } + + @Override + protected void doStop() throws Exception { + } + + 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; + } +} Added: camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java?rev=1042612&view=auto ============================================================================== --- camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java (added) +++ camel/trunk/components/camel-core-osgi/src/main/java/org/apache/camel/core/osgi/OsgiEventAdminNotifier.java Mon Dec 6 12:58:27 2010 @@ -0,0 +1,152 @@ +/** + * 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.management.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; + +import java.util.Dictionary; +import java.util.EventObject; +import java.util.Hashtable; + +/** + * This EventNotifier is in charge of propagating events to 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 tracker; + + public OsgiEventAdminNotifier(BundleContext bundleContext) { + this.bundleContext = bundleContext; + this.tracker = new ServiceTracker(bundleContext, EventAdmin.class.getName(), null); + setIgnoreExchangeEvents(true); + } + + public void notify(EventObject event) throws Exception { + EventAdmin eventAdmin = (EventAdmin) tracker.getService(); + if (eventAdmin == null) { + return; + } + + Dictionary<String, Object> props = new Hashtable<String, Object>(); + 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)); + } + + public boolean isEnabled(EventObject 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(EventObject event) { + String type = event.getClass().getSimpleName(); + if (type.endsWith("Event")) { + type = type.substring(0, type.length() - "Event".length()); + } + return type; + } + + public static String getTopic(EventObject 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; + } + +} Modified: camel/trunk/components/camel-spring/pom.xml URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/pom.xml?rev=1042612&r1=1042611&r2=1042612&view=diff ============================================================================== --- camel/trunk/components/camel-spring/pom.xml (original) +++ camel/trunk/components/camel-spring/pom.xml Mon Dec 6 12:58:27 2010 @@ -42,6 +42,7 @@ !org.apache.camel.component.xslt, org.apache.camel.*;${camel.osgi.import.strict.version}, org.osgi.framework;version="[1.3,2)", + org.osgi.service.event;resolution:=optional, org.springframework.osgi.*;version="[1.2,2)", org.springframework.*;version="[2.5,4)", * Modified: camel/trunk/components/camel-spring/src/main/java/org/apache/camel/osgi/CamelContextFactoryBean.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/main/java/org/apache/camel/osgi/CamelContextFactoryBean.java?rev=1042612&r1=1042611&r2=1042612&view=diff ============================================================================== --- camel/trunk/components/camel-spring/src/main/java/org/apache/camel/osgi/CamelContextFactoryBean.java (original) +++ camel/trunk/components/camel-spring/src/main/java/org/apache/camel/osgi/CamelContextFactoryBean.java Mon Dec 6 12:58:27 2010 @@ -21,6 +21,8 @@ import javax.xml.bind.annotation.XmlAcce import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; +import org.apache.camel.core.osgi.OsgiCamelContextPublisher; +import org.apache.camel.core.osgi.OsgiEventAdminNotifier; import org.apache.camel.spring.SpringCamelContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -58,5 +60,17 @@ public class CamelContextFactoryBean ext protected SpringCamelContext newCamelContext() { return new OsgiSpringCamelContext(getApplicationContext(), getBundleContext()); } - + + @Override + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + getContext().getManagementStrategy().addEventNotifier(new OsgiCamelContextPublisher(bundleContext)); + try { + getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin"); + getContext().getManagementStrategy().addEventNotifier(new OsgiEventAdminNotifier(bundleContext)); + } catch (Throwable t) { + // Ignore, if the EventAdmin package is not available, just don't use it + LOG.debug("EventAdmin package is not available, just don't use it"); + } + } }