package hk.hku.cecid.edi.sfrm.handler;
import hk.hku.cecid.edi.sfrm.com.PackagedPayloads;
import hk.hku.cecid.edi.sfrm.com.PayloadException;
import hk.hku.cecid.edi.sfrm.com.PayloadsState;
import hk.hku.cecid.edi.sfrm.dao.SFRMMessageDVO;
import hk.hku.cecid.edi.sfrm.dao.SFRMMessageSegmentDAO;
import hk.hku.cecid.edi.sfrm.pkg.SFRMAcknowledgementParser;
import hk.hku.cecid.edi.sfrm.pkg.SFRMConstant;
import hk.hku.cecid.edi.sfrm.spa.SFRMComponent;
import hk.hku.cecid.edi.sfrm.util.StatusQuery;
import hk.hku.cecid.piazza.commons.dao.DAOException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Vector;
public class AcknowledgementHandler extends SFRMComponent {
private static AcknowledgementHandler ackHandler;
public static AcknowledgementHandler getInstance(){
return ackHandler;
}
/**
* Initialization of this Component
*/
protected void init() throws Exception{
super.init();
ackHandler = this;
}
public void processAcknowledgementResponse(String responseContent) throws Exception{
SFRMAcknowledgementParser parser = new SFRMAcknowledgementParser(responseContent);
List<String> msgIDs = parser.getMessagesIDs();
if(msgIDs.size() != 1){
getLogger().debug("Acknowledgement response should contains only one message information");
throw new Exception("Acknowledgement response should contains only one message information");
}
String messageId = msgIDs.get(0);
String responseMessageStatus = parser.getMessageStatus(messageId);
SFRMMessageDVO mDVO = this.getMessageHandler().retrieveMessage(messageId, SFRMConstant.MSGBOX_OUT);
if(mDVO == null){
String logStr = "Message with ID '" + messageId + "' doesn't exist, cannot process the acknowledgement response";
this.getLogger().error(logStr);
throw new DAOException(logStr);
}
//If the message status responsed is PS, DF or SD, update the local message status accordingly
if(responseMessageStatus.equals(SFRMConstant.MSGS_PROCESSED)
|| responseMessageStatus.equals(SFRMConstant.MSGS_DELIVERY_FAILURE)
|| responseMessageStatus.equals(SFRMConstant.MSGS_SUSPENDED)
//Resume Case
|| (responseMessageStatus.equals(SFRMConstant.MSGS_PROCESSING) && (mDVO.getStatus().equals(SFRMConstant.MSGS_PRE_RESUME))))
{
updateMessageStatus(mDVO, responseMessageStatus);
//TODO: didn't it need to check the message status for updating the message segment status
}else {
List<Integer> segNums = parser.getMessageSegmentNums(messageId);
updateMessageSegmentStatus(mDVO, segNums, parser);
}
preCompleteMessageIfNeeded(mDVO);
}
private void stopSpeedMonitor(String messageId){
MessageStatusQueryHandler queryHandler = MessageStatusQueryHandler.getInstance();
StatusQuery query = queryHandler.removeMessageSpeedQuery(messageId);
if(query != null){
query.stop();
}
}
/**
* Update the message segment status according to the acknowledgement request content
* @param messageId
* @param segNums
* @param parser
* @throws DAOException
*/
private void updateMessageSegmentStatus(SFRMMessageDVO mDVO, List<Integer> segNums, SFRMAcknowledgementParser parser) throws DAOException{
if(segNums.size() != 0){
Vector<Integer> DFList = new Vector<Integer>();
Vector<Integer> PSList = new Vector<Integer>();
//Categorize the segment to different status group
for(int i=0 ; segNums.size() > i; i++){
String responseStatus = parser.getMessageSegmentStatus(mDVO.getMessageId(), segNums.get(i));
if(responseStatus.equals(SFRMConstant.MSGS_DELIVERY_FAILURE)){
DFList.add(segNums.get(i));
}else if(responseStatus.equals(SFRMConstant.MSGS_PROCESSED)){
PSList.add(segNums.get(i));
}
}
SFRMMessageSegmentDAO segDAO = (SFRMMessageSegmentDAO) this.getMessageSegmentHandler().getDAOInstance();
//Update segment status to PD if the response status is DF
if(DFList.size() != 0){
segDAO.updateBatchSegmentsRecoveryStatus(SFRMConstant.MSGS_PENDING, mDVO.getMessageId(), SFRMConstant.MSGBOX_OUT, SFRMConstant.MSGT_PAYLOAD, DFList);
}
//Update segment status to PS if the response status is PS
if(PSList.size() != 0){
segDAO.updateBatchSegmentsStatus(SFRMConstant.MSGS_PROCESSED, new Timestamp(System.currentTimeMillis()), mDVO.getMessageId(), SFRMConstant.MSGBOX_OUT, SFRMConstant.MSGT_PAYLOAD, PSList);
}
}
}
/**
* Check whether all of the message segements was received, if it is, set the message status to PPS
* @param messageId message ID
* @return whether the message status was marked as PPS
*/
private boolean preCompleteMessageIfNeeded(SFRMMessageDVO mDVO) throws DAOException{
if(mDVO == null){
throw new DAOException("Message ID " + mDVO.getMessageId() + " is null");
}
if(mDVO.getStatus().equals(SFRMConstant.MSGS_PROCESSED))
return true;
int numTotalSegs = mDVO.getTotalSegment();
int numPSSegs = this.getMessageSegmentHandler().retrieveMessageSegmentCount(mDVO.getMessageId(), SFRMConstant.MSGBOX_OUT, SFRMConstant.MSGT_PAYLOAD, SFRMConstant.MSGS_PROCESSED);
if(numPSSegs == numTotalSegs){
mDVO.setStatus(SFRMConstant.MSGS_PRE_PROCESSED);
boolean peristed = this.getMessageHandler().updateMessage(mDVO);
if(peristed == false){
throw new DAOException("Message ID " + mDVO.getMessageId() + " not found");
}
return true;
}
return false;
}
private SFRMMessageDVO updateMessageStatus(SFRMMessageDVO mDVO, String status) throws DAOException, PayloadException{
getLogger().debug("Inside updateMessageStatus");
mDVO.setStatus(status);
mDVO.setStatusDescription(SFRMConstant.getStatusDescription(status));
if(status.equals(SFRMConstant.MSGS_PROCESSED)){
mDVO.setCompletedTimestamp(new Timestamp(System.currentTimeMillis()));
completePayload(mDVO);
//Stop the Network speed monitoring if the message status is being PS
stopSpeedMonitor(mDVO.getMessageId());
}
this.getMessageHandler().updateMessage(mDVO);
return mDVO;
}
private void completePayload(SFRMMessageDVO mDVO) throws PayloadException{
getLogger().debug("Inside the complete payload");
//TODO: Fix the clear the packaged payload
PackagedPayloads pp = (PackagedPayloads) getOutgoingRepository().getPayload(new Object[]{
mDVO.getPartnershipId(),
mDVO.getMessageId(),
mDVO.getFilename()},
PayloadsState.PLS_PROCESSING);
if (pp != null){
pp.clearPayloadCache();
}else{
throw new PayloadException("Payload " + pp.getFilename() + " didn't existed");
}
}
}