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; 020import java.util.concurrent.ScheduledExecutorService; 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlAttribute; 024import javax.xml.bind.annotation.XmlRootElement; 025import javax.xml.bind.annotation.XmlTransient; 026 027import org.apache.camel.Expression; 028import org.apache.camel.Processor; 029import org.apache.camel.builder.ExpressionBuilder; 030import org.apache.camel.model.language.ExpressionDefinition; 031import org.apache.camel.processor.Throttler; 032import org.apache.camel.spi.RouteContext; 033 034/** 035 * Represents an XML <throttle/> element 036 * 037 * @version 038 */ 039@XmlRootElement(name = "throttle") 040@XmlAccessorType(XmlAccessType.FIELD) 041public class ThrottleDefinition extends ExpressionNode implements ExecutorServiceAwareDefinition<ThrottleDefinition> { 042 // TODO: Camel 3.0 Should not support outputs 043 044 @XmlTransient 045 private ExecutorService executorService; 046 @XmlAttribute 047 private String executorServiceRef; 048 @XmlAttribute 049 private Long timePeriodMillis; 050 @XmlAttribute 051 private Boolean asyncDelayed; 052 @XmlAttribute 053 private Boolean callerRunsWhenRejected; 054 @XmlAttribute 055 private Boolean rejectExecution; 056 057 public ThrottleDefinition() { 058 } 059 060 public ThrottleDefinition(Expression maximumRequestsPerPeriod) { 061 super(maximumRequestsPerPeriod); 062 } 063 064 @Override 065 public String toString() { 066 return "Throttle[" + description() + " -> " + getOutputs() + "]"; 067 } 068 069 protected String description() { 070 return getExpression() + " request per " + getTimePeriodMillis() + " millis"; 071 } 072 073 @Override 074 public String getShortName() { 075 return "throttle"; 076 } 077 078 @Override 079 public String getLabel() { 080 return "throttle[" + description() + "]"; 081 } 082 083 @Override 084 public Processor createProcessor(RouteContext routeContext) throws Exception { 085 Processor childProcessor = this.createChildProcessor(routeContext, true); 086 087 boolean shutdownThreadPool = ProcessorDefinitionHelper.willCreateNewThreadPool(routeContext, this, isAsyncDelayed()); 088 ScheduledExecutorService threadPool = ProcessorDefinitionHelper.getConfiguredScheduledExecutorService(routeContext, "Throttle", this, isAsyncDelayed()); 089 090 // should be default 1000 millis 091 long period = getTimePeriodMillis() != null ? getTimePeriodMillis() : 1000L; 092 093 // max requests per period is mandatory 094 Expression maxRequestsExpression = createMaxRequestsPerPeriodExpression(routeContext); 095 if (maxRequestsExpression == null) { 096 throw new IllegalArgumentException("MaxRequestsPerPeriod expression must be provided on " + this); 097 } 098 099 Throttler answer = new Throttler(routeContext.getCamelContext(), childProcessor, maxRequestsExpression, period, threadPool, shutdownThreadPool, isRejectExecution()); 100 101 if (getAsyncDelayed() != null) { 102 answer.setAsyncDelayed(getAsyncDelayed()); 103 } 104 105 if (getCallerRunsWhenRejected() == null) { 106 // should be true by default 107 answer.setCallerRunsWhenRejected(true); 108 } else { 109 answer.setCallerRunsWhenRejected(getCallerRunsWhenRejected()); 110 } 111 return answer; 112 } 113 114 private Expression createMaxRequestsPerPeriodExpression(RouteContext routeContext) { 115 ExpressionDefinition expr = getExpression(); 116 if (expr != null) { 117 return expr.createExpression(routeContext); 118 } 119 return null; 120 } 121 122 // Fluent API 123 // ------------------------------------------------------------------------- 124 /** 125 * Sets the time period during which the maximum request count is valid for 126 * 127 * @param timePeriodMillis period in millis 128 * @return the builder 129 */ 130 public ThrottleDefinition timePeriodMillis(long timePeriodMillis) { 131 setTimePeriodMillis(timePeriodMillis); 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 period 139 * @return the builder 140 */ 141 public ThrottleDefinition maximumRequestsPerPeriod(Long maximumRequestsPerPeriod) { 142 setExpression(ExpressionNodeHelper.toExpressionDefinition(ExpressionBuilder.constantExpression(maximumRequestsPerPeriod))); 143 return this; 144 } 145 146 /** 147 * Whether or not the caller should run the task when it was rejected by the thread pool. 148 * <p/> 149 * Is by default <tt>true</tt> 150 * 151 * @param callerRunsWhenRejected whether or not the caller should run 152 * @return the builder 153 */ 154 public ThrottleDefinition callerRunsWhenRejected(boolean callerRunsWhenRejected) { 155 setCallerRunsWhenRejected(callerRunsWhenRejected); 156 return this; 157 } 158 159 /** 160 * Enables asynchronous delay which means the thread will <b>no</b> block while delaying. 161 * 162 * @return the builder 163 */ 164 public ThrottleDefinition asyncDelayed() { 165 setAsyncDelayed(true); 166 return this; 167 } 168 169 /** 170 * Whether or not throttler throws the ThrottlerRejectedExecutionException when the exchange exceeds the request limit 171 * <p/> 172 * Is by default <tt>false</tt> 173 * 174 * @param rejectExecution throw the RejectExecutionException if the exchange exceeds the request limit 175 * @return the builder 176 */ 177 public ThrottleDefinition rejectExecution(boolean rejectExecution) { 178 setRejectExecution(rejectExecution); 179 return this; 180 } 181 182 /** 183 * Sets the ExecutorService which could be used by throttle definition 184 * 185 * @param executorService 186 * @return the builder 187 */ 188 public ThrottleDefinition executorService(ExecutorService executorService) { 189 setExecutorService(executorService); 190 return this; 191 } 192 193 /** 194 * Sets the ExecutorService which could be used by throttle definition 195 * 196 * @param executorServiceRef the reference id of the Executor Service 197 * @return the builder 198 */ 199 public ThrottleDefinition executorServiceRef(String executorServiceRef) { 200 setExecutorServiceRef(executorServiceRef); 201 return this; 202 } 203 204 205 206 // Properties 207 // ------------------------------------------------------------------------- 208 209 public Long getTimePeriodMillis() { 210 return timePeriodMillis; 211 } 212 213 public void setTimePeriodMillis(Long timePeriodMillis) { 214 this.timePeriodMillis = timePeriodMillis; 215 } 216 217 public Boolean getAsyncDelayed() { 218 return asyncDelayed; 219 } 220 221 public void setAsyncDelayed(Boolean asyncDelayed) { 222 this.asyncDelayed = asyncDelayed; 223 } 224 225 public boolean isAsyncDelayed() { 226 return asyncDelayed != null && asyncDelayed; 227 } 228 229 public Boolean getCallerRunsWhenRejected() { 230 return callerRunsWhenRejected; 231 } 232 233 public void setCallerRunsWhenRejected(Boolean callerRunsWhenRejected) { 234 this.callerRunsWhenRejected = callerRunsWhenRejected; 235 } 236 237 public ExecutorService getExecutorService() { 238 return executorService; 239 } 240 241 public void setExecutorService(ExecutorService executorService) { 242 this.executorService = executorService; 243 } 244 245 public String getExecutorServiceRef() { 246 return executorServiceRef; 247 } 248 249 public void setExecutorServiceRef(String executorServiceRef) { 250 this.executorServiceRef = executorServiceRef; 251 } 252 253 public boolean isRejectExecution() { 254 return rejectExecution != null ? rejectExecution : false; 255 } 256 257 public void setRejectExecution(Boolean rejectExecution) { 258 this.rejectExecution = rejectExecution; 259 } 260}