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 */
017package org.apache.camel.model;
018
019import java.util.Collections;
020import java.util.List;
021
022import javax.xml.bind.annotation.XmlAccessType;
023import javax.xml.bind.annotation.XmlAccessorType;
024import javax.xml.bind.annotation.XmlAttribute;
025import javax.xml.bind.annotation.XmlRootElement;
026
027import org.apache.camel.AsyncProcessor;
028import org.apache.camel.ErrorHandlerFactory;
029import org.apache.camel.Expression;
030import org.apache.camel.Processor;
031import org.apache.camel.model.language.ExpressionDefinition;
032import org.apache.camel.processor.DynamicRouter;
033import org.apache.camel.spi.Metadata;
034import org.apache.camel.spi.RouteContext;
035
036/**
037 * Routes messages based on dynamic rules
038 */
039@Metadata(label = "eip,endpoint,routing")
040@XmlRootElement(name = "dynamicRouter")
041@XmlAccessorType(XmlAccessType.FIELD)
042public class DynamicRouterDefinition<Type extends ProcessorDefinition<Type>> extends NoOutputExpressionNode {
043
044    public static final String DEFAULT_DELIMITER = ",";
045
046    @XmlAttribute @Metadata(defaultValue = ",")
047    private String uriDelimiter;
048    @XmlAttribute
049    private Boolean ignoreInvalidEndpoints;
050    @XmlAttribute
051    private Integer cacheSize; 
052
053    public DynamicRouterDefinition() {
054    }
055
056    public DynamicRouterDefinition(Expression expression) {
057        super(expression);
058    }
059
060    @Override
061    public String toString() {
062        return "DynamicRouter[" + getExpression() + "]";
063    }
064    
065    @Override
066    public String getShortName() {
067        return "dynamicRouter";
068    }
069
070    @Override
071    public String getLabel() {
072        return "dynamicRouter[" + getExpression() + "]";
073    }
074
075    @Override
076    public List<ProcessorDefinition<?>> getOutputs() {
077        return Collections.emptyList();
078    }
079
080    @Override
081    public Processor createProcessor(RouteContext routeContext) throws Exception {
082        Expression expression = getExpression().createExpression(routeContext);
083        String delimiter = getUriDelimiter() != null ? getUriDelimiter() : DEFAULT_DELIMITER;
084
085        DynamicRouter dynamicRouter = new DynamicRouter(routeContext.getCamelContext(), expression, delimiter);
086        if (getIgnoreInvalidEndpoints() != null) {
087            dynamicRouter.setIgnoreInvalidEndpoints(getIgnoreInvalidEndpoints());
088        }
089        if (getCacheSize() != null) {
090            dynamicRouter.setCacheSize(getCacheSize());
091        }
092
093        // and wrap this in an error handler
094        ErrorHandlerFactory builder = routeContext.getRoute().getErrorHandlerBuilder();
095        // create error handler (create error handler directly to keep it light weight,
096        // instead of using ProcessorDefinition.wrapInErrorHandler)
097        AsyncProcessor errorHandler = (AsyncProcessor) builder.createErrorHandler(routeContext, dynamicRouter.newRoutingSlipProcessorForErrorHandler());
098        dynamicRouter.setErrorHandler(errorHandler);
099
100        return dynamicRouter;
101    }
102
103    /**
104     * Expression to call that returns the endpoint(s) to route to in the dynamic routing.
105     * <p/>
106     * <b>Important:</b> The expression will be called in a while loop fashion, until the expression returns <tt>null</tt>
107     * which means the dynamic router is finished.
108     */
109    @Override
110    public void setExpression(ExpressionDefinition expression) {
111        // override to include javadoc what the expression is used for
112        super.setExpression(expression);
113    }
114
115    public void setUriDelimiter(String uriDelimiter) {
116        this.uriDelimiter = uriDelimiter;
117    }
118
119    public String getUriDelimiter() {
120        return uriDelimiter;
121    }
122
123    public void setIgnoreInvalidEndpoints(Boolean ignoreInvalidEndpoints) {
124        this.ignoreInvalidEndpoints = ignoreInvalidEndpoints;
125    }
126
127    public Boolean getIgnoreInvalidEndpoints() {
128        return ignoreInvalidEndpoints;
129    }
130
131    // Fluent API
132    // -------------------------------------------------------------------------
133
134    public Integer getCacheSize() {
135        return cacheSize;
136    }
137
138    public void setCacheSize(Integer cacheSize) {
139        this.cacheSize = cacheSize;
140    }
141
142    @Override
143    @SuppressWarnings("unchecked")
144    public Type end() {
145        // allow end() to return to previous type so you can continue in the DSL
146        return (Type) super.end();
147    }
148
149    /**
150     * Ignore the invalidate endpoint exception when try to create a producer with that endpoint
151     *
152     * @return the builder
153     */
154    public DynamicRouterDefinition<Type> ignoreInvalidEndpoints() {
155        setIgnoreInvalidEndpoints(true);
156        return this;
157    }
158
159    /**
160     * Sets the uri delimiter to use
161     *
162     * @param uriDelimiter the delimiter
163     * @return the builder
164     */
165    public DynamicRouterDefinition<Type> uriDelimiter(String uriDelimiter) {
166        setUriDelimiter(uriDelimiter);
167        return this;
168    }
169    
170    /**
171     * Sets the maximum size used by the {@link org.apache.camel.impl.ProducerCache} which is used
172     * to cache and reuse producers when using this dynamic router, when uris are reused.
173     *
174     * @param cacheSize  the cache size, use <tt>0</tt> for default cache size, or <tt>-1</tt> to turn cache off.
175     * @return the builder
176     */
177    public DynamicRouterDefinition<Type> cacheSize(int cacheSize) {
178        setCacheSize(cacheSize);
179        return this;
180    }
181
182}