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.builder; 018 019import java.util.HashMap; 020import java.util.Map; 021import java.util.Optional; 022import java.util.concurrent.Future; 023import java.util.function.Consumer; 024import java.util.function.Supplier; 025 026import org.apache.camel.CamelContext; 027import org.apache.camel.CamelExecutionException; 028import org.apache.camel.Endpoint; 029import org.apache.camel.Exchange; 030import org.apache.camel.ExchangePattern; 031import org.apache.camel.FluentProducerTemplate; 032import org.apache.camel.Message; 033import org.apache.camel.Processor; 034import org.apache.camel.ProducerTemplate; 035import org.apache.camel.processor.ConvertBodyProcessor; 036import org.apache.camel.support.ServiceSupport; 037import org.apache.camel.util.ExchangeHelper; 038import org.apache.camel.util.ObjectHelper; 039import org.apache.camel.util.ServiceHelper; 040 041public class DefaultFluentProducerTemplate extends ServiceSupport implements FluentProducerTemplate { 042 private final CamelContext context; 043 private final ClassValue<ConvertBodyProcessor> resultProcessors; 044 private Map<String, Object> headers; 045 private Object body; 046 private Optional<Consumer<ProducerTemplate>> templateCustomizer; 047 private Optional<Supplier<Exchange>> exchangeSupplier; 048 private Optional<Supplier<Processor>> processorSupplier; 049 private Optional<Endpoint> endpoint; 050 private Optional<Endpoint> defaultEndpoint; 051 private int maximumCacheSize; 052 private boolean eventNotifierEnabled; 053 private volatile ProducerTemplate template; 054 055 public DefaultFluentProducerTemplate(CamelContext context) { 056 this.context = context; 057 this.endpoint = Optional.empty(); 058 this.defaultEndpoint = Optional.empty(); 059 this.eventNotifierEnabled = true; 060 this.templateCustomizer = Optional.empty(); 061 this.exchangeSupplier = Optional.empty(); 062 this.processorSupplier = Optional.empty(); 063 this.resultProcessors = new ClassValue<ConvertBodyProcessor>() { 064 @Override 065 protected ConvertBodyProcessor computeValue(Class<?> type) { 066 return new ConvertBodyProcessor(type); 067 } 068 }; 069 } 070 071 @Override 072 public CamelContext getCamelContext() { 073 return context; 074 } 075 076 @Override 077 public int getCurrentCacheSize() { 078 if (template == null) { 079 return 0; 080 } 081 return template.getCurrentCacheSize(); 082 } 083 084 @Override 085 public void cleanUp() { 086 if (template != null) { 087 template.cleanUp(); 088 } 089 } 090 091 @Override 092 public void setDefaultEndpointUri(String endpointUri) { 093 setDefaultEndpoint(getCamelContext().getEndpoint(endpointUri)); 094 } 095 096 @Override 097 public Endpoint getDefaultEndpoint() { 098 return defaultEndpoint.orElse(null); 099 } 100 101 @Override 102 public void setDefaultEndpoint(Endpoint defaultEndpoint) { 103 this.defaultEndpoint = Optional.ofNullable(defaultEndpoint); 104 } 105 106 @Override 107 public int getMaximumCacheSize() { 108 return maximumCacheSize; 109 } 110 111 @Override 112 public void setMaximumCacheSize(int maximumCacheSize) { 113 this.maximumCacheSize = maximumCacheSize; 114 } 115 116 @Override 117 public boolean isEventNotifierEnabled() { 118 return eventNotifierEnabled; 119 } 120 121 @Override 122 public void setEventNotifierEnabled(boolean eventNotifierEnabled) { 123 this.eventNotifierEnabled = eventNotifierEnabled; 124 } 125 126 @Override 127 public FluentProducerTemplate clearAll() { 128 clearBody(); 129 clearHeaders(); 130 131 return this; 132 } 133 134 @Override 135 public FluentProducerTemplate withHeader(String key, Object value) { 136 if (headers == null) { 137 headers = new HashMap<>(); 138 } 139 140 headers.put(key, value); 141 142 return this; 143 } 144 145 @Override 146 public FluentProducerTemplate clearHeaders() { 147 if (headers != null) { 148 headers.clear(); 149 } 150 151 return this; 152 } 153 154 @Override 155 public FluentProducerTemplate withBody(Object body) { 156 this.body = body; 157 158 return this; 159 } 160 161 @Override 162 public FluentProducerTemplate withBodyAs(Object body, Class<?> type) { 163 this.body = type != null 164 ? context.getTypeConverter().convertTo(type, body) 165 : body; 166 167 return this; 168 } 169 170 @Override 171 public FluentProducerTemplate clearBody() { 172 this.body = null; 173 174 return this; 175 } 176 177 @Override 178 public FluentProducerTemplate withTemplateCustomizer(final Consumer<ProducerTemplate> templateCustomizer) { 179 this.templateCustomizer = Optional.of(templateCustomizer); 180 return this; 181 } 182 183 @Override 184 public FluentProducerTemplate withExchange(final Exchange exchange) { 185 return withExchange(() -> exchange); 186 } 187 188 @Override 189 public FluentProducerTemplate withExchange(final Supplier<Exchange> exchangeSupplier) { 190 this.exchangeSupplier = Optional.of(exchangeSupplier); 191 return this; 192 } 193 194 @Override 195 public FluentProducerTemplate withProcessor(final Processor processor) { 196 return withProcessor(() -> processor); 197 } 198 199 @Override 200 public FluentProducerTemplate withProcessor(final Supplier<Processor> processorSupplier) { 201 this.processorSupplier = Optional.of(processorSupplier); 202 return this; 203 } 204 205 @Override 206 public FluentProducerTemplate to(String endpointUri) { 207 return to(context.getEndpoint(endpointUri)); 208 } 209 210 @Override 211 public FluentProducerTemplate to(Endpoint endpoint) { 212 this.endpoint = Optional.of(endpoint); 213 return this; 214 } 215 216 // ************************ 217 // REQUEST 218 // ************************ 219 220 @Override 221 public Object request() throws CamelExecutionException { 222 return request(Object.class); 223 } 224 225 @Override 226 @SuppressWarnings("unchecked") 227 public <T> T request(Class<T> type) throws CamelExecutionException { 228 // Determine the target endpoint 229 final Endpoint target = target(); 230 231 // Create the default processor if not provided. 232 final Supplier<Processor> processorSupplier = this.processorSupplier.orElse(() -> defaultProcessor()); 233 234 T result; 235 if (type == Exchange.class) { 236 result = (T)template().request(target, processorSupplier.get()); 237 } else if (type == Message.class) { 238 Exchange exchange = template().request(target, processorSupplier.get()); 239 result = exchange.hasOut() ? (T)exchange.getOut() : (T)exchange.getIn(); 240 } else { 241 Exchange exchange = template().send( 242 target, 243 ExchangePattern.InOut, 244 processorSupplier.get(), 245 resultProcessors.get(type) 246 ); 247 248 result = context.getTypeConverter().convertTo( 249 type, 250 ExchangeHelper.extractResultBody(exchange, exchange.getPattern()) 251 ); 252 } 253 254 return result; 255 } 256 257 @Override 258 public Future<Object> asyncRequest() { 259 return asyncRequest(Object.class); 260 } 261 262 @Override 263 public <T> Future<T> asyncRequest(Class<T> type) { 264 // Determine the target endpoint 265 final Endpoint target = target(); 266 267 Future<T> result; 268 if (ObjectHelper.isNotEmpty(headers)) { 269 // Make a copy of the headers and body so that async processing won't 270 // be invalidated by subsequent reuse of the template 271 final Map<String, Object> headersCopy = new HashMap<>(headers); 272 final Object bodyCopy = body; 273 274 result = template().asyncRequestBodyAndHeaders(target, bodyCopy, headersCopy, type); 275 } else { 276 // Make a copy of the and body so that async processing won't be 277 // invalidated by subsequent reuse of the template 278 final Object bodyCopy = body; 279 280 result = template().asyncRequestBody(target, bodyCopy, type); 281 } 282 283 return result; 284 } 285 286 // ************************ 287 // SEND 288 // ************************ 289 290 @Override 291 public Exchange send() throws CamelExecutionException { 292 // Determine the target endpoint 293 final Endpoint target = target(); 294 295 return exchangeSupplier.isPresent() 296 ? template().send(target, exchangeSupplier.get().get()) 297 : template().send(target, processorSupplier.orElse(() -> defaultProcessor()).get()); 298 } 299 300 @Override 301 public Future<Exchange> asyncSend() { 302 // Determine the target endpoint 303 final Endpoint target = target(); 304 305 return exchangeSupplier.isPresent() 306 ? template().asyncSend(target, exchangeSupplier.get().get()) 307 : template().asyncSend(target, processorSupplier.orElse(() -> defaultAsyncProcessor()).get()); 308 } 309 310 // ************************ 311 // HELPERS 312 // ************************ 313 314 /** 315 * Create the FluentProducerTemplate by setting the camel context 316 * 317 * @param context the camel context 318 */ 319 public static FluentProducerTemplate on(CamelContext context) { 320 return new DefaultFluentProducerTemplate(context); 321 } 322 323 private ProducerTemplate template() { 324 ObjectHelper.notNull(context, "CamelContext"); 325 326 if (template == null) { 327 template = maximumCacheSize > 0 ? context.createProducerTemplate(maximumCacheSize) : context.createProducerTemplate(); 328 defaultEndpoint.ifPresent(template::setDefaultEndpoint); 329 template.setEventNotifierEnabled(eventNotifierEnabled); 330 templateCustomizer.ifPresent(tc -> tc.accept(template)); 331 } 332 333 return template; 334 } 335 336 private Processor defaultProcessor() { 337 return exchange -> { 338 ObjectHelper.ifNotEmpty(headers, exchange.getIn().getHeaders()::putAll); 339 ObjectHelper.ifNotEmpty(body, exchange.getIn()::setBody); 340 }; 341 } 342 343 private Processor defaultAsyncProcessor() { 344 final Map<String, Object> headersCopy = ObjectHelper.isNotEmpty(this.headers) ? new HashMap<>(this.headers) : null; 345 final Object bodyCopy = this.body; 346 347 return exchange -> { 348 ObjectHelper.ifNotEmpty(headersCopy, exchange.getIn().getHeaders()::putAll); 349 ObjectHelper.ifNotEmpty(bodyCopy, exchange.getIn()::setBody); 350 }; 351 } 352 353 private Endpoint target() { 354 if (endpoint.isPresent()) { 355 return endpoint.get(); 356 } 357 if (defaultEndpoint.isPresent()) { 358 return defaultEndpoint.get(); 359 } 360 361 throw new IllegalArgumentException("No endpoint configured on FluentProducerTemplate. You can configure an endpoint with to(uri)"); 362 } 363 364 @Override 365 protected void doStart() throws Exception { 366 if (template == null) { 367 template = template(); 368 } 369 ServiceHelper.startService(template); 370 } 371 372 @Override 373 protected void doStop() throws Exception { 374 ServiceHelper.stopService(template); 375 } 376}