/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.builder;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.model.InterceptDefinition;
import org.apache.camel.model.InterceptFromDefinition;
import org.apache.camel.model.InterceptSendToEndpointDefinition;
import org.apache.camel.model.ModelCamelContext;
import org.apache.camel.model.OnCompletionDefinition;
import org.apache.camel.model.OnExceptionDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.model.RoutesDefinition;
import org.apache.camel.model.rest.RestConfigurationDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.model.rest.RestsDefinition;
import org.apache.camel.spi.RestConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is
* used to build {@link org.apache.camel.impl.DefaultRoute} instances in a {@link CamelContext} for smart routing.
*
* @version
*/
public abstract class RouteBuilder extends BuilderSupport implements RoutesBuilder {
protected Logger log = LoggerFactory.getLogger(getClass());
private AtomicBoolean initialized = new AtomicBoolean(false);
private RestsDefinition restCollection = new RestsDefinition();
private RestConfigurationDefinition restConfiguration;
private RoutesDefinition routeCollection = new RoutesDefinition();
public RouteBuilder() {
this(null);
}
public RouteBuilder(CamelContext context) {
super(context);
}
@Override
public String toString() {
return getRouteCollection().toString();
}
/**
* <b>Called on initialization to build the routes using the fluent builder syntax.</b>
* <p/>
* This is a central method for RouteBuilder implementations to implement
* the routes using the Java fluent builder syntax.
*
* @throws Exception can be thrown during configuration
*/
public abstract void configure() throws Exception;
/**
* Configures the REST services
*
* @return the builder
*/
public RestConfigurationDefinition restConfiguration() {
if (restConfiguration == null) {
restConfiguration = new RestConfigurationDefinition();
}
return restConfiguration;
}
/**
* Creates a new REST service
*
* @return the builder
*/
public RestDefinition rest() {
getRestCollection().setCamelContext(getContext());
RestDefinition answer = getRestCollection().rest();
configureRest(answer);
return answer;
}
/**
* Creates a new REST service
*
* @param path the base path
* @return the builder
*/
public RestDefinition rest(String path) {
getRestCollection().setCamelContext(getContext());
RestDefinition answer = getRestCollection().rest(path);
configureRest(answer);
return answer;
}
/**
* Creates a new route from the given URI input
*
* @param uri the from uri
* @return the builder
*/
public RouteDefinition from(String uri) {
getRouteCollection().setCamelContext(getContext());
RouteDefinition answer = getRouteCollection().from(uri);
configureRoute(answer);
return answer;
}
/**
* Creates a new route from the given URI input
*
* @param uri the String formatted from uri
* @param args arguments for the string formatting of the uri
* @return the builder
*/
public RouteDefinition fromF(String uri, Object... args) {
getRouteCollection().setCamelContext(getContext());
RouteDefinition answer = getRouteCollection().from(String.format(uri, args));
configureRoute(answer);
return answer;
}
/**
* Creates a new route from the given endpoint
*
* @param endpoint the from endpoint
* @return the builder
*/
public RouteDefinition from(Endpoint endpoint) {
getRouteCollection().setCamelContext(getContext());
RouteDefinition answer = getRouteCollection().from(endpoint);
configureRoute(answer);
return answer;
}
/**
* Creates a new route from the given URIs input
*
* @param uris the from uris
* @return the builder
*/
public RouteDefinition from(String... uris) {
getRouteCollection().setCamelContext(getContext());
RouteDefinition answer = getRouteCollection().from(uris);
configureRoute(answer);
return answer;
}
/**
* Creates a new route from the given endpoint
*
* @param endpoints the from endpoints
* @return the builder
*/
public RouteDefinition from(Endpoint... endpoints) {
getRouteCollection().setCamelContext(getContext());
RouteDefinition answer = getRouteCollection().from(endpoints);
configureRoute(answer);
return answer;
}
/**
* Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder
*
* @param errorHandlerBuilder the error handler to be used by default for all child routes
*/
public void errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("errorHandler must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
setErrorHandlerBuilder(errorHandlerBuilder);
}
/**
* Adds a route for an interceptor that intercepts every processing step.
*
* @return the builder
*/
public InterceptDefinition intercept() {
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("intercept must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().intercept();
}
/**
* Adds a route for an interceptor that intercepts incoming messages on any inputs in this route
*
* @return the builder
*/
public InterceptFromDefinition interceptFrom() {
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("interceptFrom must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().interceptFrom();
}
/**
* Adds a route for an interceptor that intercepts incoming messages on the given endpoint.
*
* @param uri endpoint uri
* @return the builder
*/
public InterceptFromDefinition interceptFrom(String uri) {
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("interceptFrom must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().interceptFrom(uri);
}
/**
* Applies a route for an interceptor if an exchange is send to the given endpoint
*
* @param uri endpoint uri
* @return the builder
*/
public InterceptSendToEndpointDefinition interceptSendToEndpoint(String uri) {
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("interceptSendToEndpoint must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().interceptSendToEndpoint(uri);
}
/**
* <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
* for catching certain exceptions and handling them.
*
* @param exception exception to catch
* @return the builder
*/
public OnExceptionDefinition onException(Class<? extends Throwable> exception) {
// is only allowed at the top currently
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("onException must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().onException(exception);
}
/**
* <a href="http://camel.apache.org/exception-clause.html">Exception clause</a>
* for catching certain exceptions and handling them.
*
* @param exceptions list of exceptions to catch
* @return the builder
*/
public OnExceptionDefinition onException(Class<? extends Throwable>... exceptions) {
OnExceptionDefinition last = null;
for (Class<? extends Throwable> ex : exceptions) {
last = last == null ? onException(ex) : last.onException(ex);
}
return last != null ? last : onException(Exception.class);
}
/**
* <a href="http://camel.apache.org/oncompletion.html">On completion</a>
* callback for doing custom routing when the {@link org.apache.camel.Exchange} is complete.
*
* @return the builder
*/
public OnCompletionDefinition onCompletion() {
// is only allowed at the top currently
if (!getRouteCollection().getRoutes().isEmpty()) {
throw new IllegalArgumentException("onCompletion must be defined before any routes in the RouteBuilder");
}
getRouteCollection().setCamelContext(getContext());
return getRouteCollection().onCompletion();
}
// Properties
// -----------------------------------------------------------------------
public ModelCamelContext getContext() {
ModelCamelContext context = super.getContext();
if (context == null) {
context = createContainer();
setContext(context);
}
return context;
}
public void addRoutesToCamelContext(CamelContext context) throws Exception {
// must configure routes before rests
configureRoutes((ModelCamelContext)context);
configureRests((ModelCamelContext) context);
// but populate rests before routes, as we want to turn rests into routes
populateRests();
populateRoutes();
}
/**
* Configures the routes
*
* @param context the Camel context
* @return the routes configured
* @throws Exception can be thrown during configuration
*/
public RoutesDefinition configureRoutes(ModelCamelContext context) throws Exception {
setContext(context);
checkInitialized();
routeCollection.setCamelContext(context);
return routeCollection;
}
/**
* Configures the rests
*
* @param context the Camel context
* @return the rests configured
* @throws Exception can be thrown during configuration
*/
public RestsDefinition configureRests(ModelCamelContext context) throws Exception {
setContext(context);
restCollection.setCamelContext(context);
return restCollection;
}
/**
* Includes the routes from the build to this builder.
* <p/>
* This allows you to use other builds as route templates.
* @param routes other builder with routes to include
*
* @throws Exception can be thrown during configuration
*/
public void includeRoutes(RoutesBuilder routes) throws Exception {
// TODO: We should support including multiple routes so I think invoking configure()
// needs to be deferred to later
if (routes instanceof RouteBuilder) {
// if its a RouteBuilder then let it use my route collection and error handler
// then we are integrated seamless
RouteBuilder builder = (RouteBuilder) routes;
builder.setContext(this.getContext());
builder.setRouteCollection(this.getRouteCollection());
builder.setErrorHandlerBuilder(this.getErrorHandlerBuilder());
// must invoke configure on the original builder so it adds its configuration to me
builder.configure();
} else {
getContext().addRoutes(routes);
}
}
@Override
public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
super.setErrorHandlerBuilder(errorHandlerBuilder);
getRouteCollection().setErrorHandlerBuilder(getErrorHandlerBuilder());
}
// Implementation methods
// -----------------------------------------------------------------------
@SuppressWarnings("deprecation")
protected void checkInitialized() throws Exception {
if (initialized.compareAndSet(false, true)) {
// Set the CamelContext ErrorHandler here
ModelCamelContext camelContext = getContext();
if (camelContext.getErrorHandlerBuilder() != null) {
setErrorHandlerBuilder(camelContext.getErrorHandlerBuilder());
}
configure();
// mark all route definitions as custom prepared because
// a route builder prepares the route definitions correctly already
for (RouteDefinition route : getRouteCollection().getRoutes()) {
route.markPrepared();
}
}
}
protected void populateRoutes() throws Exception {
ModelCamelContext camelContext = getContext();
if (camelContext == null) {
throw new IllegalArgumentException("CamelContext has not been injected!");
}
getRouteCollection().setCamelContext(camelContext);
camelContext.addRouteDefinitions(getRouteCollection().getRoutes());
}
protected void populateRests() throws Exception {
ModelCamelContext camelContext = getContext();
if (camelContext == null) {
throw new IllegalArgumentException("CamelContext has not been injected!");
}
getRestCollection().setCamelContext(camelContext);
// setup rest configuration before adding the rests
if (getRestConfiguration() != null) {
RestConfiguration config = getRestConfiguration().asRestConfiguration(getContext());
camelContext.setRestConfiguration(config);
}
camelContext.addRestDefinitions(getRestCollection().getRests());
}
public RestsDefinition getRestCollection() {
return restCollection;
}
public RestConfigurationDefinition getRestConfiguration() {
return restConfiguration;
}
public void setRestCollection(RestsDefinition restCollection) {
this.restCollection = restCollection;
}
public void setRouteCollection(RoutesDefinition routeCollection) {
this.routeCollection = routeCollection;
}
public RoutesDefinition getRouteCollection() {
return this.routeCollection;
}
/**
* Factory method
*
* @return the CamelContext
*/
protected ModelCamelContext createContainer() {
return new DefaultCamelContext();
}
protected void configureRest(RestDefinition rest) {
// noop
}
protected void configureRoute(RouteDefinition route) {
// noop
}
/**
* Adds a collection of routes to this context
*
* @param routes the routes
* @throws Exception if the routes could not be created for whatever reason
* @deprecated will be removed in Camel 3.0. Instead use {@link #includeRoutes(org.apache.camel.RoutesBuilder) includeRoutes} instead.
*/
@Deprecated
protected void addRoutes(RoutesBuilder routes) throws Exception {
includeRoutes(routes);
}
}