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