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