Package com.salesforce.ide.core.services

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

/*******************************************************************************
* 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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourceAttributes;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.osgi.service.prefs.BackingStoreException;

import com.google.common.base.Preconditions;
import com.salesforce.ide.core.ForceIdeCorePlugin;
import com.salesforce.ide.core.compatibility.auth.IAuthorizationService;
import com.salesforce.ide.core.factories.FactoryException;
import com.salesforce.ide.core.internal.utils.Constants;
import com.salesforce.ide.core.internal.utils.DeployMessageExtractor;
import com.salesforce.ide.core.internal.utils.Messages;
import com.salesforce.ide.core.internal.utils.QualifiedNames;
import com.salesforce.ide.core.internal.utils.Utils;
import com.salesforce.ide.core.model.ApexCodeLocation;
import com.salesforce.ide.core.model.Component;
import com.salesforce.ide.core.model.ComponentList;
import com.salesforce.ide.core.model.IComponent;
import com.salesforce.ide.core.model.ProjectPackage;
import com.salesforce.ide.core.model.ProjectPackageList;
import com.salesforce.ide.core.project.BaseNature;
import com.salesforce.ide.core.project.DefaultNature;
import com.salesforce.ide.core.project.ForceProject;
import com.salesforce.ide.core.project.MarkerUtils;
import com.salesforce.ide.core.project.OnlineNature;
import com.salesforce.ide.core.remote.ForceConnectionException;
import com.salesforce.ide.core.remote.ForceRemoteException;
import com.salesforce.ide.core.remote.ICodeCoverageWarningExt;
import com.salesforce.ide.core.remote.IRunTestFailureExt;
import com.salesforce.ide.core.remote.metadata.DeployResultExt;
import com.salesforce.ide.core.remote.metadata.RetrieveMessageExt;
import com.salesforce.ide.core.remote.metadata.RetrieveResultExt;
import com.salesforce.ide.core.remote.metadata.RunTestsResultExt;
import com.sforce.soap.metadata.DeployMessage;
import com.sforce.soap.metadata.RetrieveMessage;

/**
*
* @author cwall
*/
public class ProjectService extends BaseService {

    private static final Logger logger = Logger.getLogger(ProjectService.class);
    private static final String AUTH_URL = "http://www.salesforce.com";
    private static final String AUTH_TYPE = "Basic";
    private String ideBrandName = null;
    private String platformBrandName = null;
    private String ideReleaseName = null;
    private TreeSet<String> supportedEndpointVersions = null;
    private final IAuthorizationService authService;

    public ProjectService() {
        this(new AuthorizationServicePicker());
    }

    public ProjectService(AuthorizationServicePicker factory) {
        this.authService = factory.makeAuthorizationService();
    }

    public String getIdeBrandName() {
        return ideBrandName;
    }

    public void setIdeBrandName(String ideBrandName) {
        this.ideBrandName = ideBrandName;
    }

    public String getPlatformBrandName() {
        return platformBrandName;
    }

    public void setPlatformBrandName(String platformBrandName) {
        this.platformBrandName = platformBrandName;
    }

    public String getIdeReleaseName() {
        return ideReleaseName;
    }

    public void setIdeReleaseName(String ideReleaseName) {
        this.ideReleaseName = ideReleaseName;
    }

    public TreeSet<String> getSupportedEndpointVersions() {
        return supportedEndpointVersions;
    }

    public void setSupportedEndpointVersions(TreeSet<String> supportedEndpointVersions) {
        this.supportedEndpointVersions = supportedEndpointVersions;
    }

    public boolean isSupportedEndpointVersion(String endpointVersion) {
        if (Utils.isNotEmpty(supportedEndpointVersions) && Utils.isNotEmpty(endpointVersion)) {
            endpointVersion = extractEndpointVersion(endpointVersion);
            return supportedEndpointVersions.contains(endpointVersion);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("Endpoint version [" + endpointVersion + "] is not supported");
            }
            return false;
        }
    }

    private String extractEndpointVersion(String endpoint) {
        if (endpoint.endsWith("/")) {
            endpoint = endpoint.substring(0, endpoint.length() - 1);
        }

        if (endpoint.contains("/")) {
            endpoint = endpoint.substring(endpoint.lastIndexOf("/") + 1);
        }

        return endpoint;
    }

    public String getLastSupportedEndpointVersion() {
        return Utils.isNotEmpty(supportedEndpointVersions) ? supportedEndpointVersions.last() : "";
    }

    // C R E A T E   P R O J E C T
    public IProject createProject(String projectName, String[] natures, IProgressMonitor monitor) throws CoreException {
        if (projectName == null) {
            throw new IllegalArgumentException("Project name cannot be null");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Create new project '" + projectName + "'");
        }

        IWorkspace workspace = ResourcesPlugin.getWorkspace();
        IWorkspaceRoot root = workspace.getRoot();
        IProject newProject = root.getProject(projectName);

        // if project doesn't exist, create
        IProjectDescription projectDescription = workspace.newProjectDescription(projectName);
        if (!newProject.exists()) {
            projectDescription = workspace.newProjectDescription(projectName);
            newProject.create(projectDescription, monitor);
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("Existing project '" + projectName
                        + "' found in workspace - will attempt to apply Force.com");
            }
            projectDescription = newProject.getDescription();
        }

        // open project
        newProject.open(monitor);

        // create project w/ natures does not configure builds like the following does
        if (Utils.isNotEmpty(natures) && newProject.isOpen()) {
            BaseNature.addNature(newProject, natures, monitor);
        } else {
            logger.warn("Applying no nature to new project '" + projectName + "'");
        }

        flagProjectAsNew(newProject);
        return newProject;
    }

    public void flagProjectAsNew(IProject project) throws CoreException {
        // set project property identifying this project as brand new
        // property is used downstream to skip building of new projects
        flagSkipBuilder(project);
    }

    public void flagSkipBuilder(IProject project) throws CoreException {
        if (project == null) {
            logger.error("Unable to set skip builder flag - project is null");
        }

        project.setSessionProperty(QualifiedNames.QN_SKIP_BUILDER, true);
    }

    public ProjectPackageList getProjectContents(IResource resource, IProgressMonitor monitor) throws CoreException,
            InterruptedException, FactoryException {
        if (resource == null) {
            throw new IllegalArgumentException("Resource cannot be null");
        }

        List<IResource> resources = new ArrayList<IResource>(1);
        resources.add(resource);
        return getProjectContents(resources, monitor);
    }

    public ProjectPackageList getProjectContents(List<IResource> resources, IProgressMonitor monitor)
            throws CoreException, InterruptedException, FactoryException {
        return getProjectContents(resources, false, monitor);
    }

    public ProjectPackageList getProjectContents(List<IResource> resources, boolean includeAssociated,
            IProgressMonitor monitor) throws CoreException, InterruptedException, FactoryException {
        if (Utils.isEmpty(resources)) {
            throw new IllegalArgumentException("Resources cannot be null");
        }

        ProjectPackageList projectPackageList = getProjectPackageListInstance();
        projectPackageList.setProject(resources.get(0).getProject());
        for (IResource resource : resources) {
            if (resource.getType() == IResource.PROJECT) {
                projectPackageList = getProjectContents(resource.getProject(), monitor);
            } else if (isSourceFolder(resource)) {
                projectPackageList = getProjectContents(resource.getProject(), monitor);
            } else if (isComponentFolder(resource)) {
                ComponentList componentList = getComponentsForComponentFolder((IFolder) resource, true, true);
                projectPackageList.addComponents(componentList, false);
            } else if (isSubComponentFolder(resource)) {
                ComponentList componentList = getComponentsForSubComponentFolder((IFolder) resource, true);
                projectPackageList.addComponents(componentList, false);
            } else if (isManagedFile(resource)) { //if we're in a force.com project. "isManaged" is misleading.
                Component component = getComponentFactory().getComponentFromFile((IFile) resource);
                projectPackageList.addComponent(component, true);

                // add dependent or associated components such as folder metadata component if component is sub-folder component
                if (includeAssociated) {
                    ComponentList componentList = getComponentFactory().getAssociatedComponents(component);
                    if (Utils.isNotEmpty(componentList)) {
                        projectPackageList.addComponents(componentList, false);
                    }
                }
            }
        }
        //filter out any built in folder stuff.
        // if component subfolder is built-in subfolder, then this subfolder will be available in dest org (also this subfolder is not retrievable/deployable)
        // so no need to add subfolder component to deploy list. W-623512
        ComponentList allComponentsList = getComponentFactory().getComponentListInstance();
        allComponentsList.addAll(projectPackageList.getAllComponents());
        for (Component component : allComponentsList) {
            if (Utils.isNotEmpty(component.getBuiltInSubFolders())) {
                for (String builtInSubFolder : component.getBuiltInSubFolders()) {
                    if (builtInSubFolder.equals(component.getName())) {
                        projectPackageList.removeComponent(component);
                    }
                }
            }
        }

        return projectPackageList;
    }

    public ProjectPackageList getProjectContents(IProject project, IProgressMonitor monitor) throws CoreException,
            InterruptedException, FactoryException {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }

        monitorCheck(monitor);

        // initialize container to holder contents
        ProjectPackageList projectPackageList = getProjectPackageListInstance();
        projectPackageList.setProject(project);

        // ensure project is not empty
        if (isProjectEmpty(project)) {
            return projectPackageList;
        }

        // get src folder; discontinue if not found or empty
        IResource sourceResource = project.findMember(Constants.SOURCE_FOLDER_NAME);
        if (sourceResource == null || !sourceResource.exists() || sourceResource.getType() != IResource.FOLDER
                || Utils.isEmpty(((IFolder) sourceResource).members())) {
            if (logger.isInfoEnabled()) {
                logger.info(Constants.SOURCE_FOLDER_NAME
                        + " not found, does not exist, or does not contain package folders in project '"
                        + project.getName() + "'");
            }
            return projectPackageList;
        }

        List<IFolder> componentFolders = getComponentFolders((IFolder) sourceResource);
        for (IFolder componentFolder : componentFolders) {
            monitorCheck(monitor);

            if (Utils.isEmpty(componentFolder.members())) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Skipping folder " + project.getName() + "' - no components found");
                }
                continue;
            }

            // find components in componet folder
            ComponentList componentList = getComponentsForComponentFolder(componentFolder, true, true);
            if (componentList.isEmpty()) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Component folder '" + componentFolder.getName()
                            + "' is does not contain components for enabled object types");
                }
                continue;
            }

            // add components to project package list instance including reference to package manifest
            projectPackageList.addComponents(componentList, false);
            if (logger.isDebugEnabled()) {
                logger.debug("Added '" + componentFolder.getName() + "' folder containing [" + componentList.size()
                        + "] components to project package list");
            }
        }

        return projectPackageList;
    }

    // R E S O U R C E   F I N D E R S

    /**
     * Get Force.com projects
     *
     * @param includeOnline
     *            include all projects with online nature vs. only base nature
     * @return
     */
    public List<IProject> getForceProjects() {
        List<IProject> forceProjects = new ArrayList<IProject>();
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        if (Utils.isNotEmpty(projects)) {
            for (IProject project : projects) {
                try {
                    if (project.isOpen() && project.hasNature(DefaultNature.NATURE_ID)) {
                        forceProjects.add(project);
                    }
                } catch (CoreException e) {
                    String logMessage = Utils.generateCoreExceptionLog(e);
                    logger.warn("Unable to determine project nature: " + logMessage);
                }
            }
        }
        return forceProjects;
    }

    /**
     * This method supports getting component file within sub-component folder (only 1 level down - not recursive)
     *
     * @param project
     * @param componentName
     * @param componentTypes
     * @return
     * @throws CoreException
     * @throws FactoryException
     */
    public IFile getComponentFileByNameType(IProject project, String componentName, String[] componentTypes)
            throws CoreException, FactoryException {
        if (Utils.isEmpty(componentName) || project == null || Utils.isEmpty(componentTypes)) {
            throw new IllegalArgumentException("Component name, types, and/or project cannot be null");
        }

        IFile file = null;
        for (String componentType : componentTypes) {
            file = getComponentFileByNameType(project, componentName, componentType);
            if (file != null) {
                return file;
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("File for '" + componentName + "' not found");
        }

        return file;
    }

    public IFile getComponentFileByNameType(IProject project, String componentName, String componentType)
            throws CoreException, FactoryException {
        if (Utils.isEmpty(componentName) || project == null || Utils.isEmpty(componentType)) {
            throw new IllegalArgumentException("Package name, type, and/or project cannot be null");
        }

        IFolder componentFolder = getComponentFolderByComponentType(project, componentType);
        if (componentFolder == null || !componentFolder.exists()) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find folder for type '" + componentType);
            }
            return null;
        }

        Component componentTypeInfo = getComponentFactory().getComponentByComponentType(componentType);
        IResource[] resources = componentFolder.members();
        for (IResource resource : resources) {
            String fullName = componentName;
            if (!componentName.contains(componentTypeInfo.getFileExtension())) {
                fullName = componentName + "." + componentTypeInfo.getFileExtension();
            }
            // because trigger and class may have the same name, so need to match the file extension as well
            if (resource.getType() == IResource.FILE && ((IFile) resource).getName().equalsIgnoreCase(fullName)) {
                if (logger.isInfoEnabled()) {
                    StringBuilder stringBuilder = new StringBuilder("File '");
                    stringBuilder.append(resource.getProjectRelativePath().toPortableString())
                            .append(" found for component type '").append(componentType).append("', component '")
                            .append(componentName).append("'");
                    logger.info(stringBuilder.toString());
                }
                return (IFile) resource;
            } else if (resource.getType() == IResource.FOLDER) {
                IResource[] subFolderResources = ((IFolder) resource).members();
                for (IResource subFolderResource : subFolderResources) {
                    // because trigger and class may have the same name, so need to match the file extension as well
                    if (subFolderResource.getType() == IResource.FILE
                            && ((IFile) subFolderResource).getName().equalsIgnoreCase(fullName)) {
                        if (logger.isInfoEnabled()) {
                            StringBuilder stringBuilder = new StringBuilder("File '");
                            stringBuilder.append(subFolderResource.getProjectRelativePath().toPortableString())
                                    .append(" found for component type '").append(componentType)
                                    .append("', component '").append(componentName).append("'");
                            logger.info(stringBuilder.toString());
                        }
                        return (IFile) subFolderResource;
                    }
                }
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("File not found for component '" + componentName + "'");
        }

        return null;
    }

    public IFile getCompositeFileResource(IFile file) {
        // check is file is a component and is a metadata composite, if so add composite
        Component component = null;
        try {
            component = getComponentFactory().getComponentFromFile(file, true);
        } catch (FactoryException e) {
            logger.warn("Unable to detemine if file '" + file.getName() + "' is a component");
            return null;
        }

        if (component.isPackageManifest() || !component.isMetadataComposite()) {
            return null;
        }

        // load component composite
        String compositeComponentFilePath = component.getCompositeMetadataFilePath();
        if (Utils.isEmpty(compositeComponentFilePath)) {
            logger.warn("Component metadata path is null for " + component.getFullDisplayName());
            return null;
        }
        return getComponentFileForFilePath(file.getProject(), compositeComponentFilePath);
    }

    public List<IFolder> getComponentFolders(IFolder sourceFolder) throws CoreException {
        if (sourceFolder == null) {
            throw new IllegalArgumentException("Source folder cannot be null");
        }

        if (!sourceFolder.exists() || !isSourceFolder(sourceFolder)) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find '" + Constants.SOURCE_FOLDER_NAME + " folder");
            }
            return null;
        }

        if (logger.isInfoEnabled()) {
            logger.info("Found '" + sourceFolder.getName() + "' folder");
        }

        IResource[] sourceFolderResources = sourceFolder.members();
        if (Utils.isEmpty(sourceFolderResources)) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not any package folders in '" + Constants.SOURCE_FOLDER_NAME + " folder");
            }
            return null;
        }

        List<IFolder> componentFolders = new ArrayList<IFolder>();
        for (IResource sourceFolderResource : sourceFolderResources) {
            if (sourceFolderResource.getType() != IResource.FOLDER) {
                continue;
            }

            if (isComponentFolder(sourceFolderResource)) {
                componentFolders.add((IFolder) sourceFolderResource);
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("Found [" + componentFolders.size() + "] component folders");
        }

        return componentFolders;
    }

    public IFolder getComponentFolderByComponentType(IProject project, String componentType) throws CoreException,
            FactoryException {
        Component component = getComponentFactory().getComponentByComponentType(componentType);
        if (component == null) {
            logger.warn("Unable to find component for type '" + componentType + "'");
            return null;
        }
        return getComponentFolderByName(project, component.getDefaultFolder(), false, new NullProgressMonitor());
    }

    public IFolder getComponentFolderByName(IProject project, String componentFolderName, boolean create,
            IProgressMonitor monitor) throws CoreException {
        if (Utils.isEmpty(componentFolderName) || project == null) {
            throw new IllegalArgumentException("Folder name and/or project cannot be null");
        }

        IFolder sourceFolder = getSourceFolder(project);
        if (sourceFolder == null || !sourceFolder.exists() || Utils.isEmpty(sourceFolder.members())) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find '" + Constants.SOURCE_FOLDER_NAME + " folder or folder is empty");
            }
            return null;
        }

        IFolder componentFolder = sourceFolder.getFolder(componentFolderName);
        if (componentFolder == null || !componentFolder.exists()) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find component folder '" + componentFolderName + "'");
            }
            return null;
        }

        return componentFolder;
    }

    public ProjectPackageList getComponentsForComponentTypes(IProject project, String[] componentTypes)
            throws CoreException, FactoryException {
        ProjectPackageList projectPackageList = getProjectPackageFactory().getProjectPackageListInstance(project);
        if (Utils.isNotEmpty(componentTypes)) {
            for (String componentType : componentTypes) {
                IFolder componentFolder = getComponentFolderByComponentType(project, componentType);
                if (componentFolder != null && componentFolder.exists()) {
                    ComponentList componentList = getComponentFactory().getComponentListInstance();
                    componentList.addAll(getComponentsForFolder(componentFolder, true));
                    projectPackageList.addComponents(componentList, true);
                }
            }
        }
        return projectPackageList;
    }

    public ComponentList getComponentsForComponentType(IProject project, String componentType) throws CoreException,
            FactoryException {
        IFolder componentFolder = getComponentFolderByComponentType(project, componentType);
        ComponentList componentList = getComponentFactory().getComponentListInstance();
        componentList.addAll(getComponentsForFolder(componentFolder, true));
        return componentList;
    }

    public ComponentList getComponentsForFolder(IFolder folder, boolean traverse) throws CoreException,
            FactoryException {
        return getComponentsForFolder(folder, traverse, true);
    }

    public ComponentList getComponentsForFolder(IFolder folder, boolean traverse, boolean includeManifest)
            throws CoreException, FactoryException {
        return getComponentsForFolder(folder, null, traverse, includeManifest);
    }

    public ComponentList getComponentsForFolder(IFolder folder, String[] enabledComponentTypes, boolean traverse)
            throws CoreException, FactoryException {
        return getComponentsForFolder(folder, enabledComponentTypes, traverse, true);
    }

    public ComponentList getComponentsForFolder(IFolder folder, String[] enabledComponentTypes, boolean traverse,
            boolean includeManifest) throws CoreException, FactoryException {
        if (folder == null || !folder.exists()) {
            throw new IllegalArgumentException("Folder cannot be null");
        }

        // initialize component
        ComponentList componentList = getComponentFactory().getComponentListInstance();

        // convert for contains access
        List<String> enabledComponentTypesList = null;
        if (enabledComponentTypes != null) {
            enabledComponentTypesList = Arrays.asList(enabledComponentTypes);
        }

        if (isSourceFolder(folder)) {
            // loop thru registered component list inspecting respective folder and folder contents
            ComponentList registeredComponents =
                    getComponentFactory().getEnabledRegisteredComponents(enabledComponentTypes);
            for (IComponent registeredComponent : registeredComponents) {
                if (Utils.isNotEmpty(enabledComponentTypes)
                        && !enabledComponentTypesList.contains(registeredComponent.getComponentType())) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipping component type '" + registeredComponent.getComponentType()
                                + "' - type not a selected object type");
                    }
                    continue;
                }
                String componentFolderPath =
                        Constants.SOURCE_FOLDER_NAME + "/" + registeredComponent.getDefaultFolder();
                IFolder componentFolder = folder.getProject().getFolder(componentFolderPath);

                if (componentFolder == null || !componentFolder.exists()) {
                    continue;
                }

                ComponentList tmpComponentList = getComponentsForComponentFolder(componentFolder, traverse, true);
                if (Utils.isNotEmpty(tmpComponentList)) {
                    componentList.addAll(tmpComponentList);
                }
            }
        } else if (isComponentFolder(folder)) {
            ComponentList tmpComponentList = getComponentsForComponentFolder(folder, traverse, true);
            if (Utils.isNotEmpty(tmpComponentList)) {
                componentList.addAll(tmpComponentList);
            }
        } else if (isSubComponentFolder(folder)) {
            ComponentList tmpComponentList = getComponentsForComponentFolder(folder, traverse, true);
            if (Utils.isNotEmpty(tmpComponentList)) {
                componentList.addAll(tmpComponentList);
            }
        }

        return componentList;
    }

    public ComponentList getComponentsForComponentFolder(IFolder folder, boolean traverse, boolean includeBody)
            throws CoreException, FactoryException {
        if (folder == null || !folder.exists() || Utils.isEmpty(folder.members())) {
            if (logger.isDebugEnabled()) {
                logger.debug("Component folder '" + folder.getName() + "' does not exist or does not "
                        + "contain components");
            }
            return null;
        }

        // initialize component
        ComponentList componentList = getComponentFactory().getComponentListInstance();

        IResource[] componentFolderResources = folder.members();
        for (IResource componentFolderResource : componentFolderResources) {
            if (traverse && IResource.FOLDER == componentFolderResource.getType()) {
                IFolder componentFolderWithSub = (IFolder) componentFolderResource;
                ComponentList tmpComponentList = getComponentsForSubComponentFolder(componentFolderWithSub, traverse);
                componentList.addAll(tmpComponentList);

            } else if (IResource.FILE == componentFolderResource.getType()) {
                IFile componentFile = (IFile) componentFolderResource;
                try {
                    Component tmpComponent = getComponentFactory().getComponentFromFile(componentFile, includeBody);
                    componentList.add(tmpComponent, false, true);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Added component '"
                                + componentFolderResource.getProjectRelativePath().toPortableString() + "' to list");
                    }
                } catch (FactoryException e) {
                    logger.error("Unable to create component from filepath "
                            + componentFile.getProjectRelativePath().toPortableString());
                }
            }
        }

        return componentList;
    }

    /**
     * This method is used to retrieve components under sub-componentfolder including sub-componentfolder itself in the
     * returned list. Assumption: the subComponentFolder's metadata file is located under componentFolder and naming as
     * <subComponentFolderName>-meta.xml
     *
     * @param folder
     *            - subComponentFolder
     * @param traverse
     * @return
     * @throws CoreException
     * @throws FactoryException
     */
    public ComponentList getComponentsForSubComponentFolder(IFolder folder, boolean traverse) throws CoreException,
            FactoryException {
        ComponentList componentList = getComponentsForComponentFolder(folder, traverse, true);
        if (componentList == null) {
            componentList = getComponentFactory().getComponentListInstance();
        }

        Component component = getComponentFactory().getComponentFromSubFolder(folder, false);
        componentList.add(component);
        return componentList;
    }

    public IFile getComponentFileForFilePath(IProject project, String filePath) {
        if (Utils.isEmpty(filePath) || project == null) {
            throw new IllegalArgumentException("Filepath and/or project cannot be null");
        }

        String tmpFilePath = filePath;
        if (!filePath.startsWith(Constants.SOURCE_FOLDER_NAME)) {
            IFolder packageSourceFolder = getSourceFolder(project);
            if (packageSourceFolder == null || !packageSourceFolder.exists()) {
                logger.warn("Unable to find package source folder.  Discontinuing search of file '" + filePath + "'");
                return null;
            }
            tmpFilePath = packageSourceFolder.getProjectRelativePath().toPortableString() + "/" + filePath;
        }

        IResource resource = project.findMember(tmpFilePath);
        if (resource == null || !resource.exists() || resource.getType() != IResource.FILE) {
            logger.warn("Resource not found or not a file for filepath '" + tmpFilePath + "'");
            return null;
        }

        if (logger.isInfoEnabled()) {
            logger.info("Found resource for filepath '" + tmpFilePath + "'");
        }

        return (IFile) resource;
    }

    public List<IResource> filterChildren(List<IResource> selectedResources) {
        if (Utils.isEmpty(selectedResources) || selectedResources.size() == 1) {
            return selectedResources;
        }

        for (Iterator<IResource> iterator = selectedResources.iterator(); iterator.hasNext();) {
            IResource resource = iterator.next();
            if (hasParent(selectedResources, resource)) {
                iterator.remove();
            }
        }

        return selectedResources;
    }

    private boolean hasParent(List<IResource> selectedResources, IResource resource) {
        if (resource == null || resource.getParent() == null || resource.getType() == IResource.ROOT
                || Utils.isEmpty(selectedResources)) {
            return false;
        }

        if (resource.getParent() != null && selectedResources.contains(resource.getParent())) {
            return true;
        }

        return hasParent(selectedResources, resource.getParent());
    }

    /**
     * filters out only IFiles from a list of IResources
     *
     * @param allResources
     * @return
     * @throws CoreException
     */
    public List<IResource> getAllFilesOnly(List<IResource> allResources) throws CoreException {
        if (Utils.isEmpty(allResources)
                || (allResources.size() == 1 && allResources.get(0).getType() == IResource.FILE)) {
            return allResources;
        }

        List<IResource> ret_filesList = new ArrayList<IResource>();
        for (IResource resource : allResources) {
            if (resource.getType() == IResource.PROJECT) {
                addAllFilesOnly((IProject) resource, ret_filesList);
            } else if (resource.getType() == IResource.FOLDER) {
                addAllFilesOnly((IFolder) resource, ret_filesList);
            } else if (resource.getType() == IResource.FILE && isBuildableResource(resource)) {
                ret_filesList.add(resource);
            }
        }

        return ret_filesList;
    }

    /**
     * filters out files from a list of resource given a IProject
     *
     * @param project
     *            the project in which these files belong
     * @param resourcesList
     *            a list of all resources that will be populated with IFiles
     * @throws CoreException
     */
    private void addAllFilesOnly(IProject project, List<IResource> resourcesList) throws CoreException {
        if (Utils.isEmpty(project.members())) {
            if (logger.isDebugEnabled()) {
                logger.debug("Project does not have members");
            }
            return;
        }

        for (IResource member : project.members()) {
            if (member.getType() == IResource.FOLDER) {
                addAllFilesOnly((IFolder) member, resourcesList);
            } else if (member.getType() == IResource.FILE && isBuildableResource(member)) {
                resourcesList.add(member);
            }
        }
    }

    /**
     * filters out files from a list of resources given a Ifolder
     *
     * @param folder
     *            the folder to work on.
     * @param resourcesList
     *            a list of resources which will be populated.
     * @throws CoreException
     */
    private void addAllFilesOnly(IFolder folder, List<IResource> resourcesList) throws CoreException {
        if (Utils.isEmpty(folder.members())) {
            if (logger.isDebugEnabled()) {
                logger.debug("Folder does not have members");
            }
            return;
        }

        for (IResource member : folder.members()) {
            if (member.getType() == IResource.FOLDER) {
                addAllFilesOnly((IFolder) member, resourcesList);
            } else if (member.getType() == IResource.FILE && isBuildableResource(member)) {
                resourcesList.add(member);
            }
        }
    }

    public List<IResource> getResourcesByType(List<IResource> resources, int type) {
        if (Utils.isEmpty(resources)) {
            return null;
        }

        List<IResource> specificResources = new ArrayList<IResource>(resources.size());
        for (IResource resource : resources) {
            if (resource.getType() == type) {
                specificResources.add(resource);
            }
        }
        return specificResources;
    }

    public IFolder getFolder(List<IResource> resources, String name) {
        if (Utils.isEmpty(resources)) {
            return null;
        }

        for (IResource resource : resources) {
            if (resource.getType() == IResource.FOLDER && resource.getName().endsWith(name)) {
                return (IFolder) resource;
            }
        }

        return null;
    }

    public boolean isProjectEmpty(IProject project) throws CoreException {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }

        IResource[] resources = project.members();
        if (Utils.isEmpty(resources)) {
            if (logger.isInfoEnabled()) {
                logger.info("No resources found in project '" + project.getName() + "'");
            }
            return true;
        }
        return false;
    }

    public IFolder getSourceFolder(IProject project) {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }

        IResource packageSourceFolder = project.findMember(Constants.SOURCE_FOLDER_NAME);

        if (packageSourceFolder == null || !packageSourceFolder.exists()
                || packageSourceFolder.getType() != IResource.FOLDER) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find '" + Constants.SOURCE_FOLDER_NAME + " folder");
            }
            return null;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Found '" + packageSourceFolder.getName() + "' folder");
        }

        return (IFolder) packageSourceFolder;
    }

    public IFolder getReferencedPackagesFolder(IProject project) {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }

        IResource referencedPackageFolder = project.findMember(Constants.REFERENCED_PACKAGE_FOLDER_NAME);

        if (referencedPackageFolder == null || !referencedPackageFolder.exists()
                || referencedPackageFolder.getType() != IResource.FOLDER) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find '" + Constants.REFERENCED_PACKAGE_FOLDER_NAME + " folder");
            }
            return null;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Found '" + referencedPackageFolder.getName() + "' folder");
        }

        return (IFolder) referencedPackageFolder;
    }

    public boolean hasSourceFolderContents(IProject project) throws CoreException {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }

        IResource packageSourceFolder = project.findMember(Constants.SOURCE_FOLDER_NAME);

        if (packageSourceFolder == null || !packageSourceFolder.exists()
                || packageSourceFolder.getType() != IResource.FOLDER) {
            if (logger.isInfoEnabled()) {
                logger.info("Did not find '" + Constants.SOURCE_FOLDER_NAME + " folder");
            }
            return false;
        }

        if (Utils.isEmpty(((IFolder) packageSourceFolder).members())) {
            return false;
        }

        if (logger.isInfoEnabled()) {
            logger.info("Project '" + project.getName() + "' has contents in package folders");
        }

        return true;
    }

    // N A T U R E S
    public void applyDefaultNature(IProject project, IProgressMonitor monitor) throws CoreException {
        DefaultNature.addNature(project, monitor);
        monitorWork(monitor);
    }

    public void applyOnlineNature(IProject project, IProgressMonitor monitor) throws CoreException {
        OnlineNature.addNature(project, monitor);
        monitorWork(monitor);
    }

    public void applyNatures(IProject project, IProgressMonitor monitor) throws CoreException {
        applyDefaultNature(project, monitor);
        applyOnlineNature(project, monitor);
    }

    public void removeNatures(IProject project, IProgressMonitor monitor) throws CoreException {
        OnlineNature.removeNature(project, monitor);
        monitorWork(monitor);

        DefaultNature.removeNature(project, monitor);
        monitorWork(monitor);
    }

    // I D E   M A N A G E D   R E S O U R C E   C H E C K S
    public boolean isManagedResources(List<IResource> resources) {
        if (Utils.isEmpty(resources)) {
            return false;
        }

        for (IResource resource : resources) {
            if (!isManagedResource(resource)) {
                return false;
            }
        }

        return true;
    }

    public boolean isManagedResource(IResource resource) {
        if (resource == null) {
            return false;
        }

        if (resource.getType() == IResource.FILE) {
            return isManagedFile(resource);
        } else if (resource.getType() == IResource.FOLDER) {
            return isManagedFolder(resource);
        } else if (resource.getType() == IResource.PROJECT) {
            return isManagedProject(resource);
        } else {
            if (logger.isInfoEnabled()) {
                logger.info("Resource type '" + resource.getType() + "' not managed by force");
            }
            return false;
        }

    }

    public boolean isManagedFile(IResource resource) {
        if (resource == null || resource.getType() != IResource.FILE) {
            return false;
        }

        return isManagedFile((IFile) resource);
    }

    public boolean isManagedFile(IFile file) {
        if (file == null || file.getType() != IResource.FILE) {
            return false;
        }

        if (!isInManagedProject(file)) {
            return false;
        }

        if (Utils.isEmpty(file.getProjectRelativePath().toPortableString())) {
            if (logger.isInfoEnabled()) {
                logger.info("Filepath not found for file '" + file + "'");
            }
            return false;
        }

        Component component = null;
        try {
            component = getComponentFactory().getComponentByFilePath(file.getProjectRelativePath().toPortableString());
        } catch (FactoryException e) {
            logger.warn("Unable to get component for file '" + file.getProjectRelativePath().toPortableString() + "': "
                    + e.getMessage());
            return false;
        }

        if (component != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Component found for filepath '" + file.getProjectRelativePath().toPortableString() + "'");
            }
            return true;
        }

        logger.warn("Component not found for filepath '" + file.getProjectRelativePath().toPortableString() + "'");

        return false;
    }

    public boolean isManagedFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isManagedFolder(((IFolder) resource));
    }

    public boolean isManagedFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        if (isSourceFolder(folder)) {
            return true;
        }

        if (isComponentFolder(folder)) {
            return true;
        }

        if (isSubComponentFolder(folder)) {
            return true;
        }

        if (isPackageFolder(folder)) {
            return true;
        }

        if (isReferencedPackagesFolder(folder)) {
            return true;
        }

        if (logger.isInfoEnabled()) {
            logger.info("Folder '" + folder.getProjectRelativePath().toPortableString() + "' is not "
                    + Constants.PLUGIN_NAME + " managed");
        }

        return false;
    }

    public boolean isManagedProject(IResource resource) {
        if (resource == null || resource.getType() != IResource.PROJECT) {
            return false;
        }

        IProject project = resource.getProject();

        try {
            boolean hasNature = project.hasNature(DefaultNature.NATURE_ID);
            if (logger.isDebugEnabled()) {
                logger.debug("Project '" + project.getName() + "' is " + (hasNature ? Constants.EMPTY_STRING : "not")
                        + " " + Constants.PLUGIN_NAME + " managed");
            }
            return hasNature;
        } catch (CoreException e) {
            String logMessage = Utils.generateCoreExceptionLog(e);
            logger.warn("Unable to determine if project is " + Constants.PLUGIN_NAME + " managed with exception: "
                    + logMessage);
            return false;
        }
    }

    public boolean isManagedOnlineProject(IResource resource) {
        if (resource == null || resource.getType() != IResource.PROJECT) {
            return false;
        }

        IProject project = resource.getProject();

        try {
            boolean hasNature = project.hasNature(OnlineNature.NATURE_ID);
            if (logger.isDebugEnabled()) {
                logger.debug("Project '" + project.getName() + "' is " + (hasNature ? Constants.EMPTY_STRING : "not")
                        + " " + Constants.PLUGIN_NAME + " managed");
            }
            return hasNature;
        } catch (CoreException e) {
            String logMessage = Utils.generateCoreExceptionLog(e);
            logger.warn("Unable to determine if project is " + Constants.PLUGIN_NAME + " managed: " + logMessage);
            return false;
        }
    }

    /**
     * @return true is the resource is in a managed project (that has an force nature )
     */
    public boolean isInManagedProject(IResource resource) {
        if (resource == null
                || (resource.getType() != IResource.PROJECT && resource.getType() != IResource.FOLDER && resource
                        .getType() != IResource.FILE)) {
            return false;
        }

        IProject project = resource.getProject();
        if (!project.isOpen()) {
            return false;
        }

        try {
            return project.hasNature(DefaultNature.NATURE_ID);
        } catch (CoreException e) {
            String logMessage = Utils.generateCoreExceptionLog(e);
            logger.warn("Unable to determine if resource '" + resource.getName() + "' is force managed: " + logMessage);
            return false;
        }
    }

    public boolean isSourceFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isSourceFolder((IFolder) resource);
    }

    public boolean isSourceFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        String folderName = folder.getName();

        if (folderName.equals(Constants.SOURCE_FOLDER_NAME) && isAtProjectRoot(folder)) {
            return true;
        }

        return false;
    }

    public boolean isSourceResource(IResource resource) {
        if (resource == null) {
            return false;
        }

        if (!isInManagedProject(resource)) {
            return false;
        }

        if (resource.getType() == IResource.FOLDER && isSourceFolder(resource)) {
            return true;
        }

        if (resource.getProjectRelativePath().toPortableString().startsWith(Constants.SOURCE_FOLDER_NAME)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Resource '" + resource.getProjectRelativePath().toPortableString()
                        + "' is a package resource");
            }
            return true;
        }

        return false;
    }

    public boolean hasPackageManifest(IResource resource) {
        if (resource == null || !resource.exists()) {
            return false;
        }

        IFile packageManifest =
                resource.getProject()
                        .getFile(Constants.SOURCE_FOLDER_NAME + "/" + Constants.PACKAGE_MANIFEST_FILE_NAME);
        return packageManifest != null && packageManifest.exists();
    }

    public boolean isPackageFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isPackageFolder((IFolder) resource);
    }

    public boolean isPackageFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        IResource[] members = null;
        try {
            members = folder.members();
        } catch (CoreException e) {
            String logMessage = Utils.generateCoreExceptionLog(e);
            logger.warn("Unable to get members of folder '" + folder.getProjectRelativePath().toPortableString()
                    + "': " + logMessage);
        }

        if (Utils.isEmpty(members)) {
            if (logger.isInfoEnabled()) {
                logger.info("Package manifest not found in folder '"
                        + folder.getProjectRelativePath().toPortableString() + "'");
            }
            return false;
        }

        for (IResource tmpResource : members) {
            if (tmpResource.getType() == IResource.FILE
                    && Constants.PACKAGE_MANIFEST_FILE_NAME.equals(tmpResource.getName())) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Found '" + Constants.PACKAGE_MANIFEST_FILE_NAME + "' in folder '"
                            + folder.getProjectRelativePath().toPortableString() + "'");
                }
                return true;
            }
        }

        return false;
    }

    public boolean isReferencedPackagesFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isReferencedPackagesFolder((IFolder) resource);
    }

    public boolean isReferencedPackagesFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        IResource parentResource = folder.getParent();
        if (parentResource != null && Constants.REFERENCED_PACKAGE_FOLDER_NAME.equals(folder.getName())
                && parentResource.getType() == IResource.PROJECT) {
            return true;
        }

        if (parentResource == null || !Constants.REFERENCED_PACKAGE_FOLDER_NAME.equals(parentResource.getName())) {
            if (logger.isDebugEnabled()) {
                logger.debug("'" + Constants.REFERENCED_PACKAGE_FOLDER_NAME + "' is not parent of '"
                        + folder.getProjectRelativePath().toPortableString() + "'");
            }
            return false;
        }

        return true;
    }

    /** Individual package folder under "Reference Packages" folder */
    public boolean isReferencedPackageFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isReferencedPackageFolder((IFolder) resource);
    }

    /** Individual package folder under "Reference Packages" folder */
    public boolean isReferencedPackageFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        IResource parentResource = folder.getParent();
        if (parentResource == null || !isReferencedPackagesFolder(parentResource)) {
            if (logger.isDebugEnabled()) {
                logger.debug("'" + Constants.REFERENCED_PACKAGE_FOLDER_NAME + "' is not parent of '"
                        + folder.getProjectRelativePath().toPortableString() + "'");
            }
            return false;
        }

        return true;
    }

    public boolean isReferencedPackageResource(IResource resource) {
        if (resource == null) {
            return false;
        }

        if (!isInManagedProject(resource)) {
            return false;
        }

        if (resource.getType() == IResource.FOLDER && isReferencedPackagesFolder(resource)) {
            return true;
        }

        if (resource.getProjectRelativePath().toPortableString().contains(Constants.REFERENCED_PACKAGE_FOLDER_NAME)) {
            if (logger.isInfoEnabled()) {
                logger.info("Resource '" + resource.getProjectRelativePath().toPortableString()
                        + "' is a referenced package");
            }
            return true;
        }

        return false;
    }

    public boolean isSubComponentFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }
        return isSubComponentFolder((IFolder) resource);
    }

    public boolean isSubComponentFolder(IFolder folder) {
        return folder.getParent().getType() == IResource.FOLDER && isComponentFolder((IFolder) folder.getParent());
    }

    public boolean isComponentFolder(IResource resource) {
        if (resource == null || resource.getType() != IResource.FOLDER) {
            return false;
        }

        return isComponentFolder((IFolder) resource);
    }

    public boolean isComponentFolder(IFolder folder) {
        if (folder == null || folder.getType() != IResource.FOLDER) {
            return false;
        }

        if (!isInManagedProject(folder)) {
            return false;
        }

        IResource parentFolder = folder.getParent();
        if (parentFolder == null || parentFolder.getType() != IResource.FOLDER || !isSourceFolder(parentFolder)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Parent resource of folder name '" + folder.getProjectRelativePath().toPortableString()
                        + "' is not a src folder - folder deemed not a component folder");
            }
            return false;
        }

        String folderName = folder.getName();
        Component component = null;
        try {
            component = getComponentFactory().getComponentByFolderName(folderName);
        } catch (FactoryException e) {
            logger.warn("Unable to get component for folder name '" + folderName + "'", e);
            return false;
        }

        if (component != null) {
            if (logger.isDebugEnabled()) {
                logger.debug("Component found for folder name '" + folderName + "'");
            }
            return true;
        }

        if (logger.isInfoEnabled()) {
            logger.info("Component not found for folder name '" + folderName + "'");
        }

        return false;
    }

    public boolean isPackageManifestFile(IResource resource) {
        if (resource == null || resource.getType() != IResource.FILE) {
            return false;
        }

        if (!isInManagedProject(resource)) {
            return false;
        }

        if (resource.getName().equals(Constants.PACKAGE_MANIFEST_FILE_NAME)) {
            if (logger.isDebugEnabled()) {
                logger.debug("File '" + resource.getProjectRelativePath().toPortableString()
                        + "' is a package manifest file");
            }
            return true;
        }

        return false;
    }

    public boolean isDefaultPackageManifestFile(IResource resource) {
        if (resource == null || resource.getType() != IResource.FILE) {
            return false;
        }

        if (!isInManagedProject(resource)) {
            return false;
        }

        if (resource.getProjectRelativePath().toPortableString()
                .endsWith(Constants.DEFAULT_PACKAGED_NAME + "/" + Constants.PACKAGE_MANIFEST_FILE_NAME)) {
            if (logger.isDebugEnabled()) {
                logger.debug("File '" + resource.getProjectRelativePath().toPortableString()
                        + "' is the defauult package manifest file");
            }
            return true;
        }

        return false;
    }

    /**
     * @return true is the resource is at the root of a project
     */
    private static boolean isAtProjectRoot(IResource resource) {
        return resource.getParent() instanceof IProject;
    }

    public boolean hasManagedComponents(List<IResource> resources) {
        if (Utils.isEmpty(resources)) {
            return false;
        }

        for (IResource resource : resources) {
            if (hasManagedComponents(resource)) {
                return true;
            }
        }

        return false;
    }

    public boolean hasManagedComponents(IResource resource) {
        if (resource == null) {
            return false;
        }

        if (resource.getType() == IResource.FILE) {
            return isManagedFile(resource);
        }

        IFolder rootFolder = null;
        if (resource.getType() == IResource.PROJECT) {
            rootFolder = getSourceFolder(resource.getProject());
            if (rootFolder == null || !rootFolder.exists()) {
                return false;
            }
        } else {
            rootFolder = (IFolder) resource;
        }

        ComponentList componentList = null;
        try {
            componentList = getComponentsForFolder(rootFolder, true, true);
        } catch (Exception e) {
            logger.error("Unable to get components for source folder");
            return false;
        }

        if (Utils.isEmpty(componentList)) {
            return false;
        }

        return true;
    }

    public boolean isBuildableResource(IResource resource) {
        // why isn't the formatter wrapping this???
        return (resource.getType() == IResource.FILE
                && !resource.getProjectRelativePath().toPortableString().contains(Constants.PROJECT_SETTINGS_DIR)
                && !resource.getProjectRelativePath().toPortableString().contains(Constants.PROJECT_FILE)
                /* not sure how else to do this, because isHidden() doesn't work for "." files and directories */
                && !resource.getProjectRelativePath().toPortableString().contains(Constants.SVN_DIR)
                && !resource.getProjectRelativePath().toPortableString().endsWith(Constants.SCHEMA_FILENAME) && (isManagedResource(resource) && (!isReferencedPackageResource(resource) && !isPackageManifestFile(resource))));
    }

    // F I L E   P R O P E R T I E S

    protected int getInt(IProject project, String propertyName, int defaultvalue) {
        IEclipsePreferences node = getPreferences(project);
        return node != null ? node.getInt(propertyName, defaultvalue) : defaultvalue;
    }

    protected boolean getBoolean(IProject project, String propertyName, boolean defaultvalue) {
        IEclipsePreferences node = getPreferences(project);
        return node != null ? node.getBoolean(propertyName, defaultvalue) : defaultvalue;
    }

    protected void setInt(IProject project, String propertyName, int value) {
        IEclipsePreferences node = getPreferences(project);
        if (node != null) {
            node.putInt(propertyName, value);
            try {
                node.flush();
            } catch (BackingStoreException e) {
                // TODO: no error, just a log
                Utils.openError(new InvocationTargetException(e), true, "Unable to set int.");
            }
        }
    }

    protected void setBoolean(IProject project, String propertyName, boolean value) {
        IEclipsePreferences node = getPreferences(project);
        if (node != null) {
            node.putBoolean(propertyName, value);
            try {
                node.flush();
            } catch (BackingStoreException e) {
                // TODO: no error, just a log
                Utils.openError(new InvocationTargetException(e), true, "Unable to set boolean.");
            }
        }
    }

    protected void setString(IProject project, String propertyName, String value) {
        IEclipsePreferences node = getPreferences(project);
        if (node != null) {
            node.put(propertyName, (value != null ? value : Constants.EMPTY_STRING));
            try {
                node.flush();
            } catch (BackingStoreException e) {
                // TODO: no error, just a log
                Utils.openError(new InvocationTargetException(e), true, "Unable to set string.");
            }
        }
    }

    protected String getString(IProject project, String key, String defaultvalue) {
        IEclipsePreferences node = getPreferences(project);
        return node != null ? node.get(key, (defaultvalue != null ? defaultvalue : Constants.EMPTY_STRING))
                : defaultvalue;
    }

    protected IEclipsePreferences getPreferences(IProject project) {
        ProjectScope projectScope = new ProjectScope(project);
        IEclipsePreferences node = projectScope.getNode(ForceIdeCorePlugin.getPluginId());
        return node;
    }

    public ForceProject getForceProject(IProject project) {
        ForceProject forceProject = new ForceProject();
        IEclipsePreferences preferences = getPreferences(project);
        if (preferences == null) {
            return forceProject;
        }
        forceProject.setProject(project);

        forceProject.setUserName(preferences.get(Constants.PROP_USERNAME, null));
        forceProject.setNamespacePrefix(preferences.get(Constants.PROP_NAMESPACE_PREFIX, null));

        // previous versions (<154) stored the full endpoint
        String endpoint = preferences.get(Constants.PROP_ENDPOINT, null);
        String endpointServer = preferences.get(Constants.PROP_ENDPOINT_SERVER, null);

        if (Utils.isNotEmpty(endpoint) && Utils.isEmpty(endpointServer)) {
            endpointServer = Utils.getServerNameFromUrl(endpoint);
        }

        forceProject.setPackageName(preferences.get(Constants.PROP_PACKAGE_NAME, null));
        forceProject.setEndpointServer(endpointServer);
        forceProject.setEndpointEnvironment(preferences.get(Constants.PROP_ENDPOINT_ENVIRONMENT, null));
        forceProject.setEndpointApiVersion(preferences.get(Constants.PROP_ENDPOINT_API_VERSION,
            getLastSupportedEndpointVersion()));
        forceProject.setMetadataFormatVersion(preferences.get(Constants.PROP_METADATA_FORMAT_VERSION,
            getLastSupportedEndpointVersion()));
        forceProject.setIdeVersion(preferences.get(Constants.PROP_IDE_VERSION, Constants.EMPTY_STRING));
        forceProject.setProjectIdentifier(preferences.get(Constants.PROP_PROJECT_IDENTIFIER, Constants.EMPTY_STRING));

        forceProject.setKeepEndpoint(preferences.getBoolean(Constants.PROP_KEEP_ENDPOINT, false));
        forceProject.setPreferToolingDeployment(preferences.getBoolean(Constants.PROP_PREFER_TOOLING_DEPLOYMENT, true));
        forceProject.setHttpsProtocol(preferences.getBoolean(Constants.PROP_HTTPS_PROTOCOL, true));
        forceProject.setReadTimeoutSecs(preferences.getInt(Constants.PROP_READ_TIMEOUT,
            Constants.READ_TIMEOUT_IN_SECONDS_DEFAULT));

        if (Utils.isEmpty(forceProject.getEndpointServer())) {
            logger.warn("Unable to get authorization info - endpoint is null or empty");
            return forceProject;
        }

        URL url = null;
        try {
            url = new URL(AUTH_URL);
        } catch (MalformedURLException e) {
            logger.error("Invalid URL ", e);
        }

        Map<?, ?> credentialMap = getAuthorizationService().getCredentialMap(url, project.getName(), AUTH_TYPE);
        if (credentialMap != null) {
            String password = (String) credentialMap.get(Constants.PROP_PASSWORD);
            String token = (String) credentialMap.get(Constants.PROP_TOKEN);
            // identification of old storage
            if (password.equals("") && token.equals("")) {
                Map oldCrendtialMap = migrateOldAuthInfoAndGetNewCredentials(url, project, AUTH_TYPE);
                if (oldCrendtialMap != null) {
                    password = (String) oldCrendtialMap.get(Constants.PROP_PASSWORD);
                    token = (String) oldCrendtialMap.get(Constants.PROP_TOKEN);
                }
            }
            forceProject.setPassword(password);
            forceProject.setToken(token);
        }

        defaultApiVersionCheck(forceProject);

        return forceProject;
    }

    private Map migrateOldAuthInfoAndGetNewCredentials(URL url, IProject project, String authType) {
        //get the existing password and security token
        Map authorizationInfo = Platform.getAuthorizationInfo(url, project.getName(), authType);
        //This adds the authorization information to new migrated project using default mechanism
        if (authorizationInfo != null) {
            getAuthorizationService().addAuthorizationInfo(url.toString(), project, authType, authorizationInfo);
            try {
                Platform.flushAuthorizationInfo(url, project.getName(), authType);
            } catch (CoreException e) {
                logger.error("Unable to delete old preferences", e);
            }
            return authorizationInfo;
        }
        return null;
    }

    private void defaultApiVersionCheck(ForceProject forceProject) {
        String endpointApiVesion = forceProject.getEndpointApiVersion();
        String lastSupportEndpointVersion = getLastSupportedEndpointVersion();
        if (Utils.isNotEmpty(endpointApiVesion) && endpointApiVesion.equals(lastSupportEndpointVersion)) {
            return;
        }

        StringBuilder stringBuilder = new StringBuilder("API version '");
        stringBuilder.append(endpointApiVesion)
                .append("' is not supported by this Force.com IDE release. Project will be updated to ")
                .append("latest supported API version: ").append(lastSupportEndpointVersion);
        logger.warn(stringBuilder.toString());

        getMetadataFactory().removeMetadataStubExt(forceProject);
        getConnectionFactory().removeConnection(forceProject);
        getConnectionFactory().getDescribeObjectRegistry().remove(forceProject.getProject().getName());
        forceProject.setEndpointApiVersion(lastSupportEndpointVersion);
        saveForceProject(forceProject);

        if (logger.isInfoEnabled()) {
            logger.info("Remove all cached connections and objects related to unsupported API version");
        }
    }

    public void saveForceProject(ForceProject forceProject) {
        saveForceProject(forceProject.getProject(), forceProject);
    }

    public void saveForceProject(IProject project, ForceProject forceProject) {
        setString(project, Constants.PROP_USERNAME, forceProject.getUserName());
        setString(project, Constants.PROP_NAMESPACE_PREFIX, forceProject.getNamespacePrefix());

        setString(project, Constants.PROP_PACKAGE_NAME, forceProject.getPackageName());
        setString(project, Constants.PROP_ENDPOINT_SERVER, forceProject.getEndpointServer());
        setString(project, Constants.PROP_ENDPOINT_ENVIRONMENT, forceProject.getEndpointEnvironment());
        setString(project, Constants.PROP_ENDPOINT_API_VERSION, forceProject.getEndpointApiVersion());
        setString(project, Constants.PROP_METADATA_FORMAT_VERSION, forceProject.getMetadataFormatVersion());
        setString(project, Constants.PROP_IDE_VERSION, forceProject.getIdeVersion());
        setString(project, Constants.PROP_PROJECT_IDENTIFIER, forceProject.getProjectIdentifier());
        setBoolean(project, Constants.PROP_KEEP_ENDPOINT, forceProject.isKeepEndpoint());
        setBoolean(project, Constants.PROP_HTTPS_PROTOCOL, forceProject.isHttpsProtocol());
        setBoolean(project, Constants.PROP_PREFER_TOOLING_DEPLOYMENT, forceProject.getPreferToolingDeployment());
        setInt(project, Constants.PROP_READ_TIMEOUT, forceProject.getReadTimeoutSecs());

        Map<String, String> credentialMap = new HashMap<String, String>();
        credentialMap.put(Constants.PROP_PASSWORD, forceProject.getPassword());
        credentialMap.put(Constants.PROP_TOKEN, forceProject.getToken());

        getAuthorizationService().addAuthorizationInfo(AUTH_URL, project, AUTH_TYPE, credentialMap);
    }

    public int getReadTimeout(IProject project) {
        return getInt(project, Constants.PROP_READ_TIMEOUT, Constants.READ_TIMEOUT_IN_SECONDS_DEFAULT);
    }

    public int getReadTimeoutInMilliSeconds(IProject project) {
        return (getInt(project, Constants.PROP_READ_TIMEOUT, Constants.READ_TIMEOUT_IN_SECONDS_DEFAULT) * Constants.SECONDS_TO_MILISECONDS);
    }

    public String getUsername(IProject project) {
        return getString(project, Constants.PROP_USERNAME, Constants.EMPTY_STRING);
    }

    public String getPassword(IProject project) {
        return getAuthorizationService().getPassword(project, AUTH_URL, AUTH_TYPE);
    }

    public boolean hasCredentials(IProject project) {
        return Utils.isNotEmpty(getUsername(project)) && Utils.isNotEmpty(getPassword(project));
    }

    public String getPackageName(IProject project) {
        String packageName = getString(project, Constants.PROP_PACKAGE_NAME, Constants.EMPTY_STRING);
        if (Utils.isEmpty(packageName)) {
            // attempt to infer via package.xml
            try {
                packageName = getPackageManifestFactory().getPackageNameFromPackageManifest(project);
            } catch (FactoryException e) {
                logger.warn("Unable to get package name from project's package manifest");
            }
        }

        return Utils.isNotEmpty(packageName) ? packageName : Constants.DEFAULT_PACKAGED_NAME;
    }

    public String getNamespacePrefix(IProject project) {
        return getString(project, Constants.PROP_NAMESPACE_PREFIX, Constants.EMPTY_STRING);
    }

    public String getSoapEndPoint(IProject project) {
        return getString(project, Constants.PROP_ENDPOINT_SERVER, Constants.EMPTY_STRING);
    }

    public String getIdeVersion(IProject project) {
        return getString(project, Constants.PROP_IDE_VERSION, Constants.EMPTY_STRING);
    }

    public void setIdeVersion(IProject project, String ideVersion) {
        setString(project, Constants.PROP_IDE_VERSION, ideVersion);
    }

    public String getInstalledIdeVersion() {
        String version = ForceIdeCorePlugin.getBundleVersion(true);
        if (version.split("\\.").length > 2) {
            version = version.substring(0, version.lastIndexOf("."));
        }

        return version;
    }

    public void updateIdeVersion(IProject project) {
        updateIdeVersion(project, getInstalledIdeVersion());
    }

    public void updateIdeVersion(IProject project, String version) {
        if (Utils.isEmpty(version) || version.indexOf(".") < 1) {
            version = ForceIdeCorePlugin.getBundleVersion(true);
        }

        if (version.split("\\.").length > 2) {
            version = version.substring(0, version.lastIndexOf("."));
        }

        setString(project, Constants.PROP_IDE_VERSION, version);
        setString(project, Constants.PROP_METADATA_FORMAT_VERSION, version);
        setString(project, Constants.PROP_ENDPOINT_API_VERSION, version);

        if (logger.isDebugEnabled()) {
            logger.debug("Updated project's ide version to " + version);
        }
    }

    public boolean isProjectUpgradeable(IProject project) {
        return Utils.isEqual(getIdeVersion(project), getInstalledIdeVersion());
    }

    // R E S O U R C E  H E L P E R S

    public IProject getProject(ISelection selection) {
        if (selection == null || selection.isEmpty() || selection instanceof IStructuredSelection == false) {
            return null;
        }

        IStructuredSelection ss = (IStructuredSelection) selection;
        Object obj = ss.getFirstElement();
        if (obj == null || obj instanceof IResource == false) {
            return null;
        }

        IResource resource = (IResource) obj;
        return resource.getProject();
    }

    public void setResourceAttributes(IFile file) {
        try {
            Component component = getComponentFactory().getComponentFromFile(file, false);
            if (component.isInstalled()) {
                ResourceAttributes resourceAttributes = new ResourceAttributes();
                resourceAttributes.setReadOnly(true);
            }
        } catch (Exception e) {
            logger.error("Unable to set read-only access son file " + file.getName(), e);
        }
    }

    public IFile saveToFile(IFile file, String content, IProgressMonitor monitor) throws InvocationTargetException,
            CoreException, IOException, InterruptedException {

        if (file == null || file.getType() != IResource.FILE || Utils.isEmpty(content)) {
            logger.warn("Unable to save file - file and/or content is null or empty");
            return null;
        }

        // save or update contents
        InputStream stream = new ByteArrayInputStream(content.getBytes());
        if (file.exists()) {
            file.setContents(stream, true, true, new SubProgressMonitor(monitor, 1));
        } else {
            file.create(stream, true, new SubProgressMonitor(monitor, 1));
        }

        stream.close();

        if (logger.isDebugEnabled()) {
            logger.debug("Saved file [" + content.length() + "] to file '"
                    + file.getProjectRelativePath().toPortableString() + "'");
        }
        return file;
    }

    // H A N D L E   R E T U R N E D   C O N T E N T   &   M E S S A G E S
    public boolean handleDeployResult(ProjectPackageList projectPackageList, DeployResultExt deployResultHandler,
            boolean save, IProgressMonitor monitor) throws CoreException, InterruptedException, IOException,
            InvocationTargetException, Exception {
        if (deployResultHandler == null || Utils.isEmpty(projectPackageList)) {
            throw new IllegalArgumentException("Project package list and/or deploy result cannot be null");
        }

        monitorCheck(monitor);
        monitorSubTask(monitor, "Handling save result...");

        List<IResource> resources = projectPackageList.getAllComponentResources(false);
        if (deployResultHandler.isSuccess()) {
            if (logger.isInfoEnabled()) {
                logger.info("Save succeeded!");
            }
            MarkerUtils.getInstance().clearDirty(resources.toArray(new IResource[resources.size()]));
        } else {
            logger.warn("Save failed!");
            MarkerUtils.getInstance().applyDirty(resources.toArray(new IResource[resources.size()]));
        }

        // clear all existing save markers on deployed resources
        MarkerUtils.getInstance().clearSaveMarkers(projectPackageList.getAllComponentResources(false));

        DeployMessageExtractor messageExtractor = new DeployMessageExtractor(deployResultHandler);

        handleDeployErrorMessages(projectPackageList, messageExtractor.getDeployFailures(), monitor);

        // retrieve result will clear markers for successfully saved files, so it must be
        // done before adding the deploy warning messages
        handleRetrieveResult(projectPackageList, deployResultHandler.getRetrieveResultHandler(), save, monitor);

        handleDeployWarningMessages(projectPackageList, messageExtractor.getDeployWarnings(), monitor);

        handleRunTestResult(projectPackageList, deployResultHandler.getRunTestsResultHandler(), monitor);

        monitorWork(monitor);

        // represents rolled up status of retrieve, test, etc events
        return deployResultHandler.isSuccess();
    }

    protected void handleDeployWarningMessages(ProjectPackageList projectPackageList,
            Collection<DeployMessage> deployWarnings, IProgressMonitor monitor) throws InterruptedException {
        if (deployWarnings.size() == 0) {
            if (logger.isInfoEnabled()) {
                logger.info("No deploy warnings found");
            }
        } else {
            monitorSubTask(monitor, "Evaluating warning messages...");

            for (DeployMessage warningMessage : deployWarnings) {
                monitorCheck(monitor);
                Component component = projectPackageList.getComponentByMetadataFilePath(warningMessage.getFileName());
                applySaveWarningMarker(component.getFileResource(), warningMessage);
                applyWarningsToAssociatedComponents(projectPackageList, component);
            }
        }
    }

    public void handleDeployErrorMessages(ProjectPackageList projectPackageList,
            Collection<DeployMessage> errorMessages, IProgressMonitor monitor) throws InterruptedException {
        if (Utils.isEmpty(projectPackageList)) {
            throw new IllegalArgumentException("Project package list and/or message handler cannot be null");
        }

        if (errorMessages.size() == 0) {
            if (logger.isInfoEnabled()) {
                logger.info("No deploy errors found");
            }
        } else {
            monitorSubTask(monitor, "Evaluating error messages...");

            for (DeployMessage deployMessage : errorMessages) {
                monitorCheck(monitor);

                // get resource (file, usually) to associate a message/project/failure/warning and displayed in problems
                // view
                Component component = projectPackageList.getComponentByMetadataFilePath(deployMessage.getFileName());
                if (component == null) {
                    handleMessageForNullComponent(projectPackageList, deployMessage);
                } else {
                    applySaveErrorMarker(component.getFileResource(), deployMessage);
                    applyWarningsToAssociatedComponents(projectPackageList, component);
                }
            }
            monitorWork(monitor);
        }
    }

    private void handleMessageForNullComponent(ProjectPackageList projectPackageList, DeployMessage deployMessage) {
        if (logger.isInfoEnabled()) {
            logger.warn("Unable to handle deploy message - could not find component '" + deployMessage.getFileName()
                    + "' in list.  Will attempt to find w/in project");
        }

        IFile file = getComponentFileForFilePath(projectPackageList.getProject(), deployMessage.getFileName());
        if (file != null) {
            if (deployMessage.isSuccess()) {
                if (logger.isInfoEnabled()) {
                    logger.info(deployMessage.getFileName() + " successfully saved");
                }
                MarkerUtils.getInstance().clearSaveMarkers(file);
            } else {
                applySaveErrorMarker(file, deployMessage);
            }
        } else {
            // didn't find associated resource
            logger.warn("Unable to get file resource for '" + deployMessage.getFileName() + "' for message "
                    + deployMessage.getProblem());
        }
    }

    private void applySaveErrorMarker(IResource resource, DeployMessage deployMessage) {
        if (deployMessage == null) {
            logger.error("Unable to mark resource with deploy message - deploy message is null");
            return;
        }

        MarkerUtils.getInstance().applyDirty(resource);
        boolean componentHasSubType = false;
        try {
            componentHasSubType =
                    (resource instanceof IFile) ? getComponentFactory().getComponentFromFile((IFile) resource)
                            .hasSubComponentTypes() : false;
        } catch (FactoryException e) {
            logger.debug("Unable to determine whether component " + resource.getName() + " has a subtype", e);
        }

        // Bug #221065: display fullname info only for components that have subtypes:
        String problemStr =
                (componentHasSubType) ? deployMessage.getFullName() + " : " + deployMessage.getProblem()
                        : deployMessage.getProblem();

        MarkerUtils.getInstance().applySaveErrorMarker(resource, deployMessage.getLineNumber(),
            deployMessage.getColumnNumber(), deployMessage.getColumnNumber(), problemStr);
    }

    private void applySaveWarningMarker(IResource resource, DeployMessage deployMessage) {
        Preconditions.checkNotNull(deployMessage);

        boolean componentHasSubType = false;
        try {
            componentHasSubType =
                    (resource instanceof IFile) ? getComponentFactory().getComponentFromFile((IFile) resource)
                            .hasSubComponentTypes() : false;
        } catch (FactoryException e) {
            logger.debug("Unable to determine whether component " + resource.getName() + " has a subtype", e);
        }

        // Bug #221065: display fullname info only for components that have subtypes:
        String problemStr =
                (componentHasSubType) ? deployMessage.getFullName() + " : " + deployMessage.getProblem()
                        : deployMessage.getProblem();

        MarkerUtils.getInstance().applySaveWarningMarker(resource, deployMessage.getLineNumber(),
            deployMessage.getColumnNumber(), deployMessage.getColumnNumber(), problemStr);
    }

    public boolean handleRetrieveResult(RetrieveResultExt retrieveResultHandler, boolean save, IProgressMonitor monitor)
            throws InterruptedException, CoreException, IOException, InvocationTargetException, Exception {
        if (retrieveResultHandler == null) {
            throw new IllegalArgumentException("Retrieve result cannot be null");
        }
        return handleRetrieveResult(retrieveResultHandler.getProjectPackageList(), retrieveResultHandler, save, monitor);
    }

    public boolean handleRetrieveResult(ProjectPackageList projectPackageList, RetrieveResultExt retrieveResultHandler,
            boolean save, IProgressMonitor monitor) throws InterruptedException, CoreException, IOException,
            InvocationTargetException {
        return handleRetrieveResult(projectPackageList, retrieveResultHandler, save, null, monitor);
    }

    public boolean handleRetrieveResult(final ProjectPackageList projectPackageList,
            RetrieveResultExt retrieveResultHandler, boolean save, final String[] toSaveComponentTypes,
            IProgressMonitor monitor) throws InterruptedException, CoreException, IOException,
            InvocationTargetException {
        if (projectPackageList == null) {
            throw new IllegalArgumentException("Project package list cannot be null");
        }

        //Can't handler the results if there isn't one.
        if (retrieveResultHandler == null) {
            return false;
        }

        // save results to project
        if (save) {
            if (retrieveResultHandler.getZipFileCount() == 0) {
                logger.warn("Nothing to save to project - retrieve result is empty");
                return true;
            }

            if (logger.isDebugEnabled()) {
                logger.debug("Saving returned content to project");
            }

            monitorCheckSubTask(monitor, Messages.getString("Components.Generating"));

            // clean then load clean project package list to be saved to project
            projectPackageList.removeAllComponents();
            projectPackageList.generateComponentsForComponentTypes(retrieveResultHandler.getZipFile(),
                retrieveResultHandler.getFileMetadataHandler(), toSaveComponentTypes, monitor);
            retrieveResultHandler.setProjectPackageList(projectPackageList);
            monitorWork(monitor);

            // flag builder to not build and save
            flagSkipBuilder(projectPackageList.getProject());
            monitorCheckSubTask(monitor, Messages.getString("Components.Saving"));

            ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
                @Override
                public void run(IProgressMonitor monitor) throws CoreException {
                    try {
                        projectPackageList.saveResources(toSaveComponentTypes, monitor);
                    } catch (Exception e) {
                        throw new CoreException(new Status(IStatus.ERROR, Constants.FORCE_PLUGIN_PREFIX, 0,
                                e.getMessage(), e));
                    }
                }
            }, null, IResource.NONE, monitor);

            monitorWork(monitor);
        } else {
            logger.warn("Save intentionally skipped; may be handled later downstream by client");
        }

        if (retrieveResultHandler.getMessageHandler() != null) {
            monitorSubTask(monitor, "Applying retrieve result messages to components...");
            handleRetrieveMessages(projectPackageList, retrieveResultHandler.getMessageHandler(), toSaveComponentTypes,
                monitor);
            monitorWork(monitor);
        }

        return true;
    }

    /**
     * @param projectPackageList
     * @param messageHandler
     * @param toSaveComponentTypes
     *            : This param will be value only specific component folder is selected, ex. refresh from server on
     *            layout folder
     * @param monitor
     * @throws InterruptedException
     */
    public void handleRetrieveMessages(ProjectPackageList projectPackageList, RetrieveMessageExt messageHandler,
            String[] toSaveComponentTypes, IProgressMonitor monitor) throws InterruptedException {
        if (messageHandler == null || projectPackageList == null) {
            throw new IllegalArgumentException("Project package list and/or message handler cannot be null");
        }

        monitorCheck(monitor);

        // clear problem marker for specific object type package.xml stanza when object types is specified
        if (Utils.isNotEmpty(toSaveComponentTypes)) {
            IFile packageManifestFile =
                    getPackageManifestFactory().getPackageManifestFile(projectPackageList.getProject());
            MarkerUtils.getInstance().clearRetrieveMarkers(packageManifestFile, toSaveComponentTypes);
        }

        if (Utils.isEmpty(messageHandler.getMessages())) {
            if (logger.isInfoEnabled()) {
                logger.info("No retrieve messages returned");
            }
            return;
        }

        monitorSubTask(monitor, "Evaluating retrieve messages...");

        // loop thru handling each messages and associated resource
        RetrieveMessage[] retrieveMessages = messageHandler.getMessages();
        for (RetrieveMessage retrieveMessage : retrieveMessages) {
            monitorCheck(monitor);

            Component component = projectPackageList.getComponentByMetadataFilePath(retrieveMessage.getFileName());

            if (component == null) {
                logger.warn("Unable to handle retrieve message - could not find component '"
                        + retrieveMessage.getFileName() + "' for message '" + retrieveMessage.getProblem() + "'");
                continue;
            } else if (component.isPackageManifest() && Utils.isNotEmpty(toSaveComponentTypes)) {
                // look for package.xml in f/s because refresh from server at component folder level doesn't included in
                // projectpackagelist
                IFile file =
                        getComponentFileForFilePath(projectPackageList.getProject(), retrieveMessage.getFileName());
                if (file != null) {
                    MarkerUtils.getInstance().applyRetrieveWarningMarker(file, toSaveComponentTypes,
                        retrieveMessage.getProblem());
                } else {
                    logger.warn("Unable to get file resource for '" + retrieveMessage.getFileName() + "' for message "
                            + retrieveMessage.getProblem());
                }
                continue;
            }

            MarkerUtils.getInstance().applyRetrieveWarningMarker(component.getFileResource(),
                retrieveMessage.getProblem());
            applyWarningsToAssociatedComponents(projectPackageList, component);
        }

        monitorWork(monitor);
    }

    // REVIEWME: a deploy message should be sent for aborted source/metadata saves
    private void applyWarningsToAssociatedComponents(ProjectPackageList projectPackageList, Component component) {
        if (!component.isMetadataComposite()) {
            return;
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Applying error message to associated metadata component");
        }

        String compositeComponentFilePath = component.getCompositeMetadataFilePath();
        if (Utils.isEmpty(compositeComponentFilePath)) {
            logger.warn("Unable to handle composite deploy message for '" + component.getMetadataFilePath()
                    + "' - composite filepath is null or empty");
            return;
        }

        Component componentComposite = projectPackageList.getComponentByFilePath(compositeComponentFilePath);

        if (componentComposite == null) {
            logger.warn("Unable to set error marker - composite component is null");
            return;
        }

        MarkerUtils.getInstance().clearDirty(componentComposite.getFileResource());
        MarkerUtils.getInstance().applySaveWarningMarker(componentComposite.getFileResource(),
            Messages.getString("Markers.CompositeNotSave.message"));
    }

    public void handleRunTestResult(ProjectPackageList projectPackageList, RunTestsResultExt runTestResultHandler,
            IProgressMonitor monitor) throws InterruptedException {

        // handle run tests
        handleRunTestMessages(projectPackageList, runTestResultHandler, monitor);

        // handle code coverage warnings
        handleCodeCoverageWarnings(projectPackageList, runTestResultHandler, monitor);
    }

    public void handleRunTestMessages(ProjectPackageList projectPackageList, RunTestsResultExt runTestResultHandler,
            IProgressMonitor monitor) throws InterruptedException {
        if (Utils.isEmpty(projectPackageList)) {
            throw new IllegalArgumentException("Project package list cannot be null");
        }

        monitorCheck(monitor);
        monitorSubTask(monitor, "Evaluating run test results...");

        // clear all existing run test failure markers on deployed resources
        MarkerUtils.getInstance().clearRunTestFailureMarkers(
            projectPackageList.getComponentResourcesForComponentTypes(new String[] { Constants.APEX_CLASS,
                    Constants.APEX_TRIGGER }));

        if (runTestResultHandler == null || runTestResultHandler.getNumFailures() == 0) {
            if (logger.isInfoEnabled()) {
                logger.info("No test failure results found");
            }
            return;
        }

        IRunTestFailureExt[] runTestFailures = runTestResultHandler.getFailures();
        if (logger.isInfoEnabled()) {
            logger.info("Found [" + runTestResultHandler.getNumFailures() + "] run test failures");
        }

        // loop thru handling each messages and associated resource
        for (IRunTestFailureExt runTestFailure : runTestFailures) {
            monitorCheck(monitor);

            // get resource (file, usually) to associate a message/project/failure/warning and displayed in problems
            // view
            Component component =
                    projectPackageList.getComponentByNameType(runTestFailure.getName(), Constants.APEX_CLASS);
            if (component == null) {
                logger.warn("Unable to handle run test message - could not find component '" + runTestFailure.getName()
                        + "' in list.  Will attempt to find w/in project");
                try {
                    IFile file =
                            getComponentFileByNameType(projectPackageList.getProject(), runTestFailure.getName(),
                                new String[] { Constants.APEX_CLASS });

                    if (file != null) {
                        setRunTestFailureMarker(file, runTestFailure);
                    } else if (projectPackageList.getProject() != null) {
                        StringBuffer strBuff = new StringBuffer();
                        strBuff.append("Unable to get file resource for '").append(runTestFailure.getName())
                                .append("' for code coverage warning '").append(runTestFailure.getMessage())
                                .append("'. Assigning failure to project.");
                        logger.warn(strBuff.toString());
                        MarkerUtils.getInstance().applyRunTestFailureMarker(projectPackageList.getProject(),
                            runTestFailure.getMessage());
                    } else {
                        logger.warn("Unable to get file resource for '" + runTestFailure.getName()
                                + "' for run test failure " + runTestFailure.getMessage());
                    }
                } catch (CoreException e) {
                    String logMessage = Utils.generateCoreExceptionLog(e);
                    logger.warn("Unable to get file resource for '" + runTestFailure.getName() + "' for failure "
                            + runTestFailure.getMessage() + ": " + logMessage, e);
                } catch (FactoryException e) {
                    logger.error("Unable to get file resource for '" + runTestFailure.getName() + "' for failure "
                            + runTestFailure.getMessage(), e);
                }
                continue;
            }

            MarkerUtils.getInstance().applyDirty(component.getFileResource());
            setRunTestFailureMarker(component.getFileResource(), runTestFailure);
            applyWarningsToAssociatedComponents(projectPackageList, component);

            try {
                component.getFileResource().findMarkers(MarkerUtils.getInstance().MARKER_RUN_TEST_FAILURE, true,
                    IResource.DEPTH_INFINITE);
            } catch (CoreException e) {
                String logMessage = Utils.generateCoreExceptionLog(e);
                logger.warn("Unable apply run test marker on component resource: " + logMessage, e);
            }
        }

        monitorWork(monitor);

    }

    private void setRunTestFailureMarker(IResource resource, IRunTestFailureExt runTestFailure) {
        if (runTestFailure == null) {
            logger.warn("Unable to set error marker - run test failure is null");
            return;
        }

        ApexCodeLocation apexCodeLocation =
                getLocationFromStackLine(runTestFailure.getName(), runTestFailure.getStackTrace());
        int line = apexCodeLocation != null ? apexCodeLocation.getLine() : 0;
        int charStart = apexCodeLocation != null ? apexCodeLocation.getColumn() : 0;
        int charEnd = charStart + 1;
        MarkerUtils.getInstance().clearRunTestFailureMarkers(resource);
        MarkerUtils.getInstance().applyRunTestFailureMarker(resource, line, charStart, charEnd,
            runTestFailure.getMessage());
    }

    protected ApexCodeLocation getLocationFromStackLine(String name, String stackTrace) {
        if (Utils.isEmpty(name) || Utils.isEmpty(stackTrace)) {
            logger.warn("Unable to get location from stacktrace - name and/or stacktrace is null");
            return null;
        }
        final Pattern pattern =
                Pattern.compile(".*line ([0-9]+?), column ([0-9]+?).*", Pattern.DOTALL | Pattern.MULTILINE
                        | Pattern.CASE_INSENSITIVE);
        final Matcher matcher = pattern.matcher(stackTrace);
        matcher.find();
        String line = matcher.group(1);
        String column = matcher.group(2);
        return new ApexCodeLocation(name, line, column);
    }

    public void handleCodeCoverageWarnings(ProjectPackageList projectPackageList,
            RunTestsResultExt runTestResultHandler, IProgressMonitor monitor) throws InterruptedException {
        if (Utils.isEmpty(projectPackageList)) {
            throw new IllegalArgumentException("Project package list cannot be null");
        }
        IProject project = projectPackageList.getProject();

        //clear all markers on the project
        clearAllWarningMarkers(project);

        if (runTestResultHandler == null || Utils.isEmpty(runTestResultHandler.getCodeCoverageWarnings())) {
            if (logger.isInfoEnabled()) {
                logger.info("No code coverage warnings returned");
            }
            return;
        }

        monitorCheck(monitor);
        monitorSubTask(monitor, "Evaluating code coverage warnings...");

        if (logger.isInfoEnabled()) {
            logger.info("Found [" + runTestResultHandler.getCodeCoverageWarnings().length + "] code coverage warnings");
        }

        // loop thru handling each messages and associated resource
        for (ICodeCoverageWarningExt codeCoverageWarning : runTestResultHandler.getCodeCoverageWarnings()) {
            monitorCheck(monitor);

            // if name is not provided, attach warning at the project level
            if (Utils.isEmpty(codeCoverageWarning.getName())) {
                StringBuffer strBuff = new StringBuffer();
                strBuff.append("Unable to get file resource for '").append(codeCoverageWarning.getName())
                        .append("' for code coverage warning '").append(codeCoverageWarning.getMessage())
                        .append("'. Applying warning to project.");
                logger.warn(strBuff.toString());
                applyCodeCoverageWarningMarker(project, codeCoverageWarning.getMessage());
                continue;
            }

            // get resource (file, usually) to associate a message/project/failure/warning and displayed in problems
            // view
            Component component =
                    projectPackageList.getApexCodeComponent(codeCoverageWarning.getName(),
                        codeCoverageWarning.getMessage());

            if (component == null) {
                logger.warn("Unable to handle code coverage warning - could not find component '"
                        + codeCoverageWarning.getName() + "' in list.  Will attempt to find w/in project");
                try {
                    IFile file =
                            getComponentFileByNameType(project, codeCoverageWarning.getName(), new String[] {
                                    Constants.APEX_CLASS, Constants.APEX_TRIGGER });
                    if (file != null) {
                        applyCodeCoverageWarningMarker(file, codeCoverageWarning.getMessage());
                    } else if (project != null) {
                        StringBuffer strBuff = new StringBuffer("Unable to get file resource for '");
                        strBuff.append(codeCoverageWarning.getName()).append("' for code coverage warning '")
                                .append(codeCoverageWarning.getMessage()).append("'. Assigning warning to project.");
                        logger.warn(strBuff.toString());
                        applyCodeCoverageWarningMarker(project, codeCoverageWarning.getMessage());
                    } else {
                        logger.warn("Unable to get file resource for '" + codeCoverageWarning.getName()
                                + "' for code coverage warning " + codeCoverageWarning.getMessage());
                    }
                } catch (Exception e) {
                    logger.error("Unable to get file resource for '" + codeCoverageWarning.getName()
                            + "' for code coverage warning " + codeCoverageWarning.getMessage(), e);
                }
                continue;
            }
            applyCodeCoverageWarningMarker(component.getFileResource(), codeCoverageWarning.getMessage());
        }

        monitorWork(monitor);
    }

    void clearAllWarningMarkers(IProject project) {
        MarkerUtils.getInstance().clearCodeCoverageWarningMarkers(project);
    }

    private void applyCodeCoverageWarningMarker(IResource resource, String message) {
        clearAllWarningMarkers(resource.getProject());
        MarkerUtils.getInstance().applyCodeCoverageWarningMarker(resource, message);
    }

    public boolean isResourceInSync(IResource resource, IProgressMonitor monitor) throws CoreException,
            ForceConnectionException, FactoryException, IOException, ServiceException, ForceRemoteException,
            InterruptedException {
        if (resource == null) {
            throw new IllegalArgumentException("IResource cannot be null");
        }

        if (resource.getType() == IResource.PROJECT) {
            return isProjectInSync((IProject) resource, monitor);
        } else if (getProjectService().isReferencedPackageResource(resource)) {
            logger.warn("Resource '" + resource.getName() + "' is not support by in sync check");
            return true;
        } else if (resource.getType() == IResource.FOLDER) {
            return isFolderInSync((IFolder) resource, monitor);
        } else if (resource.getType() == IResource.FILE) {
            return isFileInSync((IFile) resource, monitor);
        } else {
            logger.warn("Resource '" + resource.getName() + "' is not support by in sync check");
            return true;
        }
    }

    /**
     * Check if project contents have been update remotely.
     *
     * @param project
     * @param monitor
     * @return
     * @throws CoreException
     * @throws ForceConnectionException
     * @throws FactoryException
     * @throws InterruptedException
     * @throws IOException
     * @throws ServiceException
     */
    public boolean isProjectInSync(IProject project, IProgressMonitor monitor) throws CoreException,
            ForceConnectionException, FactoryException, IOException, ServiceException, ForceRemoteException,
            InterruptedException {
        if (project == null) {
            throw new IllegalArgumentException("Project cannot be null");
        }
        // get local and remote components
        ProjectPackageList localProjectPackageList = getProjectService().getProjectContents(project, monitor);

        if (localProjectPackageList == null) {
            logger.warn("Unable to check in sync for project '" + project.getName()
                    + "' - local local project package list is null");
            return true;
        }

        monitorCheck(monitor);
        monitor.subTask("Retrieving remote compontents...");
        RetrieveResultExt retrieveResultExt =
                getPackageRetrieveService().retrieveSelective(localProjectPackageList, true, monitor);

        monitorWork(monitor);

        if (retrieveResultExt == null) {
            logger.warn("Unable to check in sync for project '" + project.getName() + "' - retrieve result is null");
            return false;
        }

        return evaluateLocalAndRemote(localProjectPackageList, retrieveResultExt, monitor);
    }

    public boolean isFolderInSync(IFolder folder, IProgressMonitor monitor) throws CoreException,
            ForceConnectionException, FactoryException, IOException, ServiceException, ForceRemoteException,
            InterruptedException {
        if (folder == null || folder.getProject() == null) {
            throw new IllegalArgumentException("Folder and/or folder's project cannot be null");
        }

        // get local components
        monitorCheck(monitor);
        monitor.subTask("Retrieving local project contents...");
        ProjectPackageList localProjectPackageList = null;
        if (getProjectService().isPackageFolder(folder) || getProjectService().isSourceFolder(folder)) {
            localProjectPackageList = getProjectPackageFactory().loadProjectPackageList(folder, monitor);
        } else if (getProjectService().isComponentFolder(folder) || getProjectService().isSubComponentFolder(folder)) {
            localProjectPackageList = getProjectPackageFactory().loadProjectPackageList(folder, monitor);
        } else if (getProjectService().isReferencedPackageResource(folder)) {
            logger.warn("Folder '" + folder.getName() + "' is not support by in sync check");
            return true;
        }

        monitor.worked(1);

        if (localProjectPackageList == null) {
            logger.warn("Unable to check in sync for folder '" + folder.getName()
                    + "' - local local project package list is null");
            return true;
        }

        localProjectPackageList.setProject(folder.getProject());

        monitorCheck(monitor);
        monitor.subTask("Retrieving remote contents...");
        RetrieveResultExt retrieveResultExt =
                getPackageRetrieveService().retrieveSelective(localProjectPackageList, true, monitor);

        if (retrieveResultExt == null) {
            logger.warn("Unable to check in sync for folder '" + folder.getName() + "' - retrieve result is null");
            return false;
        }

        monitor.worked(1);

        return evaluateLocalAndRemote(localProjectPackageList, retrieveResultExt, monitor);
    }

    public boolean isFileInSync(IFile file, IProgressMonitor monitor) throws CoreException, ForceConnectionException,
            IOException, FactoryException, ServiceException, ForceRemoteException, InterruptedException {
        if (file == null || file.getProject() == null) {
            throw new IllegalArgumentException("File and/or file's project cannot be null");
        }

        // get local components
        monitorWorkCheck(monitor, "Retrieving local project contents...");
        monitorCheck(monitor);
        ProjectPackageList localProjectPackageList = null;

        Component component = null;
        try {
            component = getComponentFactory().getComponentFromFile(file, true);
        } catch (FactoryException e) {
            logger.warn("Unable to check in sync for file '" + file.getName()
                    + "' - unable to create component from file");
            return true;
        }

        if (component.isPackageManifest()) {
            logger.warn("Component is a package manifest - skipping as sync file resource");
            // REVIEWME: what if the user wants to sync a package manifest?
            return true;
        }

        localProjectPackageList = getProjectPackageListInstance();
        localProjectPackageList.setProject(file.getProject());
        localProjectPackageList.addComponent(component, true);

        monitorWorkCheck(monitor, "Retrieving remote contents...");
        RetrieveResultExt retrieveResultExt =
                getPackageRetrieveService().retrieveSelective(localProjectPackageList, true, monitor);

        if (retrieveResultExt == null) {
            logger.warn("Unable to check in sync for file '" + file.getName() + "' - retrieve result is null");
            return false;
        }

        return evaluateLocalAndRemote(localProjectPackageList, retrieveResultExt, monitor);
    }

    private boolean evaluateLocalAndRemote(ProjectPackageList localProjectPackageList,
            RetrieveResultExt retrieveResultExt, IProgressMonitor monitor) throws InterruptedException, IOException {

        // get remote package list to evaluate
        ProjectPackageList remoteProjectPackageList = retrieveResultExt.getProjectPackageList();

        monitorCheckSubTask(monitor, Messages.getString("Components.Generating"));
        remoteProjectPackageList.generateComponents(retrieveResultExt.getZipFile(),
            retrieveResultExt.getFileMetadataHandler(), monitor);
        monitorWork(monitor);

        monitorCheck(monitor);
        // if either local or remote are empty, assume project is out-of-sync
        if ((localProjectPackageList.isEmpty() && remoteProjectPackageList.isNotEmpty())
                || (localProjectPackageList.isNotEmpty() && remoteProjectPackageList.isEmpty())) {
            return false;
        }

        monitorSubTask(monitor, Messages.getString("Components.Evaluating"));
        // test either project package
        for (ProjectPackage localProjectPackage : localProjectPackageList) {
            monitorCheck(monitor);
            // local package does not exist remotely, assume project is out-of-sync
            if (!remoteProjectPackageList.hasPackage(localProjectPackage.getName())) {
                logger.warn("Project package '" + localProjectPackage.getName()
                        + "' does not exist remotely - assuming project is out of sync");
                return false;
            }

            // deep equal check on same-named project package
            ProjectPackage remoteProjectPackage =
                    remoteProjectPackageList.getProjectPackage(localProjectPackage.getName());
            if (!localProjectPackage.hasChanged(remoteProjectPackage)) {
                logger.warn("Project package '" + localProjectPackage.getName()
                        + "' does not jive with remote package - assuming project is out of sync");
                return false;
            }
            monitorCheck(monitor);
        }

        monitorWork(monitor);

        // sweet, project contents are up-to-date
        return true;
    }

    private IAuthorizationService getAuthorizationService() {
        return authService;
    }
}
TOP

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

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.