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