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.concurrent.ExecutorService;
020
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;
027import javax.xml.bind.annotation.XmlType;
028
029import org.apache.camel.Expression;
030import org.apache.camel.builder.ExpressionBuilder;
031import org.apache.camel.model.language.ExpressionDefinition;
032import org.apache.camel.spi.Metadata;
033
034/**
035 * Controls the rate at which messages are passed to the next node in the route
036 */
037@Metadata(label = "eip,routing")
038@XmlRootElement(name = "throttle")
039@XmlAccessorType(XmlAccessType.FIELD)
040@XmlType(propOrder = {"expression", "correlationExpression"})
041public class ThrottleDefinition extends ExpressionNode implements ExecutorServiceAwareDefinition<ThrottleDefinition> {
042
043    @XmlElement(name = "correlationExpression")
044    private ExpressionSubElementDefinition correlationExpression;
045    @XmlTransient
046    private ExecutorService executorService;
047    @XmlAttribute
048    private String executorServiceRef;
049    @XmlAttribute
050    @Metadata(defaultValue = "1000")
051    private Long timePeriodMillis;
052    @XmlAttribute
053    private Boolean asyncDelayed;
054    @XmlAttribute
055    @Metadata(defaultValue = "true")
056    private Boolean callerRunsWhenRejected;
057    @XmlAttribute
058    private Boolean rejectExecution;
059
060    public ThrottleDefinition() {
061    }
062
063    public ThrottleDefinition(Expression maximumRequestsPerPeriod) {
064        super(maximumRequestsPerPeriod);
065    }
066
067    public ThrottleDefinition(Expression maximumRequestsPerPeriod, Expression correlationExpression) {
068        this(ExpressionNodeHelper.toExpressionDefinition(maximumRequestsPerPeriod), correlationExpression);
069    }
070
071    private ThrottleDefinition(ExpressionDefinition maximumRequestsPerPeriod, Expression correlationExpression) {
072        super(maximumRequestsPerPeriod);
073
074        ExpressionSubElementDefinition cor = new ExpressionSubElementDefinition();
075        cor.setExpressionType(ExpressionNodeHelper.toExpressionDefinition(correlationExpression));
076        setCorrelationExpression(cor);
077    }
078
079    @Override
080    public String toString() {
081        return "Throttle[" + description() + "]";
082    }
083
084    protected String description() {
085        return getExpression() + " request per " + getTimePeriodMillis() + " millis";
086    }
087
088    @Override
089    public String getShortName() {
090        return "throttle";
091    }
092
093    @Override
094    public String getLabel() {
095        return "throttle[" + description() + "]";
096    }
097
098    // Fluent API
099    // -------------------------------------------------------------------------
100    /**
101     * Sets the time period during which the maximum request count is valid for
102     *
103     * @param timePeriodMillis period in millis
104     * @return the builder
105     */
106    public ThrottleDefinition timePeriodMillis(long timePeriodMillis) {
107        setTimePeriodMillis(timePeriodMillis);
108        return this;
109    }
110
111    /**
112     * Sets the time period during which the maximum request count per period
113     *
114     * @param maximumRequestsPerPeriod the maximum request count number per time
115     *            period
116     * @return the builder
117     */
118    public ThrottleDefinition maximumRequestsPerPeriod(long maximumRequestsPerPeriod) {
119        setExpression(ExpressionNodeHelper.toExpressionDefinition(ExpressionBuilder.constantExpression(maximumRequestsPerPeriod)));
120        return this;
121    }
122
123    /**
124     * Whether or not the caller should run the task when it was rejected by the
125     * thread pool.
126     * <p/>
127     * Is by default <tt>true</tt>
128     *
129     * @param callerRunsWhenRejected whether or not the caller should run
130     * @return the builder
131     */
132    public ThrottleDefinition callerRunsWhenRejected(boolean callerRunsWhenRejected) {
133        setCallerRunsWhenRejected(callerRunsWhenRejected);
134        return this;
135    }
136
137    /**
138     * Enables asynchronous delay which means the thread will <b>not</b> block
139     * while delaying.
140     *
141     * @return the builder
142     */
143    public ThrottleDefinition asyncDelayed() {
144        setAsyncDelayed(true);
145        return this;
146    }
147
148    /**
149     * Whether or not throttler throws the ThrottlerRejectedExecutionException
150     * when the exchange exceeds the request limit
151     * <p/>
152     * Is by default <tt>false</tt>
153     *
154     * @param rejectExecution throw the RejectExecutionException if the exchange
155     *            exceeds the request limit
156     * @return the builder
157     */
158    public ThrottleDefinition rejectExecution(boolean rejectExecution) {
159        setRejectExecution(rejectExecution);
160        return this;
161    }
162
163    /**
164     * To use a custom thread pool (ScheduledExecutorService) by the throttler.
165     *
166     * @param executorService the custom thread pool (must be scheduled)
167     * @return the builder
168     */
169    @Override
170    public ThrottleDefinition executorService(ExecutorService executorService) {
171        setExecutorService(executorService);
172        return this;
173    }
174
175    /**
176     * To use a custom thread pool (ScheduledExecutorService) by the throttler.
177     *
178     * @param executorServiceRef the reference id of the thread pool (must be
179     *            scheduled)
180     * @return the builder
181     */
182    @Override
183    public ThrottleDefinition executorServiceRef(String executorServiceRef) {
184        setExecutorServiceRef(executorServiceRef);
185        return this;
186    }
187
188    // Properties
189    // -------------------------------------------------------------------------
190
191    /**
192     * Expression to configure the maximum number of messages to throttle per
193     * request
194     */
195    @Override
196    public void setExpression(ExpressionDefinition expression) {
197        // override to include javadoc what the expression is used for
198        super.setExpression(expression);
199    }
200
201    public Long getTimePeriodMillis() {
202        return timePeriodMillis;
203    }
204
205    public void setTimePeriodMillis(Long timePeriodMillis) {
206        this.timePeriodMillis = timePeriodMillis;
207    }
208
209    public Boolean getAsyncDelayed() {
210        return asyncDelayed;
211    }
212
213    public void setAsyncDelayed(Boolean asyncDelayed) {
214        this.asyncDelayed = asyncDelayed;
215    }
216
217    public Boolean getCallerRunsWhenRejected() {
218        return callerRunsWhenRejected;
219    }
220
221    public void setCallerRunsWhenRejected(Boolean callerRunsWhenRejected) {
222        this.callerRunsWhenRejected = callerRunsWhenRejected;
223    }
224
225    @Override
226    public ExecutorService getExecutorService() {
227        return executorService;
228    }
229
230    @Override
231    public void setExecutorService(ExecutorService executorService) {
232        this.executorService = executorService;
233    }
234
235    @Override
236    public String getExecutorServiceRef() {
237        return executorServiceRef;
238    }
239
240    @Override
241    public void setExecutorServiceRef(String executorServiceRef) {
242        this.executorServiceRef = executorServiceRef;
243    }
244
245    public Boolean getRejectExecution() {
246        return rejectExecution;
247    }
248
249    public void setRejectExecution(Boolean rejectExecution) {
250        this.rejectExecution = rejectExecution;
251    }
252
253    /**
254     * The expression used to calculate the correlation key to use for throttle
255     * grouping. The Exchange which has the same correlation key is throttled
256     * together.
257     */
258    public void setCorrelationExpression(ExpressionSubElementDefinition correlationExpression) {
259        this.correlationExpression = correlationExpression;
260    }
261
262    public ExpressionSubElementDefinition getCorrelationExpression() {
263        return correlationExpression;
264    }
265}