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