/******************************************************************************* * Copyright (c) 2010-2012, Zoltan Ujhelyi, Mark Czotter, Istvan Rath and Daniel Varro * 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: * Zoltan Ujhelyi, Mark Czotter - initial API and implementation *******************************************************************************/ package org.eclipse.incquery.tooling.core.project; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; 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.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.incquery.runtime.IncQueryRuntimePlugin; import org.eclipse.incquery.tooling.core.generator.IncQueryGeneratorPlugin; import org.eclipse.pde.core.plugin.IExtensions; import org.eclipse.pde.core.plugin.IPluginExtension; import org.eclipse.pde.core.plugin.IPluginExtensionPoint; import org.eclipse.pde.core.plugin.IPluginModel; import org.eclipse.pde.core.plugin.IPluginObject; import org.eclipse.pde.core.project.IBundleClasspathEntry; import org.eclipse.pde.core.project.IBundleProjectDescription; import org.eclipse.pde.core.project.IBundleProjectService; import org.eclipse.pde.core.project.IPackageExportDescription; import org.eclipse.pde.core.project.IRequiredBundleDescription; import org.eclipse.pde.internal.core.PDECore; import org.eclipse.pde.internal.core.natures.PDE; import org.eclipse.pde.internal.core.plugin.WorkspacePluginModel; import org.eclipse.pde.internal.core.project.PDEProject; import org.eclipse.xtext.xbase.lib.Functions; import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.eclipse.xtext.xbase.lib.Pair; import org.eclipse.xtext.xbase.lib.StringExtensions; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.framework.Version; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; /** * A common helper class for generating IncQuery-related projects. * * @author Zoltan Ujhelyi */ @SuppressWarnings("restriction") public abstract class ProjectGenerationHelper { private static final String INVALID_PROJECT_MESSAGE = "Only existing, open plug-in projects are supported by the generator."; private static final class IDToRequireBundleTransformer implements Function<String, IRequiredBundleDescription> { private final IBundleProjectService service; private IDToRequireBundleTransformer(IBundleProjectService service) { this.service = service; } @Override public IRequiredBundleDescription apply(String input) { return service.newRequiredBundle(input, null, false, false); } } /** * Two source folders: src to be manually written and src-gen to contain generated code */ public static final List<String> SOURCEFOLDERS = ImmutableList .of(IncQueryNature.SRC_DIR, IncQueryNature.SRCGEN_DIR); /** * A single source folder named src */ public static final List<String> SINGLESOURCEFOLDER = ImmutableList.of("src"); /** * Creates a new IncQuery project: a plug-in project with src and src-gen folders and specific dependencies. * * @param description * @param proj * @param monitor * @throws CoreException * @throws CoreException */ public static void createProject(IProjectDescription description, IProject proj, List<String> additionalDependencies, IProgressMonitor monitor) throws CoreException { List<String> dependencies = Lists.newArrayList("org.eclipse.pde.core", "org.eclipse.emf.ecore", "org.eclipse.emf.transaction", IncQueryRuntimePlugin.PLUGIN_ID, "org.eclipse.xtext.xbase.lib"); if (additionalDependencies != null) { dependencies.addAll(additionalDependencies); } BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { monitor.beginTask("", 2000); /* Creating plug-in information */ context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(proj); IPath[] additionalBinIncludes = new IPath[] { new Path("plugin.xml"), new Path("queries/") }; ProjectGenerationHelper.fillProjectMetadata(proj, dependencies, service, bundleDesc, additionalBinIncludes); bundleDesc.apply(monitor); // Adding IncQuery-specific natures ProjectGenerationHelper.addNatures(proj, new String[] { IncQueryNature.NATURE_ID, "org.eclipse.xtext.ui.shared.xtextNature" }, monitor); } finally { monitor.done(); if (context != null && ref != null) { context.ungetService(ref); } } } /** * Adds a collection of natures to the project * * @param proj * @param natures * @param monitor * @return * @throws CoreException */ public static IProjectDescription addNatures(IProject proj, String[] natures, IProgressMonitor monitor) throws CoreException { IProjectDescription desc = proj.getDescription(); List<String> newNatures = new ArrayList<String>(); newNatures.addAll(Arrays.asList(desc.getNatureIds())); newNatures.addAll(Arrays.asList(natures)); desc.setNatureIds(newNatures.toArray(new String[newNatures.size()])); proj.setDescription(desc, monitor); return desc; } /** * Adds a file to a container. * * @param container * the container to add the file to * @param path * the path of the newly created file * @param contentStream * the file will be filled with this stream's contents * @param monitor * @throws CoreException */ public static void addFileToProject(IContainer container, Path path, InputStream contentStream, IProgressMonitor monitor) throws CoreException { final IFile file = container.getFile(path); if (file.exists()) { file.setContents(contentStream, true, true, monitor); } else { file.create(contentStream, true, monitor); } } /** * @param folder * @param monitor * @throws CoreException */ public static void deleteJavaFiles(IFolder folder, final IProgressMonitor monitor) throws CoreException { folder.refreshLocal(IResource.DEPTH_INFINITE, monitor); CollectDeletedElement visitor = new CollectDeletedElement(); folder.accept(visitor); for (IResource res : visitor.toDelete) { res.delete(false, new SubProgressMonitor(monitor, 1)); } } public static void initializePluginProject(IProject project, final List<String> dependencies, final IPath[] additionalBinIncludes) throws CoreException { initializePluginProject(project, dependencies, additionalBinIncludes, new NullProgressMonitor()); } public static void initializePluginProject(IProject project, final List<String> dependencies, final IPath[] additionalBinIncludes, IProgressMonitor monitor) throws CoreException { BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); fillProjectMetadata(project, dependencies, service, bundleDesc, additionalBinIncludes); bundleDesc.apply(monitor); } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Initializes the plug-in metadata of a newly created project. * * @param project * the plug-in project to create the metadata for. The plug-in id will be the same as the project name * @param dependencies * a list of required bundles to add * @param service * @param bundleDesc */ public static void fillProjectMetadata(IProject project, final List<String> dependencies, final IBundleProjectService service, IBundleProjectDescription bundleDesc, final IPath[] additionalBinIncludes) { bundleDesc.setBundleName(project.getName()); bundleDesc.setBundleVersion(new Version(0, 0, 1, "qualifier")); bundleDesc.setSingleton(true); bundleDesc.setTargetVersion(IBundleProjectDescription.VERSION_3_6); bundleDesc.setSymbolicName(project.getName()); bundleDesc.setExtensionRegistry(true); bundleDesc.setBinIncludes(additionalBinIncludes); bundleDesc.setBundleClasspath(getUpdatedBundleClasspathEntries(new IBundleClasspathEntry[0], service)); bundleDesc.setExecutionEnvironments(new String[] { IncQueryNature.EXECUTION_ENVIRONMENT }); // Adding dependencies IRequiredBundleDescription[] reqBundles = Lists.transform(dependencies, new IDToRequireBundleTransformer(service)).toArray(new IRequiredBundleDescription[dependencies.size()]); bundleDesc.setRequiredBundles(reqBundles); } /** * Checks whether the project depends on a selected bundle ID * * @param project * an existing, open plug-in project to check * @param dependency * bundle identifier * @return true, if the project depends on the given bundle * @throws CoreException */ public static boolean checkBundleDependency(IProject project, String dependency) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); for (IRequiredBundleDescription require : bundleDesc.getRequiredBundles()) { if (dependency.equals(require.getName())) { return true; } } return false; } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Updates project manifest to ensure the selected bundle dependencies are set. Does not change existing * dependencies. * * @param project * @param dependencies * @throws CoreException */ public static void ensureBundleDependencies(IProject project, final List<String> dependencies) throws CoreException { ensureBundleDependencies(project, dependencies, new NullProgressMonitor()); } /** * Updates project manifest to ensure the selected bundle dependencies are set. Does not change existing * dependencies. * * @param project * an existing, open PDE plug-in project * @param dependencies * @param monitor * @throws CoreException */ public static void ensureBundleDependencies(IProject project, final List<String> dependencies, IProgressMonitor monitor) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); if (dependencies.isEmpty()) { return; } BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); ensureBundleDependencies(service, bundleDesc, dependencies); bundleDesc.apply(monitor); } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Updates project manifest to ensure the selected bundle dependencies are set. Does not change existing * dependencies. * * @param service * @param bundleDesc * @param dependencies */ static void ensureBundleDependencies(IBundleProjectService service, IBundleProjectDescription bundleDesc, final List<String> dependencies) { IRequiredBundleDescription[] requiredBundles = bundleDesc.getRequiredBundles(); List<String> missingDependencies = new ArrayList<String>(dependencies); if (requiredBundles != null) { for (IRequiredBundleDescription bundle : requiredBundles) { if (missingDependencies.contains(bundle.getName())) { missingDependencies.remove(bundle.getName()); } } } bundleDesc.setRequiredBundles(Lists.transform(missingDependencies, new IDToRequireBundleTransformer(service)) .toArray(new IRequiredBundleDescription[missingDependencies.size()])); } /** * Updates project manifest to ensure the selected packages are exported. Does not change existing exports. * * @param project * @param dependencies * @throws CoreException */ public static void ensurePackageExports(IProject project, final Collection<String> dependencies) throws CoreException { ensurePackageExports(project, dependencies, new NullProgressMonitor()); } /** * Updates project manifest to ensure the selected packages are exported. Does not change existing exports. * * @param project * an existing, open PDE plug-in project * @param exports * a non-empty list of package exports * @param monitor * @throws CoreException */ public static void ensurePackageExports(IProject project, final Collection<String> exports, IProgressMonitor monitor) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); if (exports.isEmpty()) { return; } BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); ensurePackageExports(service, bundleDesc, exports); bundleDesc.apply(monitor); } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Updates project manifest to ensure the selected packages are removed. Does not change existing exports. * * @param project * an existing, open plug-in project * @param dependencies * @param monitor * @throws CoreException */ public static void removePackageExports(IProject project, final List<String> dependencies, IProgressMonitor monitor) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); if (dependencies.isEmpty()) { return; } BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); removePackageExports(service, bundleDesc, dependencies); bundleDesc.apply(monitor); } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Updates project manifest to ensure the selected packages are exported. Does not change existing exports. * * @param service * @param bundleDesc * @param exports */ static void ensurePackageExports(final IBundleProjectService service, IBundleProjectDescription bundleDesc, final Collection<String> exports) { IPackageExportDescription[] packageExports = bundleDesc.getPackageExports(); List<String> missingExports = new ArrayList<String>(exports); List<IPackageExportDescription> exportList = new ArrayList<IPackageExportDescription>(); if (packageExports != null) { for (IPackageExportDescription export : packageExports) { if (!missingExports.contains(export.getName())) { missingExports.remove(export.getName()); } exportList.add(export); } } exportList.addAll(Lists.transform(missingExports, new Function<String, IPackageExportDescription>() { @Override public IPackageExportDescription apply(String input) { return service.newPackageExport(input, null, true, null); } })); bundleDesc.setPackageExports(exportList.toArray(new IPackageExportDescription[exportList.size()])); } /** * Updates project manifest to ensure the selected packages are removed. Does not change existing exports. * * @param service * @param bundleDesc * @param exports */ static void removePackageExports(final IBundleProjectService service, IBundleProjectDescription bundleDesc, final List<String> exports) { IPackageExportDescription[] packageExports = bundleDesc.getPackageExports(); List<IPackageExportDescription> exportList = new ArrayList<IPackageExportDescription>(); if (packageExports != null) { for (IPackageExportDescription export : packageExports) { if (!exports.contains(export.getName())) { exportList.add(export); } } } bundleDesc.setPackageExports(exportList.toArray(new IPackageExportDescription[exportList.size()])); } /** * Updates the selected project to contain the selected extension. The extensions are identified using an identifier * and extension point together; old extensions are replaced with the new ones, other extensions are kept intact. * * @param project * @param contributedExtensions * @throws CoreException */ public static void ensureExtensions(IProject project, Iterable<IPluginExtension> contributedExtensions, Iterable<Pair<String, String>> removedExtensions) throws CoreException { ensureExtensions(project, contributedExtensions, removedExtensions, new NullProgressMonitor()); } /** * Updates the selected project to contain the selected extension. The extensions are identified using an identifier * and extension point together; old extensions are replaced with the new ones, other extensions are kept intact. An * extension will be ignored, if exist in the removedExtensions list. * * @param project * an existing, open PDE plug-in project * @param contributedExtensions * @param removedExtensions * @param monitor * @throws CoreException */ public static void ensureExtensions(IProject project, Iterable<IPluginExtension> contributedExtensions, Iterable<Pair<String, String>> removedExtensions, IProgressMonitor monitor) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); if (StringExtensions.isNullOrEmpty(project.getName())) { return; } Multimap<String, IPluginExtension> extensionMap = ArrayListMultimap.create(); for (IPluginExtension extension : contributedExtensions) { extensionMap.put(extension.getId(), extension); } // XXX Using two APIs to extension generation: one to read and one to // write IFile pluginXml = PDEProject.getPluginXml(project); IPluginModel plugin = (IPluginModel) PDECore.getDefault().getModelManager().findModel(project); WorkspacePluginModel fModel = new WorkspacePluginModel(pluginXml, false); fModel.setEditable(true); fModel.load(); // Storing a write-only plugin.xml model IExtensions extensions = fModel.getExtensions(); // Storing a read-only plugin.xml model if (plugin != null) { IExtensions readExtension = plugin.getExtensions(); nextExtension: for (final IPluginExtension extension : readExtension.getExtensions()) { String id = getExtensionId(extension, project); boolean extensionToCreateFound = isExtensionInMap(extensionMap, extension, extension.getId()); if (!extensionToCreateFound) { extensionToCreateFound = isExtensionInMap(extensionMap, extension, id); } if (extensionToCreateFound) { continue nextExtension; } // remove if contained in the removables final String extensionId = id; Pair<String, String> removable = Iterables.find(removedExtensions, new Predicate<Pair<String, String>>() { @Override public boolean apply(Pair<String, String> p) { return p.getKey().equals(extensionId) && p.getValue().equals(extension.getPoint()); } }, null); if (removable == null) { // XXX cloning extensions to remove project name prefixes IPluginExtension cloneExtension = fModel.createExtension(); cloneExtension.setId(id); String name = extension.getName(); if (name != null && !name.isEmpty()) { cloneExtension.setName(name); } cloneExtension.setPoint(extension.getPoint()); for (IPluginObject obj : extension.getChildren()) { cloneExtension.add(obj); } cloneExtension.setInTheModel(true); extensions.add(cloneExtension); } } for (IPluginExtensionPoint point : readExtension.getExtensionPoints()) { extensions.add(point); } } for (IPluginExtension contribExtension : contributedExtensions) { extensions.add(contribExtension); contribExtension.setInTheModel(true); } fModel.save(); } /** * @param extensionMap * @param extension * @param id * @return */ private static boolean isExtensionInMap(Multimap<String, IPluginExtension> extensionMap, final IPluginExtension extension, String id) { boolean extensionToCreateFound = false; if (extensionMap.containsKey(id)) { extensionToCreateFound = Iterables.any(extensionMap.get(id), new Predicate<IPluginExtension>() { @Override public boolean apply(IPluginExtension ex) { return ex.getPoint().equals(extension.getPoint()); } }); } return extensionToCreateFound; } /** * Updates project manifest to ensure the selected packages are removed. Does not change existing exports. * * @param project * @param dependencies * @throws CoreException */ public static void removePackageExports(IProject project, List<String> dependencies) throws CoreException { removePackageExports(project, dependencies, new NullProgressMonitor()); } /** * Removes all extensions from the project, if the extension's pointId equals to one of the given pointId. * * @param project * an existing, open PDE project * @param removableExtensionIdentifiers * - contains both the extension id prefix (key), and the extension point id (value) * @throws CoreException */ public static void removeAllExtension(IProject project, Collection<Pair<String, String>> removableExtensionIdentifiers) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project))); if (StringExtensions.isNullOrEmpty(project.getName())) { return; } IFile pluginXml = PDEProject.getPluginXml(project); IPluginModel plugin = (IPluginModel) PDECore.getDefault().getModelManager().findModel(project); WorkspacePluginModel fModel = new WorkspacePluginModel(pluginXml, false); fModel.setEditable(true); fModel.load(); // Storing a write-only plugin.xml model IExtensions extensions = fModel.getExtensions(); if (plugin != null) { // Storing a read-only plugin.xml model IExtensions readExtension = plugin.getExtensions(); for (final IPluginExtension extension : readExtension.getExtensions()) { String id = getExtensionId(extension, project); if (id != null && !isRemovableExtension(id, extension.getPoint(), removableExtensionIdentifiers)) { // XXX cloning extensions to remove project name prefixes IPluginExtension cloneExtension = fModel.createExtension(); cloneExtension.setId(id); cloneExtension.setName(extension.getName()); cloneExtension.setPoint(extension.getPoint()); for (IPluginObject obj : extension.getChildren()) { cloneExtension.add(obj); } cloneExtension.setInTheModel(true); extensions.add(cloneExtension); } } // add extension points for (IPluginExtensionPoint point : readExtension.getExtensionPoints()) { extensions.add(point); } } fModel.save(); } /** * Returns true if the extension is removable from the plugin.xml. If the extension id is prefixed with one of the * identifier prefix and the pointId is equals with the extension's point id, then the extension will be removed. If * the prefix is null or empty, only the pointId equality is necessary for the removal. * * @param extensionId * @param pointId * @param removableExtensionIdentifiers * @return */ private static boolean isRemovableExtension(final String extensionId, final String pointId, Collection<Pair<String, String>> removableExtensionIdentifiers) { Pair<String, String> foundOne = IterableExtensions.findFirst(removableExtensionIdentifiers, new Functions.Function1<Pair<String, String>, Boolean>() { @Override public Boolean apply(Pair<String, String> p) { if (StringExtensions.isNullOrEmpty(p.getKey())) { return pointId.equals(p.getValue()); } return extensionId.startsWith(p.getKey()) && pointId.equals(p.getValue()); } }); return foundOne != null; } /** * Returns the extension Id. Removes the plug-in name if the extension id prefixed with it. * * @param extension * @param project * @return */ private static String getExtensionId(IPluginExtension extension, IProject project) { String id = extension.getId(); if (id != null && id.startsWith(project.getName())) { int beginIndex = project.getName().length() + 1; if (beginIndex >= 0) { id = id.substring(beginIndex); } } return id; } /** * Ensures that the project contains the src and src-gen folders as source folders. * * @param project * an existing, open plug-in project * @param monitor * @throws CoreException */ public static void ensureSourceFolders(IProject project, IProgressMonitor monitor) throws CoreException { Preconditions.checkArgument(project.exists() && project.isOpen() && (PDE.hasPluginNature(project)), INVALID_PROJECT_MESSAGE); BundleContext context = null; ServiceReference<IBundleProjectService> ref = null; try { context = IncQueryGeneratorPlugin.getContext(); ref = context.getServiceReference(IBundleProjectService.class); final IBundleProjectService service = context.getService(ref); IBundleProjectDescription bundleDesc = service.getDescription(project); bundleDesc.setBundleClasspath(getUpdatedBundleClasspathEntries(bundleDesc.getBundleClasspath(), service)); bundleDesc.apply(monitor); } finally { if (context != null && ref != null) { context.ungetService(ref); } } } /** * Returns an updated the classpath entries of a project by ensuring all required source folders are present. * * @param service * @return */ private static IBundleClasspathEntry[] getUpdatedBundleClasspathEntries(final IBundleClasspathEntry[] oldClasspath, final IBundleProjectService service) { Collection<IBundleClasspathEntry> classPathSourceList = Collections2.filter(Lists.newArrayList(oldClasspath), new Predicate<IBundleClasspathEntry>() { @Override public boolean apply(IBundleClasspathEntry entry) { return entry.getSourcePath() != null && !entry.getSourcePath().isEmpty(); } }); final Collection<String> existingSourceEntries = Collections2.transform(classPathSourceList, new Function<IBundleClasspathEntry, String>() { @Override public String apply(IBundleClasspathEntry entry) { return entry.getSourcePath().toString(); } }); Collection<String> missingSourceFolders = Collections2.filter(SOURCEFOLDERS, new Predicate<String>() { @Override public boolean apply(String entry) { return !existingSourceEntries.contains(entry); } }); Collection<IBundleClasspathEntry> newClasspathEntries = Collections2.transform(missingSourceFolders, new Function<String, IBundleClasspathEntry>() { @Override public IBundleClasspathEntry apply(String input) { return service.newBundleClasspathEntry(new Path(input), null, null); } }); List<IBundleClasspathEntry> modifiedClasspathEntries = Lists.newArrayList(oldClasspath); modifiedClasspathEntries.addAll(newClasspathEntries); return modifiedClasspathEntries.toArray(new IBundleClasspathEntry[modifiedClasspathEntries.size()]); } public static String getBundleSymbolicName(IProject project) { IPluginModel plugin = (IPluginModel) PDECore.getDefault().getModelManager().findModel(project); return plugin.getBundleDescription().getSymbolicName(); } }