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
022 import javax.xml.bind.annotation.XmlAccessType;
023 import javax.xml.bind.annotation.XmlAccessorType;
024 import javax.xml.bind.annotation.XmlElement;
025 import javax.xml.bind.annotation.XmlElements;
026 import javax.xml.bind.annotation.XmlRootElement;
027 import javax.xml.bind.annotation.XmlTransient;
028
029 import org.apache.camel.RuntimeCamelException;
030 import org.apache.camel.builder.RouteBuilder;
031 import org.apache.camel.model.IdentifiedType;
032 import org.apache.camel.model.RouteContainer;
033 import org.apache.camel.model.RouteType;
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036
037 import org.springframework.beans.factory.DisposableBean;
038 import org.springframework.beans.factory.FactoryBean;
039 import org.springframework.beans.factory.InitializingBean;
040 import org.springframework.context.ApplicationContext;
041 import org.springframework.context.ApplicationContextAware;
042 import org.springframework.context.ApplicationEvent;
043 import org.springframework.context.ApplicationListener;
044 import org.springframework.context.event.ContextRefreshedEvent;
045
046 /**
047 * A Spring {@link FactoryBean} to create and initialize a
048 * {@link SpringCamelContext} and install routes either explicitly configured in
049 * Spring XML or found by searching the classpath for Java classes which extend
050 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}.
051 *
052 * @version $Revision: 565270 $
053 */
054 @XmlRootElement(name = "camelContext")
055 @XmlAccessorType(XmlAccessType.FIELD)
056 public class CamelContextFactoryBean extends IdentifiedType implements RouteContainer, FactoryBean, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener {
057 private static final Log LOG = LogFactory.getLog(CamelContextFactoryBean.class);
058 @XmlElement(name = "package", required = false)
059 private String[] packages = {};
060 @XmlElements({@XmlElement(name = "beanPostProcessor", type = CamelBeanPostProcessor.class, required = false), @XmlElement(name = "proxy", type = CamelProxyFactoryType.class, required = false),
061 @XmlElement(name = "export", type = CamelServiceExporterType.class, required = false) })
062 private List beans;
063 @XmlElement(name = "endpoint", required = false)
064 private List<EndpointFactoryBean> endpoints;
065 @XmlElement(name = "route", required = false)
066 private List<RouteType> routes = new ArrayList<RouteType>();
067 @XmlTransient
068 private SpringCamelContext context;
069 @XmlTransient
070 private RouteBuilder routeBuilder;
071 @XmlTransient
072 private List<RouteBuilder> additionalBuilders = new ArrayList<RouteBuilder>();
073 @XmlTransient
074 private ApplicationContext applicationContext;
075
076 public Object getObject() throws Exception {
077 return getContext();
078 }
079
080 public Class getObjectType() {
081 return SpringCamelContext.class;
082 }
083
084 public boolean isSingleton() {
085 return true;
086 }
087
088 public void afterPropertiesSet() throws Exception {
089
090 // lets force any lazy creation
091 getContext();
092
093 LOG.debug("Found JAXB created routes: " + getRoutes());
094 String[] names = applicationContext.getBeanNamesForType(SpringInstrumentationAgent.class);
095 if (names.length == 1) {
096 applicationContext.getBean(names[0], SpringInstrumentationAgent.class);
097 }
098
099 findRouteBuiders();
100 installRoutes();
101 }
102
103 public void destroy() throws Exception {
104 getContext().stop();
105 }
106
107 public void onApplicationEvent(ApplicationEvent event) {
108 if (LOG.isDebugEnabled()) {
109 LOG.debug("Publishing event: " + event);
110 }
111
112 if (event instanceof ContextRefreshedEvent) {
113 // now lets start the CamelContext so that all its possible
114 // dependencies are initailized
115 try {
116 LOG.debug("Starting the context now!");
117 getContext().start();
118 } catch (Exception e) {
119 throw new RuntimeCamelException(e);
120 }
121 }
122 /*
123 * if (context != null) { context.onApplicationEvent(event); }
124 */
125 }
126
127 // Properties
128 // -------------------------------------------------------------------------
129 public SpringCamelContext getContext() throws Exception {
130 if (context == null) {
131 context = new SpringCamelContext(getApplicationContext());
132 }
133 return context;
134 }
135
136 public void setContext(SpringCamelContext context) {
137 this.context = context;
138 }
139
140 public List<RouteType> getRoutes() {
141 return routes;
142 }
143
144 public void setRoutes(List<RouteType> routes) {
145 this.routes = routes;
146 }
147
148 public RouteBuilder getRouteBuilder() {
149 return routeBuilder;
150 }
151
152 /**
153 * Set a single {@link RouteBuilder} to be used to create the default routes
154 * on startup
155 */
156 public void setRouteBuilder(RouteBuilder routeBuilder) {
157 this.routeBuilder = routeBuilder;
158 }
159
160 /**
161 * Set a collection of {@link RouteBuilder} instances to be used to create
162 * the default routes on startup
163 */
164 public void setRouteBuilders(RouteBuilder[] builders) {
165 for (RouteBuilder builder : builders) {
166 additionalBuilders.add(builder);
167 }
168 }
169
170 public ApplicationContext getApplicationContext() {
171 return applicationContext;
172 }
173
174 public void setApplicationContext(ApplicationContext applicationContext) {
175 this.applicationContext = applicationContext;
176 }
177
178 public String[] getPackages() {
179 return packages;
180 }
181
182 /**
183 * Sets the package names to be recursively searched for Java classes which
184 * extend {@link RouteBuilder} to be auto-wired up to the
185 * {@link SpringCamelContext} as a route. Note that classes are excluded if
186 * they are specifically configured in the spring.xml
187 *
188 * @param packages the package names which are recursively searched
189 */
190 public void setPackages(String[] packages) {
191 this.packages = packages;
192 }
193
194 // Implementation methods
195 // -------------------------------------------------------------------------
196
197 /**
198 * Strategy to install all available routes into the context
199 */
200 protected void installRoutes() throws Exception {
201 for (RouteBuilder routeBuilder : additionalBuilders) {
202 getContext().addRoutes(routeBuilder);
203 }
204 if (routeBuilder != null) {
205 getContext().addRoutes(routeBuilder);
206 }
207 for (RouteType route : routes) {
208 route.addRoutes(getContext());
209 }
210 }
211
212 /**
213 * Strategy method to try find {@link RouteBuilder} instances on the
214 * classpath
215 */
216 protected void findRouteBuiders() throws Exception, InstantiationException {
217 if (packages != null && packages.length > 0) {
218 RouteBuilderFinder finder = new RouteBuilderFinder(getContext(), packages);
219 finder.appendBuilders(additionalBuilders);
220 }
221 }
222
223 }