| /******************************************************************************* |
| * Copyright (c) 2000, 2016 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.internal.launching; |
| |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| 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.IPath; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| import org.eclipse.dltk.core.BuildpathContainerInitializer; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IBuildpathContainer; |
| import org.eclipse.dltk.core.IBuildpathEntry; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.launching.IRuntimeBuildpathEntry; |
| import org.eclipse.dltk.launching.LaunchingMessages; |
| import org.eclipse.dltk.launching.ScriptRuntime; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| /** |
| * Default user buildpath entries for a script project |
| */ |
| public class DefaultProjectBuildpathEntry |
| extends AbstractRuntimeBuildpathEntry { |
| |
| public static final String TYPE_ID = "org.eclipse.dltk.launching.buildpathentry.defaultBuildpath"; //$NON-NLS-1$ |
| |
| /** |
| * Whether only exported entries should be on the runtime buildpath. By |
| * default all entries are on the runtime buildpath. |
| */ |
| private boolean fExportedEntriesOnly = false; |
| |
| /** |
| * Default constructor need to instantiate extensions |
| */ |
| public DefaultProjectBuildpathEntry() { |
| } |
| |
| /** |
| * Constructs a new buildpath entry for the given project. |
| * |
| * @param project |
| * Script project |
| */ |
| public DefaultProjectBuildpathEntry(IScriptProject project) { |
| setScriptProject(project); |
| } |
| |
| @Override |
| protected void buildMemento(Document document, Element memento) |
| throws CoreException { |
| memento.setAttribute("project", getScriptProject().getElementName()); //$NON-NLS-1$ |
| memento.setAttribute("exportedEntriesOnly", //$NON-NLS-1$ |
| Boolean.toString(fExportedEntriesOnly)); |
| } |
| |
| @Override |
| public void initializeFrom(Element memento) throws CoreException { |
| String name = memento.getAttribute("project"); //$NON-NLS-1$ |
| if (name == null) { |
| abort(LaunchingMessages.DefaultProjectBuildpathEntry_3, null); |
| } |
| IScriptProject project = DLTKCore.create( |
| ResourcesPlugin.getWorkspace().getRoot().getProject(name)); |
| setScriptProject(project); |
| name = memento.getAttribute("exportedEntriesOnly"); //$NON-NLS-1$ |
| if (name == null) { |
| fExportedEntriesOnly = false; |
| } else { |
| fExportedEntriesOnly = Boolean.valueOf(name).booleanValue(); |
| } |
| } |
| |
| @Override |
| public String getTypeId() { |
| return TYPE_ID; |
| } |
| |
| @Override |
| public int getType() { |
| return OTHER; |
| } |
| |
| protected IProject getProject() { |
| return getScriptProject().getProject(); |
| } |
| |
| @Override |
| public String getLocation() { |
| return getProject().getLocation().toOSString(); |
| } |
| |
| @Override |
| public URI getLocationURI() { |
| return getProject().getLocationURI(); |
| } |
| |
| @Override |
| public IPath getPath() { |
| return getProject().getFullPath(); |
| } |
| |
| @Override |
| public IResource getResource() { |
| return getProject(); |
| } |
| |
| @Override |
| public IRuntimeBuildpathEntry[] getRuntimeBuildpathEntries( |
| ILaunchConfiguration configuration) throws CoreException { |
| IBuildpathEntry entry = DLTKCore |
| .newProjectEntry(getScriptProject().getProject().getFullPath()); |
| List buildpathEntries = new ArrayList(5); |
| List<IBuildpathEntry> expanding = new ArrayList<>(5); |
| expandProject(entry, buildpathEntries, expanding); |
| IRuntimeBuildpathEntry[] runtimeEntries = new IRuntimeBuildpathEntry[buildpathEntries |
| .size()]; |
| for (int i = 0; i < runtimeEntries.length; i++) { |
| Object e = buildpathEntries.get(i); |
| if (e instanceof IBuildpathEntry) { |
| IBuildpathEntry cpe = (IBuildpathEntry) e; |
| runtimeEntries[i] = new RuntimeBuildpathEntry(cpe); |
| } else { |
| runtimeEntries[i] = (IRuntimeBuildpathEntry) e; |
| } |
| } |
| // remove bootpath entries - this is a default user buildpath |
| List<IRuntimeBuildpathEntry> ordered = new ArrayList<>( |
| runtimeEntries.length); |
| for (int i = 0; i < runtimeEntries.length; i++) { |
| if (runtimeEntries[i] |
| .getBuildpathProperty() == IRuntimeBuildpathEntry.USER_ENTRY) { |
| ordered.add(runtimeEntries[i]); |
| } |
| } |
| return ordered.toArray(new IRuntimeBuildpathEntry[ordered.size()]); |
| } |
| |
| /** |
| * Returns the transitive closure of buildpath entries for the given project |
| * entry. |
| * |
| * @param projectEntry |
| * project buildpath entry |
| * @param expandedPath |
| * a list of entries already expanded, should be empty to begin, |
| * and contains the result |
| * @param expanding |
| * a list of projects that have been or are currently being |
| * expanded (to detect cycles) |
| * @exception CoreException |
| * if unable to expand the buildpath |
| */ |
| private void expandProject(IBuildpathEntry projectEntry, List expandedPath, |
| List<IBuildpathEntry> expanding) throws CoreException { |
| expanding.add(projectEntry); |
| // 1. Get the raw buildpath |
| // 2. Replace source folder entries with a project entry |
| IPath projectPath = projectEntry.getPath(); |
| IResource res = ResourcesPlugin.getWorkspace().getRoot() |
| .findMember(projectPath.lastSegment()); |
| if (res == null) { |
| // add project entry and return |
| expandedPath.add(projectEntry); |
| return; |
| } |
| IScriptProject project = (IScriptProject) DLTKCore.create(res); |
| if (project == null || !project.getProject().isOpen() |
| || !project.exists()) { |
| // add project entry and return |
| expandedPath.add(projectEntry); |
| return; |
| } |
| |
| IBuildpathEntry[] buildPath = project.getRawBuildpath(); |
| List<IBuildpathEntry> unexpandedPath = new ArrayList<>( |
| buildPath.length); |
| // boolean projectAdded = false; |
| for (int i = 0; i < buildPath.length; i++) { |
| IBuildpathEntry buildpathEntry = buildPath[i]; |
| if (buildpathEntry.getEntryKind() == IBuildpathEntry.BPE_SOURCE) { // sources |
| // are |
| // always |
| // added |
| unexpandedPath.add(buildpathEntry); |
| } else { |
| // add exported entires, as configured |
| if (buildpathEntry.isExported()) { |
| unexpandedPath.add(buildpathEntry); |
| } else if (!isExportedEntriesOnly() |
| || project.equals(getScriptProject())) { |
| // add non exported entries from root project or if we are |
| // including all entries |
| unexpandedPath.add(buildpathEntry); |
| } |
| } |
| } |
| // 3. expand each project entry (except for the root project) |
| // 4. replace each container entry with a runtime entry associated with |
| // the project |
| Iterator<IBuildpathEntry> iter = unexpandedPath.iterator(); |
| while (iter.hasNext()) { |
| IBuildpathEntry entry = iter.next(); |
| if (entry == projectEntry) { |
| expandedPath.add(entry); |
| } else { |
| switch (entry.getEntryKind()) { |
| case IBuildpathEntry.BPE_PROJECT: |
| if (!expanding.contains(entry)) { |
| expandProject(entry, expandedPath, expanding); |
| } |
| break; |
| case IBuildpathEntry.BPE_CONTAINER: |
| IBuildpathContainer container = DLTKCore |
| .getBuildpathContainer(entry.getPath(), project); |
| int property = -1; |
| if (container != null) { |
| switch (container.getKind()) { |
| case IBuildpathContainer.K_APPLICATION: |
| property = IRuntimeBuildpathEntry.USER_ENTRY; |
| break; |
| case IBuildpathContainer.K_DEFAULT_SYSTEM: |
| property = IRuntimeBuildpathEntry.STANDARD_ENTRY; |
| break; |
| case IBuildpathContainer.K_SYSTEM: |
| property = IRuntimeBuildpathEntry.BOOTSTRAP_ENTRY; |
| break; |
| } |
| IRuntimeBuildpathEntry r = ScriptRuntime |
| .newRuntimeContainerBuildpathEntry( |
| entry.getPath(), property, project); |
| // check for duplicate/redundant entries |
| boolean duplicate = false; |
| BuildpathContainerInitializer initializer = DLTKCore |
| .getBuildpathContainerInitializer( |
| r.getPath().segment(0)); |
| for (int i = 0; i < expandedPath.size(); i++) { |
| Object o = expandedPath.get(i); |
| if (o instanceof IRuntimeBuildpathEntry) { |
| IRuntimeBuildpathEntry re = (IRuntimeBuildpathEntry) o; |
| if (re.getType() == IRuntimeBuildpathEntry.CONTAINER) { |
| BuildpathContainerInitializer initializer2 = DLTKCore |
| .getBuildpathContainerInitializer( |
| re.getPath().segment(0)); |
| Object id1 = null; |
| Object id2 = null; |
| if (initializer == null) { |
| id1 = r.getPath().segment(0); |
| } else { |
| id1 = initializer.getComparisonID( |
| r.getPath(), project); |
| } |
| if (initializer2 == null) { |
| id2 = re.getPath().segment(0); |
| } else { |
| IScriptProject context = re |
| .getScriptProject(); |
| if (context == null) { |
| context = project; |
| } |
| id2 = initializer2.getComparisonID( |
| re.getPath(), context); |
| } |
| if (id1 == null) { |
| duplicate = id2 == null; |
| } else { |
| duplicate = id1.equals(id2); |
| } |
| if (duplicate) { |
| break; |
| } |
| } |
| } |
| } |
| if (!duplicate) { |
| expandedPath.add(r); |
| } |
| } |
| break; |
| default: |
| if (!expandedPath.contains(entry)) { |
| expandedPath.add(entry); |
| } |
| break; |
| } |
| } |
| } |
| return; |
| } |
| |
| @Override |
| public boolean isComposite() { |
| return true; |
| } |
| |
| @Override |
| public String getName() { |
| if (isExportedEntriesOnly()) { |
| return MessageFormat.format( |
| LaunchingMessages.DefaultProjectBuildpathEntry_2, |
| getScriptProject().getElementName()); |
| } |
| return MessageFormat.format( |
| LaunchingMessages.DefaultProjectBuildpathEntry_4, |
| getScriptProject().getElementName()); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof DefaultProjectBuildpathEntry) { |
| DefaultProjectBuildpathEntry entry = (DefaultProjectBuildpathEntry) obj; |
| return entry.getScriptProject().equals(getScriptProject()) |
| && entry.isExportedEntriesOnly() == isExportedEntriesOnly(); |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| return getScriptProject().hashCode(); |
| } |
| |
| /** |
| * Sets whether the runtime buildpath computaion should only include |
| * exported entries in referenced projects. |
| * |
| * @param exportedOnly |
| * |
| */ |
| public void setExportedEntriesOnly(boolean exportedOnly) { |
| fExportedEntriesOnly = exportedOnly; |
| } |
| |
| /** |
| * Returns whether the buildpath computation only includes exported entries |
| * in referenced projects. |
| * |
| * @return |
| * |
| */ |
| public boolean isExportedEntriesOnly() { |
| return fExportedEntriesOnly; |
| } |
| |
| } |