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.ArrayList; 020import java.util.Arrays; 021import java.util.List; 022 023import javax.xml.bind.annotation.XmlAccessType; 024import javax.xml.bind.annotation.XmlAccessorType; 025import javax.xml.bind.annotation.XmlElement; 026import javax.xml.bind.annotation.XmlElementRef; 027import javax.xml.bind.annotation.XmlElements; 028import javax.xml.bind.annotation.XmlRootElement; 029 030import org.apache.camel.Expression; 031import org.apache.camel.model.loadbalancer.CustomLoadBalancerDefinition; 032import org.apache.camel.model.loadbalancer.FailoverLoadBalancerDefinition; 033import org.apache.camel.model.loadbalancer.RandomLoadBalancerDefinition; 034import org.apache.camel.model.loadbalancer.RoundRobinLoadBalancerDefinition; 035import org.apache.camel.model.loadbalancer.StickyLoadBalancerDefinition; 036import org.apache.camel.model.loadbalancer.TopicLoadBalancerDefinition; 037import org.apache.camel.model.loadbalancer.WeightedLoadBalancerDefinition; 038import org.apache.camel.processor.loadbalancer.LoadBalancer; 039import org.apache.camel.spi.Metadata; 040import org.apache.camel.util.CollectionStringBuffer; 041 042/** 043 * Balances message processing among a number of nodes 044 */ 045@Metadata(label = "eip,routing") 046@XmlRootElement(name = "loadBalance") 047@XmlAccessorType(XmlAccessType.FIELD) 048public class LoadBalanceDefinition extends ProcessorDefinition<LoadBalanceDefinition> implements OutputNode { 049 @XmlElements({@XmlElement(required = false, name = "failover", type = FailoverLoadBalancerDefinition.class), 050 @XmlElement(required = false, name = "random", type = RandomLoadBalancerDefinition.class), 051 @XmlElement(required = false, name = "customLoadBalancer", type = CustomLoadBalancerDefinition.class), 052 @XmlElement(required = false, name = "roundRobin", type = RoundRobinLoadBalancerDefinition.class), 053 @XmlElement(required = false, name = "sticky", type = StickyLoadBalancerDefinition.class), 054 @XmlElement(required = false, name = "topic", type = TopicLoadBalancerDefinition.class), 055 @XmlElement(required = false, name = "weighted", type = WeightedLoadBalancerDefinition.class)}) 056 private LoadBalancerDefinition loadBalancerType; 057 @XmlElementRef 058 private List<ProcessorDefinition<?>> outputs = new ArrayList<>(); 059 060 public LoadBalanceDefinition() { 061 } 062 063 @Override 064 public List<ProcessorDefinition<?>> getOutputs() { 065 return outputs; 066 } 067 068 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 069 this.outputs = outputs; 070 if (outputs != null) { 071 for (ProcessorDefinition<?> output : outputs) { 072 configureChild(output); 073 } 074 } 075 } 076 077 public LoadBalancerDefinition getLoadBalancerType() { 078 return loadBalancerType; 079 } 080 081 /** 082 * The load balancer to be used 083 */ 084 public void setLoadBalancerType(LoadBalancerDefinition loadbalancer) { 085 if (loadBalancerType != null) { 086 throw new IllegalArgumentException("Loadbalancer already configured to: " + loadBalancerType + ". Cannot set it to: " + loadbalancer); 087 } 088 loadBalancerType = loadbalancer; 089 } 090 091 // Fluent API 092 // ------------------------------------------------------------------------- 093 094 /** 095 * Uses a custom load balancer 096 * 097 * @param loadBalancer the load balancer 098 * @return the builder 099 */ 100 @Override 101 public LoadBalanceDefinition loadBalance(LoadBalancer loadBalancer) { 102 CustomLoadBalancerDefinition def = new CustomLoadBalancerDefinition(); 103 def.setCustomLoadBalancer(loadBalancer); 104 setLoadBalancerType(def); 105 return this; 106 } 107 108 /** 109 * Uses fail over load balancer 110 * <p/> 111 * Will not round robin and inherit the error handler. 112 * 113 * @return the builder 114 */ 115 public LoadBalanceDefinition failover() { 116 return failover(-1, true, false); 117 } 118 119 /** 120 * Uses fail over load balancer 121 * <p/> 122 * Will not round robin and inherit the error handler. 123 * 124 * @param exceptions exception classes which we want to failover if one of 125 * them was thrown 126 * @return the builder 127 */ 128 public LoadBalanceDefinition failover(Class<?>... exceptions) { 129 return failover(-1, true, false, exceptions); 130 } 131 132 /** 133 * Uses fail over load balancer 134 * 135 * @param maximumFailoverAttempts maximum number of failover attempts before 136 * exhausting. Use -1 to newer exhaust when round robin is also 137 * enabled. If round robin is disabled then it will exhaust when 138 * there are no more endpoints to failover 139 * @param inheritErrorHandler whether or not to inherit error handler. If 140 * <tt>false</tt> then it will failover immediately in case of an 141 * exception 142 * @param roundRobin whether or not to use round robin (which keeps state) 143 * @param exceptions exception classes which we want to failover if one of 144 * them was thrown 145 * @return the builder 146 */ 147 public LoadBalanceDefinition failover(int maximumFailoverAttempts, boolean inheritErrorHandler, boolean roundRobin, Class<?>... exceptions) { 148 return failover(maximumFailoverAttempts, inheritErrorHandler, roundRobin, false, exceptions); 149 } 150 151 /** 152 * Uses fail over load balancer 153 * 154 * @param maximumFailoverAttempts maximum number of failover attempts before 155 * exhausting. Use -1 to newer exhaust when round robin is also 156 * enabled. If round robin is disabled then it will exhaust when 157 * there are no more endpoints to failover 158 * @param inheritErrorHandler whether or not to inherit error handler. If 159 * <tt>false</tt> then it will failover immediately in case of an 160 * exception 161 * @param roundRobin whether or not to use round robin (which keeps state) 162 * @param sticky whether or not to use sticky (which keeps state) 163 * @param exceptions exception classes which we want to failover if one of 164 * them was thrown 165 * @return the builder 166 */ 167 public LoadBalanceDefinition failover(int maximumFailoverAttempts, boolean inheritErrorHandler, boolean roundRobin, boolean sticky, Class<?>... exceptions) { 168 FailoverLoadBalancerDefinition def = new FailoverLoadBalancerDefinition(); 169 def.setExceptionTypes(Arrays.asList(exceptions)); 170 def.setMaximumFailoverAttempts(maximumFailoverAttempts); 171 def.setRoundRobin(roundRobin); 172 def.setSticky(sticky); 173 setLoadBalancerType(def); 174 this.setInheritErrorHandler(inheritErrorHandler); 175 return this; 176 } 177 178 /** 179 * Uses weighted load balancer 180 * 181 * @param roundRobin used to set the processor selection algorithm. 182 * @param distributionRatio String of weighted ratios for distribution of 183 * messages. 184 * @return the builder 185 */ 186 public LoadBalanceDefinition weighted(boolean roundRobin, String distributionRatio) { 187 return weighted(roundRobin, distributionRatio, ","); 188 } 189 190 /** 191 * Uses weighted load balancer 192 * 193 * @param roundRobin used to set the processor selection algorithm. 194 * @param distributionRatio String of weighted ratios for distribution of 195 * messages. 196 * @param distributionRatioDelimiter String containing delimiter to be used 197 * for ratios 198 * @return the builder 199 */ 200 public LoadBalanceDefinition weighted(boolean roundRobin, String distributionRatio, String distributionRatioDelimiter) { 201 WeightedLoadBalancerDefinition def = new WeightedLoadBalancerDefinition(); 202 def.setRoundRobin(roundRobin); 203 def.setDistributionRatio(distributionRatio); 204 def.setDistributionRatioDelimiter(distributionRatioDelimiter); 205 setLoadBalancerType(def); 206 return this; 207 } 208 209 /** 210 * Uses round robin load balancer 211 * 212 * @return the builder 213 */ 214 public LoadBalanceDefinition roundRobin() { 215 setLoadBalancerType(new RoundRobinLoadBalancerDefinition()); 216 return this; 217 } 218 219 /** 220 * Uses random load balancer 221 * 222 * @return the builder 223 */ 224 public LoadBalanceDefinition random() { 225 setLoadBalancerType(new RandomLoadBalancerDefinition()); 226 return this; 227 } 228 229 /** 230 * Uses the custom load balancer 231 * 232 * @param ref reference to lookup a custom load balancer from the 233 * {@link org.apache.camel.spi.Registry} to be used. 234 * @return the builder 235 */ 236 public LoadBalanceDefinition custom(String ref) { 237 CustomLoadBalancerDefinition balancer = new CustomLoadBalancerDefinition(); 238 balancer.setRef(ref); 239 setLoadBalancerType(balancer); 240 return this; 241 } 242 243 /** 244 * Uses sticky load balancer 245 * 246 * @param correlationExpression the expression for correlation 247 * @return the builder 248 */ 249 public LoadBalanceDefinition sticky(Expression correlationExpression) { 250 StickyLoadBalancerDefinition def = new StickyLoadBalancerDefinition(); 251 def.setCorrelationExpression(correlationExpression); 252 setLoadBalancerType(def); 253 return this; 254 } 255 256 /** 257 * Uses topic load balancer 258 * 259 * @return the builder 260 */ 261 public LoadBalanceDefinition topic() { 262 setLoadBalancerType(new TopicLoadBalancerDefinition()); 263 return this; 264 } 265 266 @Override 267 public String getShortName() { 268 return "loadBalance"; 269 } 270 271 @Override 272 public String getLabel() { 273 CollectionStringBuffer buffer = new CollectionStringBuffer("loadBalance["); 274 List<ProcessorDefinition<?>> list = getOutputs(); 275 for (ProcessorDefinition<?> processorType : list) { 276 buffer.append(processorType.getLabel()); 277 } 278 buffer.append("]"); 279 return buffer.toString(); 280 } 281 282 @Override 283 public String toString() { 284 return "LoadBalanceType[" + loadBalancerType + ", " + getOutputs() + "]"; 285 } 286}