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.loadbalancer; 018 019import java.util.ArrayList; 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.XmlElement; 025import javax.xml.bind.annotation.XmlRootElement; 026import javax.xml.bind.annotation.XmlTransient; 027 028import org.apache.camel.model.LoadBalancerDefinition; 029import org.apache.camel.processor.loadbalancer.FailOverLoadBalancer; 030import org.apache.camel.processor.loadbalancer.LoadBalancer; 031import org.apache.camel.spi.Metadata; 032import org.apache.camel.spi.RouteContext; 033import org.apache.camel.util.ObjectHelper; 034 035/** 036 * Failover load balancer 037 * 038 * The failover load balancer is capable of trying the next processor in case an Exchange failed with an exception during processing. 039 * You can constrain the failover to activate only when one exception of a list you specify occurs. 040 * If you do not specify a list any exception will cause fail over to occur. 041 * This balancer uses the same strategy for matching exceptions as the Exception Clause does for the onException. 042 */ 043@Metadata(label = "eip,routing,loadbalance") 044@XmlRootElement(name = "failover") 045@XmlAccessorType(XmlAccessType.FIELD) 046public class FailoverLoadBalancerDefinition extends LoadBalancerDefinition { 047 @XmlTransient 048 private List<Class<?>> exceptionTypes = new ArrayList<Class<?>>(); 049 @XmlElement(name = "exception") 050 private List<String> exceptions = new ArrayList<String>(); 051 @XmlAttribute 052 private Boolean roundRobin; 053 @XmlAttribute 054 private Boolean sticky; 055 @XmlAttribute @Metadata(defaultValue = "-1") 056 private Integer maximumFailoverAttempts; 057 058 public FailoverLoadBalancerDefinition() { 059 } 060 061 @Override 062 protected LoadBalancer createLoadBalancer(RouteContext routeContext) { 063 FailOverLoadBalancer answer; 064 065 List<Class<?>> classes = new ArrayList<Class<?>>(); 066 if (!exceptionTypes.isEmpty()) { 067 classes.addAll(exceptionTypes); 068 } else if (!exceptions.isEmpty()) { 069 for (String name : exceptions) { 070 Class<?> type = routeContext.getCamelContext().getClassResolver().resolveClass(name); 071 if (type == null) { 072 throw new IllegalArgumentException("Cannot find class: " + name + " in the classpath"); 073 } 074 if (!ObjectHelper.isAssignableFrom(Throwable.class, type)) { 075 throw new IllegalArgumentException("Class is not an instance of Throwable: " + type); 076 } 077 classes.add(type); 078 } 079 } 080 if (classes.isEmpty()) { 081 answer = new FailOverLoadBalancer(); 082 } else { 083 answer = new FailOverLoadBalancer(classes); 084 } 085 086 if (getMaximumFailoverAttempts() != null) { 087 answer.setMaximumFailoverAttempts(getMaximumFailoverAttempts()); 088 } 089 if (roundRobin != null) { 090 answer.setRoundRobin(roundRobin); 091 } 092 if (sticky != null) { 093 answer.setSticky(sticky); 094 } 095 096 return answer; 097 } 098 099 public List<String> getExceptions() { 100 return exceptions; 101 } 102 103 /** 104 * A list of class names for specific exceptions to monitor. 105 * If no exceptions is configured then all exceptions is monitored 106 */ 107 public void setExceptions(List<String> exceptions) { 108 this.exceptions = exceptions; 109 } 110 111 public List<Class<?>> getExceptionTypes() { 112 return exceptionTypes; 113 } 114 115 /** 116 * A list of specific exceptions to monitor. 117 * If no exceptions is configured then all exceptions is monitored 118 */ 119 public void setExceptionTypes(List<Class<?>> exceptionTypes) { 120 this.exceptionTypes = exceptionTypes; 121 } 122 123 public Boolean getRoundRobin() { 124 return roundRobin; 125 } 126 127 /** 128 * Whether or not the failover load balancer should operate in round robin mode or not. 129 * If not, then it will always start from the first endpoint when a new message is to be processed. 130 * In other words it restart from the top for every message. 131 * If round robin is enabled, then it keeps state and will continue with the next endpoint in a round robin fashion. 132 * <p/> 133 * You can also enable sticky mode together with round robin, if so then it will pick the last known good endpoint 134 * to use when starting the load balancing (instead of using the next when starting). 135 */ 136 public void setRoundRobin(Boolean roundRobin) { 137 this.roundRobin = roundRobin; 138 } 139 140 public Boolean getSticky() { 141 return sticky; 142 } 143 144 /** 145 * Whether or not the failover load balancer should operate in sticky mode or not. 146 * If not, then it will always start from the first endpoint when a new message is to be processed. 147 * In other words it restart from the top for every message. 148 * If sticky is enabled, then it keeps state and will continue with the last known good endpoint. 149 * <p/> 150 * You can also enable sticky mode together with round robin, if so then it will pick the last known good endpoint 151 * to use when starting the load balancing (instead of using the next when starting). 152 */ 153 public void setSticky(Boolean sticky) { 154 this.sticky = sticky; 155 } 156 157 public Integer getMaximumFailoverAttempts() { 158 return maximumFailoverAttempts; 159 } 160 161 /** 162 * A value to indicate after X failover attempts we should exhaust (give up). 163 * Use -1 to indicate never give up and continuously try to failover. Use 0 to never failover. 164 * And use e.g. 3 to failover at most 3 times before giving up. 165 * his option can be used whether or not roundRobin is enabled or not. 166 */ 167 public void setMaximumFailoverAttempts(Integer maximumFailoverAttempts) { 168 this.maximumFailoverAttempts = maximumFailoverAttempts; 169 } 170 171 @Override 172 public String toString() { 173 return "FailoverLoadBalancer"; 174 } 175}