Copyright (c) 2000, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Frits Jalvingh - Contribution for Bug 459831 - [launching] Support attaching external annotations to a JRE container
/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Frits Jalvingh - Contribution for Bug 459831 - [launching] Support attaching * external annotations to a JRE container *******************************************************************************/
package org.eclipse.jdt.internal.launching; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.IVMInstallChangedListener; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; import org.eclipse.jdt.launching.PropertyChangeEvent; import org.eclipse.jdt.launching.environments.IExecutionEnvironment; import org.eclipse.osgi.util.NLS;
JRE Container - resolves a classpath container variable to a JRE
/** * JRE Container - resolves a classpath container variable to a JRE */
public class JREContainer implements IClasspathContainer {
Corresponding JRE
/** * Corresponding JRE */
private IVMInstall fVMInstall = null;
Container path used to resolve to this JRE
/** * Container path used to resolve to this JRE */
private IPath fPath = null;
The project this container is for
/** * The project this container is for */
private IJavaProject fProject = null;
Cache of classpath entries per VM install. Cleared when a VM changes.
/** * Cache of classpath entries per VM install. Cleared when a VM changes. */
private static Map<IVMInstall, IClasspathEntry[]> fgClasspathEntries = new HashMap<>(10);
Variable to return an empty array of IAccessRules
/** * Variable to return an empty array of <code>IAccessRule</code>s */
private static IAccessRule[] EMPTY_RULES = new IAccessRule[0];
Map of {IVMInstall -> Map of {{IExeuctionEnvironment, IAccessRule[][]} -> {IClasspathEntry[]}}
/** * Map of {IVMInstall -> Map of {{IExeuctionEnvironment, IAccessRule[][]} -> {IClasspathEntry[]}} */
private static Map<RuleKey, RuleEntry> fgClasspathEntriesWithRules = new HashMap<>(10);
A single key entry for the cache of access rules and classpath entries A rule key is made up of an IVMInstall and an execution environment id
Since:3.3
/** * A single key entry for the cache of access rules and classpath entries * A rule key is made up of an <code>IVMInstall</code> and an execution environment id * @since 3.3 */
static class RuleKey { private String fEnvironmentId = null; private IVMInstall fInstall = null;
Constructor
Params:
  • install – the VM
  • environmentId – the environment
/** * Constructor * @param install the VM * @param environmentId the environment */
public RuleKey(IVMInstall install, String environmentId) { fInstall = install; fEnvironmentId = environmentId; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (obj instanceof RuleKey) { RuleKey key = (RuleKey) obj; return fEnvironmentId.equals(key.fEnvironmentId) && fInstall.equals(key.fInstall); } return false; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return fEnvironmentId.hashCode() + fInstall.hashCode(); } }
Holds an entry for the cache of access rules/classpath entries. An entry is made up of an array of classpath entries and the collection of access rules.
Since:3.3
/** * Holds an entry for the cache of access rules/classpath entries. * An entry is made up of an array of classpath entries and the collection of access rules. * @since 3.3 */
static class RuleEntry { private IAccessRule[][] fRules = null; private IClasspathEntry[] fEntries = null;
Constructor
Params:
  • rules – the rules
  • entries – the entries
/** * Constructor * @param rules the rules * @param entries the entries */
public RuleEntry(IAccessRule[][] rules, IClasspathEntry[] entries) { fRules = rules; fEntries = entries; }
Returns the collection of classpath entries for this RuleEntry
Returns:the cached array of classpath entries
/** * Returns the collection of classpath entries for this RuleEntry * @return the cached array of classpath entries */
public IClasspathEntry[] getClasspathEntries() { return fEntries; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { IAccessRule[][] rules = null; if(obj instanceof RuleEntry) { rules = ((RuleEntry)obj).fRules; } if(obj instanceof IAccessRule[][]) { rules = (IAccessRule[][]) obj; } if (fRules == rules) { return true; } if(rules != null) { if (fRules.length == rules.length) { for (int i = 0; i < fRules.length; i++) { if (!rulesEqual(fRules[i], rules[i])){ return false; } } return true; } } return false; }
Checks if the two arrays of rules are equal (same rules in each position in the array)
Params:
  • a – First list of rules to compare, must not be null
  • b – Second list of rules to compare, must not be null
Returns:true if the arrays are equal, false otherwise
/** * Checks if the two arrays of rules are equal (same rules in each position in the array) * * @param a First list of rules to compare, must not be <code>null</code> * @param b Second list of rules to compare, must not be <code>null</code> * @return <code>true</code> if the arrays are equal, <code>false</code> otherwise */
private static boolean rulesEqual(IAccessRule[] a, IAccessRule[] b){ if (a == b){ return true; } if (a.length != b.length){ return false; } for (int j = 0; j < a.length; j++) { if (!a[j].equals(b[j])) { return false; } } return true; } }
Add a VM changed listener to clear cached values when a VM changes or is removed
/** * Add a VM changed listener to clear cached values when a VM changes or is removed */
static { IVMInstallChangedListener listener = new IVMInstallChangedListener() { /* (non-Javadoc) * @see org.eclipse.jdt.launching.IVMInstallChangedListener#defaultVMInstallChanged(org.eclipse.jdt.launching.IVMInstall, org.eclipse.jdt.launching.IVMInstall) */ @Override public void defaultVMInstallChanged(IVMInstall previous, IVMInstall current) {} /* (non-Javadoc) * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmAdded(org.eclipse.jdt.launching.IVMInstall) */ @Override public void vmAdded(IVMInstall newVm) {} /* (non-Javadoc) * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent) */ @Override public void vmChanged(PropertyChangeEvent event) { if (event.getSource() != null) { fgClasspathEntries.remove(event.getSource()); removeRuleEntry(event.getSource()); } } /* (non-Javadoc) * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmRemoved(org.eclipse.jdt.launching.IVMInstall) */ @Override public void vmRemoved(IVMInstall removedVm) { fgClasspathEntries.remove(removedVm); removeRuleEntry(removedVm); }
Removes all occurrences of the given VM found as part key members in the current cache for classpath entries
Params:
  • obj – an object which should be castable to IVMInstall
/** * Removes all occurrences of the given VM found as part key members in the current * cache for classpath entries * @param obj an object which should be castable to IVMInstall */
private void removeRuleEntry(Object obj) { if(obj instanceof IVMInstall) { IVMInstall install = (IVMInstall) obj; RuleKey key = null; ArrayList<RuleKey> list = new ArrayList<>(); for(Iterator<RuleKey> iter = fgClasspathEntriesWithRules.keySet().iterator(); iter.hasNext();) { key = iter.next(); if(key.fInstall.equals(install)) { list.add(key); } } for(int i = 0; i < list.size(); i++) { fgClasspathEntriesWithRules.remove(list.get(i)); } } } }; JavaRuntime.addVMInstallChangedListener(listener); }
Returns the classpath entries associated with the given VM in the context of the given path and project.
Params:
  • vm – the VM
  • containerPath – the container path resolution is for
  • project – project the resolution is for
Returns:classpath entries
/** * Returns the classpath entries associated with the given VM * in the context of the given path and project. * * @param vm the VM * @param containerPath the container path resolution is for * @param project project the resolution is for * @return classpath entries */
private static IClasspathEntry[] getClasspathEntries(IVMInstall vm, IPath containerPath, IJavaProject project) { String id = JavaRuntime.getExecutionEnvironmentId(containerPath); IClasspathEntry[] entries = null; if (id == null) { // cache classpath entries per JRE when not bound to an EE entries = fgClasspathEntries.get(vm); if (entries == null) { entries = computeClasspathEntries(vm, project, id); fgClasspathEntries.put(vm, entries); } } else { if (LaunchingPlugin.DEBUG_JRE_CONTAINER) { LaunchingPlugin.trace("\tEE:\t" + id); //$NON-NLS-1$ } // dynamically compute entries when bound to an EE entries = computeClasspathEntries(vm, project, id); } return entries; }
Computes the classpath entries associated with a VM - one entry per library in the context of the given path and project.
Params:
  • vm – the VM
  • project – the project the resolution is for
  • environmentId – execution environment the resolution is for, or null
Returns:classpath entries
/** * Computes the classpath entries associated with a VM - one entry per library * in the context of the given path and project. * * @param vm the VM * @param project the project the resolution is for * @param environmentId execution environment the resolution is for, or <code>null</code> * @return classpath entries */
private static IClasspathEntry[] computeClasspathEntries(IVMInstall vm, IJavaProject project, String environmentId) { LibraryLocation[] libs = vm.getLibraryLocations(); boolean overrideJavaDoc = false; if (libs == null) { libs = JavaRuntime.getLibraryLocations(vm); overrideJavaDoc = true; } IAccessRule[][] rules = null; if (environmentId != null) { // compute access rules for execution environment IExecutionEnvironment environment = JavaRuntime.getExecutionEnvironmentsManager().getEnvironment(environmentId); if (environment != null) { rules = environment.getAccessRules(vm, libs, project); } } RuleKey key = null; if (vm != null && rules != null && environmentId != null) { key = new RuleKey(vm, environmentId); RuleEntry entry = fgClasspathEntriesWithRules.get(key); if(entry != null && entry.equals(rules)) { return entry.getClasspathEntries(); } } List<IClasspathEntry> entries = new ArrayList<>(libs.length); for (int i = 0; i < libs.length; i++) { if (!libs[i].getSystemLibraryPath().isEmpty()) { IPath sourcePath = libs[i].getSystemLibrarySourcePath(); if (sourcePath.isEmpty()) { sourcePath = null; } IPath rootPath = libs[i].getPackageRootPath(); if (rootPath.isEmpty()) { rootPath = null; } // construct the classpath attributes for this library location IClasspathAttribute[] attributes = JREContainer.buildClasspathAttributes(vm, libs[i], overrideJavaDoc); IAccessRule[] libRules = null; if (rules != null) { libRules = rules[i]; } else { libRules = EMPTY_RULES; } entries.add(JavaCore.newLibraryEntry(libs[i].getSystemLibraryPath(), sourcePath, rootPath, libRules, attributes, false)); } } IClasspathEntry[] cpEntries = entries.toArray(new IClasspathEntry[entries.size()]); if (key != null && rules != null) { fgClasspathEntriesWithRules.put(key, new RuleEntry(rules, cpEntries)); } return cpEntries; } private static IClasspathAttribute[] buildClasspathAttributes(final IVMInstall vm, final LibraryLocation lib, final boolean overrideJavaDoc) { List<IClasspathAttribute> classpathAttributes = new LinkedList<>(); // process the javadoc location URL javadocLocation = lib.getJavadocLocation(); if (overrideJavaDoc && javadocLocation == null) { javadocLocation = vm.getJavadocLocation(); } if(javadocLocation != null) { IClasspathAttribute javadocCPAttribute = JavaCore.newClasspathAttribute(IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME, javadocLocation.toExternalForm()); classpathAttributes.add(javadocCPAttribute); } // process the index location URL indexLocation = lib.getIndexLocation(); if(indexLocation != null) { IClasspathAttribute indexCPLocation = JavaCore.newClasspathAttribute(IClasspathAttribute.INDEX_LOCATION_ATTRIBUTE_NAME, indexLocation.toExternalForm()); classpathAttributes.add(indexCPLocation); } IPath annotationsPath = lib.getExternalAnnotationsPath(); if (null != annotationsPath && !annotationsPath.isEmpty()) { IClasspathAttribute xAnnLocation = JavaCore.newClasspathAttribute(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH, annotationsPath.toPortableString()); classpathAttributes.add(xAnnLocation); } return classpathAttributes.toArray(new IClasspathAttribute[classpathAttributes.size()]); }
Constructs a JRE classpath container on the given VM install
Params:
  • vm – VM install - cannot be null
  • path – container path used to resolve this JRE
  • project – the project context
/** * Constructs a JRE classpath container on the given VM install * * @param vm VM install - cannot be <code>null</code> * @param path container path used to resolve this JRE * @param project the project context */
public JREContainer(IVMInstall vm, IPath path, IJavaProject project) { fVMInstall = vm; fPath = path; fProject = project; }
See Also:
  • getClasspathEntries.getClasspathEntries()
/** * @see IClasspathContainer#getClasspathEntries() */
@Override public IClasspathEntry[] getClasspathEntries() { if (LaunchingPlugin.DEBUG_JRE_CONTAINER) { LaunchingPlugin.trace("<JRE_CONTAINER> getClasspathEntries() " + this.toString()); //$NON-NLS-1$ LaunchingPlugin.trace("\tJRE:\t" + fVMInstall.getName()); //$NON-NLS-1$ LaunchingPlugin.trace("\tPath:\t" + getPath().toString()); //$NON-NLS-1$ LaunchingPlugin.trace("\tProj:\t" + fProject.getProject().getName()); //$NON-NLS-1$ } IClasspathEntry[] entries = getClasspathEntries(fVMInstall, getPath(), fProject); if (LaunchingPlugin.DEBUG_JRE_CONTAINER) { LaunchingPlugin.trace("\tResolved " + entries.length + " entries:"); //$NON-NLS-1$//$NON-NLS-2$ } return entries; }
See Also:
  • getDescription.getDescription()
/** * @see IClasspathContainer#getDescription() */
@Override public String getDescription() { String environmentId = JavaRuntime.getExecutionEnvironmentId(getPath()); String tag = null; if (environmentId == null) { tag = fVMInstall.getName(); } else { tag = environmentId; } return NLS.bind(LaunchingMessages.JREContainer_JRE_System_Library_1, new String[]{tag}); }
See Also:
  • getKind.getKind()
/** * @see IClasspathContainer#getKind() */
@Override public int getKind() { return IClasspathContainer.K_DEFAULT_SYSTEM; }
See Also:
  • getPath.getPath()
/** * @see IClasspathContainer#getPath() */
@Override public IPath getPath() { return fPath; } }