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}