/*
* Copyright(c) 2005 Center for E-Commerce Infrastructure Development, The
* University of Hong Kong (HKU). All Rights Reserved.
*
* This software is licensed under the GNU GENERAL PUBLIC LICENSE Version 2.0 [1]
*
* [1] http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
*/
package hk.hku.cecid.edi.as2.module;
import hk.hku.cecid.edi.as2.AS2Exception;
import hk.hku.cecid.edi.as2.dao.AS2DAOHandler;
import hk.hku.cecid.edi.as2.dao.MessageDAO;
import hk.hku.cecid.edi.as2.dao.MessageDVO;
import hk.hku.cecid.edi.as2.dao.PartnershipDVO;
import hk.hku.cecid.edi.as2.dao.RepositoryDAO;
import hk.hku.cecid.edi.as2.dao.RepositoryDVO;
import hk.hku.cecid.edi.as2.pkg.AS2Header;
import hk.hku.cecid.edi.as2.pkg.AS2Message;
import hk.hku.cecid.edi.as2.pkg.Disposition;
import hk.hku.cecid.edi.as2.pkg.DispositionNotification;
import hk.hku.cecid.piazza.commons.module.SystemComponent;
import hk.hku.cecid.piazza.commons.security.KeyStoreManager;
import hk.hku.cecid.piazza.commons.security.SMimeMessage;
import hk.hku.cecid.piazza.commons.servlet.RequestListenerException;
import java.io.InputStream;
/**
* IncomingMessageProcessor
*
* @author Hugo Y. K. Lam
*
*
*/
public class IncomingMessageProcessor extends SystemComponent {
private static final String KEYSTORE_MANAGER = "keystore-manager";
public void processReceipt(AS2Message receipt) throws AS2Exception {
try {
getLogger().info(receipt + " received");
if (receipt.getMessageID() == null) {
receipt.setMessageID(AS2Message.generateID());
}
DispositionNotification dn;
try {
dn = receipt.getDispositionNotification();
}
catch (Exception e) {
throw new AS2Exception("Invalid disposition notification\n"+new String(receipt.toByteArray()), e);
}
AS2DAOHandler daoHandler = new AS2DAOHandler(getDAOFactory());
PartnershipDVO partnership = daoHandler.findPartnership(receipt, true);
MessageDAO messageDAO = daoHandler.createMessageDAO();
MessageDVO originalMessageDVO = (MessageDVO)messageDAO.createDVO();
originalMessageDVO.setMessageId(dn.getOriginalMessageID());
originalMessageDVO.setMessageBox(MessageDVO.MSGBOX_OUT);
if (!messageDAO.retrieve(originalMessageDVO) || !originalMessageDVO.isReceiptRequested()) {
throw new RequestListenerException("Unexpected disposition notification for message " + dn.getOriginalMessageID());
}
if (originalMessageDVO.isAcknowledged()) {
throw new RequestListenerException("Duplicated disposition notification for message " + dn.getOriginalMessageID());
}
SMimeMessage smime = new SMimeMessage(receipt.getBodyPart(), partnership.getEffectiveVerifyCertificate());
if (originalMessageDVO.getMicValue() != null) {
try {
if (smime.isSigned()) {
try {
smime = smime.verify();
}
catch (Exception e) {
throw new AS2Exception("Signature verification failed", e);
}
}
else {
throw new AS2Exception("Signed receipt is required.");
}
}
catch (Exception e) {
AS2Exception t = new AS2Exception("Receipt ("+receipt.getMessageID()+") rejected for security reason. Original message: "+dn.getOriginalMessageID(), e);
originalMessageDVO.setStatusDescription(t.toString());
daoHandler.createMessageDAO().persist(originalMessageDVO);
throw t;
}
if (!dn.matchOriginalContentMIC(originalMessageDVO.getMicValue())) {
getLogger().warn("Message Integrity Check failed - Original Message: " + originalMessageDVO.getMessageId() + ", Original MIC: " + originalMessageDVO.getMicValue() + ", Recevied MIC: " + dn.getReceivedContentMIC());
}
else {
getLogger().info("Message Integrity Check succeeded - Original Message: " + originalMessageDVO.getMessageId());
}
}
Disposition disposition = dn.getDisposition();
try {
disposition.validate();
}
catch (Exception e) {
getLogger().warn("Message " + originalMessageDVO.getMessageId() + " was sent but the receipt indicated an error occurred", e);
}
/* Persist the receipt message */
RepositoryDVO replyRepositoryDVO = daoHandler.createRepositoryDVO(receipt, true);
MessageDVO replyMessageDVO = daoHandler.createMessageDVO(receipt, true);
replyMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED);
originalMessageDVO.setIsAcknowledged(true);
originalMessageDVO.setStatusDescription(disposition.toString());
if (disposition.isError()) {
originalMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED_ERROR);
}
else {
originalMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED);
}
daoHandler.createMessageStore().storeReceipt(
replyMessageDVO, replyRepositoryDVO, originalMessageDVO);
AS2EventModule eventModule = (AS2EventModule)
getModule().getGroup().getModule(AS2EventModule.MODULE_ID);
if (disposition.isError()) {
eventModule.fireErrorOccurred(receipt);
} else {
eventModule.fireResponseReceived(receipt);
}
getLogger().info("Receipt for message " + originalMessageDVO.getMessageId() + " has been processed successfully");
}
catch (Exception e) {
throw new AS2Exception("Error in processing AS2 receipt message", e);
}
}
public AS2Message processMessage(AS2Message requestMessage) throws AS2Exception {
try {
getLogger().info(requestMessage + " received");
/* Persist the incoming message */
AS2DAOHandler daoHandler = new AS2DAOHandler(getDAOFactory());
RepositoryDVO requestRepositoryDVO = daoHandler.createRepositoryDVO(requestMessage, true);
MessageDVO requestMessageDVO = daoHandler.createMessageDVO(requestMessage, true);
requestMessageDVO.setStatus(requestMessage.isReceiptSynchronous()? MessageDVO.STATUS_PROCESSING:MessageDVO.STATUS_RECEIVED);
daoHandler.createMessageStore().storeMessage(requestMessageDVO, requestRepositoryDVO);
/* Process the message at once if it is a synchronous request */
if (requestMessage.isReceiptSynchronous()) {
try {
return processReceivedMessage(requestMessage);
}
catch (Exception e) {
requestMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED_ERROR);
requestMessageDVO.setStatusDescription(e.toString());
daoHandler.createMessageDAO().persist(requestMessageDVO);
throw e;
}
}
else {
return null;
}
}
catch (Exception e) {
throw new AS2Exception("Error in processing AS2 incoming message", e);
}
}
protected AS2Message processReceivedMessage(AS2Message requestMessage) throws AS2Exception {
try{
getLogger().info(requestMessage + " is being processed");
AS2DAOHandler daoHandler = new AS2DAOHandler(getDAOFactory());
KeyStoreManager keyman = (KeyStoreManager) getComponent(KEYSTORE_MANAGER);
IncomingMessage imsg = new IncomingMessage(requestMessage,keyman,daoHandler, getLogger());
/* Handle the SMIME features */
imsg.processSMime();
AS2Message responseMessage = null;
RepositoryDVO responseRepositoryDVO = null;
MessageDVO responseMessageDVO = null;
/* Generate a reply message if requested */
if (requestMessage.isReceiptRequested()) {
getLogger().info(requestMessage + " is being replied");
responseMessage = imsg.generateReceipt();
responseMessageDVO = daoHandler.createMessageDVO(responseMessage, false);
responseRepositoryDVO = daoHandler.createRepositoryDVO(responseMessage, false);
if (requestMessage.isReceiptSynchronous()) {
responseMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED);
}
else {
responseMessageDVO.setReceiptUrl(requestMessage.getHeader(AS2Header.RECEIPT_DELIVERY_OPTION));
}
}
/* Update the original message and persist the reply message if any */
MessageDAO messageDAO = daoHandler.createMessageDAO();
MessageDVO requestMessageDVO = (MessageDVO)messageDAO.createDVO();
requestMessageDVO.setMessageId(requestMessage.getMessageID());
requestMessageDVO.setMessageBox(MessageDVO.MSGBOX_IN);
if (!messageDAO.retrieve(requestMessageDVO)) {
throw new AS2Exception("Unable to update message status. Missing message: "+requestMessage.getMessageID());
}
requestMessageDVO.setIsAcknowledged(requestMessage.isReceiptRequested());
requestMessageDVO.setStatusDescription(imsg.getDisposition().toString());
/* Dispatch the message if there is no error */
if (imsg.getDisposition().isError()) {
requestMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED_ERROR);
}
else {
//imsg.dispatchMessage(); //Instead of dispatch message to repository, push to database instread
//Retrieve Original Payload Content
RepositoryDAO repoDAO = daoHandler.createRepositoryDAO();
RepositoryDVO repoDVO = (RepositoryDVO) repoDAO.createDVO();
repoDVO.setMessageId(requestMessageDVO.getMessageId());
repoDVO.setMessageBox(requestMessageDVO.getMessageBox());
if(!repoDAO.retrieve(repoDVO)){
throw new AS2Exception("Unable to update payload content. Missing message: " + requestMessageDVO.getMessageId());
}
AS2Message decrytedMessage = imsg.getDecrytedMessage();
InputStream contentIns =
decrytedMessage.getBodyPart().getDataHandler().getInputStream();
repoDVO.setContent(decrytedMessage.toByteArray());
repoDAO.persist(repoDVO);
requestMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED);
}
daoHandler.createMessageStore().storeReceipt(responseMessageDVO, responseRepositoryDVO, requestMessageDVO);
if (!imsg.getDisposition().isError()) {
AS2Message decrytedMessage = imsg.getDecrytedMessage();
AS2EventModule eventModule = (AS2EventModule)
getModule().getGroup().getModule(AS2EventModule.MODULE_ID);
eventModule.fireMessageReceived(decrytedMessage);
}
getLogger().info(requestMessage + " has been processed successfully");
return responseMessage;
}
catch (Exception e) {
throw new AS2Exception("Error in processing AS2 received message", e);
}
}
}