FileDocCategorySizeDatePackage
ProgressObjectSink.javaAPI DocGlassfish v2 API18358Fri May 04 22:34:28 BST 2007com.sun.enterprise.deployapi

ProgressObjectSink

public class ProgressObjectSink extends Object implements javax.enterprise.deploy.spi.status.ProgressListener, com.sun.enterprise.deployment.client.JESProgressObject
This class acts as a sink for ProgressObject. It registers itself as ProgressObject listener for multiple deployment actions and tunnel all events to registered ProgressObject listener.

Whenever this class receives a progress event from one of its sources (one of the deploymentFacility actions) it forwards that event on to the sink's listeners, changing the state of the event to "running." Then, after the sink receives the completion or failure event from the last source, it forwards that event as running (as it had all earlier events) and then sends one final aggregate completion or failure event.

The sink always follows this pattern, even if it encapsulates only a single source. JSR88 clients should be aware of this behavior.

author
Jerome Dochez

Fields Summary
private static String
LINE_SEPARATOR
private Vector
registeredPL
private Vector
deliveredEvents
private javax.enterprise.deploy.shared.StateType
finalStateType
private String
finalMessage
private Vector
targetModuleIDs
private Vector
sources
private static com.sun.enterprise.util.LocalStringManagerImpl
localStrings
private com.sun.enterprise.deployment.backend.DeploymentStatus
completedStatus
private boolean
completedStatusReady
Constructors Summary
Methods Summary
public voidaddProgressListener(javax.enterprise.deploy.spi.status.ProgressListener progressListener)
Register a new ProgressListener

param
the new listener instance

        
	Collection clone;
        synchronized(registeredPL) {
            registeredPL.add(progressListener);
        
            // now let's deliver all the events we already received.
            clone = (Collection) deliveredEvents.clone();
        }
        
        for (Iterator itr=clone.iterator();itr.hasNext();) {
            ProgressEvent pe = (ProgressEvent) itr.next();
            progressListener.handleProgressEvent(pe);
        }
    
private intaggregateStages(int worstStatusSoFar, java.lang.StringBuffer msgs, com.sun.enterprise.deployment.backend.DeploymentStatus stage)

        /*
         *Starting with the stage passed in, see if its severity is more urgent than that seen so far.
         *If so, then discard the messages accumulated so far for the less urgent severity and save
         *this stage's message and severity as the worst seen so far.
         */
        int stageStatus = stage.getStageStatus();
        if (stageStatus < worstStatusSoFar) {
            worstStatusSoFar = stageStatus;
            msgs.delete(0,msgs.length());
        }
        
        /*
         *If the stage's severity is the same as the currently worst seen, then add this stage's message
         *to the aggregate message.
         */
        if (stageStatus == worstStatusSoFar) {
            msgs.append(stage.getStageStatusMessage()).append(LINE_SEPARATOR);
        }
        
        /*
         *Now, do the same for each substage.
         */
        for (Iterator it = stage.getSubStages(); it.hasNext(); ) {
            com.sun.enterprise.deployment.backend.DeploymentStatus substage = (com.sun.enterprise.deployment.backend.DeploymentStatus) it.next();
            worstStatusSoFar = aggregateStages(worstStatusSoFar, msgs, substage);
        }
        
        return worstStatusSoFar;
    
public voidcancel()

        if (!isCancelSupported()) {
            throw new OperationUnsupportedException("cancel");
        }
        for (Iterator itr=getSources().iterator();itr.hasNext();) {
            ProgressObject source = (ProgressObject) itr.next();
            source.cancel();
        }        
    
public javax.enterprise.deploy.spi.status.ClientConfigurationgetClientConfiguration(javax.enterprise.deploy.spi.TargetModuleID targetModuleID)

        // since we are never called upon deploying, I don't 
        // have to deal with this at this time.
        return null;
    
public com.sun.enterprise.deployment.backend.DeploymentStatusgetCompletedStatus()
Report completed status for deploytool.

return
null if not completed, or the backend.DeploymentStatus set to reflect the completion

	com.sun.enterprise.deployment.backend.DeploymentStatus answer = null;
        if (completedStatusReady) {
            answer = completedStatus;
        }
        return answer;
    
public javax.enterprise.deploy.spi.status.DeploymentStatusgetDeploymentStatus()

        DeploymentStatusImpl status = new DeploymentStatusImpl();
        if (sources.isEmpty()) {
            status.setState(finalStateType);
            status.setMessage(finalMessage);
        } else {
            status.setState(StateType.RUNNING);
        }
        return status;        
    
public javax.enterprise.deploy.spi.TargetModuleID[]getResultTargetModuleIDs()

        
        TargetModuleID[] ids = new TargetModuleID[targetModuleIDs.size()];
        targetModuleIDs.copyInto(ids);
        return ids;
    
private java.util.CollectiongetSources()

        return (Collection) sources.clone();
    
public voidhandleProgressEvent(javax.enterprise.deploy.spi.status.ProgressEvent progressEvent)
receives notification of a progress event from one of our registered interface.

        
        ProgressEvent forwardedEvent;
        DeploymentStatus forwardedDS = progressEvent.getDeploymentStatus();
        
        // we intercept all events...
        if (!forwardedDS.isRunning()) {
            // this mean we are either completed or failed...
            if (forwardedDS.isFailed()) {
                /*
                 *Once at least one operation fails, we know that the aggregate state will have
                 *to be failed.
                 */
                finalStateType = StateType.FAILED;
            }
            
            // since this is the completion event 
            // we are done with that progress listener;
            Object source = progressEvent.getSource();
            if (source instanceof ProgressObject) {
                ProgressObject po = (ProgressObject) source;
                po.removeProgressListener(this);
                
                sources.remove(source);
                
                if (forwardedDS.isCompleted()) {
                
                    TargetModuleID[] ids = po.getResultTargetModuleIDs();
                    for (int i=0;i<ids.length;i++) {
                        targetModuleIDs.add(ids[i]);
                    }
                }
            } else {
                throw new RuntimeException(localStrings.getLocalString(
                    "enterprise.deployment.client.noprogressobject",
                    "Progress event does not contain a ProgressObject source"
                    ));
            }
            
            /*
             *Update the completionStatus by adding a stage to it and recording the completion
             *of this event as the newest stage.
             */
            updateCompletedStatus(forwardedDS);
            
            // now we change our event state to running.  We always forward every event from a
            // source to the listeners with "running" status because the sink is not yet completely
            // finished.  We will also send a final aggregate completion event
            // if this is a completion event from our last source (see below).
            DeploymentStatusImpl forwardedStatus = new DeploymentStatusImpl();
            forwardedStatus.setState(StateType.RUNNING);
            forwardedStatus.setMessage(forwardedDS.getMessage());
            forwardedStatus.setCommand(forwardedDS.getCommand());
            forwardedEvent = new ProgressEvent(this, progressEvent.getTargetModuleID(), forwardedStatus);
        } else {
            // This is a "running" event from one of our sources, so we just need to swap the source...
            forwardedEvent = new ProgressEvent(this, progressEvent.getTargetModuleID(), 
                forwardedDS);
        }
        
        // we need to fire the received event to our listeners
        Collection clone;
        ProgressEvent finalEvent = null;
        
        synchronized(registeredPL) {
            clone = (Collection) registeredPL.clone();
            deliveredEvents.add(forwardedEvent);
            /*
             *If we are done with all of our sources, let's wrap up by creating a final event that will
             *be broadcast to the listeners along with the forwarded event.  Also create the completed status
             *that meets the requirements of the JESProgressObject interface.
             */
            if (sources.isEmpty()) {
                prepareCompletedStatus();
                DeploymentStatusImpl status = new DeploymentStatusImpl();
                status.setState(finalStateType);
                if (finalStateType.equals(StateType.FAILED)) {
                    status.setMessage(localStrings.getLocalString(
                        "enterprise.deployment.client.aggregatefailure",
                        "At least one operation failed"
                        ));
                } else {
                    status.setMessage(localStrings.getLocalString(
                        "enterprise.deployment.client.aggregatesuccess",
                        "All operations completed successfully"
                        ));
                }
                finalEvent = new ProgressEvent(this, null, status);
                deliveredEvents.add(finalEvent);
            }
        }        
        
        for (Iterator itr=clone.iterator();itr.hasNext();) {
            ProgressListener pl = (ProgressListener) itr.next();
            pl.handleProgressEvent(forwardedEvent);
        }

        /*
         *Send the final event if there is one.
         */
        if (finalEvent != null) {
            for (Iterator itr=clone.iterator();itr.hasNext();) {
                ProgressListener pl = (ProgressListener) itr.next();
                pl.handleProgressEvent(finalEvent);
            }
        }
    
public booleanisCancelSupported()

        
        // if only one of our sources does not support cancel, we don't
        for (Iterator itr=getSources().iterator();itr.hasNext();) {
            ProgressObject source = (ProgressObject) itr.next();
            if (!source.isCancelSupported()) {
                return false;
            }
        }
        return true;
    
public booleanisStopSupported()

        
        // if only one of our sources does not support stop, we don't
        for (Iterator itr=getSources().iterator();itr.hasNext();) {
            ProgressObject source = (ProgressObject) itr.next();
            if (!source.isStopSupported()) {
                return false;
            }
        }
        return true;
    
private voidprepareCompletedStatus()

        /*
         *The substages may have status values of success when in fact a warning is present
         *in a substage.  Traverse all the substages, composing the true aggregate state and
         *message based on the most severe state that is present in the entire stage tree.
         */
        int worstStatus = com.sun.enterprise.deployment.backend.DeploymentStatus.NOTINITIALIZED;
        StringBuffer msgs = new StringBuffer();

        int newWorstStatus = aggregateStages(worstStatus, msgs, completedStatus);
        completedStatus.setStageStatus(newWorstStatus);
        completedStatus.setStageStatusMessage(msgs.toString());
        
        completedStatusReady = true;
    
public voidremoveProgressListener(javax.enterprise.deploy.spi.status.ProgressListener progressListener)
removes a ProgressListener from our list of listeners

param
the ProgressListener to remove

        registeredPL.remove(progressListener);
    
private voidreviseStatusAndMessage(javax.enterprise.deploy.spi.status.DeploymentStatus ds, com.sun.enterprise.deployment.backend.DeploymentStatus newStageStatus)

        String msgKey = null;
        int stageStatus = -1;
        
        if (ds.isCompleted()) {
            /*
             *The deployment status for this source was successful. 
             */
            msgKey = "enterprise.deployment.client.action_completed";
            stageStatus = com.sun.enterprise.deployment.backend.DeploymentStatus.SUCCESS;
        } else {
            /*
             *The deployment status for this source failed.
             */
            msgKey = "enterprise.deployment.client.action_failed";
            stageStatus = com.sun.enterprise.deployment.backend.DeploymentStatus.FAILURE;
        }

        String i18msg = localStrings.getLocalString(msgKey, ds.getMessage());
        newStageStatus.setStageStatus(stageStatus);
        newStageStatus.setStageStatusMessage(i18msg);
    
public voidsinkProgressObject(javax.enterprise.deploy.spi.status.ProgressObject source)
register to a new ProgressObject for ProgressEvent notifications

    
                 
        
        /*
         *The following two statements must appear in the order shown.  Otherwise, a race condition can exist. 
         */
        sources.add(source);
        source.addProgressListener(this);
    
public voidstop()

        if (!isStopSupported()) {
            throw new OperationUnsupportedException("stop");
        }
        for (Iterator itr=getSources().iterator();itr.hasNext();) {
            ProgressObject source = (ProgressObject) itr.next();
            source.stop();
        }
        
    
private voidupdateCompletedStatus(javax.enterprise.deploy.spi.status.DeploymentStatus ds)

        /*
         *If the status passed in is already a backend.DeploymentStatus then add it as a new stage to the 
         *completed status.  Otherwise, create a new backend.DeploymentStatus, fill it in as much as 
         *possible, and add it as the next stage.
         */
        
        com.sun.enterprise.deployment.backend.DeploymentStatus newStageStatus = null;
        if (ds instanceof DeploymentStatusImpl) {
            DeploymentStatusImpl dsi = (DeploymentStatusImpl) ds;
            newStageStatus = dsi.progressObject.getCompletedStatus();
        } else {
            /*
             *Create a new status stage and add it to the completed status.
             */
            newStageStatus = new com.sun.enterprise.deployment.backend.DeploymentStatus(completedStatus);
            /*
             *The new state status depends on the DeploymentStatus outcome.
             */
            String msgKey = null;
            int stageStatus = -1;
            Throwable exc;

            reviseStatusAndMessage(ds, newStageStatus);
        }
        if (newStageStatus != null) {
            /*
             *Update the final status state if this new stage's state is worse than the final status's
             *current state.
             */
            completedStatus.addSubStage(newStageStatus);
            /*
             *The status being reported may say it is successful but there could be warnings in substages 
             *(or substages of substages...).  So the truly final state and message for the completed 
             *status is determined once, after the last source of events is removed.
             */
        } else {
            System.err.println("A newStageStatus was null");
        }