/*
 * Copyright 1999-2004 The Apache Software Foundation.
 * 
 * Licensed 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.sandesha2.msgprocessors;

import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.addressing.RelatesTo;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.OperationContext;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.sandesha2.MessageValidator;
import org.apache.sandesha2.RMMsgContext;
import org.apache.sandesha2.Sandesha2Constants;
import org.apache.sandesha2.SandeshaException;
import org.apache.sandesha2.client.SandeshaClientConstants;
import org.apache.sandesha2.client.SandeshaListener;
import org.apache.sandesha2.i18n.SandeshaMessageHelper;
import org.apache.sandesha2.i18n.SandeshaMessageKeys;
import org.apache.sandesha2.policy.SandeshaPolicyBean;
import org.apache.sandesha2.security.SecurityManager;
import org.apache.sandesha2.security.SecurityToken;
import org.apache.sandesha2.storage.StorageManager;
import org.apache.sandesha2.storage.Transaction;
import org.apache.sandesha2.storage.beanmanagers.RMSBeanMgr;
import org.apache.sandesha2.storage.beanmanagers.SenderBeanMgr;
import org.apache.sandesha2.storage.beans.RMDBean;
import org.apache.sandesha2.storage.beans.RMSBean;
import org.apache.sandesha2.storage.beans.SenderBean;
import org.apache.sandesha2.util.RMMsgCreator;
import org.apache.sandesha2.util.SOAPAbstractFactory;
import org.apache.sandesha2.util.SandeshaUtil;
import org.apache.sandesha2.util.SequenceManager;
import org.apache.sandesha2.wsrm.CreateSequence;
import org.apache.sandesha2.wsrm.SequenceOffer;

/**
 * Responsible for processing an incoming Application message.
 */

public class ApplicationMsgProcessor implements MsgProcessor {

	private static final Log log = LogFactory.getLog(ApplicationMsgProcessor.class);

	private String inboundSequence = null;
	private long   inboundMessageNumber;
	
	public ApplicationMsgProcessor() {
		// Nothing to do
	}
	
	public ApplicationMsgProcessor(String inboundSequenceId, long inboundMessageNumber) {
		this.inboundSequence = inboundSequenceId;
		this.inboundMessageNumber = inboundMessageNumber;
	}
	
	public boolean processInMessage(RMMsgContext rmMsgCtx, Transaction transaction) {
		if (log.isDebugEnabled()) {
			log.debug("Enter: ApplicationMsgProcessor::processInMessage");
			log.debug("Exit: ApplicationMsgProcessor::processInMessage");
		}
		return false;
	}
	
	public boolean processOutMessage(RMMsgContext rmMsgCtx) throws AxisFault {
		if (log.isDebugEnabled())
			log.debug("Enter: ApplicationMsgProcessor::processOutMessage");

		MessageContext msgContext = rmMsgCtx.getMessageContext();
		ConfigurationContext configContext = msgContext.getConfigurationContext();

		//validating the outgoing message
		MessageValidator.validateOutgoingMessage(rmMsgCtx);
		
		// setting the Fault callback
		SandeshaListener faultCallback = (SandeshaListener) msgContext.getOptions().getProperty(
				SandeshaClientConstants.SANDESHA_LISTENER);
		if (faultCallback != null) {
			OperationContext operationContext = msgContext.getOperationContext();
			if (operationContext != null) {
				operationContext.setProperty(SandeshaClientConstants.SANDESHA_LISTENER, faultCallback);
			}
		}

		StorageManager storageManager = SandeshaUtil.getSandeshaStorageManager(configContext, configContext
				.getAxisConfiguration());

		boolean serverSide = msgContext.isServerSide();

		// setting message Id if null
		if (msgContext.getMessageID() == null)
			msgContext.setMessageID(SandeshaUtil.getUUID());

		// find internal sequence id
		String internalSequenceId = null;

		String storageKey = SandeshaUtil.getUUID(); // the key which will be
													// used to store this
													// message.

		/*
		 * Internal sequence id is the one used to refer to the sequence (since
		 * actual sequence id is not available when first msg arrives) server
		 * side - a derivation of the sequenceId of the incoming sequence client
		 * side - a derivation of wsaTo & SeequenceKey
		 */

		boolean lastMessage = false;
		if (serverSide) {
			if (inboundSequence == null || "".equals(inboundSequence)) {
				String message = SandeshaMessageHelper.getMessage(SandeshaMessageKeys.incomingSequenceNotValidID, inboundSequence);
				log.debug(message);
				throw new SandeshaException(message);
			}

			internalSequenceId = SandeshaUtil.getOutgoingSideInternalSequenceID(inboundSequence);
		} else {
			// set the internal sequence id for the client side.
			EndpointReference toEPR = msgContext.getTo();
			if (toEPR == null || toEPR.getAddress() == null || "".equals(toEPR.getAddress())) {
				String message = SandeshaMessageHelper.getMessage(SandeshaMessageKeys.toEPRNotValid, null);
				log.debug(message);
				throw new SandeshaException(message);
			}

			String to = toEPR.getAddress();
			String sequenceKey = (String) msgContext.getProperty(SandeshaClientConstants.SEQUENCE_KEY);
			internalSequenceId = SandeshaUtil.getInternalSequenceID(to, sequenceKey);

			String lastAppMessage = (String) msgContext.getProperty(SandeshaClientConstants.LAST_MESSAGE);
			if (lastAppMessage != null && "true".equals(lastAppMessage))
				lastMessage = true;
		}
		
		if (internalSequenceId!=null)
			rmMsgCtx.setProperty(Sandesha2Constants.MessageContextProperties.INTERNAL_SEQUENCE_ID,internalSequenceId);

		/*
		 * checking weather the user has given the messageNumber (most of the
		 * cases this will not be the case where the system will generate the
		 * message numbers
		 */

		// User should set it as a long object.
		Long messageNumberLng = (Long) msgContext.getProperty(SandeshaClientConstants.MESSAGE_NUMBER);

		long givenMessageNumber = -1;
		if (messageNumberLng != null) {
			givenMessageNumber = messageNumberLng.longValue();
			if (givenMessageNumber <= 0) {
				throw new SandeshaException(SandeshaMessageHelper.getMessage(
						SandeshaMessageKeys.msgNumberMustBeLargerThanZero, Long.toString(givenMessageNumber)));
			}
		}

		// A dummy message is a one which will not be processed as a actual
		// application message.
		// The RM handlers will simply let these go.
		String dummyMessageString = (String) msgContext.getOptions().getProperty(SandeshaClientConstants.DUMMY_MESSAGE);
		boolean dummyMessage = false;
		if (dummyMessageString != null && Sandesha2Constants.VALUE_TRUE.equals(dummyMessageString))
			dummyMessage = true;

		RMSBean rmsBean = SandeshaUtil.getRMSBeanFromInternalSequenceId(storageManager, internalSequenceId);

		//see if the sequence is closed
		if(rmsBean != null && rmsBean.isSequenceClosedClient()){
			throw new SandeshaException(SandeshaMessageHelper.getMessage(SandeshaMessageKeys.cannotSendMsgAsSequenceClosed, internalSequenceId));
		}

		//see if the sequence is terminated
		if(rmsBean != null && rmsBean.isTerminateAdded()) {
			throw new SandeshaException(SandeshaMessageHelper.getMessage(SandeshaMessageKeys.cannotSendMsgAsSequenceTerminated, internalSequenceId));
		}

		//see if the sequence is timed out
		if(rmsBean != null && rmsBean.isTimedOut()){
			throw new SandeshaException(SandeshaMessageHelper.getMessage(SandeshaMessageKeys.cannotSendMsgAsSequenceTimedout, internalSequenceId));
		}
		
		// If the call application is a 2-way MEP, and uses a anonymous replyTo, and the
		// RM 1.1 spec level, then we must have MakeConnection enabled. We check that here,
		// before we start creating a new Sequence.
		if(!serverSide) {
			AxisOperation op = msgContext.getAxisOperation();
			int mep = WSDLConstants.MEP_CONSTANT_INVALID;
			if(op != null) {
				mep = op.getAxisSpecificMEPConstant();
			}
			if(mep == WSDLConstants.MEP_CONSTANT_OUT_IN) {
				String specVersion = null;
				if(rmsBean == null) {
					specVersion = SequenceManager.getSpecVersion(msgContext, storageManager);
				} else {
					specVersion = rmsBean.getRMVersion();
				}
				if(specVersion == Sandesha2Constants.SPEC_VERSIONS.v1_1) {
					EndpointReference replyTo = msgContext.getReplyTo();
					if(replyTo == null || replyTo.hasAnonymousAddress()) {
						//we are sync
						SandeshaPolicyBean policy = SandeshaUtil.getPropertyBean(configContext.getAxisConfiguration());
						if(!policy.isEnableMakeConnection()) {
							String message = SandeshaMessageHelper.getMessage(SandeshaMessageKeys.makeConnectionDisabled);
							throw new SandeshaException(message);
						}						
					}
				}
			}
		}

		//setting the reference msg store key.
		if (rmsBean!=null && rmsBean.getReferenceMessageStoreKey()==null) {
			//setting this application message as the reference, if it hsnt already been set.
			
			String referenceMsgKey = SandeshaUtil.getUUID();
			storageManager.storeMessageContext(referenceMsgKey, msgContext);
			rmsBean.setReferenceMessageStoreKey(referenceMsgKey);
		}
		
		String outSequenceID = null;

		if (rmsBean == null) { 
			// SENDING THE CREATE SEQUENCE.
			synchronized (RMSBeanMgr.class) {
				// There is a timing window where 2 sending threads can hit this point
				// at the same time and both will create an RMSBean to the same endpoint
				// with the same internal sequenceid
				// Check that someone hasn't created the bean
				rmsBean = SandeshaUtil.getRMSBeanFromInternalSequenceId(storageManager, internalSequenceId);
				// if first message - setup the sending side sequence - both for the
				// server and the client sides.
				if (rmsBean == null) {
					rmsBean = SequenceManager.setupNewClientSequence(msgContext, internalSequenceId, storageManager);
					rmsBean = addCreateSequenceMessage(rmMsgCtx, rmsBean, storageManager);
				}
			}
		
		} else {
			outSequenceID = rmsBean.getSequenceID();
		}
		
		// the message number that was last used.
		long systemMessageNumber = rmsBean.getNextMessageNumber();

		// The number given by the user has to be larger than the last stored
		// number.
		if (givenMessageNumber > 0 && givenMessageNumber <= systemMessageNumber) {
			String message = SandeshaMessageHelper.getMessage(SandeshaMessageKeys.msgNumberNotLargerThanLastMsg, Long
					.toString(givenMessageNumber));
			throw new SandeshaException(message);
		}

		// Finding the correct message number.
		long messageNumber = -1;
		if (givenMessageNumber > 0) // if given message number is valid use it.
									// (this is larger than the last stored due
									// to the last check)
			messageNumber = givenMessageNumber;
		else if (systemMessageNumber > 0) { // if system message number is valid
											// use it.
			messageNumber = systemMessageNumber + 1;
		} else { // This is the first message (systemMessageNumber = -1)
			messageNumber = 1;
		}

		if (serverSide) {
			// Deciding whether this is the last message. We assume it is if it relates to
			// a message which arrived with the LastMessage flag on it. 
			RMDBean rmdBean = SandeshaUtil.getRMDBeanFromSequenceId(storageManager, inboundSequence);			
			// Get the last in message
			String lastRequestId = rmdBean.getLastInMessageId();
			RelatesTo relatesTo = msgContext.getRelatesTo();
			if(relatesTo != null && lastRequestId != null &&
					lastRequestId.equals(relatesTo.getValue())) {
				lastMessage = true;
			}
			
			//or a constant property may call it as the last msg
			Boolean inboundLast = (Boolean) msgContext.getProperty(Sandesha2Constants.MessageContextProperties.INBOUND_LAST_MESSAGE); 
			if (inboundLast!=null && inboundLast.booleanValue())
				lastMessage = true;
		}
		
		if (lastMessage) 
			rmsBean.setLastOutMessage(messageNumber);		

		// set this as the response highest message.
		rmsBean.setHighestOutMessageNumber(messageNumber);
		
		// saving the used message number, and the expected reply count
		boolean startPolling = false;
		if (!dummyMessage) {
			rmsBean.setNextMessageNumber(messageNumber);

			// Identify the MEP associated with the message.
			AxisOperation op = msgContext.getAxisOperation();
			int mep = WSDLConstants.MEP_CONSTANT_INVALID;
			if(op != null) {
				mep = op.getAxisSpecificMEPConstant();
			}

			if(mep == WSDLConstants.MEP_CONSTANT_OUT_IN) {
				// We only match up requests and replies when we are doing sync interactions
				EndpointReference replyTo = msgContext.getReplyTo();
				if(replyTo == null || replyTo.hasAnonymousAddress()) {
					long expectedReplies = rmsBean.getExpectedReplies();
					rmsBean.setExpectedReplies(expectedReplies + 1);
				}

				// If we support the RM anonymous URI then rewrite the ws-a anon to use the RM equivalent.
				//(do should be done only for WSRM 1.1)
				
				if (Sandesha2Constants.SPEC_VERSIONS.v1_1.equals(rmMsgCtx.getRMSpecVersion())) {
					String oldAddress = (replyTo == null) ? null : replyTo.getAddress();
					EndpointReference newReplyTo = SandeshaUtil.rewriteEPR(rmsBean, msgContext
							.getReplyTo(), configContext);
					String newAddress = (newReplyTo == null) ? null : newReplyTo.getAddress();
					if (newAddress != null && !newAddress.equals(oldAddress)) {
						// We have rewritten the replyTo. If this is the first message that we have needed to
						// rewrite then we should set the sequence up for polling, and once we have saved the
						// changes to the sequence then we can start the polling thread.
						msgContext.setReplyTo(newReplyTo);
						if (!rmsBean.isPollingMode()) {
							rmsBean.setPollingMode(true);
							startPolling = true;
						}
					}
				}
			}
		}
		
		RelatesTo relatesTo = msgContext.getRelatesTo();
		if(relatesTo != null) {
			rmsBean.setHighestOutRelatesTo(relatesTo.getValue());
		}

		// setting async ack endpoint for the server side. (if present)
		if (serverSide) {
			if (rmsBean.getToEPR() != null) {
				msgContext.setProperty(SandeshaClientConstants.AcksTo, rmsBean.getToEPR());
			}
		}

		// Update the rmsBean
        rmsBean.setApplicationMessageMessageId(msgContext.getMessageID());
        storageManager.getRMSBeanMgr().update(rmsBean);
		
		if(startPolling) {
			SandeshaUtil.startWorkersForSequence(msgContext.getConfigurationContext(), rmsBean);
		}
		
		SOAPEnvelope env = rmMsgCtx.getSOAPEnvelope();
		if (env == null) {
			SOAPEnvelope envelope = SOAPAbstractFactory.getSOAPFactory(SandeshaUtil.getSOAPVersion(env))
					.getDefaultEnvelope();
			rmMsgCtx.setSOAPEnvelop(envelope);
		}

		SOAPBody soapBody = rmMsgCtx.getSOAPEnvelope().getBody();
		if (soapBody == null) {
			String message = SandeshaMessageHelper.getMessage(SandeshaMessageKeys.soapBodyNotPresent);
			log.debug(message);
			throw new SandeshaException(message);
		}

		String messageId1 = SandeshaUtil.getUUID();
		if (rmMsgCtx.getMessageId() == null) {
			rmMsgCtx.setMessageId(messageId1);
		}

		EndpointReference toEPR = msgContext.getTo();

		
		if (toEPR != null) {
			// setting default actions.
			String to = toEPR.getAddress();
			String operationName = msgContext.getOperationContext().getAxisOperation().getName().getLocalPart();
			if (msgContext.getWSAAction() == null) {
				msgContext.setWSAAction(to + "/" + operationName);
			}
			if (msgContext.getSoapAction() == null) {
				msgContext.setSoapAction("\"" + to + "/" + operationName + "\"");
			}
		}
		
		// processing the response if not an dummy.
		if (!dummyMessage)
			processResponseMessage(rmMsgCtx, rmsBean, internalSequenceId, outSequenceID, messageNumber, storageKey, storageManager);
		
		//Users wont be able to get reliable response msgs in the back channel in the back channel of a 
		//reliable message. If he doesn't have a endpoint he should use polling mechanisms.
		msgContext.pause();
		
		if (log.isDebugEnabled())
			log.debug("Exit: ApplicationMsgProcessor::processOutMessage " + Boolean.TRUE);
		return true;
	}

	private RMSBean addCreateSequenceMessage(RMMsgContext applicationRMMsg, RMSBean rmsBean,
			StorageManager storageManager) throws AxisFault {

		if (log.isDebugEnabled())
			log.debug("Enter: ApplicationMsgProcessor::addCreateSequenceMessage, " + rmsBean);

		MessageContext applicationMsg = applicationRMMsg.getMessageContext();
		ConfigurationContext configCtx = applicationMsg.getConfigurationContext();

		// generating a new create sequeuce message.
		RMMsgContext createSeqRMMessage = RMMsgCreator.createCreateSeqMsg(rmsBean, applicationRMMsg);

		createSeqRMMessage.setFlow(MessageContext.OUT_FLOW);
		CreateSequence createSequencePart = (CreateSequence) createSeqRMMessage
				.getMessagePart(Sandesha2Constants.MessageParts.CREATE_SEQ);

		SenderBeanMgr retransmitterMgr = storageManager.getSenderBeanMgr();

		SequenceOffer offer = createSequencePart.getSequenceOffer();
		if (offer != null) {
			String offeredSequenceId = offer.getIdentifer().getIdentifier();

			rmsBean.setOfferedSequence(offeredSequenceId);
		}

		MessageContext createSeqMsg = createSeqRMMessage.getMessageContext();
		createSeqMsg.setRelationships(null); // create seq msg does not
												// relateTo anything
		
		String createSequenceMessageStoreKey = SandeshaUtil.getUUID(); // the key that will be used to store 
																	   //the create sequence message.
		
		rmsBean.setCreateSeqMsgID(createSeqMsg.getMessageID());
		rmsBean.setCreateSequenceMsgStoreKey(createSequenceMessageStoreKey);
		
		//cloning the message and storing it as a reference.
		MessageContext clonedMessage = SandeshaUtil.cloneMessageContext(createSeqMsg);
		String clonedMsgStoreKey = SandeshaUtil.getUUID();
		storageManager.storeMessageContext(clonedMsgStoreKey, clonedMessage);
		rmsBean.setReferenceMessageStoreKey(clonedMsgStoreKey);
		
		SecurityToken token = (SecurityToken) createSeqRMMessage.getProperty(Sandesha2Constants.MessageContextProperties.SECURITY_TOKEN);
		if(token != null) {
			SecurityManager secManager = SandeshaUtil.getSecurityManager(configCtx);
			rmsBean.setSecurityTokenData(secManager.getTokenRecoveryData(token));
		}
		
		storageManager.getRMSBeanMgr().insert(rmsBean);

		SenderBean createSeqEntry = new SenderBean();
		createSeqEntry.setMessageContextRefKey(createSequenceMessageStoreKey);
		createSeqEntry.setTimeToSend(System.currentTimeMillis());
		createSeqEntry.setMessageID(createSeqRMMessage.getMessageId());
		createSeqEntry.setInternalSequenceID(rmsBean.getInternalSequenceID());
		// this will be set to true in the sender
		createSeqEntry.setSend(true);
		// Indicate that this message is a create sequence
		createSeqEntry.setMessageType(Sandesha2Constants.MessageTypes.CREATE_SEQ);
		EndpointReference to = createSeqRMMessage.getTo();
		if (to!=null)
			createSeqEntry.setToAddress(to.getAddress());
		// If this message is targetted at an anonymous address then we must not have a transport
		// ready for it, as the create sequence is not a reply.
		if(to == null || to.hasAnonymousAddress())
			createSeqEntry.setTransportAvailable(false);

		createSeqMsg.setProperty(Sandesha2Constants.QUALIFIED_FOR_SENDING, Sandesha2Constants.VALUE_FALSE);
		
		SandeshaUtil.executeAndStore(createSeqRMMessage, createSequenceMessageStoreKey);

		retransmitterMgr.insert(createSeqEntry);

		// Setup enough of the workers to get this create sequence off the box.
		SandeshaUtil.startWorkersForSequence(configCtx, rmsBean);
		
		if (log.isDebugEnabled())
			log.debug("Exit: ApplicationMsgProcessor::addCreateSequenceMessage, " + rmsBean);
		return rmsBean;
	}

	private void processResponseMessage(RMMsgContext rmMsg, RMSBean rmsBean, String internalSequenceId, String outSequenceID, long messageNumber,
			String storageKey, StorageManager storageManager) throws AxisFault {
		if (log.isDebugEnabled())
			log.debug("Enter: ApplicationMsgProcessor::processResponseMessage, " + internalSequenceId + ", " + outSequenceID);

		MessageContext msg = rmMsg.getMessageContext();

		SenderBeanMgr retransmitterMgr = storageManager.getSenderBeanMgr();

		// setting last message
		boolean lastMessage = false;
		if (msg.isServerSide()) {
			Boolean inboundLast = (Boolean) msg.getProperty(Sandesha2Constants.MessageContextProperties.INBOUND_LAST_MESSAGE);
			if (inboundLast != null && inboundLast.booleanValue()) {
				lastMessage = true;
			}

		} else {
			// client side
			Object obj = msg.getProperty(SandeshaClientConstants.LAST_MESSAGE);
			if (obj != null && "true".equals(obj)) {
				lastMessage = true;
			}
		}

		// Now that we have decided which sequence to use for the message, make sure that we secure
		// it with the correct token.
		RMMsgCreator.secureOutboundMessage(rmsBean, msg);

		// Retransmitter bean entry for the application message
		SenderBean appMsgEntry = new SenderBean();

		appMsgEntry.setMessageContextRefKey(storageKey);

		appMsgEntry.setTimeToSend(System.currentTimeMillis());
		appMsgEntry.setMessageID(rmMsg.getMessageId());
		appMsgEntry.setMessageNumber(messageNumber);
		appMsgEntry.setLastMessage(lastMessage);
		
		SOAPEnvelope envelope = rmMsg.getSOAPEnvelope();
		if (lastMessage && envelope!=null && envelope.getBody().getFirstOMChild()==null)
			appMsgEntry.setMessageType(Sandesha2Constants.MessageTypes.LAST_MESSAGE);
		else
			appMsgEntry.setMessageType(Sandesha2Constants.MessageTypes.APPLICATION);
		
		appMsgEntry.setInboundSequenceId(inboundSequence);
		appMsgEntry.setInboundMessageNumber(inboundMessageNumber);
		if (outSequenceID == null) {
			appMsgEntry.setSend(false);
		} else {
			appMsgEntry.setSend(true);
			// Send will be set to true at the sender.
			msg.setProperty(Sandesha2Constants.SET_SEND_TO_TRUE, Sandesha2Constants.VALUE_TRUE);
			appMsgEntry.setSequenceID(outSequenceID);
		}
		
		//If the sequence is in replay mode. We set the reSend to false. 
		//In replay mode we cannot do retransmissions unless the request message get duplicated.
		if (rmsBean.isReplayModel())
			appMsgEntry.setReSend(false);
		
		EndpointReference to = rmMsg.getTo();
		if (to!=null)
			appMsgEntry.setToAddress(to.getAddress());
		
		appMsgEntry.setInternalSequenceID(internalSequenceId);

		msg.setProperty(Sandesha2Constants.QUALIFIED_FOR_SENDING, Sandesha2Constants.VALUE_FALSE);

		// increasing the current handler index, so that the message will not be
		// going throught the SandeshaOutHandler again.
		msg.setCurrentHandlerIndex(msg.getCurrentHandlerIndex() + 1);

		SandeshaUtil.executeAndStore(rmMsg, storageKey);

		retransmitterMgr.insert(appMsgEntry);

		if (log.isDebugEnabled())
			log.debug("Exit: ApplicationMsgProcessor::processResponseMessage");
	}

}
