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 javax.xml.bind.annotation.XmlAccessType; 020import javax.xml.bind.annotation.XmlAccessorType; 021import javax.xml.bind.annotation.XmlAttribute; 022import javax.xml.bind.annotation.XmlRootElement; 023import javax.xml.bind.annotation.XmlTransient; 024 025import org.apache.camel.CamelContextAware; 026import org.apache.camel.Endpoint; 027import org.apache.camel.Processor; 028import org.apache.camel.processor.PollEnricher; 029import org.apache.camel.processor.aggregate.AggregationStrategy; 030import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter; 031import org.apache.camel.spi.Metadata; 032import org.apache.camel.spi.RouteContext; 033import org.apache.camel.util.ObjectHelper; 034 035/** 036 * Enriches messages with data polled from a secondary resource 037 * 038 * @see org.apache.camel.processor.Enricher 039 */ 040@Metadata(label = "eip,transformation") 041@XmlRootElement(name = "pollEnrich") 042@XmlAccessorType(XmlAccessType.FIELD) 043public class PollEnrichDefinition extends NoOutputDefinition<PollEnrichDefinition> implements EndpointRequiredDefinition { 044 @XmlAttribute(name = "uri") 045 private String resourceUri; 046 // TODO: For Camel 3.0 we should remove this ref attribute as you can do that in the uri, by prefixing with ref: 047 @XmlAttribute(name = "ref") 048 @Deprecated 049 private String resourceRef; 050 @XmlAttribute @Metadata(defaultValue = "-1") 051 private Long timeout; 052 @XmlAttribute(name = "strategyRef") 053 private String aggregationStrategyRef; 054 @XmlAttribute(name = "strategyMethodName") 055 private String aggregationStrategyMethodName; 056 @XmlAttribute(name = "strategyMethodAllowNull") 057 private Boolean aggregationStrategyMethodAllowNull; 058 @XmlAttribute 059 private Boolean aggregateOnException; 060 @XmlTransient 061 private AggregationStrategy aggregationStrategy; 062 063 public PollEnrichDefinition() { 064 } 065 066 public PollEnrichDefinition(AggregationStrategy aggregationStrategy, String resourceUri, long timeout) { 067 this.aggregationStrategy = aggregationStrategy; 068 this.resourceUri = resourceUri; 069 this.timeout = timeout; 070 } 071 072 @Override 073 public String toString() { 074 return "PollEnrich[" + description() + " " + aggregationStrategy + "]"; 075 } 076 077 protected String description() { 078 return FromDefinition.description(getResourceUri(), getResourceRef(), (Endpoint) null); 079 } 080 081 @Override 082 public String getLabel() { 083 return "pollEnrich[" + description() + "]"; 084 } 085 086 @Override 087 public String getEndpointUri() { 088 if (resourceUri != null) { 089 return resourceUri; 090 } else { 091 return null; 092 } 093 } 094 095 @Override 096 public Processor createProcessor(RouteContext routeContext) throws Exception { 097 if (ObjectHelper.isEmpty(resourceUri) && ObjectHelper.isEmpty(resourceRef)) { 098 throw new IllegalArgumentException("Either uri or ref must be provided for resource endpoint"); 099 } 100 101 // lookup endpoint 102 Endpoint endpoint; 103 if (resourceUri != null) { 104 endpoint = routeContext.resolveEndpoint(resourceUri); 105 } else { 106 endpoint = routeContext.resolveEndpoint(null, resourceRef); 107 } 108 109 PollEnricher enricher; 110 if (timeout != null) { 111 enricher = new PollEnricher(null, endpoint.createPollingConsumer(), timeout); 112 } else { 113 // if no timeout then we should block, and there use a negative timeout 114 enricher = new PollEnricher(null, endpoint.createPollingConsumer(), -1); 115 } 116 117 AggregationStrategy strategy = createAggregationStrategy(routeContext); 118 if (strategy == null) { 119 enricher.setDefaultAggregationStrategy(); 120 } else { 121 enricher.setAggregationStrategy(strategy); 122 } 123 if (getAggregateOnException() != null) { 124 enricher.setAggregateOnException(getAggregateOnException()); 125 } 126 127 return enricher; 128 } 129 130 private AggregationStrategy createAggregationStrategy(RouteContext routeContext) { 131 AggregationStrategy strategy = getAggregationStrategy(); 132 if (strategy == null && aggregationStrategyRef != null) { 133 Object aggStrategy = routeContext.lookup(aggregationStrategyRef, Object.class); 134 if (aggStrategy instanceof AggregationStrategy) { 135 strategy = (AggregationStrategy) aggStrategy; 136 } else if (aggStrategy != null) { 137 AggregationStrategyBeanAdapter adapter = new AggregationStrategyBeanAdapter(aggStrategy, getAggregationStrategyMethodName()); 138 if (getAggregationStrategyMethodAllowNull() != null) { 139 adapter.setAllowNullNewExchange(getAggregationStrategyMethodAllowNull()); 140 adapter.setAllowNullOldExchange(getAggregationStrategyMethodAllowNull()); 141 } 142 strategy = adapter; 143 } else { 144 throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + aggregationStrategyRef); 145 } 146 } 147 148 if (strategy != null && strategy instanceof CamelContextAware) { 149 ((CamelContextAware) strategy).setCamelContext(routeContext.getCamelContext()); 150 } 151 152 return strategy; 153 } 154 155 public String getResourceUri() { 156 return resourceUri; 157 } 158 159 /** 160 * The endpoint uri for the external service to poll enrich from. You must use either uri or ref. 161 */ 162 public void setResourceUri(String resourceUri) { 163 this.resourceUri = resourceUri; 164 } 165 166 public String getResourceRef() { 167 return resourceRef; 168 } 169 170 /** 171 * Refers to the endpoint for the external service to poll enrich from. You must use either uri or ref. 172 * 173 * @deprecated use uri with ref:uri instead 174 */ 175 @Deprecated 176 public void setResourceRef(String resourceRef) { 177 this.resourceRef = resourceRef; 178 } 179 180 public Long getTimeout() { 181 return timeout; 182 } 183 184 /** 185 * Timeout in millis when polling from the external service. 186 * <p/> 187 * The timeout has influence about the poll enrich behavior. It basically operations in three different modes: 188 * <ul> 189 * <li>negative value - Waits until a message is available and then returns it. Warning that this method could block indefinitely if no messages are available.</li> 190 * <li>0 - Attempts to receive a message exchange immediately without waiting and returning <tt>null</tt> if a message exchange is not available yet.</li> 191 * <li>positive value - Attempts to receive a message exchange, waiting up to the given timeout to expire if a message is not yet available. Returns <tt>null</tt> if timed out</li> 192 * </ul> 193 * The default value is -1 and therefore the method could block indefinitely, and therefore its recommended to use a timeout value 194 */ 195 public void setTimeout(Long timeout) { 196 this.timeout = timeout; 197 } 198 199 public String getAggregationStrategyRef() { 200 return aggregationStrategyRef; 201 } 202 203 /** 204 * Refers to an AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. 205 * By default Camel will use the reply from the external service as outgoing message. 206 */ 207 public void setAggregationStrategyRef(String aggregationStrategyRef) { 208 this.aggregationStrategyRef = aggregationStrategyRef; 209 } 210 211 public String getAggregationStrategyMethodName() { 212 return aggregationStrategyMethodName; 213 } 214 215 /** 216 * This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy. 217 */ 218 public void setAggregationStrategyMethodName(String aggregationStrategyMethodName) { 219 this.aggregationStrategyMethodName = aggregationStrategyMethodName; 220 } 221 222 public Boolean getAggregationStrategyMethodAllowNull() { 223 return aggregationStrategyMethodAllowNull; 224 } 225 226 /** 227 * If this option is false then the aggregate method is not used if there was no data to enrich. 228 * If this option is true then null values is used as the oldExchange (when no data to enrich), 229 * when using POJOs as the AggregationStrategy. 230 */ 231 public void setAggregationStrategyMethodAllowNull(Boolean aggregationStrategyMethodAllowNull) { 232 this.aggregationStrategyMethodAllowNull = aggregationStrategyMethodAllowNull; 233 } 234 235 public AggregationStrategy getAggregationStrategy() { 236 return aggregationStrategy; 237 } 238 239 /** 240 * Sets the AggregationStrategy to be used to merge the reply from the external service, into a single outgoing message. 241 * By default Camel will use the reply from the external service as outgoing message. 242 */ 243 public void setAggregationStrategy(AggregationStrategy aggregationStrategy) { 244 this.aggregationStrategy = aggregationStrategy; 245 } 246 247 public Boolean getAggregateOnException() { 248 return aggregateOnException; 249 } 250 251 /** 252 * If this option is false then the aggregate method is not used if there was an exception thrown while trying 253 * to retrieve the data to enrich from the resource. Setting this option to true allows end users to control what 254 * to do if there was an exception in the aggregate method. For example to suppress the exception 255 * or set a custom message body etc. 256 */ 257 public void setAggregateOnException(Boolean aggregateOnException) { 258 this.aggregateOnException = aggregateOnException; 259 } 260}