/*
* 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.AS2Processor;
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.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.Component;
import hk.hku.cecid.piazza.commons.security.KeyStoreManager;
import hk.hku.cecid.piazza.commons.security.SMimeMessage;
import hk.hku.cecid.piazza.commons.servlet.RequestListenerException;
/**
* IncomingMessageProcessor
*
* @author Hugo Y. K. Lam
*
*/
public class IncomingMessageProcessor extends Component {
public void processReceipt(AS2Message receipt) throws AS2Exception {
try {
AS2Processor.core.log.info(receipt + " received");
if (receipt.getMessageID() == null) {
receipt.setMessageID(AS2Message.generateID());
}
/* Capture the MDN message */
AS2Processor.core.log.debug(receipt + " is being captured");
AS2Processor.getMessageRepository().persistMessage(receipt);
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(AS2Processor.core.dao);
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())) {
AS2Processor.core.log.warn("Message Integrity Check failed - Original Message: " + originalMessageDVO.getMessageId() + ", Original MIC: " + originalMessageDVO.getMicValue() + ", Recevied MIC: " + dn.getReceivedContentMIC());
}
else {
AS2Processor.core.log.info("Message Integrity Check succeeded - Original Message: " + originalMessageDVO.getMessageId());
}
}
Disposition disposition = dn.getDisposition();
try {
disposition.validate();
}
catch (Exception e) {
AS2Processor.core.log.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);
AS2Processor.core.log.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 {
AS2Processor.core.log.info(requestMessage + " received");
/* Capture the incoming message */
AS2Processor.core.log.debug(requestMessage + " is being captured");
AS2Processor.getMessageRepository().persistMessage(requestMessage);
/* Persist the incoming message */
AS2DAOHandler daoHandler = new AS2DAOHandler(AS2Processor.core.dao);
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{
AS2Processor.core.log.info(requestMessage + " is being processed");
AS2DAOHandler daoHandler = new AS2DAOHandler(AS2Processor.core.dao);
KeyStoreManager keyman = AS2Processor.getKeyStoreManager();
IncomingMessage imsg = new IncomingMessage(requestMessage,keyman,daoHandler);
/* Handle the SMIME features */
imsg.processSMime();
AS2Message responseMessage = null;
RepositoryDVO responseRepositoryDVO = null;
MessageDVO responseMessageDVO = null;
/* Generate a reply message if requested */
if (requestMessage.isReceiptRequested()) {
AS2Processor.core.log.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));
}
/* Capture the reply message */
AS2Processor.core.log.debug(responseMessage + " is being captured");
AS2Processor.getMessageRepository().persistMessage(responseMessage);
}
/* 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();
requestMessageDVO.setStatus(MessageDVO.STATUS_PROCESSED);
}
daoHandler.createMessageStore().storeReceipt(responseMessageDVO, responseRepositoryDVO, requestMessageDVO);
AS2Processor.core.log.info(requestMessage + " has been processed successfully");
return responseMessage;
}
catch (Exception e) {
throw new AS2Exception("Error in processing AS2 received message", e);
}
}
}