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.test.junit4;
018
019 import java.io.InputStream;
020 import java.util.Hashtable;
021 import java.util.List;
022 import java.util.Map;
023 import java.util.Properties;
024
025 import javax.naming.Context;
026 import javax.naming.InitialContext;
027
028 import org.apache.camel.CamelContext;
029 import org.apache.camel.ConsumerTemplate;
030 import org.apache.camel.Endpoint;
031 import org.apache.camel.Exchange;
032 import org.apache.camel.Expression;
033 import org.apache.camel.Message;
034 import org.apache.camel.Predicate;
035 import org.apache.camel.Processor;
036 import org.apache.camel.ProducerTemplate;
037 import org.apache.camel.Service;
038 import org.apache.camel.builder.RouteBuilder;
039 import org.apache.camel.component.mock.MockEndpoint;
040 import org.apache.camel.impl.DefaultCamelContext;
041 import org.apache.camel.impl.JndiRegistry;
042 import org.apache.camel.management.JmxSystemPropertyKeys;
043 import org.apache.camel.spi.Language;
044 import org.apache.camel.spring.CamelBeanPostProcessor;
045 import org.apache.camel.util.CamelContextHelper;
046 import org.junit.After;
047 import org.junit.Before;
048
049 /**
050 * A useful base class which creates a {@link org.apache.camel.CamelContext} with some routes
051 * along with a {@link org.apache.camel.ProducerTemplate} for use in the test case
052 *
053 * @version $Revision: 786457 $
054 */
055 public abstract class CamelTestSupport extends TestSupport {
056
057 protected CamelContext context;
058 protected ProducerTemplate template;
059 protected ConsumerTemplate consumer;
060 private boolean useRouteBuilder = true;
061 private Service camelContextService;
062
063 public boolean isUseRouteBuilder() {
064 return useRouteBuilder;
065 }
066
067 public void setUseRouteBuilder(boolean useRouteBuilder) {
068 this.useRouteBuilder = useRouteBuilder;
069 }
070
071 public Service getCamelContextService() {
072 return camelContextService;
073 }
074
075 /**
076 * Allows a service to be registered a separate lifecycle service to start
077 * and stop the context; such as for Spring when the ApplicationContext is
078 * started and stopped, rather than directly stopping the CamelContext
079 */
080 public void setCamelContextService(Service camelContextService) {
081 this.camelContextService = camelContextService;
082 }
083
084 @Before
085 public void setUp() throws Exception {
086 context = createCamelContext();
087 assertValidContext(context);
088
089 template = context.createProducerTemplate();
090 consumer = context.createConsumerTemplate();
091
092 postProcessTest();
093
094 if (isUseRouteBuilder()) {
095 RouteBuilder[] builders = createRouteBuilders();
096 for (RouteBuilder builder : builders) {
097 log.debug("Using created route builder: " + builder);
098 context.addRoutes(builder);
099 }
100 startCamelContext();
101 log.debug("Routing Rules are: " + context.getRoutes());
102 } else {
103 log.debug("Using route builder from the created context: " + context);
104 }
105 log.debug("Routing Rules are: " + context.getRoutes());
106 }
107
108 @After
109 public void tearDown() throws Exception {
110 log.debug("tearDown test ");
111 if (consumer != null) {
112 consumer.stop();
113 }
114 if (template != null) {
115 template.stop();
116 }
117 stopCamelContext();
118 }
119
120 /**
121 * Lets post process this test instance to process any Camel annotations.
122 * Note that using Spring Test or Guice is a more powerful approach.
123 */
124 protected void postProcessTest() throws Exception {
125 CamelBeanPostProcessor processor = new CamelBeanPostProcessor();
126 processor.setCamelContext(context);
127 processor.postProcessBeforeInitialization(this, "this");
128 }
129
130 protected void stopCamelContext() throws Exception {
131 if (camelContextService != null) {
132 camelContextService.stop();
133 } else {
134 if (context != null) {
135 context.stop();
136 }
137 }
138 }
139
140 protected void startCamelContext() throws Exception {
141 if (camelContextService != null) {
142 camelContextService.start();
143 } else {
144 if (context instanceof DefaultCamelContext) {
145 DefaultCamelContext defaultCamelContext = (DefaultCamelContext)context;
146 if (!defaultCamelContext.isStarted()) {
147 defaultCamelContext.start();
148 }
149 } else {
150 context.start();
151 }
152 }
153 }
154
155 protected CamelContext createCamelContext() throws Exception {
156 return new DefaultCamelContext(createRegistry());
157 }
158
159 protected JndiRegistry createRegistry() throws Exception {
160 return new JndiRegistry(createJndiContext());
161 }
162
163 protected Context createJndiContext() throws Exception {
164 Properties properties = new Properties();
165
166 // jndi.properties is optional
167 InputStream in = getClass().getClassLoader().getResourceAsStream("jndi.properties");
168 if (in != null) {
169 log.debug("Using jndi.properties from classpath root");
170 properties.load(in);
171 } else {
172 properties.put("java.naming.factory.initial", "org.apache.camel.util.jndi.CamelInitialContextFactory");
173 }
174 return new InitialContext(new Hashtable(properties));
175 }
176
177 /**
178 * Factory method which derived classes can use to create a {@link RouteBuilder}
179 * to define the routes for testing
180 */
181 protected RouteBuilder createRouteBuilder() throws Exception {
182 return new RouteBuilder() {
183 public void configure() {
184 // no routes added by default
185 }
186 };
187 }
188
189 /**
190 * Factory method which derived classes can use to create an array of
191 * {@link org.apache.camel.builder.RouteBuilder}s to define the routes for testing
192 *
193 * @see #createRouteBuilder()
194 */
195 protected RouteBuilder[] createRouteBuilders() throws Exception {
196 return new RouteBuilder[] {createRouteBuilder()};
197 }
198
199 /**
200 * Resolves a mandatory endpoint for the given URI or an exception is thrown
201 *
202 * @param uri the Camel <a href="">URI</a> to use to create or resolve an endpoint
203 * @return the endpoint
204 */
205 protected Endpoint resolveMandatoryEndpoint(String uri) {
206 return resolveMandatoryEndpoint(context, uri);
207 }
208
209 /**
210 * Resolves a mandatory endpoint for the given URI and expected type or an exception is thrown
211 *
212 * @param uri the Camel <a href="">URI</a> to use to create or resolve an endpoint
213 * @return the endpoint
214 */
215 protected <T extends Endpoint> T resolveMandatoryEndpoint(String uri, Class<T> endpointType) {
216 return resolveMandatoryEndpoint(context, uri, endpointType);
217 }
218
219 /**
220 * Resolves the mandatory Mock endpoint using a URI of the form <code>mock:someName</code>
221 *
222 * @param uri the URI which typically starts with "mock:" and has some name
223 * @return the mandatory mock endpoint or an exception is thrown if it could not be resolved
224 */
225 protected MockEndpoint getMockEndpoint(String uri) {
226 return resolveMandatoryEndpoint(uri, MockEndpoint.class);
227 }
228
229 /**
230 * Sends a message to the given endpoint URI with the body value
231 *
232 * @param endpointUri the URI of the endpoint to send to
233 * @param body the body for the message
234 */
235 protected void sendBody(String endpointUri, final Object body) {
236 template.send(endpointUri, new Processor() {
237 public void process(Exchange exchange) {
238 Message in = exchange.getIn();
239 in.setBody(body);
240 }
241 });
242 }
243
244 /**
245 * Sends a message to the given endpoint URI with the body value and specified headers
246 *
247 * @param endpointUri the URI of the endpoint to send to
248 * @param body the body for the message
249 * @param headers any headers to set on the message
250 */
251 protected void sendBody(String endpointUri, final Object body, final Map<String, Object> headers) {
252 template.send(endpointUri, new Processor() {
253 public void process(Exchange exchange) {
254 Message in = exchange.getIn();
255 in.setBody(body);
256 for (Map.Entry<String, Object> entry : headers.entrySet()) {
257 in.setHeader(entry.getKey(), entry.getValue());
258 }
259 }
260 });
261 }
262
263 /**
264 * Sends messages to the given endpoint for each of the specified bodies
265 *
266 * @param endpointUri the endpoint URI to send to
267 * @param bodies the bodies to send, one per message
268 */
269 protected void sendBodies(String endpointUri, Object... bodies) {
270 for (Object body : bodies) {
271 sendBody(endpointUri, body);
272 }
273 }
274
275 /**
276 * Creates an exchange with the given body
277 */
278 protected Exchange createExchangeWithBody(Object body) {
279 return createExchangeWithBody(context, body);
280 }
281
282 /**
283 * Asserts that the given language name and expression evaluates to the
284 * given value on a specific exchange
285 */
286 protected void assertExpression(Exchange exchange, String languageName, String expressionText, Object expectedValue) {
287 Language language = assertResolveLanguage(languageName);
288
289 Expression expression = language.createExpression(expressionText);
290 assertNotNull("No Expression could be created for text: " + expressionText + " language: " + language, expression);
291
292 assertExpression(expression, exchange, expectedValue);
293 }
294
295 /**
296 * Asserts that the given language name and predicate expression evaluates
297 * to the expected value on the message exchange
298 */
299 protected void assertPredicate(String languageName, String expressionText, Exchange exchange, boolean expected) {
300 Language language = assertResolveLanguage(languageName);
301
302 Predicate predicate = language.createPredicate(expressionText);
303 assertNotNull("No Predicate could be created for text: " + expressionText + " language: " + language, predicate);
304
305 assertPredicate(predicate, exchange, expected);
306 }
307
308 /**
309 * Asserts that the language name can be resolved
310 */
311 protected Language assertResolveLanguage(String languageName) {
312 Language language = context.resolveLanguage(languageName);
313 assertNotNull("No language found for name: " + languageName, language);
314 return language;
315 }
316
317 /**
318 * Asserts that all the expectations of the Mock endpoints are valid
319 */
320 protected void assertMockEndpointsSatisfied() throws InterruptedException {
321 MockEndpoint.assertIsSatisfied(context);
322 }
323
324 protected void assertValidContext(CamelContext context) {
325 assertNotNull("No context found!", context);
326 }
327
328 protected <T> List<T> getSingletonEndpoints(Class<T> type) {
329 return CamelContextHelper.getSingletonEndpoints(context, type);
330 }
331
332 protected <T extends Endpoint> T getMandatoryEndpoint(String uri, Class<T> type) {
333 T endpoint = context.getEndpoint(uri, type);
334 assertNotNull("No endpoint found for uri: " + uri, endpoint);
335 return endpoint;
336 }
337
338 protected Endpoint getMandatoryEndpoint(String uri) {
339 Endpoint endpoint = context.getEndpoint(uri);
340 assertNotNull("No endpoint found for uri: " + uri, endpoint);
341 return endpoint;
342 }
343
344 /**
345 * Disables the JMX agent. Must be called before the {@link #setUp()} method.
346 */
347 protected void disableJMX() {
348 System.setProperty(JmxSystemPropertyKeys.DISABLED, "true");
349 }
350
351 /**
352 * Enables the JMX agent. Must be called before the {@link #setUp()} method.
353 */
354 protected void enableJMX() {
355 System.setProperty(JmxSystemPropertyKeys.DISABLED, "false");
356 }
357 }