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