All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.deployapi.ProgressObjectImpl Maven / Gradle / Ivy

There is a newer version: 10.0-b28
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2008 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.deployapi;

//import com.sun.enterprise.util.i18n.StringManager;

import com.sun.enterprise.util.LocalStringManagerImpl;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Vector;

import javax.enterprise.deploy.shared.CommandType;
import javax.enterprise.deploy.shared.ModuleType;
import javax.enterprise.deploy.shared.StateType;
import javax.enterprise.deploy.spi.Target;
import javax.enterprise.deploy.spi.exceptions.OperationUnsupportedException;
import javax.enterprise.deploy.spi.status.ClientConfiguration;
import javax.enterprise.deploy.spi.status.DeploymentStatus;
import javax.enterprise.deploy.spi.status.ProgressEvent;
import javax.enterprise.deploy.spi.status.ProgressListener;
import javax.enterprise.deploy.spi.TargetModuleID;
import org.glassfish.deployment.client.DFDeploymentStatus;
import org.glassfish.deployment.client.DFProgressObject;

/**
 * Implementation of the Progress Object 
 * @author  dochez
 * @author  tjquinn
 */
public class ProgressObjectImpl implements DFProgressObject {

    private final static LocalStringManagerImpl localStrings = new LocalStringManagerImpl(ProgressObjectImpl.class);
    
    protected CommandType commandType;
    protected Object[] args;
    private Vector listeners = new Vector(); // <-- needs to be synchronized
    protected TargetImpl target;
    protected TargetImpl[] targetsList;
    protected String moduleID;
    protected ModuleType moduleType;
    protected DeploymentStatusImpl deploymentStatus =null;
    protected TargetModuleID[] targetModuleIDs = null;
    protected Vector deliveredEvents = new Vector();
    protected DFDeploymentStatus finalDeploymentStatus = null;
    protected boolean deployActionCompleted;
    protected String warningMessages;
    
    private final static String MODULE_ID = 
        DFDeploymentStatus.MODULE_ID;
    private final static String MODULE_TYPE = 
        DFDeploymentStatus.MODULE_TYPE;
    private final static String KEY_SEPARATOR = 
        DFDeploymentStatus.KEY_SEPARATOR;
    private final static String SUBMODULE_COUNT = 
        DFDeploymentStatus.SUBMODULE_COUNT;
    private final static String CONTEXT_ROOT = 
        DFDeploymentStatus.CONTEXT_ROOT;
    private final static String WARNING_PREFIX = "WARNING: ";

    /** Creates a new instance of ProgressObjectImpl */
    public ProgressObjectImpl(TargetImpl target) {
        this.target = target;
        deploymentStatus = new DeploymentStatusImpl(this);
        deploymentStatus.setState(StateType.RELEASED);
        finalDeploymentStatus = new DFDeploymentStatus();
        deployActionCompleted = false;
    }

    public ProgressObjectImpl(TargetImpl[] targets) {
        this.targetsList = targets;
        deploymentStatus = new DeploymentStatusImpl(this);
        deploymentStatus.setState(StateType.RELEASED);
        finalDeploymentStatus = new DFDeploymentStatus();
        deployActionCompleted = false;
    }
    
    public ProgressObjectImpl(Target[] targets) {
        this(toTargetImpl(targets));
    }
    
    public ProgressObjectImpl(Target target) {
        this(toTargetImpl(target));
    }
    
    // XXX should be stricter than public
    public static TargetImpl toTargetImpl(Target target) {
        if (target instanceof TargetImpl) {
            return (TargetImpl) target;
        } else {
                throw new IllegalArgumentException(localStrings.getLocalString(
                        "enterprise.deployapi.spi.wrongImpl",
                        "Expected Target implementation class of {0} but found instance of {1} instead",
                        TargetImpl.class.getName(),
                        target.getClass().getName()));
            }
    }
    
    // XXX should be stricter than public
    public static TargetImpl[] toTargetImpl(Target[] targets) {
        TargetImpl[] result = new TargetImpl[targets.length];
        int i = 0;
        for (Target t : targets) {
            result[i++] = toTargetImpl(t);
        }
        return result;
    }
    
    /** Add a listener to receive Progress events on deployment
     * actions.
     *
     * @param The listener to receive events
     * @see ProgressEvent
     */
    public void addProgressListener(ProgressListener pol) {
	synchronized (listeners) {
            listeners.add(pol);
	    if (deliveredEvents.size() > 0) {
//		Print.dprintln("Delivering undelivered messages...");
	        for (Iterator i = deliveredEvents.iterator(); i.hasNext();) {
		    pol.handleProgressEvent((ProgressEvent)i.next());
	        }
	    }
	}
    }
    
    /** (optional)
     * A cancel request on an in-process operation
     * stops all further processing of the operation and returns
     * the environment to it original state before the operation
     * was executed.  An operation that has run to completion
     * cannot be cancelled.
     *
     * @throws OperationUnsupportedException this optional command
     *         is not supported by this implementation.
     */
    public void cancel() throws OperationUnsupportedException {
        throw new OperationUnsupportedException("cancel not supported");
    }
    
    /** Return the ClientConfiguration object associated with the
     * TargetModuleID.
     *
     * @return ClientConfiguration for a given TargetModuleID or
     *         null if none exists.
     */
    public ClientConfiguration getClientConfiguration(TargetModuleID id) {
        return null;
    }
    
    /** Retrieve the status of this activity.
     *
     * @return An object containing the status
     *          information.
     */
    public DeploymentStatus getDeploymentStatus() {
        DeploymentStatusImpl result = new DeploymentStatusImpl(this);
        result.setState(deploymentStatus.getState());
        result.setMessage(deploymentStatus.getMessage());
        
        return result;
    }

    /**
     * Retrieve the final deployment status which has complete details for each stage
     */
    public DFDeploymentStatus getCompletedStatus() {
        if(deployActionCompleted) {
            return finalDeploymentStatus;
        }
        return null;
    }
    
    /** Retrieve the list of TargetModuleIDs successfully
     * processed or created by the associated DeploymentManager
     * operation.
     *
     * @return a list of TargetModuleIDs.
     */
    public TargetModuleID[] getResultTargetModuleIDs() {

//        /**
//         * this should go once CTS has fixed their bugs...
//         */
//        if (targetModuleIDs==null) {
//            if(target != null) {
//                initializeTargetModuleIDs(moduleID);
//            } else if(targetsList != null) {
//                initializeTargetModuleIDForAllServers(null, null);
//            }
//        }
        // will return null until the operation is completed
        return targetModuleIDs;
    }
    
//    /**
//     * initialize the target module IDs with the passed application moduleID
//     * and the descriptors
//     */
//    protected void initializeTargetModuleIDs(String moduleID) {
//        TargetModuleIDImpl parentTargetModuleID = new TargetModuleIDImpl(target, moduleID);        
//        
//        targetModuleIDs = new TargetModuleIDImpl[1];        
//        targetModuleIDs[0] = parentTargetModuleID;
//    }
//
//    /**
//     * Initialize the target module IDs with the application information stored
//     * in the DeploymentStatus for all the server in the target list.
//     */
//    protected void initializeTargetModuleIDForAllServers(
//        DFDeploymentStatus status) {
//
//        if(targetsList == null) {
//            return;
//        }
//
//        targetModuleIDs = new TargetModuleIDImpl[targetsList.length];
//        String tmpModuleID = status == null 
//                        ? this.moduleID : status.getProperty(MODULE_ID);
//        String key = tmpModuleID + KEY_SEPARATOR + MODULE_TYPE;
//        ModuleType type = status == null
//                        ? getModuleType()
//                        : ModuleType.getModuleType((new Integer(status.getProperty(key))).intValue());
//
//        for(int i=0; itrue if canceling an
     *         activity is supported by this platform.
     */
    public boolean isCancelSupported() {
        return false;
    }
    
    /** Tests whether the vendor supports a stop
     * opertation for deployment activities.
     *
     * @return true if canceling an
     *         activity is supported by this platform.
     */
    public boolean isStopSupported() {
        return false;
    }
    
    /** Remove a ProgressObject listener.
     *
     * @param The listener being removed
     * @see ProgressEvent
     */
    public void removeProgressListener(ProgressListener pol) {
	synchronized (listeners) {
            listeners.remove(pol);
	}
    }
    
    /** (optional)
     * A stop request on an in-process operation allows the
     * operation on the current TargetModuleID to run to completion but
     * does not process any of the remaining unprocessed TargetModuleID
     * objects.  The processed TargetModuleIDs must be returned by the
     * method getResultTargetModuleIDs.
     *
     * @throws OperationUnsupportedException this optional command
     *         is not supported by this implementation.
     */
    public void stop() throws OperationUnsupportedException {
        throw new OperationUnsupportedException("stop not supported");
    }

    
    public void setCommand(CommandType commandType, Object[] args) {
        this.commandType = commandType;
        this.args = args;
    }
    
    /**
     * Notifies all listeners that have registered interest for ProgressEvent notification. 
     */
    protected void fireProgressEvent(ProgressEvent progressEvent) {
        /*
         *Bug 4977764
         *Iteration failed due to concurrent modification of the vector.  Even though the add, remove, and fire 
         *methods synchronize on the listeners vector, a listener could conceivably invoke add or remove 
         *recursively, thereby triggering the concurrent modification exception.
         *
         *Fix: clone the listeners vector and iterate through the clone.  
         */
	Vector currentListeners = null;
        synchronized (listeners) {
            currentListeners = (Vector) listeners.clone();
            /*
             *The following add must remain inside the synchronized block.  Otherwise, there will be a small window
             *in which a new listener's registration could interleave with fireProgressEvent, registering itself 
             *after the listeners vector had been cloned (thus excluding the new listener from the iteration a
             *few lines below) but before the list of previously-delivered events had been updated.  
             *This would cause the new listener to miss the event that was firing.  
             *Keeping the following add inside the synchronized block ensures that updates to the listeners 
             *vector by addProgressListener and to deliveredEvents by fireProgressEvent do not interleave and therefore
             *all listeners will receive all events.
             */
            
            deliveredEvents.add(progressEvent);
        }

        for (Iterator listenersItr = currentListeners.iterator(); listenersItr.hasNext();) {
            ((ProgressListener)listenersItr.next()).handleProgressEvent(progressEvent);
        }
        currentListeners = null;
    }


    /**
     * Notifies all listeners that have registered interest for ProgressEvent notification. 
     */
    protected void fireProgressEvent(StateType state, String message) {
        fireProgressEvent(state, message, target);
    }

    /**
     * Notifies all listeners that have registered interest for ProgressEvent notification. 
     */
    protected void fireProgressEvent(StateType state, String message, TargetImpl aTarget) {
        
        StateType stateToBroadcast = (state != null) ? state : deploymentStatus.getState();

        /* new copy of DeploymentStatus */
	DeploymentStatusImpl depStatus = new DeploymentStatusImpl(this);
	depStatus.setState(stateToBroadcast);
        depStatus.setMessage(message);

        /*
         *Update this progress object's status before notifying listeners.
         */
        if (state != null) {
            deploymentStatus.setMessage(message);
            deploymentStatus.setState(state); // retain current state
	}
        
        /* send notification */
	TargetModuleIDImpl tmi = new TargetModuleIDImpl(aTarget, moduleID);
	fireProgressEvent(new ProgressEvent(this, tmi, depStatus));
    }

    CommandType getCommandType() {
        return commandType;
    }
    
    /**
     * Sets the module type for this deployed module
     * @param the module type
     */
    public void setModuleType(ModuleType moduleType) {
        this.moduleType = moduleType;
    }
    
    /**
     * @return the module type of this deployed module
     */ 
    public ModuleType getModuleType() {
        return moduleType;
    }    

    /**
     * Since DeploymentStatus only provides the ability to pass a String to the
     * ProgressListener, the following is a convenience method for allowing the
     * stack-trace from a Throwable to be converted to a String to send to the
     * ProgressListeners.
     */
    protected String getThrowableString(Throwable t) {
	ByteArrayOutputStream bos = new ByteArrayOutputStream();
	PrintStream ps = new PrintStream(bos);
	t.printStackTrace(ps);
	ps.close(); // may not be necessary
	return bos.toString();
    }
    
    protected static final String APPS_CONFIGMBEAN_OBJNAME =
                                  "com.sun.appserv:type=applications,category=config";    

    protected String getDeploymentStatusMessage(DFDeploymentStatus status) {
        return getDeploymentStatusMessage(status, false);
    }
    /**
     * Parse the DeploymentStatus to get the status message within
     */
    protected String getDeploymentStatusMessage(DFDeploymentStatus status, boolean isStartPhase) {
        if(status == null) {
            return null;
        }
        // if stage status is success, return as it is
        if (status!=null && DFDeploymentStatus.Status.SUCCESS.isWorseThan(status.getStatus())) {
            return null;
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(bos);
        DFDeploymentStatus.parseDeploymentStatus(status, pw);
        byte[] statusBytes = bos.toByteArray();
        String statusString = new String(statusBytes);
        // if stage status is WARNING, collect the warning messages
        if(status.getStatus() == DFDeploymentStatus.Status.WARNING) {
            if(warningMessages==null) {
                warningMessages = WARNING_PREFIX + statusString;
            } else {
                warningMessages += statusString;
            }

            // add additional messages if it failed at loading.
            if (isStartPhase) { 
                warningMessages = localStrings.getLocalString(
                        "enterprise.deployment.client.start_failed_msg",
                        "Error occurred during application loading phase. The application will not run properly. Please fix your application and redeploy.\n") + warningMessages;
            }

            return null;
        }
        // Failed stage; return the failure message
        return statusString;
    }

    // XXX should be stricter than public
    public void setupForNormalExit(
            String message, 
            TargetImpl aTarget, 
            DFDeploymentStatus mainStatus,
            TargetModuleIDImpl[] tmids) {
//        String i18nmsg;
//        // If we ever got some warning during any of the stages, the the final status is warning; else status=success
//        if(warningMessages == null) {
//            i18nmsg = localStrings.getLocalString(
//                    "enterprise.deployment.client.action_completed",
//                    "{0} completed successfully",
//                    message);
//            finalDeploymentStatus.setStageStatus(DFDeploymentStatus.Status.SUCCESS);
//        } else {
//            i18nmsg = localStrings.getLocalString(
//                    "enterprise.deployment.client.action_completed_with_warning", 
//                    warningMessages);
//            finalDeploymentStatus.setStageStatus(DFDeploymentStatus.Status.WARNING);            
//        }
//        finalDeploymentStatus.setStageStatusMessage(i18nmsg);
        deployActionCompleted = true;
        finalDeploymentStatus = mainStatus;
        targetModuleIDs = tmids;
//        fireProgressEvent(StateType.COMPLETED, i18nmsg, aTarget);
        for (TargetModuleIDImpl tmid : tmids) {
            fireProgressEvent(StateType.COMPLETED, message, tmid.getTargetImpl());
        }
        return;
    }
    
    // XXX should be stricter than public
    public void setupForAbnormalExit(String errorMsg, TargetImpl aTarget, DFDeploymentStatus mainStatus) {
//        String i18nmsg = localStrings.getLocalString(
//                "enterprise.deployment.client.action_failed", 
//                errorMsg);
//        finalDeploymentStatus.setStageStatus(DFDeploymentStatus.Status.FAILURE);
//        finalDeploymentStatus.setStageStatusMessage(i18nmsg);
        
        deployActionCompleted = true;
        finalDeploymentStatus = mainStatus;
//        fireProgressEvent(StateType.FAILED, i18nmsg, aTarget);
        fireProgressEvent(StateType.FAILED, errorMsg, aTarget);
        return;
    }

    private DFDeploymentStatus preSetupForAbnormalExit(String errorMsg) {
        String i18nmsg = localStrings.getLocalString(
                "enterprise.deployment.client.action_failed", 
                "Action failed {0}",
                errorMsg);
        DFDeploymentStatus result = new DFDeploymentStatus();
        result.setStageStatus(DFDeploymentStatus.Status.FAILURE);
        result.setStageStatusMessage(i18nmsg);
        
        deployActionCompleted = true;
        return result;
    }
    
    // XXX should be stricter than public
    public void setupForAbnormalExit(String errorMsg, TargetImpl aTarget) {
        finalDeploymentStatus = preSetupForAbnormalExit(errorMsg);
        fireProgressEvent(StateType.FAILED, finalDeploymentStatus.getStageStatusMessage(), aTarget);
        return;
    }

    // XXX should be stricter than public
    public void setupForAbnormalExit(String errorMsg, TargetImpl aTarget, Throwable th) {
        finalDeploymentStatus = preSetupForAbnormalExit(errorMsg);
        finalDeploymentStatus.setStageException(th);
        fireProgressEvent(StateType.FAILED, finalDeploymentStatus.getStageStatusMessage(), aTarget);
        return;
    }

//    public boolean checkStatusAndAddStage(TargetImpl aTarget, /* RollBackAction rollback,*/ String action, /* ConnectionSource dasConnection, */ DFDeploymentStatus currentStatus) {
//        return checkStatusAndAddStage(aTarget, /* rollback, */ action, /* dasConnection, */
//            currentStatus, false);
//    }

//    /**
//     * Given a Deployment status, this checks if the status is success
//     * If the status is failed, it tries roll back operations (if rollback is specified) and then sets up
//     * for an abnormal exit
//     */
//    public boolean checkStatusAndAddStage(TargetImpl aTarget, /* RollBackAction rollback, */ String action, /* ConnectionSource dasConnection, */ DFDeploymentStatus currentStatus, boolean isStartPhase) {
//        String statusMsg = getDeploymentStatusMessage(currentStatus, 
//            isStartPhase);
//        finalDeploymentStatus.addSubStage(currentStatus);
//        if(statusMsg == null) {
//            fireProgressEvent(StateType.RUNNING,
//                                localStrings.getLocalString(
//                                    "enterprise.deployment.client.action_completed", 
//                                    "{0} completed successfully",
//                                    action),
//                                aTarget);
//            return true;
//        }
////        if(rollback != null) {
////            DFDeploymentStatus tmp = new
////                        DFDeploymentStatus();
////            if(!rollback.rollback(dasConnection, tmp)) {
////                fireProgressEvent(StateType.RUNNING, 
////                                localStrings.getString("enterprise.deployment.client.action_failed", "Rollback failed"),
////                                        aTarget);
////                tmp.setStageStatus(DFDeploymentStatus.FAILURE);
////                tmp.setStageStatusMessage(localStrings.getString("enterprise.deployment.client.action_failed", "Rollback failed"));
////            } else {
////                fireProgressEvent(StateType.RUNNING, 
////                                localStrings.getString("enterprise.deployment.client.action_completed", "Rollback"),
////                                        aTarget);
////                tmp.setStageStatus(DFDeploymentStatus.SUCCESS);
////                tmp.setStageStatusMessage(localStrings.getString("enterprise.deployment.client.action_completed", "Rollback"));
////            }
////            finalDeploymentStatus.addSubStage(tmp);
////        }
//        setupForAbnormalExit(localStrings.getLocalString(
//                    "enterprise.deployment.client.action_failed_with_message",
//                    "{0} failed; {1}",
//                    action, 
//                    statusMsg),
//                aTarget);
//        return false;
//    }
    
    public DFDeploymentStatus waitFor() {
        DFDeploymentStatus status = null;
        do {
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException ie) {
                // Exception swallowed deliberately
            }
            status = getCompletedStatus();
        } while(status == null);
        return status;
        
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy