Package com.salesforce.ide.upgrade.internal

Source Code of com.salesforce.ide.upgrade.internal.UpgradeController

/*******************************************************************************
* 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.upgrade.internal;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import javax.xml.bind.UnmarshalException;

import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.progress.IProgressService;

import com.salesforce.ide.api.metadata.types.MetadataExt;
import com.salesforce.ide.api.metadata.types.MetadataValidationEventCollector;
import com.salesforce.ide.api.metadata.types.Package;
import com.salesforce.ide.core.ForceIdeCorePlugin;
import com.salesforce.ide.core.factories.FactoryException;
import com.salesforce.ide.core.internal.context.ContainerDelegate;
import com.salesforce.ide.core.internal.controller.Controller;
import com.salesforce.ide.core.internal.utils.Constants;
import com.salesforce.ide.core.internal.utils.ForceExceptionUtils;
import com.salesforce.ide.core.internal.utils.Utils;
import com.salesforce.ide.core.model.Component;
import com.salesforce.ide.core.model.ComponentList;
import com.salesforce.ide.core.model.ProjectPackageList;
import com.salesforce.ide.core.project.ForceProject;
import com.salesforce.ide.core.project.ForceProjectException;
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.metadata.RetrieveResultExt;
import com.salesforce.ide.core.services.ServiceException;
import com.salesforce.ide.core.services.ServiceTimeoutException;
import com.salesforce.ide.upgrade.ForceIdeUpgradePlugin;
import com.salesforce.ide.upgrade.internal.ide.IInternalUpgrade;
import com.salesforce.ide.upgrade.project.UpgradeMarkerUtils;
import com.salesforce.ide.upgrade.project.UpgradeNature;

/**
* Handles upgrade analysis and related project and IDE upgrades.
*
* @author chris
*/
public class UpgradeController extends Controller {
    private static final Logger logger = Logger.getLogger(UpgradeController.class);

    private String installedIdeVersion = null;

    private ComponentList upgradeableComponentList = null;
    private List<String> excludeFileExtensions = null;
    private final List<IInternalUpgrade> ideInternalUpgrades = new ArrayList<IInternalUpgrade>();

    public UpgradeController() throws ForceProjectException, FactoryException {
        super();
        model = new UpgradeModel(ContainerDelegate.getInstance().getServiceLocator().getProjectService().getPlatformBrandName(), ContainerDelegate.getInstance().getServiceLocator().getProjectService().getIdeReleaseName(),
                ContainerDelegate.getInstance().getServiceLocator().getProjectService().getIdeBrandName());

        installedIdeVersion = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getInstalledIdeVersion();

        upgradeableComponentList = new ComponentList();
                             
        String[] upgradableTypes = new String[] {
            Constants.APEX_CLASS,
            Constants.APEX_COMPONENT,
            Constants.APEX_PAGE,
            Constants.APEX_TRIGGER,
            Constants.CUSTOM_OBJECT,
            Constants.CUSTOM_OBJECT_TRANSLATION,
            Constants.CUSTOM_SITE,
            Constants.CUSTOM_TAB,           
            Constants.DASHBOARD,
            Constants.DOCUMENT,
            Constants.DATACATEGORYGROUP,
            Constants.EMAIL_TEMPLATE,           
            Constants.LAYOUT,
            Constants.PROFILE,
            Constants.REPORT,
            Constants.RECORD_TYPE,
            Constants.WORKFLOW
        };
       
        for (String type : upgradableTypes) {
          upgradeableComponentList.add(ContainerDelegate.getInstance().getFactoryLocator().getComponentFactory().getComponentByComponentType(type));
        }
       
        excludeFileExtensions = new ArrayList<String>();
       
        String[] excludedFileExtensions = new String[] {
            Constants.APEX_CLASS,
            Constants.APEX_COMPONENT,
            Constants.APEX_PAGE,
            Constants.APEX_TRIGGER,
            Constants.EMAIL_TEMPLATE           
        };
       
        for (String excludedExtension : excludedFileExtensions) {
            excludeFileExtensions.add(ContainerDelegate.getInstance().getFactoryLocator().getComponentFactory().getComponentByComponentType(excludedExtension)
                    .getFileExtension());         
        }
    }

    // M E T H O D S
    @Override
    public void init() throws ForceProjectException {
    // not implemented
    }

    @Override
    public void setProject(IProject project) {
        getUpgradeModel().setProject(project);
        super.setProject(project);
    }

    public UpgradeModel getUpgradeModel() {
        return (UpgradeModel)model;
    }

    public List<String> getExcludeFileExtensions() {
        return excludeFileExtensions;
    }

    public void setExcludeFileExtensions(List<String> excludeFileExtensions) {
        this.excludeFileExtensions = excludeFileExtensions;
    }

    public ComponentList getUpgradeableComponentList() {
        return upgradeableComponentList;
    }

    public void setUpgradeableComponentList(ComponentList upgradeableComponentList) {
        this.upgradeableComponentList = upgradeableComponentList;
    }

    public List<IInternalUpgrade> getIdeInternalUpgrades() {
        return ideInternalUpgrades;
    }

    public boolean addInternalUpgradeInstance(IInternalUpgrade internalUpgrade) {
        ideInternalUpgrades.add(internalUpgrade);
        sortIdeInternals();
        return true;
    }

    /**
     * Analyzes project content against release schema and corresponding remote content to determine component
     * upgradeability.
     *
     * @param monitor
     * @throws ForceConnectionException
     * @throws ForceRemoteException
     * @throws FactoryException
     * @throws ServiceException
     * @throws InterruptedException
     * @throws CoreException
     * @throws IOException
     */
    public void initConflicts(IProgressMonitor monitor) throws ForceConnectionException, ForceRemoteException,
            FactoryException, ServiceException, InterruptedException, CoreException, IOException {
     
        logStatus();
        initConflicts(monitor, model.getProject());
    }

  public void initConflicts(IProgressMonitor monitor, IProject project)
      throws InterruptedException, CoreException, FactoryException,
      ForceConnectionException, ForceRemoteException, ServiceException,
      IOException {
    // if not components are noted for upgrade in this release, then there's no metadata to upgrade
        if (Utils.isEmpty(upgradeableComponentList)) {
            if (logger.isInfoEnabled()) {
                logger.info("No component types upgrade-able for " + installedIdeVersion + "version");
            }
            return;
        }

        // get local and remote components
        monitorCheckSubTask(monitor, "Gathering project contents");
        List<String> componentTypes = upgradeableComponentList.getComponentTypes();       
    ProjectPackageList localProjectPackageList = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getComponentsForComponentTypes(
                project, componentTypes.toArray(new String[componentTypes.size()]));
        monitorWork(monitor);

        if (Utils.isEmpty(localProjectPackageList.getAllComponents(false))) {
            if (logger.isInfoEnabled()) {
                logger.info("Project is empty - nothing to upgrade");
            }
            return;
        }

        monitorCheckSubTask(monitor, "Retrieving remote content for upgrade analysis");
        ProjectPackageList remoteProjectPackageList = getRemoteProjectPackageList(localProjectPackageList,
                new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN));
        monitorWork(monitor);

        if (Utils.isEmpty(localProjectPackageList)) {
            if (logger.isInfoEnabled()) {
                logger.info("Remote content empty - nothing to upgrade");
            }
            return;
        }

        // store to-be-upgrade components
        Map<String, List<UpgradeConflict>> upgradeConflicts = new HashMap<String, List<UpgradeConflict>>();

        monitorCheckSubTask(monitor, "Inspecting project contents for upgradeability");
        SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN);
        // upgrade inspection
        // upgradeability is determine by a straight diff of local vs. remote
        ComponentList localComponentList = localProjectPackageList.getAllComponents();
        for (Component localComponent : localComponentList) {
            if (!isIncludedComponent(localComponent) || isExcludedFileExtension(localComponent)
                    || localComponent.isPackageManifest()) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Excluding " + localComponent.getFullDisplayName() + " from upgrade consideration");
                }
                continue;
            }

            // upgrade analysis is a two phase process. if the first phase check, a xml validation against
            // current schema, passes, the second phase checks the local and remote checksum to determine difference.

            // if exist and has changed, store to be exposed in ui and later saved to project
            Component remoteComponent = remoteProjectPackageList.getComponentByFilePath(localComponent
                    .getMetadataFilePath());

            // phase 1 - validate xml against current schema
            MetadataValidationEventCollector metadataValidationEventCollector = new MetadataValidationEventCollector();
            MetadataExt metadataExt = null;
            try {
                metadataExt = localComponent.getMetadataExtFromBody(true, metadataValidationEventCollector);

                // if validation issues are found, we have a conflict
                if (metadataValidationEventCollector.hasValidationIssues()) {
                    if (metadataExt != null) {
                        metadataValidationEventCollector.logValidationMessages(metadataExt.getFullName());
                    }
                    // store conflict and continue to next bypassing phase two
                    addConflict(upgradeConflicts, localComponent, remoteComponent);

                    if (logger.isDebugEnabled()) {
                        logger.debug("Added " + localComponent.getFullDisplayName()
                                + " as upgrade consideration - schema validation failed");
                    }

                    monitorWork(subMonitor);
                    continue;
                }
            } catch (UnmarshalException e) {
                // sometimes, for some reason, parsing issues will throw an exception despite
                // MetadataValidationEventCollector.failOnValidateError used in
                // MetadataValidationEventCollector.handleEvent to capture parsing issues and enable recovery
                if (metadataExt != null) {
                    metadataValidationEventCollector.logValidationMessages(metadataExt.getFullName());
                }
                // store conflict and continue to next bypassing phase two
                addConflict(upgradeConflicts, localComponent, remoteComponent);

                if (logger.isDebugEnabled()) {
                    logger.debug("Added " + localComponent.getFullDisplayName()
                            + " as upgrade consideration - schema validation failed");
                }

                monitorWork(subMonitor);
                continue;
            } catch (Exception e) {
                logger.warn("Unable to parse and validate " + localComponent.getFullDisplayName()
                        + " - will continue to second phase inspection, content diff: "
                        + ForceExceptionUtils.getRootCauseMessage(e));
            }

            // phase 2 - local and remote checksum to determine difference find component in remote list
            if (remoteComponent != null && localComponent.hasEitherChanged(remoteComponent, monitor)) {
                addConflict(upgradeConflicts, localComponent, remoteComponent);

                if (logger.isDebugEnabled()) {
                    logger.debug("Added " + localComponent.getFullDisplayName()
                            + " as upgrade consideration - local file differs from remote");
                }
            }

            monitorWork(subMonitor);
        }
        monitorWork(monitor);

        // store upgrade components
        getUpgradeModel().setUpgradeConflicts(upgradeConflicts);
  }

  private void logStatus() {
    // log include component types and excluded file extensions
        if (logger.isDebugEnabled()) {
            StringBuffer strBuff = new StringBuffer(installedIdeVersion
                    + " version upgrades include the following component types:");
            int cnt = 0;
            if (Utils.isNotEmpty(upgradeableComponentList)) {
                for (Component upgradeableComponent : upgradeableComponentList) {
                    strBuff.append("\n  ").append("(").append(++cnt).append(") ").append(
                            upgradeableComponent.getComponentType());
                }
            } else {
                strBuff.append(" n/a");
            }
            logger.debug(strBuff.toString());

            strBuff = new StringBuffer(installedIdeVersion
                    + " version upgrades excludes the following file extensions:");
            cnt = 0;
            if (Utils.isNotEmpty(excludeFileExtensions)) {
                for (String excludeFileExtension : excludeFileExtensions) {
                    strBuff.append("\n  ").append("(").append(++cnt).append(") ").append(excludeFileExtension);
                }
            } else {
                strBuff.append(" n/a");
            }
            logger.debug(strBuff.toString());

        }
  }

    public boolean isIncludedComponent(Component component) {
      return ! component.getName().contains(Constants.UNFILED_PUBLIC_FOLDER_NAME);
    }

    public boolean isExcludedFileExtension(Component component) {
        IFile fileResource = component.getFileResource();
    if (Utils.isNotEmpty(excludeFileExtensions) && Utils.isNotEmpty(component.getFileName()) && fileResource != null) {
            String fileExtension = fileResource.getFileExtension();
      if (excludeFileExtensions.contains(fileExtension)) { return true; }
        }
        return false;
    }

    protected void addConflict(Map<String, List<UpgradeConflict>> upgradeConflicts, Component localComponent,
            Component remoteComponent) {
        if(null==localComponent || null==remoteComponent){
            return;
        }
       
        // set file resource to be saved over-top w/ remote instance
        remoteComponent.setFileResource(localComponent.getFileResource());

        // wrapper to contain local and remote
        UpgradeConflict upgradeConflict = new UpgradeConflict(localComponent, remoteComponent);

        // list containing components - remote and local - stored together by type
        List<UpgradeConflict> componetTypeUpgradeConflict = null;
        if (!upgradeConflicts.containsKey(localComponent.getComponentType())) {
            componetTypeUpgradeConflict = new ArrayList<UpgradeConflict>();
            upgradeConflicts.put(localComponent.getComponentType(), componetTypeUpgradeConflict);
        } else {
            componetTypeUpgradeConflict = upgradeConflicts.get(localComponent.getComponentType());
        }

        // add conflict to list
        componetTypeUpgradeConflict.add(upgradeConflict);
    }

    public boolean hasConflicts() {
        return getUpgradeModel().hasUpgradeComponents();
    }

    private ProjectPackageList getRemoteProjectPackageList(ProjectPackageList localProjectPackageList,
            IProgressMonitor monitor) throws ForceConnectionException, ForceRemoteException, FactoryException,
            ServiceException, InterruptedException, IOException {

        // declare return list
        ProjectPackageList remoteProjectPackageList = null;

        // update package manifest version to current ide version
        Package packageManifest = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getPackageManifestFactory().getPackageManifest(model.getProject());
        packageManifest.setVersion(installedIdeVersion);

        // remove existing, stored connection, change endpoint version, and get new connection
        ForceProject forceProject = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getForceProject(model.getProject());
        ContainerDelegate.getInstance().getFactoryLocator().getConnectionFactory().removeConnection(forceProject);
        ContainerDelegate.getInstance().getFactoryLocator().getMetadataFactory().removeMetadataStubExt(forceProject);
        ContainerDelegate.getInstance().getFactoryLocator().getToolingFactory().removeToolingStubExt(forceProject);
        forceProject.setEndpointApiVersion(installedIdeVersion);
        Connection connection = ContainerDelegate.getInstance().getFactoryLocator().getConnectionFactory().getConnection(forceProject);

        // perform retrieve
        RetrieveResultExt retrieveResultHandler = null;
        try {
            retrieveResultHandler = ContainerDelegate.getInstance().getServiceLocator().getPackageRetrieveService().retrieveSelective(connection,
                    localProjectPackageList, true, packageManifest, monitor);
        } catch (ServiceTimeoutException ex) {
            //FIXME: Best way to handle?
        }

        if (retrieveResultHandler == null) {
            logger.warn("Unable to get remote content - retrieve result is null");
            return remoteProjectPackageList;
        }

        monitorWork(monitor);

        remoteProjectPackageList = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getProjectPackageFactory().getProjectPackageListInstance();
        remoteProjectPackageList.setProject(model.getProject());
        remoteProjectPackageList.generateComponents(retrieveResultHandler.getZipFile(), retrieveResultHandler
                .getFileMetadataHandler(), monitor);

        return remoteProjectPackageList;
    }

    @Override
    public void dispose() {

    }

    @Override
    public void finish(IProgressMonitor monitor) throws Exception {
      if(monitor==null){
        monitor = new NullProgressMonitor();
      }

        IProgressService service = PlatformUI.getWorkbench().getProgressService();

        service.run(false, true, new WorkspaceModifyOperation() {
            @Override
            protected void execute(IProgressMonitor monitor) throws CoreException, InvocationTargetException,
                    InterruptedException {
              if(monitor==null){
                monitor = new NullProgressMonitor();
              }
                monitor.beginTask("", 3);
                try {

                    if (getUpgradeModel().hasUpgradeComponents()) {
                        monitorSubTask(monitor, "Upgrade project component(s)");

                        // temp turn off builder
                        ContainerDelegate.getInstance().getServiceLocator().getProjectService().flagSkipBuilder(model.getProject());

                        // upgrade components
                        Map<String, List<UpgradeConflict>> upgradedComponents = getUpgradeModel().getUpgradeConflicts();
                        Set<String> componentTypes = upgradedComponents.keySet();
                        for (String componentType : componentTypes) {
                            List<UpgradeConflict> upgradeConflicts = upgradedComponents.get(componentType);
                            for (UpgradeConflict upgradeConflict : upgradeConflicts) {
                                // save remove, upgraded component to project
                                upgradeConflict.getRemoteComponent().saveToFile(true,
                                        new SubProgressMonitor(monitor, IProgressMonitor.UNKNOWN));

                                // clear upgrade markers and any existing save marker
                                UpgradeMarkerUtils.clearAllUpgradeMarkers(upgradeConflict.getRemoteComponent()
                                        .getFileResource());

                                // handle associated composite resource, if applicable
                                if (upgradeConflict.getRemoteComponent().isMetadataComposite()) {
                                    IFile compositeFile = model.getProject().getFile(
                                            upgradeConflict.getRemoteComponent().getCompositeResourceFilePath());
                                    if (compositeFile != null && compositeFile.exists()) {
                                        UpgradeMarkerUtils.clearAllUpgradeMarkers(compositeFile);
                                    }

                                }
                            }

                        }

                        // upgrade package.xml version
                        Package packageManifest = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getPackageManifestFactory().getPackageManifest(model.getProject());
                        packageManifest.setVersion(installedIdeVersion);
                        IFile packageManifestFile = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getPackageManifestFactory().getPackageManifestFile(
                                model.getProject());
                        ContainerDelegate.getInstance().getServiceLocator().getProjectService().saveToFile(packageManifestFile, packageManifest.getXMLString(), monitor);

                        monitorWork(monitor);

                        monitorSubTask(monitor, "Refresh referenced packages(s)");
                        // upgrade install, managed content
                        upgradeManagedInstalledPackages(model.getProject(), new SubProgressMonitor(monitor,
                                IProgressMonitor.UNKNOWN));
                        monitorWork(monitor);
                    }

                    // upgrade any ide stuff
                    try {
                        upgradeIdeInternals();
                    } catch (Exception e) {
                        logger.warn("Unable to perform upgrade of ide internals: " + e.getMessage());
                        undoIdeInternals();
                        throw new InvocationTargetException(e);
                    }

                    // update ide version saved w/ project
                    ContainerDelegate.getInstance().getServiceLocator().getProjectService().updateIdeVersion(model.getProject());
                    if (logger.isDebugEnabled()) {
                        String installedIdeVersion = ForceIdeCorePlugin.getBundleVersion(true);
                        logger.debug("Upgrade project to version current ide version [" + installedIdeVersion + "]");
                    }

                    monitorSubTask(monitor, "Re-enabling project");
                    // remove upgrade nature and re-apply online nature
                    UpgradeNature.removeNature(model.getProject(), monitor);

                    // clear upgrade problem marker
                    UpgradeMarkerUtils.clearUpgradeRequiredMarker(model.getProject(), true);

                    monitorWork(monitor);
                } catch (InterruptedException e) {
                    throw e;
                } catch (InvocationTargetException e) {
                    throw e;
                } catch (Exception e) {
                    throw new InvocationTargetException(e);
                } finally {
                        monitor.done();
                }
            }
        });
    }

    // refresh installed managed packages
    protected boolean upgradeManagedInstalledPackages(IProject project, IProgressMonitor monitor)
            throws InterruptedException, ForceConnectionException, ForceRemoteException, FactoryException,
            CoreException, InvocationTargetException, IOException, ServiceException, Exception {
        if (project == null) { throw new IllegalArgumentException("Project cannot be null"); }

        if (logger.isInfoEnabled()) {
            logger.info("Fetching and saving all installed, managed components for '" + project.getName() + "'");
        }

        // set reference pkg folder contents to readonly=false so save of retrieve content
        // doesn't prompt with 'unable to write'
        IFolder referencePkgFolder = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getReferencedPackagesFolder(project);
        Utils.adjustResourceReadOnly(referencePkgFolder, false, true);

        monitorCheck(monitor);
        RetrieveResultExt retrieveResultHandler = null;
        try {
            retrieveResultHandler = ContainerDelegate.getInstance().getServiceLocator().getPackageRetrieveService().retrieveManagedInstalledPackages(
                    project, monitor);
        } catch (ServiceTimeoutException ex) {
            retrieveResultHandler = ContainerDelegate.getInstance().getServiceLocator().getPackageRetrieveService().handleRetrieveServiceTimeoutException(
                    ex, "upgrade resource(s)", monitor);
            if (retrieveResultHandler != null) {
                Connection connection = ContainerDelegate.getInstance().getFactoryLocator().getConnectionFactory().getConnection(project);
                ProjectPackageList projectPackageList = ContainerDelegate.getInstance().getServiceLocator().getProjectService().getProjectPackageFactory().getManagedInstalledProjectPackages(
                        connection);
                if (projectPackageList != null) {
                    projectPackageList.setProject(project);
                }
                retrieveResultHandler.setProjectPackageList(projectPackageList);
            }
        }

        if (retrieveResultHandler == null) {
            logger.warn("Unable to refresh installed packages - retrieve result is null");
            return false;
        }

        if (retrieveResultHandler.getZipFileCount() == 0) { return true; }

        if (Utils.isNotEmpty(retrieveResultHandler.getProjectPackageList())) {
            retrieveResultHandler.getProjectPackageList().setProject(project);
        }

        monitorCheck(monitor);
        return ContainerDelegate.getInstance().getServiceLocator().getProjectService().handleRetrieveResult(retrieveResultHandler.getProjectPackageList(),
                retrieveResultHandler, true, null, monitor);
    }

    /**
     * Execute upgrade method on each IDE internal upgrade class. Perform undo is upgrade unsuccessful.
     * REVIEWME: if one is not successful, fail all?
     *
     * @return
     */
    protected boolean upgradeIdeInternals() throws Exception {
        initIdeInterals();

        if (Utils.isNotEmpty(ideInternalUpgrades)) {
            for (IInternalUpgrade internalUpgrade : ideInternalUpgrades) {
                if (!internalUpgrade.upgrade()) {
                    internalUpgrade.undo();
                }
            }
        } else {
            if (logger.isInfoEnabled()) {
                logger.info("No internal IDE upgrades found for this release");
            }
        }

        return true;
    }

    /**
     * Discover and register IDE internal upgrade classes
     *
     * @throws Exception
     */
    protected void initIdeInterals() throws Exception {
        Class<?>[] tmpIdeUpgradeClasses = getInternalUpgradeClasses();
        if (Utils.isEmpty(tmpIdeUpgradeClasses)) { return; }

        for (Class<?> tmpClass : tmpIdeUpgradeClasses) {
            if (tmpClass.isInterface() || Utils.isEmpty(tmpClass.getInterfaces())) {
                continue;
            } else if ((Arrays.asList(tmpClass.getInterfaces())).contains(IInternalUpgrade.class)) {
                ideInternalUpgrades.add((IInternalUpgrade)tmpClass.newInstance());
            }
        }
        sortIdeInternals();
    }

    // sort IDE internal class execution by their order value
    private void sortIdeInternals() {
        Collections.sort(ideInternalUpgrades, new Comparator<IInternalUpgrade>() {
            public int compare(IInternalUpgrade o1, IInternalUpgrade o2) {
                if (o1 == o2) {
                    return 0;
                } else if (o1.getOrder() > o2.getOrder()) {
                    return 1;
                } else {
                    return -1;
                }
            }
        });
    }

    /**
     * Execute undo method for each IDE internal class
     *
     * @return
     */
    protected boolean undoIdeInternals() {
        for (IInternalUpgrade internalUpgrade : ideInternalUpgrades) {
            internalUpgrade.undo();
        }
        return true;
    }

    /**
     * Get list of class in com.salesforce.ide.upgrade.internal.ide package. Classes perform IDE upgrades.
     *
     * @return
     * @throws Exception
     */
    protected Class<?>[] getInternalUpgradeClasses() throws Exception {
        String pkgname = this.getClass().getPackage().getName() + ".ide";

        if (logger.isDebugEnabled()) {
            logger.debug("Searching for ide ugprade classes in package '" + pkgname + "'");
        }

        String pkgPath = pkgname.replace(".", "/");
        URL resource = ForceIdeUpgradePlugin.getFullUrlResource(pkgPath);
        if (resource == null) {
            logger.warn("Unable to load ide upgrade change class - resource for package '" + pkgPath + "' null");
            return null;
        }

        String path = null;
        try {
            path = FileLocator.resolve(resource).getPath();
        } catch (Exception e) {
            logger.warn("Could not get path from FileLocator: " + e.getMessage());
            path = resource.getFile();
        }

        if (Utils.isEmpty(path)) {
            logger.warn("Unable to get root resource for package '" + path + "'");
            return null;
        }

        ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
        if (path.contains(".jar!")) {
            String jarPath = path.substring(path.indexOf(":") + 1, path.lastIndexOf("!"));
            logger.info("Inspecting jar:\n " + jarPath);
            JarInputStream jarFile = new JarInputStream(new FileInputStream(jarPath));
            while (true) {
                JarEntry jarEntry = jarFile.getNextJarEntry();
                if (jarEntry == null) {
                    break;
                }

                if (jarEntry.getName().startsWith(pkgname.replaceAll("\\.", "/"))
                        && jarEntry.getName().endsWith(".class")) {
                    String className = jarEntry.getName().substring(jarEntry.getName().lastIndexOf("/") + 1,
                            jarEntry.getName().lastIndexOf("."));
                    className = pkgname + "." + className;
                    try {
                        // classes.add(Class.forName(className));
                        classes.add(Class.forName(className, true, this.getClass().getClassLoader()));
                        if (logger.isDebugEnabled()) {
                            logger.debug("Added ide internal change class: " + className);
                        }
                    } catch (ClassNotFoundException e) {
                        logger.warn("Unable to add ide internal change class '" + className + "': " + e.getMessage());
                    }
                }
            }
        } else {
            // get a file object for the package
            File directory = new File(path);
            if (directory.exists()) {
                File[] files = directory.listFiles(new FilenameFilter() {
                    public boolean accept(File dir, String name) {
                        return name.endsWith(".class");
                    }
                });

                if (Utils.isNotEmpty(files)) {
                    Arrays.sort(files, new Comparator<File>() {
                        public int compare(File o1, File o2) {
                            return o1.getName().compareTo(o2.getName());
                        }
                    });

                    for (File file : files) {
                        String className = pkgname + '.' + file.getName().substring(0, file.getName().length() - 6);
                        try {
                            classes.add(Class.forName(className, true, this.getClass().getClassLoader()));
                            if (logger.isDebugEnabled()) {
                                logger.debug("Added ide internal change class: " + className);
                            }
                        } catch (Exception e) {
                            logger.warn("Unable to add class '" + className + "': " + e.getMessage());
                        }
                    }
                } else {
                    logger.warn(pkgname + " does not appear to be a valid package - class directory '" + path
                            + "' not found");
                }
            } else {
                logger.warn(pkgname + " does not appear to be a valid package - class directory '" + path
                        + "' not found");
            }
        }

        Class<?>[] classesA = new Class<?>[classes.size()];
        classes.toArray(classesA);
        return classesA;
    }
}
TOP

Related Classes of com.salesforce.ide.upgrade.internal.UpgradeController

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.