/* * Copyright (C) 2015 * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.cleverbus.component.externalcall; import static org.apache.commons.lang.BooleanUtils.isNotTrue; import static org.springframework.util.StringUtils.hasText; import org.cleverbus.api.asynch.AsynchConstants; import org.cleverbus.api.entity.ExternalCall; import org.cleverbus.api.entity.Message; import org.cleverbus.api.exception.LockFailureException; import org.cleverbus.api.extcall.ExtCallComponentParams; import org.cleverbus.common.log.Log; import org.cleverbus.spi.extcall.ExternalCallService; import org.apache.camel.Exchange; import org.apache.camel.impl.DefaultProducer; import org.springframework.util.Assert; /** * See {@link ExternalCallComponent} */ public class ExternalCallProducer extends DefaultProducer { public ExternalCallProducer(ExternalCallEndpoint externalCallEndpoint) { super(externalCallEndpoint); } @Override public void process(final Exchange exchange) throws Exception { Message message = getMessage(exchange); String targetURI = getTargetURI(exchange); String operation = getOperation(exchange); String key = getOperationKey(exchange); ExternalCallService service = getService(exchange); Log.debug("External call check: operation URI = {}, operation key = {}, msgTimestamp = {}", operation, key, message.getMsgTimestamp()); ExternalCall externalCall = prepareExternalCall(operation, key, message, service); if (externalCall != null) { try { executeExternalCall(exchange, targetURI); } finally { finalizeExternalCall(exchange, externalCall, service); // in either case release the external call } } else { Log.debug("External call was skipped. See external call service log for detailed info. " + "Call: target={} operation={} key={} msgId={} msgTimestamp={}", targetURI, operation, key, message.getMsgId(), message.getMsgTimestamp()); } } protected ExternalCall prepareExternalCall( String operation, String key, Message message, ExternalCallService service) { try { return service.prepare(operation, key, message); } catch (LockFailureException exc) { throw exc; // don't re-wrap lock failure } catch (Exception exc) { throw new LockFailureException(String.format( "External call lock failure, please retry. " + "Call: operation=%s key=%s msgId=%s msgTimestamp=%s", operation, key, message.getMsgId(), message.getMsgTimestamp()), exc); } } protected void executeExternalCall(Exchange exchange, String targetURI) { try { // success should not be determined before the call is made exchange.removeProperty(ExtCallComponentParams.EXTERNAL_CALL_SUCCESS); // route exchange to external call target getEndpoint().getProducerTemplate().send(targetURI, exchange); } catch (Exception exc) { exchange.setException(exc); // this also marks exchange as failed } } protected void finalizeExternalCall(Exchange exchange, ExternalCall externalCall, ExternalCallService service) { Boolean success = exchange.getProperty(ExtCallComponentParams.EXTERNAL_CALL_SUCCESS, Boolean.class); if (success == null) { // success is not defined forcefully -> determine success normally success = !exchange.isFailed() && isNotTrue(exchange.getProperty(Exchange.ROUTE_STOP, Boolean.class)); } if (success) { service.complete(externalCall); } else { service.failed(externalCall); } // cleanup: exchange.removeProperty(ExtCallComponentParams.EXTERNAL_CALL_OPERATION); exchange.removeProperty(ExtCallComponentParams.EXTERNAL_CALL_KEY); exchange.removeProperty(ExtCallComponentParams.EXTERNAL_CALL_SUCCESS); } protected Message getMessage(Exchange exchange) { Message message = exchange.getIn().getHeader(AsynchConstants.MSG_HEADER, Message.class); Assert.notNull(message, "Message must be provided in header '" + AsynchConstants.MSG_HEADER + "'"); return message; } protected String getTargetURI(Exchange exchange) { return getEndpoint().getTargetURI(); } protected String getOperation(Exchange exchange) { String operation = exchange.getProperty(ExtCallComponentParams.EXTERNAL_CALL_OPERATION, String.class); return hasText(operation) ? operation : getTargetURI(exchange); } protected String getOperationKey(Exchange exchange) { return getEndpoint().getKeyType().getExpression().evaluate(exchange, Object.class).toString(); } protected ExternalCallService getService(Exchange exchange) { return getEndpoint().getService(); } @Override public ExternalCallEndpoint getEndpoint() { return (ExternalCallEndpoint) super.getEndpoint(); } }