/** * Contains the set of active module collector for * handling packaging, segmenting, sending, joining and unpacking of payloads. */ package hk.hku.cecid.edi.sfrm.task; import java.io.IOException; import java.util.Properties; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import hk.hku.cecid.edi.sfrm.spa.SFRMProcessor; import hk.hku.cecid.edi.sfrm.spa.SFRMLog; import hk.hku.cecid.edi.sfrm.util.BandWidthOptimizer; import hk.hku.cecid.edi.sfrm.com.PackagedPayloads; import hk.hku.cecid.edi.sfrm.com.PayloadsState; import hk.hku.cecid.edi.sfrm.dao.SFRMPartnershipDVO; import hk.hku.cecid.edi.sfrm.dao.SFRMMessageDVO; import hk.hku.cecid.edi.sfrm.dao.SFRMMessageSegmentDVO; import hk.hku.cecid.edi.sfrm.handler.MessageStatusQueryHandler; import hk.hku.cecid.edi.sfrm.pkg.SFRMConstant; import hk.hku.cecid.piazza.commons.dao.DAOException; import hk.hku.cecid.piazza.commons.module.ActiveTaskModule; import hk.hku.cecid.piazza.commons.module.LimitedActiveTaskList; import hk.hku.cecid.piazza.commons.util.StringUtilities; /** * The outgoing segment payloads collector collect all segmented * payload at the database which is ready for * sending to receiver. (status: PS).<br><br> * * Creation Date: 25/10/2006<br><br> * * @author Twinsen Tsang * @version 1.0.2 * @since 1.0.1 */ public class OutgoingSegmentCollector extends LimitedActiveTaskList { private boolean isFirstLoad = true; /** * The partnership DVO that query from the last time the collector execute. */ private SFRMPartnershipDVO lastQueryPDVO; /** * The message DVO that query from the last time the collector execute. */ private SFRMMessageDVO lastQueryMsgDVO; /** * The packaged payload working from the last time the collector execute. */ private PackagedPayloads lastWorkingPayloads; // private long lastTimestamp = 0; private BandWidthOptimizer optimizer; private MessageStatusQueryHandler statusQueryHandler; private boolean initialized = false; /* How long this collector is said to be active */ private long activeDuration = 120000; private long lastActiveTimestamp = -1; /** * * * @return */ private boolean compareNullAndKey(Object src, Object srcKey, Object destKey){ if (src == null || !srcKey.equals(destKey)) return true; return false; } /** * Get the list that contains <code>OutgoingSegmentPayloadsTask</code> * transformed through <code>SFRMMessageSegmentDVO</code>. * * @param taskList * The reference task list to insert. * @param status * The segment status you want to select. * @param sgtType * The segment type you want to select. * @return * The reference <code>taskList</code> */ private List getTaskList(ArrayList taskList, String status, String sgtType){ try{ // Grab all message segments that are ready to send. Iterator itr = SFRMProcessor.getInstance().getMessageSegmentHandler().retrieveIncompleteSegments( SFRMConstant.MSGBOX_OUT, status, sgtType, this.getMaxTasksPerList()).iterator(); // Get message and message segment handler. String sType = null; while(itr.hasNext()){ SFRMMessageSegmentDVO sgtDVO = (SFRMMessageSegmentDVO) itr.next(); try{ // Check whether the segment type is PAYLOAD. sType = sgtDVO.getSegmentType(); boolean isPayload = sType.equals(SFRMConstant.MSGT_PAYLOAD); // Retrieve the message if the last one is null or the message id is different. // If it is required to change, then the remaining two part // (partnership, packed_payload) should also be changed. String mID = sgtDVO.getMessageId(); if (this.compareNullAndKey( this.lastQueryMsgDVO , this.lastQueryMsgDVO != null ? this.lastQueryMsgDVO.getMessageId(): null , mID)){ // Update the last query msg DVO depending on it's segment type. this.lastQueryMsgDVO = SFRMProcessor.getInstance().getMessageHandler() .retrieveMessage( sgtDVO.getMessageId(), isPayload ? SFRMConstant.MSGBOX_OUT: SFRMConstant.MSGBOX_IN); // Check null if (this.lastQueryMsgDVO == null) throw new NullPointerException( "Missing Message Record for MID: " + mID); // Retrieve the new partnership. String pID = this.lastQueryMsgDVO.getPartnershipId(); this.lastQueryPDVO = SFRMProcessor.getInstance().getPartnershipHandler() .retreivePartnership(pID, mID); /** * @since 2.0.0 - Retrieve the single file properties, if it is single file */ String filename = lastQueryMsgDVO.getFilename(); if (this.lastQueryPDVO == null) throw new NullPointerException( "Missing Partnership Record for PID: " + pID); if (isPayload){ /** * @since 2.0.0 added the code to retrieve filename fields also */ this.lastWorkingPayloads = (PackagedPayloads) SFRMProcessor. getInstance().getOutgoingRepository() .getPayload(new Object[]{ pID, mID, filename } ,PayloadsState.PLS_PROCESSING); if (this.lastWorkingPayloads == null) throw new IOException( " Missing Packaged Payload with partnership id: " + pID +" and message id: " + mID); } // Log information. SFRMProcessor.getInstance().getLogger().info( SFRMLog.OSPTC_CALLER + "Switching working task to MSG id: " + mID +" and partnership id: " + pID); } sgtDVO.setStatus(SFRMConstant.MSGS_PROCESSING); SFRMProcessor.getInstance().getMessageSegmentHandler().getDAOInstance().persist(sgtDVO); // Add a new payload task for each segmented payload. taskList.add(new OutgoingSegmentTask( sgtDVO, this.lastQueryPDVO, this.lastQueryMsgDVO, this.lastWorkingPayloads)); } // Using un-specified exception is acceptable. catch(Exception e){ SFRMProcessor.getInstance().getLogger().error(SFRMLog.OSPTC_CALLER + "Error", e); } } }catch(DAOException daoe){ SFRMProcessor.getInstance().getLogger().error(SFRMLog.OSPTC_CALLER + "Unable to retrieve sgts from DB", daoe); // Catch any exception so that the task-list does not terminate under any condition. }catch(Exception e){ SFRMProcessor.getInstance().getLogger().error(SFRMLog.OSPTC_CALLER + "Unknown Error", e); } return taskList; } /** * It get the set of payload directory from the segmented * payloads repository and pass to outgoing segmented * payload tasks for process. * * @return A list of Outgoing segmented payloads task. */ public List getTaskList() { if(!initialized){ initialize(); initialized = true; } ArrayList taskList = new ArrayList(); if (this.isFirstLoad){ SFRMProcessor.getInstance().getLogger().info(SFRMLog.OSPTC_CALLER + SFRMLog.FIRST_LOAD + " Resend PR and DL Segments"); this.getTaskList(taskList, SFRMConstant.MSGS_PROCESSING, "%"); this.getTaskList(taskList, SFRMConstant.MSGS_DELIVERED, SFRMConstant.MSGT_PAYLOAD); this.isFirstLoad = false; } // Get all pending segments for all segment type. taskList = (ArrayList) this.getTaskList(taskList, SFRMConstant.MSGS_PENDING, "%"); // For marking the execution interval //markTimestamp(); //TODO: Remove this for testing purpose only double totalSpeed = statusQueryHandler.getTotalSpeed(); if(optimizer.isFoundOptimized() && totalSpeed > 0.0){ ((ActiveTaskModule) this.getModule()).setExecutionInterval(optimizer.getOptimizedEI()); } if(!optimizer.isFoundOptimized()){ optimizer.findMaxSpeed(); } //TODO: End Remove this for testing purpose only //When there have a message segment to send, it is said to be active if(taskList.size() > 0){ long currentTime = System.currentTimeMillis(); long duration = currentTime - lastActiveTimestamp; //If this collector is waiting too long for sending the message segment, reset the bandwidth optimizer if(duration > activeDuration){ optimizer.reset(); } lastActiveTimestamp = currentTime; } return taskList; } /* private void markTimestamp(){ long currentTime = System.currentTimeMillis(); long duration = currentTime - lastTimestamp; lastTimestamp = currentTime; SFRMProcessor.getInstance().getLogger().debug("segment collector interval:," + Long.toString(duration) + ","); } */ protected void init() throws Exception{ super.init(); Properties param = getParameters(); long eiInc = StringUtilities.parseLong(param.getProperty("ei-delta"), 500); int maxRound = StringUtilities.parseInt(param.getProperty("max-round"), 20); long minEI = StringUtilities.parseLong(param.getProperty("min-ei"), 500); long maxEI = StringUtilities.parseLong(param.getProperty("max-ei"), 500); double speedGradientTolerance = StringUtilities.parseDouble(param.getProperty("speed-gradient-tolerance"), 100.0); double eiSpeedGradientTolerance = StringUtilities.parseDouble(param.getProperty("ei-speed-gradient-tolerance"), 50.0); activeDuration = StringUtilities.parseLong(param.getProperty("active-duration"), 120000); optimizer = new BandWidthOptimizer((ActiveTaskModule) this.getModule()); optimizer.setEIIncrement(eiInc); optimizer.setMaxRound(maxRound); optimizer.setMinExecutionInterval(minEI); optimizer.setMaxExecutionInterval(maxEI); optimizer.setSpeedGradientTolerance(speedGradientTolerance); optimizer.setEISpeedGradientTolerance(eiSpeedGradientTolerance); } private void initialize(){ statusQueryHandler = SFRMProcessor.getInstance().getMessageSpeedQueryHandler(); } }