/* * 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.asynchchild; import org.apache.camel.CamelExecutionException; import org.apache.camel.Exchange; import org.apache.camel.ExchangePattern; import org.apache.camel.ProducerTemplate; import org.apache.camel.impl.DefaultProducer; import org.apache.commons.lang.StringUtils; import org.cleverbus.api.asynch.AsynchConstants; import org.cleverbus.api.asynch.msg.ChildMessage; import org.cleverbus.api.entity.ExternalSystemExtEnum; import org.cleverbus.api.entity.Message; import org.cleverbus.api.entity.MsgStateEnum; import org.cleverbus.api.entity.ServiceExtEnum; import org.cleverbus.common.log.Log; import org.cleverbus.spi.msg.MessageService; import org.joda.time.DateTime; import org.springframework.util.Assert; import java.util.*; /** * Producer for {@link AsynchChildComponent asynch-child} component. * * @author <a href="mailto:petr.juza@cleverlance.com">Petr Juza</a> */ public class AsynchChildProducer extends DefaultProducer { public static final String DEFAULT_EXTERNAL_SYSTEM = "IP"; /** * Creates new producer. * * @param endpoint the endpoint */ public AsynchChildProducer(AsynchChildEndpoint endpoint) { super(endpoint); } @Override public final void process(Exchange exchange) throws Exception { Message parentMsg = exchange.getIn().getHeader(AsynchConstants.MSG_HEADER, Message.class); String body = exchange.getIn().getBody(String.class); Assert.hasText(body, "the body must not be empty"); final AsynchChildEndpoint endpoint = (AsynchChildEndpoint) getEndpoint(); String correlationId = (StringUtils.isNotEmpty(endpoint.getCorrelationId()) ? endpoint.getCorrelationId() : generateCorrelationId()); Log.debug("Creates child message from " + (parentMsg != null ? "synchronous" : "asynchronous") + " message."); ServiceExtEnum serviceExt = new ServiceExtEnum() { @Override public String getServiceName() { return endpoint.getService(); } }; ExternalSystemExtEnum externalSystemExt = new ExternalSystemExtEnum() { @Override public String getSystemName() { return StringUtils.isNotEmpty(endpoint.getSourceSystem()) ? endpoint.getSourceSystem() : DEFAULT_EXTERNAL_SYSTEM; } }; Message newMsg; if (parentMsg != null) { // for asynchronous parent message - creates child message ChildMessage childMessage = new ChildMessage(parentMsg, endpoint.getBindingType(), serviceExt, endpoint.getOperationName(), body, endpoint.getObjectId(), null, StringUtils.isBlank(endpoint.getFunnelValue()) ? null : Collections.singletonList(endpoint.getFunnelValue())); newMsg = ChildMessage.createMessage(childMessage); if (StringUtils.isNotEmpty(endpoint.getSourceSystem())) { newMsg.setSourceSystem(externalSystemExt); } } else { // for synchronous message newMsg = createNewMessage(serviceExt, externalSystemExt, endpoint.getOperationName(), body, endpoint.getObjectId()); } // set correlationID newMsg.setCorrelationId(correlationId); // save message try { insertMessage(newMsg); } catch (Exception ex) { if (parentMsg != null) { // it's better to reset parent flag parentMsg.setParentMessage(false); } } // send message for next processing sendForNextProcessing(newMsg); } /** * Creates the {@link Message} object that represents asynchronous message to next step processing. * * @param service the calling service * @param externalSystem the external system * @param operationName the name of operation * @param payload the original payload * @param objectId the object ID * @return the {@link Message} object that represents asynchronous message to next step processing */ private Message createNewMessage(ServiceExtEnum service, ExternalSystemExtEnum externalSystem, String operationName, String payload, String objectId) { Date currDate = DateTime.now().toDate(); Message msg = new Message(); msg.setState(MsgStateEnum.PROCESSING); msg.setStartProcessTimestamp(currDate); msg.setCorrelationId(""); // will be set later msg.setLastUpdateTimestamp(currDate); msg.setMsgTimestamp(currDate); msg.setReceiveTimestamp(currDate); msg.setSourceSystem(externalSystem); msg.setService(service); msg.setOperationName(operationName); msg.setPayload(payload); msg.setObjectId(objectId); return msg; } /** * Generates unique ID via {@link UUID#randomUUID()}. * * @return unique ID */ protected String generateCorrelationId() { return UUID.randomUUID().toString(); } /** * Inserts new messages into DB. * * @param msg the message */ protected void insertMessage(Message msg) { getMessageService().insertMessages(Arrays.asList(msg)); } /** * Gets {@link MessageService} instance from Camel Context. * * @return MessageService * @throws IllegalStateException when there is no MessageService */ protected MessageService getMessageService() { if (!isStarted() && !isStarting()) { throw new IllegalStateException(getClass().getName() + " is not started so far!"); } Set<MessageService> services = getEndpoint().getCamelContext().getRegistry().findByType(MessageService.class); Assert.state(services.size() >= 1, "MessageService must be at least one."); return services.iterator().next(); } /** * Sends message for next asynchronous processing. * * @param msg the message */ protected void sendForNextProcessing(Message msg) { try { getProducerTemplate().sendBodyAndHeader(AsynchConstants.URI_ASYNC_MSG, ExchangePattern.InOnly, msg, AsynchConstants.MSG_QUEUE_INSERT_HEADER, System.currentTimeMillis()); } catch (CamelExecutionException ex) { Log.error("Error occurred in message " + msg.toHumanString() + " processing", ex); throw ex; } } /** * Gets {@link ProducerTemplate} default instance from Camel Context. * * @return ProducerTemplate * @throws IllegalStateException when there is no ProducerTemplate */ protected ProducerTemplate getProducerTemplate() { if (!isStarted() && !isStarting()) { throw new IllegalStateException(getClass().getName() + " is not started so far!"); } Set<ProducerTemplate> templates = getEndpoint().getCamelContext().getRegistry().findByType(ProducerTemplate.class); Assert.state(templates.size() >= 1, "ProducerTemplate must be at least one."); return templates.iterator().next(); } }