org.eclipse.acceleo.ide.ui.resources.AcceleoProject.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.acceleo.ide.ui.resources.AcceleoProject.java

Source

/*******************************************************************************
 * Copyright (c) 2008, 2012 Obeo.
 * 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:
 *     Obeo - initial API and implementation
 *******************************************************************************/
package org.eclipse.acceleo.ide.ui.resources;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.acceleo.common.IAcceleoConstants;
import org.eclipse.acceleo.common.utils.CompactHashSet;
import org.eclipse.acceleo.common.utils.ModelUtils;
import org.eclipse.acceleo.engine.AcceleoEnginePlugin;
import org.eclipse.acceleo.ide.ui.AcceleoUIActivator;
import org.eclipse.acceleo.model.mtl.MtlPackage;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IBundleGroup;
import org.eclipse.core.runtime.IBundleGroupProvider;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IPluginDescriptor;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.pde.core.plugin.IPluginModelBase;
import org.eclipse.pde.core.plugin.PluginRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.Constants;

/**
 * A Acceleo project represents a view of a project resource in terms of Acceleo elements. Each Acceleo
 * project has a classpath, defining which folders contain source code and where templates are located. Each
 * Acceleo project also has an output location. The extension of a template is '.acceleo' and the extension of
 * an output file is '.emtl'.
 * 
 * @author <a href="mailto:jonathan.musset@obeo.fr">Jonathan Musset</a>
 */
public class AcceleoProject {

    /**
     * Save the found URIs of the EMTL files in the plug-ins. The key is the bundle symbolic name and the
     * values are the URIs of the bundle EMTL files.
     */
    private static Map<String, List<URI>> bundle2outputFiles = new HashMap<String, List<URI>>();

    /**
     * Indicates if the saved map is complete.
     */
    private static boolean allBundlesOutputFilesFound;

    /**
     * Indicates if the EMF registry has been initialized.
     */
    private static boolean registryInitialized;

    /**
     * The project.
     */
    private IProject project;

    /**
     * The folders that contain the Acceleo sources (A Acceleo source folder is a Java source folder).
     */
    private List<IPath> sourceFolders;

    /**
     * Output file cache for MANIFEST.MF dependencies.
     */
    private List<URI> outputFilesWithManifest;

    /**
     * The MANIFEST.MF file modification stamp. If the modification stamp doesn't change, we haven't to
     * compute the MANIFEST.MF dependencies. We can use the variable 'outputFilesWithManifest' to get the
     * dependencies while the MANIFEST.MF file doesn't change.
     */
    private long manifestModificationStamp = -1;

    /**
     * Constructor.
     * 
     * @param project
     *            is the project
     */
    public AcceleoProject(IProject project) {
        if (!registryInitialized) {
            registryInitialized = true;
            registerPackages();
        }
        this.project = project;
        this.sourceFolders = new ArrayList<IPath>();
        final IJavaProject javaProject = JavaCore.create(project);
        IClasspathEntry[] entries;
        try {
            entries = javaProject.getResolvedClasspath(true);
        } catch (JavaModelException e1) {
            entries = new IClasspathEntry[] {};
        }
        for (int i = 0; i < entries.length; i++) {
            IClasspathEntry entry = entries[i];
            if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                this.sourceFolders.add(entry.getPath());
            }
        }
    }

    /**
     * Register the Acceleo metamodel NsURI.
     */
    private static void registerPackages() {
        if (!EPackage.Registry.INSTANCE.containsKey(MtlPackage.eINSTANCE.getNsURI())) {
            EPackage.Registry.INSTANCE.put(org.eclipse.ocl.ecore.EcorePackage.eINSTANCE.getNsURI(),
                    org.eclipse.ocl.ecore.EcorePackage.eINSTANCE);
            EPackage.Registry.INSTANCE.put(org.eclipse.ocl.expressions.ExpressionsPackage.eINSTANCE.getNsURI(),
                    org.eclipse.ocl.expressions.ExpressionsPackage.eINSTANCE);
            EPackage.Registry.INSTANCE.put("http://www.eclipse.org/ocl/1.1.0/oclstdlib.ecore", //$NON-NLS-1$
                    getOCLStdLibPackage());
            EPackage.Registry.INSTANCE.put(MtlPackage.eINSTANCE.getNsURI(), MtlPackage.eINSTANCE);
        }
    }

    /**
     * Returns the package containing the OCL standard library.
     * 
     * @return The package containing the OCL standard library.
     * @generated
     */
    private static EPackage getOCLStdLibPackage() {
        EcoreEnvironmentFactory factory = new EcoreEnvironmentFactory();
        EcoreEnvironment environment = (EcoreEnvironment) factory.createEnvironment();
        return (EPackage) EcoreUtil.getRootContainer(environment.getOCLStandardLibrary().getBag());
    }

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof AcceleoProject) {
            return ((AcceleoProject) obj).project.equals(project);
        }
        return false;
    }

    /**
     * {@inheritDoc}
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return project.getName().hashCode();
    }

    /**
     * Returns a list of existing Acceleo files (Acceleo files only) in this resource.
     * 
     * @return all the Acceleo files
     * @throws CoreException
     *             contains a status object describing the cause of the exception
     */
    public List<IFile> getInputFiles() throws CoreException {
        List<IFile> filesInput = new ArrayList<IFile>();
        for (Iterator<IPath> itSourceFolders = sourceFolders.iterator(); itSourceFolders.hasNext();) {
            IPath sourceFolderPath = itSourceFolders.next();
            if (sourceFolderPath.segmentCount() > 1) {
                IFolder sourceFolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(sourceFolderPath);
                if (sourceFolder != null && sourceFolder.isAccessible()) {
                    computeInputFiles(filesInput, sourceFolder);
                }
            }
        }
        return filesInput;
    }

    /**
     * Computes a list of existing Acceleo files (Acceleo files only) in this resource.
     * 
     * @param filesInput
     *            an output parameter to get all the Acceleo files
     * @param container
     *            is the container to browse
     * @throws CoreException
     *             contains a status object describing the cause of the exception
     */
    private void computeInputFiles(List<IFile> filesInput, IContainer container) throws CoreException {
        if (container != null) {
            IResource[] children = container.members();
            if (children != null) {
                for (int i = 0; i < children.length; ++i) {
                    IResource resource = children[i];
                    if (resource instanceof IFile
                            && IAcceleoConstants.MTL_FILE_EXTENSION.equals(((IFile) resource).getFileExtension())) {
                        filesInput.add((IFile) resource);
                    } else if (resource instanceof IContainer) {
                        computeInputFiles(filesInput, (IContainer) resource);
                    }
                }
            }
        }
    }

    /**
     * Gets the output file path (EMTL) for the given Acceleo file. For example : <br>
     * '/MyProject/src/org/eclipse/acceleo/file.acceleo' becomes
     * '/MyProject/bin/org/eclipse/acceleo/file.emtl' </br>
     * 
     * @param fileAcceleo
     *            is the Acceleo file
     * @return the output file path
     */
    public IPath getOutputFilePath(IFile fileAcceleo) {
        IPath projectPath = project.getRawLocation();
        if (projectPath == null) {
            projectPath = project.getLocation();
        }
        IPath acceleoFilePath = fileAcceleo.getRawLocation();
        if (acceleoFilePath == null) {
            acceleoFilePath = fileAcceleo.getLocation();
        }

        IPath filePath = makeRelativeTo(acceleoFilePath, projectPath);
        IFolder folder = getOutputFolder(project);
        if (folder != null) {
            for (Iterator<IPath> itSourceFolders = sourceFolders.iterator(); itSourceFolders.hasNext();) {
                IPath sourcePath = makeRelativeTo(itSourceFolders.next(), project.getFullPath());
                if (sourcePath.isPrefixOf(filePath)) {
                    IPath relativePath = filePath.removeFirstSegments(sourcePath.segmentCount());
                    return folder.getFullPath().append(relativePath.removeFileExtension()
                            .addFileExtension(IAcceleoConstants.EMTL_FILE_EXTENSION));
                }
            }
        }
        return null;
    }

    /**
     * Gets the input file path (Acceleo) for the given EMTL file path. For example : <br>
     * '/MyProject/bin/org/eclipse/acceleo/file.emtl' becomes
     * '/MyProject/src-gen/org/eclipse/acceleo/file.acceleo' </br>
     * 
     * @param fileEMTL
     *            is the EMTL file path
     * @return the input file, or null if the given file isn't valid
     */
    public IPath getInputFilePath(IPath fileEMTL) {
        IFolder folder = getOutputFolder(project);
        if (folder != null && folder.getFullPath().isPrefixOf(fileEMTL)) {
            IPath relativePath = fileEMTL.removeFileExtension()
                    .addFileExtension(IAcceleoConstants.MTL_FILE_EXTENSION)
                    .removeFirstSegments(folder.getFullPath().segmentCount());
            for (Iterator<IPath> itSourceFolders = sourceFolders.iterator(); itSourceFolders.hasNext();) {
                IPath sourcePath = itSourceFolders.next().append(relativePath);
                if (ResourcesPlugin.getWorkspace().getRoot().exists(sourcePath)) {
                    return sourcePath;
                }
            }
        }
        return null;
    }

    /**
     * This is a helper method returning the resolved classpath for the project as a list of simple classpath
     * entries.
     * 
     * @return the classpath entries
     */
    public List<IPath> getResolvedClasspath() {
        List<IPath> result = new ArrayList<IPath>();
        final IJavaProject javaProject = JavaCore.create(project);
        IClasspathEntry[] entries;
        try {
            entries = javaProject.getResolvedClasspath(true);
        } catch (JavaModelException e1) {
            AcceleoUIActivator.getDefault().getLog().log(e1.getStatus());
            entries = new IClasspathEntry[] {};
        }
        for (int i = 0; i < entries.length; i++) {
            IClasspathEntry entry = entries[i];
            result.add(entry.getPath());
        }
        return result;
    }

    /**
     * Gets the full name of the package which contains the Acceleo file. For example : <br>
     * '/MyProject/src/org/eclipse/acceleo/file.acceleo' becomes 'org.eclipse.acceleo' </br>
     * 
     * @param fileAcceleo
     *            is the Acceleo file
     * @return the full name of the package, or an empty string if the file is not valid
     */
    public String getPackageName(IFile fileAcceleo) {
        IPath projectPath = project.getRawLocation();
        if (projectPath == null) {
            projectPath = project.getLocation();
        }
        IPath acceleoFilePath = fileAcceleo.getRawLocation();
        if (acceleoFilePath == null) {
            acceleoFilePath = fileAcceleo.getLocation();
        }

        IPath filePath = makeRelativeTo(acceleoFilePath, projectPath);
        for (Iterator<IPath> itSourceFolders = sourceFolders.iterator(); itSourceFolders.hasNext();) {
            IPath sourcePath = makeRelativeTo(itSourceFolders.next(), project.getFullPath());
            if (sourcePath.isPrefixOf(filePath)) {
                StringBuffer name = new StringBuffer();
                String[] segments = filePath.removeFirstSegments(sourcePath.segmentCount()).removeLastSegments(1)
                        .segments();
                for (int i = 0; i < segments.length; i++) {
                    if (i > 0) {
                        name.append("."); //$NON-NLS-1$
                    }
                    name.append(segments[i]);
                }
                return name.toString();
            }
        }
        return ""; //$NON-NLS-1$
    }

    /**
     * Gets the output folder of the project. For example : '/MyProject/bin'.
     * 
     * @param aProject
     *            is a project of the workspace
     * @return the output folder of the project, or null if it doesn't exist
     * @see org.eclipse.acceleo.internal.ide.ui.editors.template.actions.refactor.AcceleoRefactoringUtils#getOutputFolder(IProject
     *      aProject)
     */
    private static IFolder getOutputFolder(IProject aProject) {
        final IJavaProject javaProject = JavaCore.create(aProject);
        try {
            IPath output = javaProject.getOutputLocation();
            if (output != null && output.segmentCount() > 1) {
                IFolder folder = aProject.getWorkspace().getRoot().getFolder(output);
                if (folder.isAccessible()) {
                    return folder;
                }
            }
        } catch (JavaModelException e) {
            // continue
            AcceleoUIActivator.getDefault().getLog().log(e.getStatus());
        }
        return null;
    }

    /**
     * Gets all the output files (EMTL) of this project. It means the files of the project and not the files
     * of the required plugins.
     * 
     * @return the URIs of the output files, there are only 'workspace' URIs...
     */
    public List<URI> getOutputFiles() {
        List<URI> outputURIs = new ArrayList<URI>();
        computeAccessibleOutputFilesInFolder(outputURIs, getOutputFolder(project));
        return outputURIs;
    }

    /**
     * Gets all the accessible output files (EMTL) of this project. It means the files of the project and the
     * files of the required plugins.
     * 
     * @return the URIs of the output files, there are 'plugin' URIs and 'workspace' URIs...
     */
    public List<URI> getAccessibleOutputFiles() {
        List<URI> outputURIs = new ArrayList<URI>();
        computeAccessibleOutputFilesInFolder(outputURIs, getOutputFolder(project));
        computeAccessibleOutputFilesWithPluginXML(outputURIs, project);
        computeAccessibleOutputFilesWithProjectDependencies(outputURIs, project);
        return outputURIs;
    }

    /**
     * Computes the URIs of all the accessible output files (EMTL) in the given folder.
     * 
     * @param outputURIs
     *            is an output parameter with all the URIs
     * @param folder
     *            is the folder to browse
     */
    private static void computeAccessibleOutputFilesInFolder(List<URI> outputURIs, IContainer folder) {
        if (folder == null) {
            return;
        }
        try {
            IResource[] members = folder.members();
            for (int i = 0; i < members.length; i++) {
                IResource member = members[i];
                if (member instanceof IFile) {
                    if (IAcceleoConstants.EMTL_FILE_EXTENSION.equals(((IFile) member).getFileExtension())) {
                        URI uri = URI.createPlatformResourceURI(((IFile) member).getFullPath().toString(), false);
                        if (!outputURIs.contains(uri)) {
                            outputURIs.add(uri);
                        }
                    }
                } else if (member instanceof IContainer) {
                    computeAccessibleOutputFilesInFolder(outputURIs, (IContainer) member);
                }
            }
        } catch (CoreException e) {
            AcceleoUIActivator.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, AcceleoUIActivator.PLUGIN_ID, e.getMessage(), e));
        }
    }

    /**
     * Returns the URIs of the emtl files in the required plugin of the given project.
     * 
     * @param project
     *            The project
     * @return The URIs of the emtl files in the required plugin of the given project.
     * @since 3.3
     */
    public static List<URI> computeAcceleoModuleInRequiredPlugins(IProject project) {
        List<URI> uris = new ArrayList<URI>();
        AcceleoProject acceleoProject = new AcceleoProject(project);
        acceleoProject.computeAccessibleOutputFilesWithPluginXML(uris, project);
        return uris;
    }

    /**
     * Computes the URIs of all the accessible output files (EMTL) in the dependencies of the current plug-in
     * (project). It browses all the required plug-ins declared in the 'plugin.xml' file.
     * 
     * @param outputURIs
     *            is an output parameter with all the URIs
     * @param aProject
     *            is the current plug-in
     */
    private void computeAccessibleOutputFilesWithPluginXML(List<URI> outputURIs, IProject aProject) {
        IFile manifest = aProject.getFile(new Path("META-INF/MANIFEST.MF")); //$NON-NLS-1$
        if (outputFilesWithManifest == null
                || (manifest.isAccessible() && manifest.getModificationStamp() != manifestModificationStamp)) {
            outputFilesWithManifest = new ArrayList<URI>();
            manifestModificationStamp = manifest.getModificationStamp();
            IPluginModelBase plugin = PluginRegistry.findModel(aProject);
            if (plugin != null && plugin.getBundleDescription() != null) {
                BundleDescription[] requiredPlugins = plugin.getBundleDescription().getResolvedRequires();
                for (int i = 0; i < requiredPlugins.length; i++) {
                    String requiredSymbolicName = requiredPlugins[i].getSymbolicName();
                    IProject requiredProject = ResourcesPlugin.getWorkspace().getRoot()
                            .getProject(requiredSymbolicName);
                    if (requiredProject != null && requiredProject.isAccessible()) {
                        computeAccessibleOutputFilesInFolder(outputFilesWithManifest,
                                getOutputFolder(requiredProject));
                    } else {
                        computeAccessibleOutputFilesWithBundle(outputFilesWithManifest,
                                Platform.getBundle(requiredSymbolicName));
                    }
                }
            }
        }
        for (URI uri : outputFilesWithManifest) {
            if (!outputURIs.contains(uri)) {
                outputURIs.add(uri);
            }
        }
    }

    /**
     * Computes the URIs of all the accessible output files (EMTL) in the given bundle. The bundle represents
     * a plug-in. It browses all the entries of the bundle, to get the '.emtl' files.
     * 
     * @param outputURIs
     *            is an output parameter with all the URIs
     * @param bundle
     *            is the current bundle
     */
    private static void computeAccessibleOutputFilesWithBundle(List<URI> outputURIs, Bundle bundle) {
        if (bundle != null) {
            if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE
                    || bundle.getState() == Bundle.INSTALLED || bundle.getState() == Bundle.STARTING) {
                outputURIs.addAll(getOrCreatePlatformPluginSavedURIs(bundle));
            }
        }
    }

    /**
     * Computes the URIs of all the accessible output files (EMTL) in the dependencies of the current project.
     * It browses the resolved classpath of the java project, and keeps each entry of type
     * 'IClasspathEntry.CPE_PROJECT'.
     * 
     * @param outputURIs
     *            is an output parameter with all the URIs
     * @param aProject
     *            is the current project
     */
    private void computeAccessibleOutputFilesWithProjectDependencies(List<URI> outputURIs, IProject aProject) {
        final IJavaProject javaProject = JavaCore.create(aProject);
        IClasspathEntry[] entries;
        try {
            entries = javaProject.getResolvedClasspath(true);
        } catch (JavaModelException e1) {
            AcceleoUIActivator.getDefault().getLog().log(e1.getStatus());
            entries = new IClasspathEntry[] {};
        }
        for (int i = 0; i < entries.length; i++) {
            IClasspathEntry entry = entries[i];
            if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
                IProject requiredProject = ResourcesPlugin.getWorkspace().getRoot()
                        .getProject(entry.getPath().toString());
                if (requiredProject != null && requiredProject.exists()) {
                    computeAccessibleOutputFilesInFolder(outputURIs, getOutputFolder(requiredProject));
                }
            }
        }
    }

    /**
     * Gets all the accessible Acceleo projects of the workspace. It means that the current project is
     * included.
     * 
     * @return the accessible Acceleo projects
     */
    public List<AcceleoProject> getRecursivelyAccessibleAcceleoProjects() {
        List<AcceleoProject> result = new ArrayList<AcceleoProject>();
        for (IProject aProject : getRecursivelyAccessibleProjects()) {
            try {
                if (aProject.isAccessible() && aProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) {
                    result.add(new AcceleoProject(aProject));
                }
            } catch (CoreException e) {
                AcceleoUIActivator.getDefault().getLog().log(e.getStatus());
            }
        }
        return result;
    }

    /**
     * Gets all the accessible projects of the workspace. It means that the current project is included.
     * 
     * @return the accessible projects
     * @since 3.0
     */
    public List<IProject> getRecursivelyAccessibleProjects() {
        List<IProject> result = new ArrayList<IProject>();
        computeAccessibleProjects(result, project);
        return result;
    }

    /**
     * Computes all the accessible projects.
     * 
     * @param accessibleProjects
     *            is the output list that will contain all the accessible projects
     * @param current
     *            is the current project
     */
    private void computeAccessibleProjects(List<IProject> accessibleProjects, IProject current) {
        if (!accessibleProjects.contains(current)) {
            accessibleProjects.add(current);
            IPluginModelBase plugin = PluginRegistry.findModel(current);
            if (plugin != null && plugin.getBundleDescription() != null) {
                BundleDescription[] requiredPlugins = plugin.getBundleDescription().getResolvedRequires();
                for (int i = 0; i < requiredPlugins.length; i++) {
                    String requiredSymbolicName = requiredPlugins[i].getSymbolicName();
                    IProject requiredProject = ResourcesPlugin.getWorkspace().getRoot()
                            .getProject(requiredSymbolicName);
                    if (requiredProject != null && requiredProject.isAccessible()) {
                        computeAccessibleProjects(accessibleProjects, requiredProject);
                    }
                }
            }
            final IJavaProject javaProject = JavaCore.create(current);
            IClasspathEntry[] entries;
            try {
                entries = javaProject.getResolvedClasspath(true);
            } catch (JavaModelException e1) {
                AcceleoUIActivator.getDefault().getLog().log(e1.getStatus());
                entries = new IClasspathEntry[] {};
            }
            for (int i = 0; i < entries.length; i++) {
                IClasspathEntry entry = entries[i];
                if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
                    IProject requiredProject = ResourcesPlugin.getWorkspace().getRoot()
                            .getProject(entry.getPath().toString());
                    if (requiredProject != null && requiredProject.exists()) {
                        computeAccessibleProjects(accessibleProjects, requiredProject);
                    }
                }
            }
        }
    }

    /**
     * Gets in a single resource set all the accessible AST resources (EMTL). It means the files of the
     * project and the files of the required plugins. You must unload the resources of the returned resource
     * set by yourself.
     * 
     * @return a resource set which contains all the accessible resources
     * @deprecated It's a long time operation, the monitor allows the operation to be canceled. Now you have
     *             to use : loadAccessibleOutputFiles(IProgressMonitor monitor)
     */
    @Deprecated
    public ResourceSet loadAccessibleOutputFiles() {
        return loadAccessibleOutputFiles(new NullProgressMonitor());
    }

    /**
     * Gets in a single resource set all the accessible AST resources (EMTL). It means the files of the
     * project and the files of the required plugins. You must unload the resources of the returned resource
     * set by yourself.
     * 
     * @param monitor
     *            is the monitor
     * @return a resource set which contains all the accessible resources
     * @since 3.0
     */
    public ResourceSet loadAccessibleOutputFiles(IProgressMonitor monitor) {
        ResourceSet oResourceSet = new ResourceSetImpl();
        List<URI> outputURIs = getAccessibleOutputFiles();
        for (Iterator<URI> itOutputURIs = outputURIs.iterator(); itOutputURIs.hasNext() && !monitor.isCanceled();) {
            URI oURI = itOutputURIs.next();
            try {
                ModelUtils.load(oURI, oResourceSet);
            } catch (WrappedException e) {
                // continue and do nothing because it occurs when the EMTL file has been deleted
            } catch (IOException e) {
                // continue and do nothing because it occurs when the EMTL file has been deleted
            }
        }
        return oResourceSet;
    }

    /**
     * Gets in a single resource set all the not accessible AST resources (EMTL). It means all the EMTL files
     * of the Eclipse instance (plugin and workspace) not in the project and not in the required plugins. You
     * must unload the resources of the returned resource set by yourself.
     * 
     * @param monitor
     *            is the monitor
     * @return a resource set which contains all the not accessible resources
     * @since 3.0
     */
    public ResourceSet loadNotAccessibleOutputFiles(IProgressMonitor monitor) {
        return loadAllPlatformOutputFiles(this, monitor);
    }

    /**
     * Gets in a single resource set all the EMTL files of the Eclipse instance, it means in the plug-ins and
     * in the workspace. You must unload the resources of the returned resource set by yourself.
     * 
     * @param monitor
     *            is the monitor
     * @return a resource set which contains all the not accessible resources
     * @since 3.0
     */
    public static ResourceSet loadAllPlatformOutputFiles(IProgressMonitor monitor) {
        if (!registryInitialized) {
            registryInitialized = true;
            registerPackages();
        }
        return loadAllPlatformOutputFiles(null, monitor);
    }

    /**
     * Gets in a single resource set all the EMTL files of the Eclipse instance, it means in the plug-ins and
     * in the workspace. You must unload the resources of the returned resource set by yourself. We can ignore
     * the accessible output files, it means all the EMTL files of the given project and its required plugins.
     * 
     * @param excludeAccessible
     *            the accessible output files we want to exclude, null indicates that we don't want to ignore
     *            anything
     * @param monitor
     *            is the monitor
     * @return a resource set which contains all the not accessible resources
     */
    private static ResourceSet loadAllPlatformOutputFiles(AcceleoProject excludeAccessible,
            IProgressMonitor monitor) {
        ResourceSet oResourceSet = new ResourceSetImpl();
        List<URI> outputURIs = new ArrayList<URI>();
        for (IProject aProject : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
            try {
                if (aProject.isAccessible() && aProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) {
                    computeAccessibleOutputFilesInFolder(outputURIs, getOutputFolder(aProject));
                }
            } catch (CoreException e) {
                AcceleoUIActivator.getDefault().getLog().log(e.getStatus());
            }
        }
        outputURIs.addAll(getAllPlatformPluginOutputFiles());
        List<URI> excludeURIs;
        if (excludeAccessible != null) {
            excludeURIs = excludeAccessible.getAccessibleOutputFiles();
        } else {
            excludeURIs = null;
        }
        for (Iterator<URI> itOutputURIs = outputURIs.iterator(); itOutputURIs.hasNext() && !monitor.isCanceled();) {
            URI oURI = itOutputURIs.next();
            if (excludeURIs == null || !excludeURIs.contains(oURI)) {
                try {
                    ModelUtils.load(oURI, oResourceSet);
                } catch (WrappedException e) {
                    // continue and do nothing because it occurs when the EMTL file has been deleted
                } catch (IOException e) {
                    // continue and do nothing because it occurs when the EMTL file has been deleted
                }
            }
        }
        return oResourceSet;
    }

    /**
     * Gets the URIs of all the EMTL files in the workspace.
     * 
     * @return the URIs of all the EMTL files
     * @since 3.0
     */
    public static List<URI> getAllPlatformResourceOutputFiles() {
        List<URI> outputURIs = new ArrayList<URI>();
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        for (IProject aProject : projects) {
            try {
                if (aProject.isAccessible() && aProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) {
                    computeAccessibleOutputFilesInFolder(outputURIs, getOutputFolder(aProject));
                }
            } catch (CoreException e) {
                AcceleoUIActivator.getDefault().getLog().log(e.getStatus());
            }
        }
        return outputURIs;
    }

    /**
     * Returns the URIs of the EMTL files in the bundle dependencies of the given project.
     * 
     * @param project
     *            The project
     * @return The URIs of the EMTL files in the bundle dependencies of the given project.
     * @since 3.3
     */
    public static List<URI> getAccessiblePluginModules(IProject project) {
        List<URI> outputURIs = new ArrayList<URI>();
        List<String> bundles = new ArrayList<String>();

        IPluginModelBase plugin = PluginRegistry.findModel(project);
        if (plugin != null && plugin.getBundleDescription() != null) {
            BundleDescription[] requiredPlugins = plugin.getBundleDescription().getResolvedRequires();
            for (int i = 0; i < requiredPlugins.length; i++) {
                String requiredSymbolicName = requiredPlugins[i].getSymbolicName();
                bundles.add(requiredSymbolicName);
            }
        }

        for (String bundle : bundles) {
            outputURIs.addAll(bundle2outputFiles.get(bundle));
        }
        return outputURIs;
    }

    /**
     * Gets the URIs of all the EMTL files in the plug-ins. It also creates the EMTL files if only the MTL
     * files are available. The workspace files are ignored.
     * 
     * @return the URIs of all the EMTL files
     * @since 3.0
     */
    public static List<URI> getAllPlatformPluginOutputFiles() {
        List<URI> outputURIs = new ArrayList<URI>();
        if (!allBundlesOutputFilesFound) {
            Set<String> done = new CompactHashSet<String>();
            IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
            for (IProject aProject : projects) {
                try {
                    if (aProject.isAccessible() && aProject.hasNature(IAcceleoConstants.ACCELEO_NATURE_ID)) {
                        done.add(aProject.getName());
                    }
                } catch (CoreException e) {
                    AcceleoUIActivator.getDefault().getLog().log(e.getStatus());
                }
            }
            IBundleGroupProvider[] providers = Platform.getBundleGroupProviders();
            for (IBundleGroupProvider provider : providers) {
                for (IBundleGroup group : provider.getBundleGroups()) {
                    for (Bundle bundle : group.getBundles()) {
                        String name = bundle.getSymbolicName();
                        if (!done.contains(name)) {
                            if (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE
                                    || bundle.getState() == Bundle.INSTALLED
                                    || bundle.getState() == Bundle.STARTING) {
                                done.add(name);
                                outputURIs.addAll(getOrCreatePlatformPluginSavedURIs(bundle));
                            }
                        }
                    }
                }
            }
            // Deprecated? Yes, but the following API give more results
            for (IPluginDescriptor descriptor : Platform.getPluginRegistry().getPluginDescriptors()) {
                String name = descriptor.getUniqueIdentifier();
                if (!done.contains(name)) {
                    done.add(name);
                    Bundle bundle = Platform.getBundle(name);
                    if (bundle != null) {
                        outputURIs.addAll(getOrCreatePlatformPluginSavedURIs(bundle));
                    }
                }
            }
            allBundlesOutputFilesFound = true;
        } else {
            for (List<URI> values : bundle2outputFiles.values()) {
                outputURIs.addAll(values);
            }
        }
        return outputURIs;
    }

    /**
     * Gets and saves the URIs of all the EMTL files in the plug-ins. The workspace files are ignored. We
     * search the URIs only one time, because the bundles won't change. This method only saves the found URIs
     * of the EMTL files for the given plug-in.
     * 
     * @param bundle
     *            is the OSGI bundle of the plug-in
     * @return the URIs of all the EMTL files in the plug-ins
     */
    private static List<URI> getOrCreatePlatformPluginSavedURIs(Bundle bundle) {
        String name = bundle.getSymbolicName();
        List<URI> savedURIs = bundle2outputFiles.get(name);
        if (savedURIs == null) {
            savedURIs = new ArrayList<URI>();
            bundle2outputFiles.put(name, savedURIs);
            String required = (String) bundle.getHeaders().get(Constants.REQUIRE_BUNDLE);
            if (required != null && required.indexOf(AcceleoEnginePlugin.PLUGIN_ID) != -1) {
                computeSaveURIs(bundle, savedURIs);
            }
        }
        return savedURIs;
    }

    /**
     * Computes the saved URIs of the given bundle.
     * 
     * @param bundle
     *            the bundle to browse
     * @param savedURIs
     *            the EMTL files URIs to get, it is an input/output parameter
     */
    @SuppressWarnings("unchecked")
    private static void computeSaveURIs(Bundle bundle, List<URI> savedURIs) {
        // The first time we would like to be sure to extract the MTL files of the plug-in jar.
        Enumeration<URL> entriesMTL = bundle.findEntries("/", "*." + IAcceleoConstants.MTL_FILE_EXTENSION, true); //$NON-NLS-1$ //$NON-NLS-2$
        Enumeration<URL> entriesEMTL = bundle.findEntries("/", "*." + IAcceleoConstants.EMTL_FILE_EXTENSION, true); //$NON-NLS-1$ //$NON-NLS-2$
        if (entriesEMTL != null && entriesEMTL.hasMoreElements()) {
            while (entriesEMTL.hasMoreElements()) {
                URL entry = entriesEMTL.nextElement();
                if (entry != null) {
                    IPath path = new Path(entry.getPath());
                    if (path.segmentCount() > 0) {
                        savedURIs.add(URI.createPlatformPluginURI(
                                new Path(bundle.getSymbolicName()).append(path).toString(), false));
                    }
                }
            }
        }
    }

    /**
     * Returns the list of source folders in the project.
     * 
     * @return The list of source folders in the project.
     * @since 3.1
     */
    public List<IPath> getSourceFolders() {
        // We create a copy to prevent problems.
        return new ArrayList<IPath>(this.sourceFolders);
    }

    /**
     * Make relative to.
     * 
     * @param path1
     *            The first path
     * @param path2
     *            the second path
     * @return The first path relative to the second path.
     * @since 3.1
     */
    public static IPath makeRelativeTo(IPath path1, IPath path2) {
        IPath path = path1;

        // can't make relative if devices are not equal
        if (path1.getDevice() == path2.getDevice()
                || (path1.getDevice() != null && path1.getDevice().equalsIgnoreCase(path2.getDevice()))) {
            int commonLength = path1.matchingFirstSegments(path2);
            final int differenceLength = path2.segmentCount() - commonLength;
            final int newSegmentLength = differenceLength + path1.segmentCount() - commonLength;
            if (newSegmentLength == 0) {
                return Path.EMPTY;
            }
            path = new Path(""); //$NON-NLS-1$
            String[] newSegments = new String[newSegmentLength];
            // add parent references for each segment different from the base
            Arrays.fill(newSegments, 0, differenceLength, ".."); //$NON-NLS-1$
            // append the segments of this path not in common with the base
            System.arraycopy(path1.segments(), commonLength, newSegments, differenceLength,
                    newSegmentLength - differenceLength);
            for (String segment : newSegments) {
                path = path.append(new Path(segment));
            }
        }

        return path;
    }
}