/** * Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.synapse.message.processor.impl.sampler; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.ManagedLifecycle; import org.apache.synapse.Mediator; import org.apache.synapse.MessageContext; import org.apache.synapse.SynapseException; import org.apache.synapse.core.SynapseEnvironment; import org.apache.synapse.message.MessageConsumer; import org.apache.synapse.message.processor.MessageProcessor; import org.apache.synapse.message.processor.MessageProcessorConstants; import org.apache.synapse.task.Task; /** * This {@link Task} injects a message to a given sequence. It also supports * Throttling scenarios. * */ public class SamplingService implements Task, ManagedLifecycle { private static Log log = LogFactory.getLog(SamplingService.class); // The consumer that is associated with the particular message store private MessageConsumer messageConsumer; // Owner of the this job private MessageProcessor messageProcessor; // Determines how many messages at a time it should execute private int concurrency = 1; // Represents the send sequence of a message private String sequence; private SynapseEnvironment synapseEnvironment; private boolean initialized = false; private final String concurrencyPropName; private final String sequencePropName; /** * Specifies whether the service should be started as deactivated or not */ private boolean isDeactivatedAtStartup = false; public SamplingService(MessageProcessor messageProcessor, SynapseEnvironment synapseEnvironment, String concurrencyPropName, String sequencePropName) { super(); this.messageProcessor = messageProcessor; this.synapseEnvironment = synapseEnvironment; this.concurrencyPropName = concurrencyPropName; this.sequencePropName = sequencePropName; } public SamplingService(MessageProcessor messageProcessor, SynapseEnvironment synapseEnvironment, String concurrencyPropName, String sequencePropName, boolean isDeactivatedAtStartup) { super(); this.messageProcessor = messageProcessor; this.synapseEnvironment = synapseEnvironment; this.concurrencyPropName = concurrencyPropName; this.sequencePropName = sequencePropName; this.isDeactivatedAtStartup = isDeactivatedAtStartup; } /** * Starts the execution of this task which grabs a message from the message * queue and inject it to a given sequence. */ public void execute() { if(isDeactivatedAtStartup){ //This delay is required until tasks are paused from ScheduledMessageProcessor since message processor is // inactive try { TimeUnit.MILLISECONDS.sleep(MessageProcessorConstants.INITIAL_EXECUTION_DELAY); } catch (InterruptedException exception) { log.warn("Initial delay interrupted when Sampling service started as inactive " , exception); } isDeactivatedAtStartup = false; } try { /* * Initialize only if it is NOT already done. This will make sure * that the initialization is done only once. */ if (!initialized) { this.init(synapseEnvironment); } if (!this.messageProcessor.isDeactivated()) { for (int i = 0; i < concurrency; i++) { final MessageContext messageContext = fetch(messageConsumer); if (messageContext != null) { dispatch(messageContext); } else { // either the connection is broken or there are no new // massages. if (log.isDebugEnabled()) { log.debug("No messages were received for message processor [" + messageProcessor.getName() + "]"); } } } } else { if (log.isDebugEnabled()) { log.debug("Exiting service since the message processor is deactivated"); } } } catch (Throwable t) { // All the possible recoverable exceptions are handles case by case // and yet if it comes this // we have to shutdown the processor log.fatal("Deactivating the message processor [" + this.messageProcessor.getName() + "]", t); this.messageProcessor.stop(); } if (log.isDebugEnabled()) { log.debug("Exiting service thread of message processor [" + this.messageProcessor.getName() + "]"); } } public void init(SynapseEnvironment se) { // Setting up the JMS consumer here. setMessageConsumer(); Map<String, Object> parameterMap = messageProcessor.getParameters(); sequence = (String) parameterMap.get(sequencePropName); String conc = (String) parameterMap.get(concurrencyPropName); if (conc != null) { try { concurrency = Integer.parseInt(conc); } catch (NumberFormatException e) { parameterMap.remove(concurrencyPropName); log.error("Invalid value for concurrency switching back to default value", e); } } /* * Make sure to set the isInitialized flag too TRUE in order to avoid * re-initialization. */ initialized = true; } /** * Receives the next message from the message store. * * @param msgConsumer * message consumer * @return {@link MessageContext} of the last message received from the * store. */ public MessageContext fetch(MessageConsumer msgConsumer) { MessageContext newMsg = messageConsumer.receive(); if (newMsg != null) { messageConsumer.ack(); } return newMsg; } /** * Sends the message to a given sequence. * * @param messageContext * message to be injected. */ public void dispatch(final MessageContext messageContext) { final ExecutorService executor = messageContext.getEnvironment(). getExecutorService(); executor.submit(new Runnable() { public void run() { try { Mediator processingSequence = messageContext.getSequence(sequence); if (processingSequence != null) { processingSequence.mediate(messageContext); } } catch (SynapseException syne) { if (!messageContext.getFaultStack().isEmpty()) { (messageContext.getFaultStack().pop()).handleFault(messageContext, syne); } log.error("Error occurred while executing the message", syne); } catch (Throwable t) { log.error("Error occurred while executing the message", t); } } }); } /** * Terminates the job of the message processor. * * @return <code>true</code> if the job is terminated successfully, * <code>false</code> otherwise. */ public boolean terminate() { messageConsumer.cleanup(); return true; } private boolean setMessageConsumer() { final String messageStore = messageProcessor.getMessageStoreName(); messageConsumer = synapseEnvironment.getSynapseConfiguration() .getMessageStore(messageStore).getConsumer(); /* * Make sure to set the same message consumer in the message processor * since it is used by life-cycle management methods. Specially by the * deactivate method to cleanup the connection before the deactivation. */ return messageProcessor.setMessageConsumer(messageConsumer); } /** * Checks whether this TaskService is properly initialized or not. * * @return <code>true</code> if this TaskService is properly initialized. * <code>false</code> otherwise. */ public boolean isInitialized() { return initialized; } public void destroy() { terminate(); } }