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 = "configuration,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 @Metadata(defaultValue = "-1")
054    private Integer maximumFailoverAttempts;
055
056    public FailoverLoadBalancerDefinition() {
057    }
058
059    @Override
060    protected LoadBalancer createLoadBalancer(RouteContext routeContext) {
061        FailOverLoadBalancer answer;
062
063        List<Class<?>> classes = new ArrayList<Class<?>>();
064        if (!exceptionTypes.isEmpty()) {
065            classes.addAll(exceptionTypes);
066        } else if (!exceptions.isEmpty()) {
067            for (String name : exceptions) {
068                Class<?> type = routeContext.getCamelContext().getClassResolver().resolveClass(name);
069                if (type == null) {
070                    throw new IllegalArgumentException("Cannot find class: " + name + " in the classpath");
071                }
072                if (!ObjectHelper.isAssignableFrom(Throwable.class, type)) {
073                    throw new IllegalArgumentException("Class is not an instance of Throwable: " + type);
074                }
075                classes.add(type);
076            }
077        }
078        if (classes.isEmpty()) {
079            answer = new FailOverLoadBalancer();
080        } else {
081            answer = new FailOverLoadBalancer(classes);
082        }
083
084        if (getMaximumFailoverAttempts() != null) {
085            answer.setMaximumFailoverAttempts(getMaximumFailoverAttempts());
086        }
087        if (roundRobin != null) {
088            answer.setRoundRobin(roundRobin);
089        }
090
091        return answer;
092    }
093
094    public List<String> getExceptions() {
095        return exceptions;
096    }
097
098    /**
099     * A list of class names for specific exceptions to monitor.
100     * If no exceptions is configured then all exceptions is monitored
101     */
102    public void setExceptions(List<String> exceptions) {
103        this.exceptions = exceptions;
104    }
105
106    public List<Class<?>> getExceptionTypes() {
107        return exceptionTypes;
108    }
109
110    /**
111     * A list of specific exceptions to monitor.
112     * If no exceptions is configured then all exceptions is monitored
113     */
114    public void setExceptionTypes(List<Class<?>> exceptionTypes) {
115        this.exceptionTypes = exceptionTypes;
116    }
117
118    public Boolean getRoundRobin() {
119        return roundRobin;
120    }
121
122    /**
123     * Whether or not the failover load balancer should operate in round robin mode or not.
124     * If not, then it will always start from the first endpoint when a new message is to be processed.
125     * In other words it restart from the top for every message.
126     * If round robin is enabled, then it keeps state and will continue with the next endpoint in a round robin fashion.
127     * When using round robin it will not stick to last known good endpoint, it will always pick the next endpoint to use.
128     */
129    public void setRoundRobin(Boolean roundRobin) {
130        this.roundRobin = roundRobin;
131    }
132
133    public Integer getMaximumFailoverAttempts() {
134        return maximumFailoverAttempts;
135    }
136
137    /**
138     * A value to indicate after X failover attempts we should exhaust (give up).
139     * Use -1 to indicate never give up and continuously try to failover. Use 0 to never failover.
140     * And use e.g. 3 to failover at most 3 times before giving up.
141     * his option can be used whether or not roundRobin is enabled or not.
142     */
143    public void setMaximumFailoverAttempts(Integer maximumFailoverAttempts) {
144        this.maximumFailoverAttempts = maximumFailoverAttempts;
145    }
146
147    @Override
148    public String toString() {
149        return "FailoverLoadBalancer";
150    }
151}