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