/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/source/org/openeai/jms/consumer/commands/SyncCommandImpl.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.xml.*;
import org.openeai.config.*;
import org.openeai.moa.*;
import org.openeai.moa.jmsobjects.*;
import org.openeai.moa.objects.resources.*;
import org.openeai.jms.producer.PubSubProducer;
import org.openeai.jms.producer.MessageProducer;
import java.io.*;
import javax.jms.*;
import org.jdom.output.XMLOutputter;
import org.jdom.Document;
import org.jdom.Element;
import org.openeai.transport.ProducerId;
/**
* The "default" anscestor of all SyncCommands that are executed by a PubSubConsumer.
*<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 RequestCommandImpl
* @see SyncCommand
*/
public class SyncCommandImpl extends ConsumerCommand {
private Document m_syncErrorSyncDoc = null;
private PubSubProducer m_syncErrorPublisher = null;
private String m_syncErrorSyncPrimedDocumentUri = "";
public SyncCommandImpl() {
}
/**
* Default constructor behavior that will apply to all SyncCommand implementations.
* This is the constructor called by AppConfig/ConsumerConfig during gateway initialization.
* Calls the ConsumerCommand constructor. Additionally, this constructor verifies
* that the SyncCommand implementation being initialized contains the appropriate
* SyncErrorPublisher and SyncErrorSyncProperties objects in the CommandConfig
* object passed in.
*<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 SyncCommandImpl(CommandConfig cConfig) throws InstantiationException {
super(cConfig);
// must have a syncerrorsync primed document uri
try {
PropertyConfig pConfig = null;
String uri = null;
try {
pConfig = (PropertyConfig)getAppConfig().getObject("SyncErrorSyncProperties");
}
catch (Exception e) {
// temporarily ignoring this error and letting it fall through...
}
if (pConfig == null) {
logger.warn("Missing 'SyncErrorSyncProperties' PropertyConfig element in configuration document.");
}
else {
uri = pConfig.getProperties().getProperty("SyncErrorSyncPrimedDocumentUri",null);
}
if (uri == null) {
logger.warn("Missing 'SyncErrorSyncPrimedDocumentUri' property in 'SyncErrorSyncProperties' PropertyConfig element. Can't continue.");
}
setSyncErrorSyncPrimedDocumentUri(uri);
}
catch (Exception e) {
logger.fatal("Exception occurred obtaining 'SyncErrorSyncPrimedDocumentUri' property. Can't continue.");
logger.fatal(e.getMessage(), e);
throw new InstantiationException(e.getMessage());
}
// must have a sync error publisher...
try {
setSyncErrorPublisher((PubSubProducer)getAppConfig().getObject("SyncErrorPublisher"));
}
catch (Exception e) {
String errorMessage = "[SyncCommand] Could not find SyncErrorPublisher in AppConfig! Exception: " + e.getMessage();
logger.fatal(errorMessage);
throw new InstantiationException(errorMessage);
}
if (getSyncErrorPublisher().isStarted() == false) {
try {
if (getSyncErrorPublisher().startPublisher() == false) {
String errorMessage = "[SyncCommand] Could not start SyncErrorPublisher!";
logger.fatal(errorMessage);
throw new InstantiationException(errorMessage);
}
}
catch (JMSException e) {
String errorMessage = "[SyncCommand] Exception starting SyncErrorPublisher! Exception: " + e.getMessage();
logger.fatal(errorMessage);
throw new InstantiationException(errorMessage);
}
}
}
/**
* Returns the Sync-Error-Sync primed document URI that will be used to build
* the primed sync error sync Document used as a starting point when publishing
* Sync errors.
* <P>
* @return String the URI.
**/
final protected String getSyncErrorSyncPrimedDocumentUri() {
return m_syncErrorSyncPrimedDocumentUri;
}
/**
* Sets the Sync-Error-Sync primed document URI that will be used to build
* the primed sync error sync Document used as a starting point when publishing
* Sync errors.
* <P>
* @param uri String the URI.
**/
final protected void setSyncErrorSyncPrimedDocumentUri(String uri) {
m_syncErrorSyncPrimedDocumentUri = uri;
}
/**
* Sets the Sync-Error-Sync primed Document object built from the
* SyncErrorSyncPrimedDocument URI that will be used as
* the primed sync error sync Document used as a starting point
* when publishing Sync errors.
* <P>
* @param doc Document the primed sync error document
**/
public final void setSyncErrorSyncDoc(Document doc) {
m_syncErrorSyncDoc = doc;
}
/**
* Returns the Sync-Error-Sync primed Document object built from the
* SyncErrorSyncPrimedDocument URI that will be used as
* the primed sync error sync Document used as a starting point
* when publishing Sync errors.
* <P>
* @return Document the primed sync error document
**/
public final Document getSyncErrorSyncDoc() {
return m_syncErrorSyncDoc;
}
/**
* Set SyncErrorPublisher associated to this command. This is only required if the command
* is an implementation of SyncCommand. It is called in the
* constructor of Command.
* @param pubSub PubSubProducer
*/
private void setSyncErrorPublisher(PubSubProducer pubSub) {
m_syncErrorPublisher = pubSub;
}
/**
* Get SyncErrorPublisher associated to this command. It is called by commands
* when they need to publish a sync error via the publishSyncError method also
* defined in Command.
* @return PubSubProducer
*/
public final PubSubProducer getSyncErrorPublisher() {
return m_syncErrorPublisher;
}
/**
* This method is used to publish a Sync-Error-Sync message when/if the Command has
* any errors during processing (during the 'execute' method).
*<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
* published the message this Command consumed).
*<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 has occurred in the ScheduledCommand. This exception will be added
* to the list of errors passed in.
*/
final protected void publishSyncError(Element senderControlArea, java.util.List errors, Throwable e) {
org.openeai.moa.objects.resources.Error anError =
new org.openeai.moa.objects.resources.Error();
ByteArrayOutputStream bw = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter(bw, true);
e.printStackTrace(pw);
String errMessage = "Exception: " + e.getMessage() + "\n" + bw.toString();
anError.setType("system");
anError.setErrorNumber("COMMAND-1001");
anError.setErrorDescription(errMessage);
errors.add(anError);
publishSyncError(senderControlArea, errors);
}
/**
* This method is used to publish a Sync-Error-Sync message when/if the Command has
* any errors during processing (during the 'execute' method).
*<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
* published the message this Command consumed).
*<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 void publishSyncError(Element senderControlArea, java.util.List errors) {
XmlDocumentReader xmlReader = new XmlDocumentReader();
Document syncErrorDoc = null;
try {
syncErrorDoc =
xmlReader.initializeDocument(getSyncErrorSyncPrimedDocumentUri(), getOutboundXmlValidation());
if (syncErrorDoc == null) {
String errMessage = "[PublishSyncError] Missing 'SyncErrorSyncPrimedDocumentUri' property in configuration document. Can't publish sync error.";
logger.fatal(errMessage);
return;
}
}
catch (XmlDocumentReaderException e) {
logger.fatal("[PublishSyncError] Error initializing Sync-Error-Sync primed document, could not publish the sync error sync message.");
logger.fatal(e.getMessage(), e);
return;
}
Element eControlArea = getControlArea(syncErrorDoc.getRootElement());
Result aResult = new Result();
ProcessedMessageId processedMsgId = new ProcessedMessageId();
String action = null;
if (senderControlArea.getContentSize()==0) {
// an empty control area was passed so we can't use it.
// We'll have to use the primed document's control area.
processedMsgId.setProducerId("None");
processedMsgId.setSenderAppId("None");
processedMsgId.setMessageSeq("None");
}
else {
// Build the dynamic portion of the sync document's control area
// This is going to have the sending application's "Sender" information in it
// that we'll need to use to build the Result object in our
// sync error document.
// Our sender information will go in the "Sender" element of the primed
// document
// Set the sender element
// Build the ProcessedMessageId Object out of the contents of the
// Sender's control area.
try {
action = senderControlArea.getAttribute(MESSAGE_ACTION).getValue();
Element eSender = senderControlArea.getChild("Sender");
processedMsgId.setProducerId(eSender.getChild("MessageId").
getChild("ProducerId").getText());
processedMsgId.setSenderAppId(eSender.getChild("MessageId").
getChild("SenderAppId").getText());
processedMsgId.setMessageSeq(eSender.getChild("MessageId").
getChild("MessageSeq").getText());
}
catch (Exception e) {
logger.fatal("Error building ProcessedMessageId Element in Sync-Error-Sync message!");
logger.fatal(e.getMessage(), e);
}
}
// This is the control area information relevant to this Gateway
eControlArea.removeChild("Result");
eControlArea.removeChild("Datetime");
eControlArea.removeChild("Sender");
Sender sender = new Sender();
MessageId msgId = new MessageId();
msgId.setProducerId(getSyncErrorPublisher().getProducerId(null).getId());
msgId.setSenderAppId(getAppName());
msgId.setMessageSeq(Integer.toString(getSyncErrorPublisher().incrementMessageSequence()));
sender.setMessageId(msgId);
Authentication auth = new Authentication();
auth.setAuthUserId(getAppName());
auth.setAuthUserSignature(getAppName());
sender.setAuthentication(auth);
Element eSender = null;
try {
eSender = (Element)sender.buildOutputFromObject();
}
catch (Exception e) {
logger.fatal("[publishSyncError1] Exception occurred building an Element from the Sender object. Can't publish Sync error. Exception: " + e.getMessage());
logger.fatal(e.getMessage(), e);
return;
}
// Set the datetime element
Datetime dt = new Datetime();
Element eDatetime = null;
try {
eDatetime = (Element)dt.buildOutputFromObject();
}
catch (Exception e) {
logger.fatal("[publishSyncError1] Exception occurred building an Element from the Datetime object. Can't publish Sync error. Exception: " + e.getMessage());
logger.fatal(e.getMessage(), e);
return;
}
eControlArea.addContent(eSender);
eControlArea.addContent(eDatetime);
if (action == null) {
action = "Unknown";
}
aResult.setAction(action);
aResult.setStatus("failure");
aResult.setProcessedMessageId(processedMsgId);
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);
}
try {
Element eResult = (Element)aResult.buildOutputFromObject();
eControlArea.addContent(eResult);
syncErrorDoc.getRootElement().removeContent(eControlArea);
syncErrorDoc.getRootElement().addContent(eControlArea);
TextMessage syncErrorMessage = getSyncErrorPublisher().createTextMessage();
XMLOutputter xmlOut = new XMLOutputter();
syncErrorMessage.setText(xmlOut.outputString(syncErrorDoc));
if (getSyncErrorPublisher().getDefaultCommandName().length() == 0 ||
getSyncErrorPublisher().getDefaultCommandName() == null) {
getSyncErrorPublisher().setDefaultCommandName("EnterpriseSyncErrorSync");
}
syncErrorMessage.setStringProperty(MessageProducer.MESSAGE_ID,msgId.toString());
syncErrorMessage.setStringProperty(MessageProducer.COMMAND_NAME,getSyncErrorPublisher().getDefaultCommandName());
//TODO: change this...
getSyncErrorPublisher().publishMessage(syncErrorMessage);
}
catch (Exception e) {
logger.fatal("Error publishing Sync-Error-Sync message!");
logger.fatal(e.getMessage(), e);
}
}
}