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", javaType = "java.lang.Long")
051    private String timePeriodMillis;
052    @XmlAttribute
053    @Metadata(javaType = "java.lang.Boolean")
054    private String asyncDelayed;
055    @XmlAttribute
056    @Metadata(defaultValue = "true", javaType = "java.lang.Boolean")
057    private String callerRunsWhenRejected;
058    @XmlAttribute
059    @Metadata(javaType = "java.lang.Boolean")
060    private String rejectExecution;
061
062    public ThrottleDefinition() {
063    }
064
065    public ThrottleDefinition(Expression maximumRequestsPerPeriod) {
066        super(maximumRequestsPerPeriod);
067    }
068
069    public ThrottleDefinition(Expression maximumRequestsPerPeriod, Expression correlationExpression) {
070        this(ExpressionNodeHelper.toExpressionDefinition(maximumRequestsPerPeriod), correlationExpression);
071    }
072
073    private ThrottleDefinition(ExpressionDefinition maximumRequestsPerPeriod, Expression correlationExpression) {
074        super(maximumRequestsPerPeriod);
075
076        ExpressionSubElementDefinition cor = new ExpressionSubElementDefinition();
077        cor.setExpressionType(ExpressionNodeHelper.toExpressionDefinition(correlationExpression));
078        setCorrelationExpression(cor);
079    }
080
081    @Override
082    public String toString() {
083        return "Throttle[" + description() + "]";
084    }
085
086    protected String description() {
087        return getExpression() + " request per " + getTimePeriodMillis() + " millis";
088    }
089
090    @Override
091    public String getShortName() {
092        return "throttle";
093    }
094
095    @Override
096    public String getLabel() {
097        return "throttle[" + description() + "]";
098    }
099
100    // Fluent API
101    // -------------------------------------------------------------------------
102    /**
103     * Sets the time period during which the maximum request count is valid for
104     *
105     * @param timePeriodMillis period in millis
106     * @return the builder
107     */
108    public ThrottleDefinition timePeriodMillis(long timePeriodMillis) {
109        return timePeriodMillis(Long.toString(timePeriodMillis));
110    }
111
112    /**
113     * Sets the time period during which the maximum request count is valid for
114     *
115     * @param timePeriodMillis period in millis
116     * @return the builder
117     */
118    public ThrottleDefinition timePeriodMillis(String timePeriodMillis) {
119        setTimePeriodMillis(timePeriodMillis);
120        return this;
121    }
122
123    /**
124     * Sets the time period during which the maximum request count per period
125     *
126     * @param maximumRequestsPerPeriod the maximum request count number per time
127     *            period
128     * @return the builder
129     */
130    public ThrottleDefinition maximumRequestsPerPeriod(long maximumRequestsPerPeriod) {
131        setExpression(ExpressionNodeHelper.toExpressionDefinition(ExpressionBuilder.constantExpression(maximumRequestsPerPeriod)));
132        return this;
133    }
134
135    /**
136     * Sets the time period during which the maximum request count per period
137     *
138     * @param maximumRequestsPerPeriod the maximum request count number per time
139     *            period
140     * @return the builder
141     */
142    public ThrottleDefinition maximumRequestsPerPeriod(String maximumRequestsPerPeriod) {
143        setExpression(ExpressionNodeHelper.toExpressionDefinition(ExpressionBuilder.simpleExpression(maximumRequestsPerPeriod)));
144        return this;
145    }
146
147    /**
148     * Whether or not the caller should run the task when it was rejected by the
149     * thread pool.
150     * <p/>
151     * Is by default <tt>true</tt>
152     *
153     * @param callerRunsWhenRejected whether or not the caller should run
154     * @return the builder
155     */
156    public ThrottleDefinition callerRunsWhenRejected(boolean callerRunsWhenRejected) {
157        return callerRunsWhenRejected(Boolean.toString(callerRunsWhenRejected));
158    }
159
160    /**
161     * Whether or not the caller should run the task when it was rejected by the
162     * thread pool.
163     * <p/>
164     * Is by default <tt>true</tt>
165     *
166     * @param callerRunsWhenRejected whether or not the caller should run
167     * @return the builder
168     */
169    public ThrottleDefinition callerRunsWhenRejected(String callerRunsWhenRejected) {
170        setCallerRunsWhenRejected(callerRunsWhenRejected);
171        return this;
172    }
173
174    /**
175     * Enables asynchronous delay which means the thread will <b>not</b> block
176     * while delaying.
177     *
178     * @return the builder
179     */
180    public ThrottleDefinition asyncDelayed() {
181        return asyncDelayed(true);
182    }
183
184    /**
185     * Enables asynchronous delay which means the thread will <b>not</b> block
186     * while delaying.
187     *
188     * @return the builder
189     */
190    public ThrottleDefinition asyncDelayed(boolean asyncDelayed) {
191        return asyncDelayed(Boolean.toString(asyncDelayed));
192    }
193
194    /**
195     * Enables asynchronous delay which means the thread will <b>not</b> block
196     * while delaying.
197     *
198     * @return the builder
199     */
200    public ThrottleDefinition asyncDelayed(String asyncDelayed) {
201        setAsyncDelayed(asyncDelayed);
202        return this;
203    }
204
205    /**
206     * Whether or not throttler throws the ThrottlerRejectedExecutionException
207     * when the exchange exceeds the request limit
208     * <p/>
209     * Is by default <tt>false</tt>
210     *
211     * @param rejectExecution throw the RejectExecutionException if the exchange
212     *            exceeds the request limit
213     * @return the builder
214     */
215    public ThrottleDefinition rejectExecution(boolean rejectExecution) {
216        return rejectExecution(Boolean.toString(rejectExecution));
217    }
218
219    /**
220     * Whether or not throttler throws the ThrottlerRejectedExecutionException
221     * when the exchange exceeds the request limit
222     * <p/>
223     * Is by default <tt>false</tt>
224     *
225     * @param rejectExecution throw the RejectExecutionException if the exchange
226     *            exceeds the request limit
227     * @return the builder
228     */
229    public ThrottleDefinition rejectExecution(String rejectExecution) {
230        setRejectExecution(rejectExecution);
231        return this;
232    }
233
234    /**
235     * To use a custom thread pool (ScheduledExecutorService) by the throttler.
236     *
237     * @param executorService the custom thread pool (must be scheduled)
238     * @return the builder
239     */
240    @Override
241    public ThrottleDefinition executorService(ExecutorService executorService) {
242        setExecutorService(executorService);
243        return this;
244    }
245
246    /**
247     * To use a custom thread pool (ScheduledExecutorService) by the throttler.
248     *
249     * @param executorServiceRef the reference id of the thread pool (must be
250     *            scheduled)
251     * @return the builder
252     */
253    @Override
254    public ThrottleDefinition executorServiceRef(String executorServiceRef) {
255        setExecutorServiceRef(executorServiceRef);
256        return this;
257    }
258
259    // Properties
260    // -------------------------------------------------------------------------
261
262    /**
263     * Expression to configure the maximum number of messages to throttle per
264     * request
265     */
266    @Override
267    public void setExpression(ExpressionDefinition expression) {
268        // override to include javadoc what the expression is used for
269        super.setExpression(expression);
270    }
271
272    public String getTimePeriodMillis() {
273        return timePeriodMillis;
274    }
275
276    public void setTimePeriodMillis(String timePeriodMillis) {
277        this.timePeriodMillis = timePeriodMillis;
278    }
279
280    public String getAsyncDelayed() {
281        return asyncDelayed;
282    }
283
284    public void setAsyncDelayed(String asyncDelayed) {
285        this.asyncDelayed = asyncDelayed;
286    }
287
288    public String getCallerRunsWhenRejected() {
289        return callerRunsWhenRejected;
290    }
291
292    public void setCallerRunsWhenRejected(String callerRunsWhenRejected) {
293        this.callerRunsWhenRejected = callerRunsWhenRejected;
294    }
295
296    @Override
297    public ExecutorService getExecutorService() {
298        return executorService;
299    }
300
301    @Override
302    public void setExecutorService(ExecutorService executorService) {
303        this.executorService = executorService;
304    }
305
306    @Override
307    public String getExecutorServiceRef() {
308        return executorServiceRef;
309    }
310
311    @Override
312    public void setExecutorServiceRef(String executorServiceRef) {
313        this.executorServiceRef = executorServiceRef;
314    }
315
316    public String getRejectExecution() {
317        return rejectExecution;
318    }
319
320    public void setRejectExecution(String rejectExecution) {
321        this.rejectExecution = rejectExecution;
322    }
323
324    /**
325     * The expression used to calculate the correlation key to use for throttle
326     * grouping. The Exchange which has the same correlation key is throttled
327     * together.
328     */
329    public void setCorrelationExpression(ExpressionSubElementDefinition correlationExpression) {
330        this.correlationExpression = correlationExpression;
331    }
332
333    public ExpressionSubElementDefinition getCorrelationExpression() {
334        return correlationExpression;
335    }
336}