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: 36507 $
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 }