blob: 89ec6788407a9deabe26154d6ce0633b57413487 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}