Package com.salesforce.ide.core.services

Source Code of com.salesforce.ide.core.services.DeployResultAdapter

/*******************************************************************************
* Copyright (c) 2014 Salesforce.com, inc..
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Salesforce.com, inc. - initial API and implementation
******************************************************************************/
package com.salesforce.ide.core.services;

import java.io.IOException;
import java.util.Date;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IProgressMonitor;

import com.salesforce.ide.api.metadata.MetadataDebuggingInfoHandler;
import com.salesforce.ide.core.internal.utils.DialogUtils;
import com.salesforce.ide.core.internal.utils.ForceExceptionUtils;
import com.salesforce.ide.core.internal.utils.Messages;
import com.salesforce.ide.core.internal.utils.OperationStats;
import com.salesforce.ide.core.internal.utils.Utils;
import com.salesforce.ide.core.internal.utils.ZipUtils;
import com.salesforce.ide.core.model.ProjectPackage;
import com.salesforce.ide.core.model.ProjectPackageList;
import com.salesforce.ide.core.remote.Connection;
import com.salesforce.ide.core.remote.ForceConnectionException;
import com.salesforce.ide.core.remote.ForceRemoteException;
import com.salesforce.ide.core.remote.InsufficientPermissionsException;
import com.salesforce.ide.core.remote.MetadataStubExt;
import com.salesforce.ide.core.remote.metadata.DeployMessageExt;
import com.salesforce.ide.core.remote.metadata.DeployResultExt;
import com.salesforce.ide.core.remote.metadata.DescribeMetadataResultExt;
import com.sforce.soap.metadata.AsyncResult;
import com.sforce.soap.metadata.DeployOptions;
import com.sforce.soap.metadata.DeployResult;
import com.sforce.soap.metadata.DeployStatus;
import com.sforce.soap.metadata.LogInfo;

public class PackageDeployService extends BasePackageService {
    private static final Logger logger = Logger.getLogger(PackageDeployService.class);

    private static OperationStats operationStats;

    private static final String OPERATION = "Deploy";

    public PackageDeployService() {
        operationStats = new OperationStats(OPERATION);
    }

    public static OperationStats getOperationStats() {
        return operationStats;
    }

    /**
     * Get deploy option for validate deployment (checkOnly) and true deployment (not checkOnly).
     *
     * @param checkOnly
     *
     * @return
     * @throws ForceConnectionException
     */
    public DeployOptions getDeployOptions(boolean checkOnly) throws ForceConnectionException {
        DeployOptions deployOptions = makeDefaultDeployOptions(checkOnly);
        deployOptions.setRollbackOnError(true);
        deployOptions.setAutoUpdatePackage(false);
        deployOptions.setPerformRetrieve(false);
        deployOptions.setRunAllTests(false);
        return deployOptions;
    }

    public DeployOptions getRunTestDeployOptions(String[] tests) {
        DeployOptions deployOptions = makeDefaultDeployOptions(true);
        deployOptions.setPerformRetrieve(false);

        if (Utils.isNotEmpty(tests)) {
            deployOptions.setRunTests(tests);
            if (logger.isDebugEnabled()) {
                logger.debug("Running the following tests:\n");
                for (String test : tests) {
                    logger.debug("  " + test);
                }
            }
        }

        return deployOptions;
    }

    public DeployOptions makeDefaultDeployOptions(boolean checkOnly) {
        DeployOptions deployOptions = new DeployOptions();
        // tell deploy to ignore missing files.  this will save on the one component
        deployOptions.setAllowMissingFiles(true);
        // if successful, return refreshed component
        deployOptions.setPerformRetrieve(true);
        // send back update package manifest too
        deployOptions.setAutoUpdatePackage(true);
        // oh and, if other components don't comply (fail to compile, failed tests, etc), save the ones that do comply
        // REVIEWME: apparently the api only handles test failures.  so, if one component fails
        //   to compile (for example, the whole lot will fail to save).
        deployOptions.setRollbackOnError(true);
        deployOptions.setCheckOnly(checkOnly);
        deployOptions.setRunAllTests(false);
        deployOptions.setSinglePackage(true);
        return deployOptions;
    }

    public DeployResultExt deploy(ProjectPackageList projectPackageList, IProgressMonitor monitor)
            throws ServiceException, ForceRemoteException, InterruptedException, ForceConnectionException {
        if (Utils.isEmpty(projectPackageList) || projectPackageList.getProject() == null) {
            throw new IllegalArgumentException("Project and/or project package list cannot be null");
        }
        Connection connection = getConnectionFactory().getConnection(projectPackageList.getProject());
        return deploy(connection, projectPackageList, monitor);
    }

    public DeployResultExt deploy(ProjectPackageList projectPackageList, IProgressMonitor monitor, DeployOptions options)
            throws ServiceException, ForceRemoteException, InterruptedException, ForceConnectionException {
        if (Utils.isEmpty(projectPackageList) || projectPackageList.getProject() == null) {
            throw new IllegalArgumentException("Project and/or project package list cannot be null");
        }
        Connection connection = getConnectionFactory().getConnection(projectPackageList.getProject());
        return deploy(connection, projectPackageList, options, monitor);
    }

    public DeployResultExt deploy(Connection connection, ProjectPackageList projectPackageList, IProgressMonitor monitor)
            throws ServiceException, ForceRemoteException, InterruptedException, ForceConnectionException {
        if (connection == null || Utils.isEmpty(projectPackageList)) {
            throw new IllegalArgumentException("Connection and/or project package list cannot be null");
        }

        DeployOptions deployOptions = makeDefaultDeployOptions(false);
        return deploy(connection, projectPackageList, deployOptions, monitor);
    }

    DeployResultExt deploy(Connection connection, ProjectPackageList projectPackageList, DeployOptions deployOptions,
            IProgressMonitor monitor) throws ServiceException, ForceRemoteException, InterruptedException {
        return deploy(connection, projectPackageList, deployOptions, null, true, monitor);
    }

    public DeployResultExt deploy(Connection connection, byte[] zipFile, IProgressMonitor monitor)
            throws ServiceException, ForceRemoteException, InterruptedException, ForceConnectionException {
        if (connection == null || Utils.isEmpty(zipFile)) {
            throw new IllegalArgumentException("Connection and/or file zip cannot be null");
        }

        DeployOptions deployOptions = makeDefaultDeployOptions(false);
        return deploy(connection, zipFile, deployOptions, null, monitor);
    }

    public DeployResultExt deploy(Connection connection, ProjectPackageList projectPackageList,
            DeployOptions deployOptions, LogInfo[] logInfos, boolean adjust, IProgressMonitor monitor)
            throws ServiceException, ForceRemoteException, InterruptedException {
        DeployResultExt deployResultExt =
                deployWork(connection, getZip(projectPackageList), deployOptions, logInfos, adjust, monitor);

        deployResultExt.getRetrieveResultHandler().setProjectPackageList(projectPackageList);
        return deployResultExt;
    }

    public DeployResultExt deployDelete(ProjectPackageList projectPackageList, boolean checkOnly,
            IProgressMonitor monitor) throws ServiceException, ForceRemoteException, InterruptedException,
            ForceConnectionException {
        if (Utils.isEmpty(projectPackageList) || projectPackageList.getProject() == null) {
            throw new IllegalArgumentException("Project and/or project package list cannot be null");
        }
        Connection connection = getConnectionFactory().getConnection(projectPackageList.getProject());
        return deployDelete(connection, projectPackageList, checkOnly, monitor);
    }

    public DeployResultExt deployDelete(Connection connection, ProjectPackageList projectPackageList,
            boolean checkOnly, IProgressMonitor monitor) throws ServiceException, ForceRemoteException,
            InterruptedException {
        DeployOptions deployOptions = makeDefaultDeployOptions(checkOnly);
        // set autoUpdatePackage and PerformRetrieve to true for retreiving updated package.xml
        // W-632267
        deployOptions.setAutoUpdatePackage(true);
        deployOptions.setPerformRetrieve(true);
        DeployResultExt deployResultExt =
                deploy(connection, getZip(projectPackageList, true), deployOptions, null, monitor);
        deployResultExt.getRetrieveResultHandler().setProjectPackageList(projectPackageList);
        return deployResultExt;
    }

    public DeployResultExt deploy(Connection connection, byte[] zipFile, DeployOptions deployOptions,
            LogInfo[] logInfos, IProgressMonitor monitor) throws ServiceException, ForceRemoteException,
            InterruptedException {
        return deployWork(connection, zipFile, deployOptions, logInfos, true, monitor);
    }

    public DeployResultExt getDeployResult(DeployResultExt deployResultExt, AsyncResult asyncResult,
            MetadataStubExt metadataStubExt, IProgressMonitor monitor) throws ServiceTimeoutException,
            ServiceException, ForceRemoteException, ForceRemoteException, InterruptedException {
        if (metadataStubExt == null) {
            throw new IllegalArgumentException("MetadataStubExt cannot be null");
        }

        DeployResult deployResult;
        try {
            IFileBasedResultAdapter result =
                    waitForResult(new DeployResultAdapter(asyncResult, metadataStubExt), metadataStubExt,
                        operationStats, monitor);
            deployResult = ((DeployResultAdapter) result).getDeployResult();
        } catch (ServiceTimeoutException ex) {
            ex.setMetadataResultExt(deployResultExt);
            throw ex;
        }

        monitorCheckSubTask(monitor, "Preparing results...");

        if (logger.isDebugEnabled()) {
            logger.debug("Received deploy() result at " + (new Date()).toString());
        }

        // REVIEWME: should we create an empty wrapper?
        if (deployResultExt == null) {
            deployResultExt = new DeployResultExt();
        }

        deployResultExt.setDeployResult(deployResult);
        deployResultExt.setDebugLog(MetadataDebuggingInfoHandler.getDebugLog());

        monitorWork(monitor);

        // log results
        logResult(deployResultExt);

        return deployResultExt;
    }

    public DeployResultExt handleDeployServiceTimeoutException(ServiceTimeoutException ex, String operation,
            IProgressMonitor monitor) throws InterruptedException, ServiceException, ForceRemoteException,
            InsufficientPermissionsException {

        // REVIEW: ui-stuff (dialog to continue) should be handled outside of services  -cwall 09/2//09
        boolean proceed = DialogUtils.getInstance().presentCycleLimitExceptionDialog(ex, monitor);
        if (proceed) {
            try {
                return getPackageDeployService().getDeployResult((DeployResultExt) ex.getMetadataResultExt(),
                    ex.getAsyncResult(), ex.getMetadataStubExt(), monitor);
            } catch (ServiceTimeoutException e) {
                return handleDeployServiceTimeoutException(e, operation, monitor);
            }
        }
        throw new InterruptedException("User canceled " + operation + " due to cycle polling limits reached: "
                + ex.getMessage());
    }

    // workhorse for deploying
    private DeployResultExt deployWork(Connection connection, byte[] zipFile, DeployOptions deployOptions,
            LogInfo[] logInfos, boolean adjust, IProgressMonitor monitor) throws ServiceException,
            ForceRemoteException, InterruptedException {
        if (connection == null || Utils.isEmpty(zipFile)) {
            throw new IllegalArgumentException("Connection and/or zip file name cannot be null");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("");
            logger.debug("***   D E P L O Y   P A C K A G E ( S )   ***");
        }

        monitorCheck(monitor);

        DeployResultExt deployResultHandler = new DeployResultExt();

        // log deployment details
        logDeploy(connection, zipFile, deployOptions);

        try {
            // prepare deployment stub
            MetadataStubExt metadataStubExt = getMetadataFactory().getMetadataStubExt(connection);
            metadataStubExt.setMetadataDebugHeader(logInfos);

            if (adjust) {
                // adjust deploy options based on org settings
                adjustDeployOptions(metadataStubExt, deployOptions, monitor);
            }

            monitorCheckSubTask(monitor, "Deploying components...");

            // call deploy and wait for response
            if (logger.isDebugEnabled()) {
                logger.debug("Calling deploy() at " + (new Date()).toString());
            }

            AsyncResult asyncResult = metadataStubExt.deploy(zipFile, deployOptions);
            monitorWork(monitor);

            // get async result
            deployResultHandler = getDeployResult(deployResultHandler, asyncResult, metadataStubExt, monitor);

        } catch (InterruptedException e) {
            throw e;
        } catch (ServiceTimeoutException e) {
            throw e;
        } catch (InsufficientPermissionsException e) {
            throw e;
        } catch (ServiceException e) {
            logger.warn("Unable to retrieve components: " + ForceExceptionUtils.getRootCauseMessage(e));
            throw new DeployException(e, connection, zipFile, deployOptions, logInfos);
        } catch (Exception e) {
            logger.error("Unable to retrieve components: " + ForceExceptionUtils.getRootCauseMessage(e));
            throw new DeployException(e, connection, zipFile, deployOptions, logInfos);
        }

        return deployResultHandler;
    }

    private void adjustDeployOptions(MetadataStubExt metadataStubExt, DeployOptions deployOptions,
            IProgressMonitor monitor) throws ForceConnectionException, ForceRemoteException, InterruptedException {
        DescribeMetadataResultExt describeMetadataResultExt =
                getMetadataService().getDescribeMetadata(metadataStubExt, monitor);
        // assume that org is prod
        if (describeMetadataResultExt.isPartialSaveAllowed()) {
            deployOptions.setRollbackOnError(false);
            if (logger.isDebugEnabled()) {
                logger.debug("Partial save is allowed - rollback on error set to false");
            }
        } else {
            deployOptions.setRollbackOnError(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Partial save is not allowed - rollback on error set to true");
            }
        }
    }

    protected byte[] getZip(Object obj) throws DeployException {
        return getZip(obj, false);
    }

    private byte[] getZip(Object obj, boolean manifestsOnly) throws DeployException {
        byte[] zip = null;
        try {
            if (obj instanceof ProjectPackageList) {
                zip = ((ProjectPackageList) obj).getZip(manifestsOnly);
            } else if (obj instanceof ProjectPackage) {
                zip = ((ProjectPackage) obj).getZip(manifestsOnly);
            } else {
                logger.warn("Do not know how to get zip from unknown object type");
            }
        } catch (IOException e) {
            logger.error("Unable to get zip", e);
            throw new DeployException("Unable to get zip", e);
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Got zip file of size [" + (Utils.isNotEmpty(zip) ? zip.length : null)
                    + "] for project package");
        }

        return zip;
    }

    private void logDeploy(Connection connection, byte[] zipFile, DeployOptions deployOptions) {
        if (logger.isDebugEnabled()) {
            logger.debug("Deploying to " + connection.getLogDisplay());

            String filePathLog = getFilePathLog("Deploying the following components", zipFile);
            logger.debug(filePathLog);

            if (deployOptions != null) {
                StringBuffer strBuff = new StringBuffer("Deploy options:");
                strBuff.append("\n  Check only = " + deployOptions.isCheckOnly())
                        .append("\n  Single package = " + deployOptions.isSinglePackage())
                        .append("\n  Run all tests = " + deployOptions.isRunAllTests())
                        .append("\n  Update package manifest = " + deployOptions.isAutoUpdatePackage())
                        .append("\n  Save w/ missing files = " + deployOptions.isAllowMissingFiles())
                        .append("\n  Rollback on error = " + deployOptions.isRollbackOnError())
                        .append("\n  Perform retrieve = " + deployOptions.isPerformRetrieve());
                logger.debug(strBuff.toString());
                if (Utils.isNotEmpty(deployOptions.getRunTests())) {
                    String[] tests = deployOptions.getRunTests();
                    strBuff = new StringBuffer("Deploy options set to run the following tests");
                    int testCnt = 0;
                    for (String test : tests) {
                        strBuff.append("\n (").append(++testCnt).append(") ").append(test);
                    }
                    logger.debug("\n" + strBuff.toString());
                }
            } else {
                logger.debug("Deploy options not set");
            }
        } else if (logger.isInfoEnabled()) {
            logger.info("Deploying to " + connection.getLogDisplay());
            String filePathLog = getFilePathLog("Deploying the following components", zipFile);
            logger.info(filePathLog);
        }
    }

    private void logResult(DeployResultExt deployResultHandler) {
        if (logger.isDebugEnabled()) {
            // write zip to f/s
            String filePathLog = null;
            if (deployResultHandler.getRetrieveResultHandler() != null) {
                byte[] zipFile = deployResultHandler.getRetrieveResultHandler().getZipFile();
                filePathLog = getFilePathLog("Deployed returned the following components:", zipFile);
                if (Utils.isNotEmpty(zipFile)) {
                    ZipUtils.writeRetrieveZipToTempDir(zipFile);
                }
            }
            logger.debug(filePathLog);

            // log deploy messages
            DeployMessageExt messageHandler = deployResultHandler.getMessageHandler();
            if (messageHandler != null) {
                messageHandler.logMessage();
            }

            // log api log
            if (deployResultHandler.getDeployResult() != null) {
                logger.debug("Metadata debug log:\n"
                        + (Utils.isNotEmpty(deployResultHandler.getDebugLog()) ? deployResultHandler.getDebugLog()
                                : "n/a"));
            }
        } else if (logger.isInfoEnabled()) {
            DeployMessageExt messageHandler = deployResultHandler.getMessageHandler();
            if (messageHandler != null) {
                messageHandler.logMessage();
            }
        }

    }
}

/**
* Adapts the DeployResult to our common interface.
*
* @author nchen
*
*/
class DeployResultAdapter implements IFileBasedResultAdapter {

    private AsyncResult asyncResult;
    private DeployResult deployResult;
    private MetadataStubExt metadataStubExt;

    public DeployResultAdapter(AsyncResult asyncResult, MetadataStubExt metadataStubExt) {
        this.asyncResult = asyncResult;
        this.metadataStubExt = metadataStubExt;
    }

    @Override
    public AsyncResult getAsyncResult() {
        return asyncResult;
    }

    @Override
    public IFileBasedResultAdapter checkStatus() throws ForceRemoteException {
        deployResult = metadataStubExt.checkDeployStatus(asyncResult.getId());
        return this;
    }

    @Override
    public boolean isDone() {
        return deployResult.isDone();
    }

    @Override
    public boolean isFailure() {
        return deployResult.getStatus().equals(DeployStatus.Failed) && deployResult.getErrorStatusCode() != null;
    }

    @Override
    public String logFailure(Logger logger) {
        StringBuffer strBuff =
                new StringBuffer().append(deployResult.getErrorStatusCode()).append(" (")
                        .append(deployResult.getErrorMessage()).append(")");
        logger.warn("Deploy or retrieve operation to '" + metadataStubExt.getServerName() + "' failed: "
                + strBuff.toString());
        return strBuff.toString();
    }

    @Override
    public String logResult(Logger logger, OperationStats operationStats) {
        StringBuffer errorMessageBuffer = new StringBuffer();

        errorMessageBuffer.append("\n'Operation' [Total count :Error count :Success count]\n").append("'")
                .append(operationStats.getOperationName()).append("' Components [")
                .append(deployResult.getNumberComponentsTotal()).append(":")
                .append(deployResult.getNumberComponentErrors()).append(":")
                .append(deployResult.getNumberComponentsDeployed()).append("] Tests : [")
                .append(deployResult.getNumberTestsTotal()).append(":").append(deployResult.getNumberTestErrors())
                .append(":").append(deployResult.getNumberTestsCompleted()).append("]").append("\nState Detail : ")
                .append(deployResult.getStateDetail());

        logger.debug(errorMessageBuffer.toString());
        return errorMessageBuffer.toString();
    }

    @Override
    public String logStatus(Logger logger) {
        String status =
                "Deploy state is '" + deployResult.getStatus().toString() + "' for operation id '"
                        + asyncResult.getId() + "'";
        logger.debug(status);
        return status;
    }

    @Override
    public String retrieveRealTimeStatusUpdatesIfAny() {
        if (deployResult != null && deployResult.getStatus() != null) {
            return Messages.getString(
                "Deploy.ReportingStatus",
                new Object[] { deployResult.getStatus(), deployResult.getNumberComponentsDeployed(),
                        deployResult.getNumberComponentsTotal(), new Date() });
        }
        return Messages.getString("PackageService.Polling", new Object[] { metadataStubExt.getServerName() });
    }

    public DeployResult getDeployResult() {
        return deployResult;
    }
}
TOP

Related Classes of com.salesforce.ide.core.services.DeployResultAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.