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