/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/jms/consumer/commands/RequestCommandImpl.java,v $
$Revision: 1.12 $
*******************************************************************************/
/**********************************************************************
This file is part of the OpenEAI Application Foundation or
OpenEAI Message Object API created by Tod Jackson
(tod@openeai.org) and Steve Wheat (steve@openeai.org) at
the University of Illinois Urbana-Champaign.
Copyright (C) 2002 The OpenEAI Software Foundation
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For specific licensing details and examples of how this software
can be used to build commercial integration software or to implement
integrations for your enterprise, visit http://www.OpenEai.org/licensing.
***********************************************************************/
package org.openeai.jms.consumer.commands;
import org.openeai.*;
import org.openeai.xml.*;
import org.openeai.config.*;
import org.openeai.layouts.XmlLayout;
import org.openeai.moa.*;
import org.openeai.moa.objects.resources.*;
import java.io.*;
import javax.jms.*;
import java.util.ArrayList;
import org.jdom.output.XMLOutputter;
import org.jdom.Document;
import org.jdom.Element;
/**
* The "default" anscestor of all RequestCommands that are executed by a PointToPointConsumer.
*<P>
* Organizations can add an additional layer between this class and the command implementations they develop
* or they can even eliminate the use of this class altogether. This class provides many useful convenience
* methods that are commonly needed by all RequestCommand implementations. Additional common routines will be added
* to this layer as time goes by...
* <P>
* @author Tod Jackson (tod@openeai.org)
* @author Steve Wheat (steve@openeai.org)
* @version 3.0 - 28 January 2003
*<P>
* @see ConsumerCommand
* @see RequestCommand
* @see SyncCommandImpl
* @see SyncCommand
*/
public class RequestCommandImpl extends ConsumerCommand {
public RequestCommandImpl() {
}
/**
* Default constructor behavior that will apply to all RequestCommand implementations.
* This is the constructor called by AppConfig/ConsumerConfig during gateway initialization.
* Calls the ConsumerCommand constructor.
*<P>
* @param cConfig CommandConfig the CommandConfig Java object that wraps the CommandConfig
* Element from the deployment document.
* @throws InstantiationException if errors occur during initialization.
*/
public RequestCommandImpl(CommandConfig cConfig) throws InstantiationException {
super(cConfig);
}
/**
* Adds the supplied reply contents to the supplied message, and returns the message.
* @param msg the message to which reply contents are to be added
* @param replyContents the reply contents to add to the message
**/
final
protected Message getMessage( TextMessage msg, String replyContents ) throws CommandException {
try {
msg.setText( replyContents );
} catch (Exception e) {
logger.fatal( e.getMessage(), e );
throw new CommandException( e.getMessage(), e );
}
return msg;
}
/**
* This method is used to build a reply document that contains error specified by the
* command returning the reply (during it's 'execute' method execution). This is the
* data (containing the error(s)) that will be returned to the requesting application.
*<P>
* @param senderControlArea Element the control area from the message consumed by the Command. This will be used
* to determine the message action and Requesting message id information (the messaging component that
* produced the request this Command consumed).
*<P>
* @param replyDoc Document the 'primed' reply document being returned. This will typically be either a
* Generic-Response-Reply document or a 'response-reply' document specific to the message object/action
* being processed (e.g. InstitutionalIdentity-Response-Reply).
*<P>
* @param errors java.util.List a List of org.openeai.moa.objects.Error objects that have
* been built with the appropriate error number, error type and error descriptions.
*/
final protected String buildReplyDocumentWithErrors(Element senderControlArea,
Document replyDoc, java.util.List errors) {
// Just to be safe, we'll remove the DataArea message object if one exists..
// We're only going to want to re-add an empty DataArea if it had one to begin
// with (Provides). In the case of "Responses" there won't be one so we won't
// want to add one.
Element replyDataArea = replyDoc.getRootElement().getChild(DATA_AREA);
boolean needsDataArea = false;
if (replyDataArea != null) {
needsDataArea = true;
replyDoc.getRootElement().removeChild(DATA_AREA);
}
// Build the reply document as if there were no errors.
String strReplyDoc = buildReplyDocument(senderControlArea, replyDoc);
XMLOutputter xmlOut = new XMLOutputter();
// Now add the errors into the control area
Result aResult = new Result();
Document localReplyDoc = null;
try {
XmlDocumentReader xmlReader = new XmlDocumentReader();
localReplyDoc = xmlReader.initializeDocument(new ByteArrayInputStream(strReplyDoc.getBytes()), false);
Element replyControlArea = getControlArea(localReplyDoc.getRootElement());
localReplyDoc.getRootElement().removeContent(replyControlArea);
Element eResult = replyControlArea.getChild("Result");
aResult.buildObjectFromInput(eResult);
aResult.setStatus("failure");
for (int i=0; i<errors.size(); i++) {
org.openeai.moa.objects.resources.Error anError =
(org.openeai.moa.objects.resources.Error)errors.get(i);
aResult.addError(anError);
}
replyControlArea.removeChild("Result");
replyControlArea.addContent((Element)aResult.buildOutputFromObject());
localReplyDoc.getRootElement().addContent(replyControlArea);
if (needsDataArea) {
localReplyDoc.getRootElement().addContent(new Element(DATA_AREA));
}
return xmlOut.outputString(localReplyDoc);
}
catch (Exception e) {
// We'll just have to return the replyDoc after we've added our error
// to it without the Dynamic ControlArea information...
logger.fatal("Error building error reply document.");
logger.fatal(e.getMessage(), e);
return strReplyDoc;
}
}
/**
* This method is used to build a reply document that contains error specified by the
* command returning the reply (during it's 'execute' method execution). This is the
* data (containing the error(s)) that will be returned to the requesting application.
* This method also accepts an Exception that can be passed that will be 'appended' to the list
* of errors being returned in the reply document. This method should be used if an Exception
* is caught during the 'execution' of the command.
*<P>
* @param senderControlArea Element the control area from the message consumed by the Command. This will be used
* to determine the message action and Requesting message id information (the messaging component that
* produced the request this Command consumed).
*<P>
* @param replyDoc Document the 'primed' reply document being returned. This will typically be either a
* Generic-Response-Reply document or a 'response-reply' document specific to the message object/action
* being processed (e.g. InstitutionalIdentity-Response-Reply).
*<P>
* @param errors java.util.List a List of org.openeai.moa.objects.Error objects that have
* been built with the appropriate error number, error type and error descriptions.
*<P>
* @param e Throwable an Exception that occurrred.
*/
final protected String buildReplyDocumentWithErrors(Element senderControlArea,
Document replyDoc, java.util.List errors, Throwable e) {
ByteArrayOutputStream bw = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(bw, true);
e.printStackTrace(pw);
String errMessage = "Exception: " + e.getMessage() + "\n" + bw.toString();
org.openeai.moa.objects.resources.Error anError =
new org.openeai.moa.objects.resources.Error();
anError.setType("system");
anError.setErrorNumber("COMMAND-1001");
anError.setErrorDescription(errMessage);
errors.add(anError);
return buildReplyDocumentWithErrors(senderControlArea, replyDoc, errors);
}
/**
* This method is used to build a standard reply document that contains data specified by the
* command returning the reply (during it's 'execute' method execution). This is the
* data that will be returned to the requesting application. It 'augments' the current contents
* of the reply document passed in with dynamic ControlAreaReply information.
*<P>
* @param senderControlArea Element the control area from the message consumed by the Command. This will be used
* to determine the message action and Requesting message id information (the messaging component that
* produced the request this Command consumed).
*<P>
* @param replyDoc Document the 'primed' reply document being returned. This will typically be either a
* Generic-Response-Reply document or a 'response-reply' document specific to the message object/action
* being processed (e.g. InstitutionalIdentity-Response-Reply).
*/
public final String buildReplyDocument(Element senderControlArea, Document replyDoc) {
XMLOutputter xmlOut = new XMLOutputter();
Document localReplyDoc = (Document)replyDoc.clone();
String msgAction = senderControlArea.getAttribute(MESSAGE_ACTION).getValue();
Element replyControlArea = getControlArea(localReplyDoc.getRootElement());
localReplyDoc.getRootElement().removeContent(replyControlArea);
// A DataArea will only exist for some reply documents,
// later when we rebuild the reply document, we'll check to see
// if this element is null before we try to add it back into
// the document. We need to do this so when we re-build the document
// we can add the ControlArea and DataAreas in the proper order...
Element replyDataArea = localReplyDoc.getRootElement().getChild(DATA_AREA);
if (replyDataArea != null) {
localReplyDoc.getRootElement().removeChild(DATA_AREA);
}
replyControlArea.removeChild("Result");
replyControlArea.removeChild("Datetime");
replyControlArea.removeChild("Sender");
Result aResult = new Result();
ProcessedMessageId processedMsgId = new ProcessedMessageId();
Element eRequestSender = senderControlArea.getChild("Sender");
processedMsgId.setProducerId(eRequestSender.getChild("MessageId").
getChild("ProducerId").getText());
processedMsgId.setSenderAppId(eRequestSender.getChild("MessageId").
getChild("SenderAppId").getText());
processedMsgId.setMessageSeq(eRequestSender.getChild("MessageId").
getChild("MessageSeq").getText());
aResult.setAction(msgAction);
aResult.setStatus("success");
aResult.setProcessedMessageId(processedMsgId);
// Set the sender element (the replier)
Sender sender = new Sender();
MessageId replierMsgId = new MessageId();
replierMsgId.setProducerId(eRequestSender.getChild("MessageId").
getChild("ProducerId").getText());
replierMsgId.setSenderAppId(getAppName());
replierMsgId.setMessageSeq(eRequestSender.getChild("MessageId").
getChild("MessageSeq").getText());
sender.setMessageId(replierMsgId);
Authentication auth = new Authentication();
auth.setAuthUserId(getAppName());
auth.setAuthUserSignature(getAppName());
sender.setAuthentication(auth);
Element eSender = null;
try {
XmlLayout xmlLayout = (XmlLayout)sender.getOutputLayoutManager("xml");
sender.setOutputLayoutManager(xmlLayout);
eSender = (Element)sender.buildOutputFromObject();
}
catch (Exception e) {
logger.fatal("[buildReplyDocument] Exception occurred building an Element from the Sender object. Exception: " + e.getMessage());
return xmlOut.outputString(replyDoc);
}
// Set the datetime element (for the replier)
Datetime dt = new Datetime();
Element eDatetime = null;
try {
eDatetime = (Element)dt.buildOutputFromObject();
}
catch (Exception e) {
logger.fatal("[buildReplyDocument] Exception occurred building an Element from the Datetime object. Exception: " + e.getMessage());
return xmlOut.outputString(replyDoc);
}
try {
replyControlArea.addContent(eSender);
replyControlArea.addContent(eDatetime);
replyControlArea.addContent((Element)aResult.buildOutputFromObject());
localReplyDoc.getRootElement().addContent(replyControlArea);
if (replyDataArea != null) {
localReplyDoc.getRootElement().addContent(replyDataArea);
}
}
catch (Exception e) {
logger.fatal("Error building reply document, returning Reply Document passed in");
logger.fatal(e.getMessage(), e);
return xmlOut.outputString(replyDoc);
}
return xmlOut.outputString(localReplyDoc);
}
protected ArrayList logErrors(String errNumber, String errMessage, Throwable e, Document inDoc) {
logger.fatal(errMessage, e);
logger.fatal("Message sent in is: \n" + getMessageBody(inDoc));
ArrayList errors = new ArrayList();
errors.add(buildError("application", errNumber, errMessage));
return errors;
}
protected ArrayList logErrors(String errNumber, String errMessage, Document inDoc) {
logger.fatal(errMessage);
logger.fatal("Message sent in is: \n" + getMessageBody(inDoc));
ArrayList errors = new ArrayList();
errors.add(buildError("application", errNumber, errMessage));
return errors;
}
}