001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.camel.spring; 018 019 import java.util.ArrayList; 020 import java.util.List; 021 import java.util.Map; 022 023 import javax.management.MBeanServer; 024 import javax.xml.bind.annotation.XmlAccessType; 025 import javax.xml.bind.annotation.XmlAccessorType; 026 import javax.xml.bind.annotation.XmlAttribute; 027 import javax.xml.bind.annotation.XmlElement; 028 import javax.xml.bind.annotation.XmlElementRef; 029 import javax.xml.bind.annotation.XmlElements; 030 import javax.xml.bind.annotation.XmlRootElement; 031 import javax.xml.bind.annotation.XmlTransient; 032 033 import org.apache.camel.RuntimeCamelException; 034 import org.apache.camel.builder.RouteBuilder; 035 import org.apache.camel.model.IdentifiedType; 036 import org.apache.camel.model.RouteBuilderRef; 037 import org.apache.camel.model.RouteContainer; 038 import org.apache.camel.model.RouteType; 039 import org.apache.camel.model.dataformat.DataFormatType; 040 import org.apache.camel.spi.InstrumentationAgent; 041 import org.apache.commons.logging.Log; 042 import org.apache.commons.logging.LogFactory; 043 import org.springframework.beans.factory.DisposableBean; 044 import org.springframework.beans.factory.FactoryBean; 045 import org.springframework.beans.factory.InitializingBean; 046 import org.springframework.context.ApplicationContext; 047 import org.springframework.context.ApplicationContextAware; 048 import org.springframework.context.ApplicationEvent; 049 import org.springframework.context.ApplicationListener; 050 import org.springframework.context.event.ContextRefreshedEvent; 051 052 /** 053 * A Spring {@link FactoryBean} to create and initialize a 054 * {@link SpringCamelContext} and install routes either explicitly configured in 055 * Spring XML or found by searching the classpath for Java classes which extend 056 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}. 057 * 058 * @version $Revision: 641676 $ 059 */ 060 @XmlRootElement(name = "camelContext") 061 @XmlAccessorType(XmlAccessType.FIELD) 062 public class CamelContextFactoryBean extends IdentifiedType implements RouteContainer, FactoryBean, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener { 063 private static final Log LOG = LogFactory.getLog(CamelContextFactoryBean.class); 064 @XmlAttribute(required = false) 065 private Boolean useJmx; 066 @XmlAttribute(required = false) 067 private String mbeanServer; 068 @XmlAttribute(required = false) 069 private Boolean autowireRouteBuilders = Boolean.TRUE; 070 @XmlElement(name = "package", required = false) 071 private String[] packages = {}; 072 @XmlElements({ 073 @XmlElement(name = "beanPostProcessor", type = CamelBeanPostProcessor.class, required = false), 074 @XmlElement(name = "template", type = CamelTemplateFactoryBean.class, required = false), 075 @XmlElement(name = "proxy", type = CamelProxyFactoryType.class, required = false), 076 @XmlElement(name = "export", type = CamelServiceExporterType.class, required = false), 077 @XmlElement(name = "jmxAgent", required = false)}) 078 private List beans; 079 @XmlElement(name = "routeBuilderRef", required = false) 080 private List<RouteBuilderRef> builderRefs = new ArrayList<RouteBuilderRef>(); 081 @XmlElement(name = "endpoint", required = false) 082 private List<EndpointFactoryBean> endpoints; 083 @XmlElementRef 084 private List<DataFormatType> dataFormats; 085 @XmlElement(name = "route", required = false) 086 private List<RouteType> routes = new ArrayList<RouteType>(); 087 @XmlTransient 088 private SpringCamelContext context; 089 @XmlTransient 090 private RouteBuilder routeBuilder; 091 @XmlTransient 092 private List<RouteBuilder> additionalBuilders = new ArrayList<RouteBuilder>(); 093 @XmlTransient 094 private ApplicationContext applicationContext; 095 @XmlTransient 096 private ClassLoader contextClassLoaderOnStart; 097 @XmlTransient 098 private InstrumentationAgent instrumentationAgent; 099 100 public CamelContextFactoryBean() { 101 102 // Lets keep track of the class loader for when we actually do start things up 103 contextClassLoaderOnStart = Thread.currentThread().getContextClassLoader(); 104 } 105 106 public Object getObject() throws Exception { 107 return getContext(); 108 } 109 110 public Class getObjectType() { 111 return SpringCamelContext.class; 112 } 113 114 public boolean isSingleton() { 115 return true; 116 } 117 118 public void afterPropertiesSet() throws Exception { 119 // lets force any lazy creation 120 getContext().addRouteDefinitions(routes); 121 122 if (instrumentationAgent == null && isJmxEnabled()) { 123 SpringInstrumentationAgent agent = new SpringInstrumentationAgent(); 124 agent.setCamelContext(getContext()); 125 String name = getMbeanServer(); 126 if (name != null) { 127 MBeanServer mbeanServer = (MBeanServer) getApplicationContext().getBean(name, MBeanServer.class); 128 agent.setMBeanServer(mbeanServer); 129 } 130 instrumentationAgent = agent; 131 instrumentationAgent.start(); 132 } 133 134 LOG.debug("Found JAXB created routes: " + getRoutes()); 135 136 findRouteBuiders(); 137 installRoutes(); 138 } 139 140 public void destroy() throws Exception { 141 getContext().stop(); 142 } 143 144 public void onApplicationEvent(ApplicationEvent event) { 145 if (LOG.isDebugEnabled()) { 146 LOG.debug("Publishing event: " + event); 147 } 148 149 if (event instanceof ContextRefreshedEvent) { 150 // now lets start the CamelContext so that all its possible 151 // dependencies are initailized 152 try { 153 LOG.debug("Starting the context now!"); 154 getContext().start(); 155 } catch (Exception e) { 156 throw new RuntimeCamelException(e); 157 } 158 } 159 /* 160 * if (context != null) { context.onApplicationEvent(event); } 161 */ 162 } 163 164 // Properties 165 // ------------------------------------------------------------------------- 166 public SpringCamelContext getContext() throws Exception { 167 if (context == null) { 168 context = createContext(); 169 } 170 return context; 171 } 172 173 public void setContext(SpringCamelContext context) { 174 this.context = context; 175 } 176 177 public List<RouteType> getRoutes() { 178 return routes; 179 } 180 181 public void setRoutes(List<RouteType> routes) { 182 this.routes = routes; 183 } 184 185 public RouteBuilder getRouteBuilder() { 186 return routeBuilder; 187 } 188 189 /** 190 * Set a single {@link RouteBuilder} to be used to create the default routes 191 * on startup 192 */ 193 public void setRouteBuilder(RouteBuilder routeBuilder) { 194 this.routeBuilder = routeBuilder; 195 } 196 197 /** 198 * Set a collection of {@link RouteBuilder} instances to be used to create 199 * the default routes on startup 200 */ 201 public void setRouteBuilders(RouteBuilder[] builders) { 202 for (RouteBuilder builder : builders) { 203 additionalBuilders.add(builder); 204 } 205 } 206 207 public ApplicationContext getApplicationContext() { 208 if (applicationContext == null) { 209 throw new IllegalArgumentException("No applicationContext has been injected!"); 210 } 211 return applicationContext; 212 } 213 214 public void setApplicationContext(ApplicationContext applicationContext) { 215 this.applicationContext = applicationContext; 216 } 217 218 public String[] getPackages() { 219 return packages; 220 } 221 222 /** 223 * Sets the package names to be recursively searched for Java classes which 224 * extend {@link RouteBuilder} to be auto-wired up to the 225 * {@link SpringCamelContext} as a route. Note that classes are excluded if 226 * they are specifically configured in the spring.xml 227 * 228 * @param packages the package names which are recursively searched 229 */ 230 public void setPackages(String[] packages) { 231 this.packages = packages; 232 } 233 234 public String getMbeanServer() { 235 return mbeanServer; 236 } 237 238 public void setMbeanServer(String mbeanServer) { 239 this.mbeanServer = mbeanServer; 240 } 241 242 public boolean isJmxEnabled() { 243 return useJmx != null && useJmx.booleanValue(); 244 } 245 246 public Boolean getUseJmx() { 247 return useJmx; 248 } 249 250 public void setUseJmx(Boolean useJmx) { 251 this.useJmx = useJmx; 252 } 253 254 public List<RouteBuilderRef> getBuilderRefs() { 255 return builderRefs; 256 } 257 258 public void setBuilderRefs(List<RouteBuilderRef> builderRefs) { 259 this.builderRefs = builderRefs; 260 } 261 262 /** 263 * If enabled this will force all {@link RouteBuilder} classes configured in the Spring 264 * {@link ApplicationContext} to be registered automatically with this CamelContext. 265 */ 266 public void setAutowireRouteBuilders(Boolean autowireRouteBuilders) { 267 this.autowireRouteBuilders = autowireRouteBuilders; 268 } 269 270 // Implementation methods 271 // ------------------------------------------------------------------------- 272 273 /** 274 * Create the context 275 */ 276 protected SpringCamelContext createContext() { 277 SpringCamelContext ctx = new SpringCamelContext(getApplicationContext()); 278 ctx.setName(getId()); 279 return ctx; 280 } 281 282 /** 283 * Strategy to install all available routes into the context 284 */ 285 protected void installRoutes() throws Exception { 286 if (autowireRouteBuilders != null && autowireRouteBuilders.booleanValue()) { 287 Map builders = getApplicationContext().getBeansOfType(RouteBuilder.class, true, true); 288 if (builders != null) { 289 for (Object builder : builders.values()) { 290 getContext().addRoutes((RouteBuilder) builder); 291 } 292 } 293 } 294 for (RouteBuilder routeBuilder : additionalBuilders) { 295 getContext().addRoutes(routeBuilder); 296 } 297 if (routeBuilder != null) { 298 getContext().addRoutes(routeBuilder); 299 } 300 301 // lets add route builders added from references 302 if (builderRefs != null) { 303 for (RouteBuilderRef builderRef : builderRefs) { 304 RouteBuilder builder = builderRef.createRouteBuilder(getContext()); 305 getContext().addRoutes(builder); 306 } 307 } 308 } 309 310 /** 311 * Strategy method to try find {@link RouteBuilder} instances on the 312 * classpath 313 */ 314 protected void findRouteBuiders() throws Exception, InstantiationException { 315 if (packages != null && packages.length > 0) { 316 RouteBuilderFinder finder = new RouteBuilderFinder(getContext(), packages, contextClassLoaderOnStart); 317 finder.appendBuilders(additionalBuilders); 318 } 319 } 320 }