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.Iterator;
021import java.util.List;
022
023import javax.xml.bind.annotation.XmlAccessType;
024import javax.xml.bind.annotation.XmlAccessorType;
025import javax.xml.bind.annotation.XmlAttribute;
026import javax.xml.bind.annotation.XmlElement;
027import javax.xml.bind.annotation.XmlElementRef;
028import javax.xml.bind.annotation.XmlRootElement;
029import javax.xml.bind.annotation.XmlTransient;
030
031import org.apache.camel.Processor;
032import org.apache.camel.spi.Metadata;
033import org.apache.camel.spi.RouteContext;
034
035/**
036 * Hystrix Circuit Breaker EIP
037 */
038@Metadata(label = "eip,routing,circuitbreaker")
039@XmlRootElement(name = "hystrix")
040@XmlAccessorType(XmlAccessType.FIELD)
041public class HystrixDefinition extends ProcessorDefinition<HystrixDefinition> {
042
043    @XmlElement
044    private HystrixConfigurationDefinition hystrixConfiguration;
045    @XmlElementRef
046    private List<ProcessorDefinition<?>> outputs = new ArrayList<>();
047    @XmlTransient
048    private OnFallbackDefinition onFallback;
049    @XmlAttribute
050    private String hystrixConfigurationRef;
051
052    public HystrixDefinition() {
053    }
054
055    @Override
056    public String toString() {
057        return "Hystrix[" + getOutputs() + "]";
058    }
059
060    @Override
061    public String getShortName() {
062        return "hystrix";
063    }
064
065    @Override
066    public String getLabel() {
067        return "hystrix";
068    }
069
070    @Override
071    public Processor createProcessor(RouteContext routeContext) throws Exception {
072        throw new IllegalStateException("Cannot find camel-hystrix on the classpath.");
073    }
074
075    public List<ProcessorDefinition<?>> getOutputs() {
076        return outputs;
077    }
078
079    public boolean isOutputSupported() {
080        return true;
081    }
082
083    public void setOutputs(List<ProcessorDefinition<?>> outputs) {
084        this.outputs = outputs;
085        if (outputs != null) {
086            for (ProcessorDefinition<?> output : outputs) {
087                configureChild(output);
088            }
089        }
090    }
091
092    @Override
093    public void addOutput(ProcessorDefinition<?> output) {
094        if (output instanceof OnFallbackDefinition) {
095            onFallback = (OnFallbackDefinition) output;
096        } else {
097            if (onFallback != null) {
098                onFallback.addOutput(output);
099            } else {
100                super.addOutput(output);
101            }
102        }
103    }
104
105    @Override
106    public ProcessorDefinition<?> end() {
107        if (onFallback != null) {
108            // end fallback as well
109            onFallback.end();
110        }
111        return super.end();
112    }
113
114    protected void preCreateProcessor() {
115        // move the fallback from outputs to fallback which we need to ensure
116        // such as when using the XML DSL
117        Iterator<ProcessorDefinition<?>> it = outputs.iterator();
118        while (it.hasNext()) {
119            ProcessorDefinition<?> out = it.next();
120            if (out instanceof OnFallbackDefinition) {
121                onFallback = (OnFallbackDefinition) out;
122                it.remove();
123            }
124        }
125    }
126
127    // Getter/Setter
128    // -------------------------------------------------------------------------
129
130    public HystrixConfigurationDefinition getHystrixConfiguration() {
131        return hystrixConfiguration;
132    }
133
134    public void setHystrixConfiguration(HystrixConfigurationDefinition hystrixConfiguration) {
135        this.hystrixConfiguration = hystrixConfiguration;
136    }
137
138    public String getHystrixConfigurationRef() {
139        return hystrixConfigurationRef;
140    }
141
142    /**
143     * Refers to a Hystrix configuration to use for configuring the Hystrix EIP.
144     */
145    public void setHystrixConfigurationRef(String hystrixConfigurationRef) {
146        this.hystrixConfigurationRef = hystrixConfigurationRef;
147    }
148
149    public OnFallbackDefinition getOnFallback() {
150        return onFallback;
151    }
152
153    public void setOnFallback(OnFallbackDefinition onFallback) {
154        this.onFallback = onFallback;
155    }
156
157    // Fluent API
158    // -------------------------------------------------------------------------
159
160    /**
161     * Sets the group key to use. The default value is CamelHystrix.
162     */
163    public HystrixDefinition groupKey(String groupKey) {
164        hystrixConfiguration().groupKey(groupKey);
165        return this;
166    }
167
168    /**
169     * Sets the thread pool key to use. The default value is CamelHystrix.
170     */
171    public HystrixDefinition threadPoolKey(String threadPoolKey) {
172        hystrixConfiguration().threadPoolKey(threadPoolKey);
173        return this;
174    }
175
176    /**
177     * Configures the Hystrix EIP
178     * <p/>
179     * Use <tt>end</tt> when configuration is complete, to return back to the Hystrix EIP.
180     */
181    public HystrixConfigurationDefinition hystrixConfiguration() {
182        hystrixConfiguration = hystrixConfiguration == null ? new HystrixConfigurationDefinition(this) : hystrixConfiguration;
183        return hystrixConfiguration;
184    }
185    
186    /**
187     * Configures the Hystrix EIP using the given configuration
188     */
189    public HystrixDefinition hystrixConfiguration(HystrixConfigurationDefinition configuration) {
190        hystrixConfiguration = configuration;
191        return this;
192    }
193
194    /**
195     * Refers to a Hystrix configuration to use for configuring the Hystrix EIP.
196     */
197    public HystrixDefinition hystrixConfiguration(String ref) {
198        hystrixConfigurationRef = ref;
199        return this;
200    }
201
202    /**
203     * The Hystrix fallback route path to execute that does <b>not</b> go over the network.
204     * <p>
205     * This should be a static or cached result that can immediately be returned upon failure.
206     * If the fallback requires network connection then use {@link #onFallbackViaNetwork()}.
207     */
208    public HystrixDefinition onFallback() {
209        onFallback = new OnFallbackDefinition();
210        onFallback.setParent(this);
211        return this;
212    }
213
214    /**
215     * The Hystrix fallback route path to execute that will go over the network.
216     * <p/>
217     * If the fallback will go over the network it is another possible point of failure and so it also needs to be
218     * wrapped by a HystrixCommand. It is important to execute the fallback command on a separate thread-pool,
219     * otherwise if the main command were to become latent and fill the thread-pool
220     * this would prevent the fallback from running if the two commands share the same pool.
221     */
222    public HystrixDefinition onFallbackViaNetwork() {
223        onFallback = new OnFallbackDefinition();
224        onFallback.setFallbackViaNetwork(true);
225        onFallback.setParent(this);
226        return this;
227    }
228
229}