0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.launching;
0011:
0012: import java.io.BufferedInputStream;
0013: import java.io.ByteArrayInputStream;
0014: import java.io.File;
0015: import java.io.FileInputStream;
0016: import java.io.IOException;
0017: import java.io.InputStream;
0018: import java.io.StringReader;
0019: import java.net.MalformedURLException;
0020: import java.net.URL;
0021: import java.util.ArrayList;
0022: import java.util.HashMap;
0023: import java.util.HashSet;
0024: import java.util.Hashtable;
0025: import java.util.Iterator;
0026: import java.util.List;
0027: import java.util.Map;
0028: import java.util.Set;
0029:
0030: import javax.xml.parsers.DocumentBuilder;
0031:
0032: import org.eclipse.core.resources.IProject;
0033: import org.eclipse.core.resources.IResource;
0034: import org.eclipse.core.resources.IWorkspaceRoot;
0035: import org.eclipse.core.resources.ResourcesPlugin;
0036: import org.eclipse.core.runtime.CoreException;
0037: import org.eclipse.core.runtime.IConfigurationElement;
0038: import org.eclipse.core.runtime.IExtensionPoint;
0039: import org.eclipse.core.runtime.IPath;
0040: import org.eclipse.core.runtime.IProgressMonitor;
0041: import org.eclipse.core.runtime.IStatus;
0042: import org.eclipse.core.runtime.MultiStatus;
0043: import org.eclipse.core.runtime.Path;
0044: import org.eclipse.core.runtime.Platform;
0045: import org.eclipse.core.runtime.Preferences;
0046: import org.eclipse.core.runtime.Status;
0047: import org.eclipse.core.variables.IStringVariableManager;
0048: import org.eclipse.core.variables.VariablesPlugin;
0049: import org.eclipse.debug.core.ILaunchConfiguration;
0050: import org.eclipse.debug.core.sourcelookup.ISourceContainer;
0051: import org.eclipse.jdt.core.IClasspathAttribute;
0052: import org.eclipse.jdt.core.IClasspathContainer;
0053: import org.eclipse.jdt.core.IClasspathEntry;
0054: import org.eclipse.jdt.core.IJavaModel;
0055: import org.eclipse.jdt.core.IJavaProject;
0056: import org.eclipse.jdt.core.JavaCore;
0057: import org.eclipse.jdt.internal.launching.CompositeId;
0058: import org.eclipse.jdt.internal.launching.DefaultEntryResolver;
0059: import org.eclipse.jdt.internal.launching.DefaultProjectClasspathEntry;
0060: import org.eclipse.jdt.internal.launching.JREContainerInitializer;
0061: import org.eclipse.jdt.internal.launching.JavaSourceLookupUtil;
0062: import org.eclipse.jdt.internal.launching.LaunchingMessages;
0063: import org.eclipse.jdt.internal.launching.LaunchingPlugin;
0064: import org.eclipse.jdt.internal.launching.ListenerList;
0065: import org.eclipse.jdt.internal.launching.RuntimeClasspathEntry;
0066: import org.eclipse.jdt.internal.launching.RuntimeClasspathEntryResolver;
0067: import org.eclipse.jdt.internal.launching.RuntimeClasspathProvider;
0068: import org.eclipse.jdt.internal.launching.SocketAttachConnector;
0069: import org.eclipse.jdt.internal.launching.StandardVMType;
0070: import org.eclipse.jdt.internal.launching.VMDefinitionsContainer;
0071: import org.eclipse.jdt.internal.launching.VMListener;
0072: import org.eclipse.jdt.internal.launching.VariableClasspathEntry;
0073: import org.eclipse.jdt.internal.launching.environments.EnvironmentsManager;
0074: import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
0075: import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
0076: import org.w3c.dom.Element;
0077: import org.w3c.dom.Node;
0078: import org.w3c.dom.NodeList;
0079: import org.xml.sax.InputSource;
0080: import org.xml.sax.SAXException;
0081:
0082: import com.ibm.icu.text.MessageFormat;
0083:
0084: /**
0085: * The central access point for launching support. This class manages
0086: * the registered VM types contributed through the
0087: * <code>"org.eclipse.jdt.launching.vmType"</code> extension point.
0088: * As well, this class provides VM install change notification,
0089: * and computes class paths and source lookup paths for launch
0090: * configurations.
0091: * <p>
0092: * This class provides static methods only; it is not intended to be
0093: * instantiated or sub-classed by clients.
0094: * </p>
0095: */
0096: public final class JavaRuntime {
0097:
0098: /**
0099: * Classpath variable name used for the default JRE's library
0100: * (value <code>"JRE_LIB"</code>).
0101: */
0102: public static final String JRELIB_VARIABLE = "JRE_LIB"; //$NON-NLS-1$
0103:
0104: /**
0105: * Classpath variable name used for the default JRE's library source
0106: * (value <code>"JRE_SRC"</code>).
0107: */
0108: public static final String JRESRC_VARIABLE = "JRE_SRC"; //$NON-NLS-1$
0109:
0110: /**
0111: * Classpath variable name used for the default JRE's library source root
0112: * (value <code>"JRE_SRCROOT"</code>).
0113: */
0114: public static final String JRESRCROOT_VARIABLE = "JRE_SRCROOT"; //$NON-NLS-1$
0115:
0116: /**
0117: * Simple identifier constant (value <code>"runtimeClasspathEntryResolvers"</code>) for the
0118: * runtime classpath entry resolvers extension point.
0119: *
0120: * @since 2.0
0121: */
0122: public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS = "runtimeClasspathEntryResolvers"; //$NON-NLS-1$
0123:
0124: /**
0125: * Simple identifier constant (value <code>"classpathProviders"</code>) for the
0126: * runtime classpath providers extension point.
0127: *
0128: * @since 2.0
0129: */
0130: public static final String EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS = "classpathProviders"; //$NON-NLS-1$
0131:
0132: /**
0133: * Simple identifier constant (value <code>"executionEnvironments"</code>) for the
0134: * execution environments extension point.
0135: *
0136: * @since 3.2
0137: */
0138: public static final String EXTENSION_POINT_EXECUTION_ENVIRONMENTS = "executionEnvironments"; //$NON-NLS-1$
0139:
0140: /**
0141: * Simple identifier constant (value <code>"vmInstalls"</code>) for the
0142: * VM installs extension point.
0143: *
0144: * @since 3.2
0145: */
0146: public static final String EXTENSION_POINT_VM_INSTALLS = "vmInstalls"; //$NON-NLS-1$
0147:
0148: /**
0149: * Classpath container used for a project's JRE
0150: * (value <code>"org.eclipse.jdt.launching.JRE_CONTAINER"</code>). A
0151: * container is resolved in the context of a specific Java project, to one
0152: * or more system libraries contained in a JRE. The container can have zero
0153: * or two path segments following the container name. When no segments
0154: * follow the container name, the workspace default JRE is used to build a
0155: * project. Otherwise the segments identify a specific JRE used to build a
0156: * project:
0157: * <ol>
0158: * <li>VM Install Type Identifier - identifies the type of JRE used to build the
0159: * project. For example, the standard VM.</li>
0160: * <li>VM Install Name - a user defined name that identifies that a specific VM
0161: * of the above kind. For example, <code>IBM 1.3.1</code>. This information is
0162: * shared in a projects classpath file, so teams must agree on JRE naming
0163: * conventions.</li>
0164: * </ol>
0165: * <p>
0166: * Since 3.2, the path may also identify an execution environment as follows:
0167: * <ol>
0168: * <li>Execution environment extension point name
0169: * (value <code>executionEnvironments</code>)</li>
0170: * <li>Identifier of a contributed execution environment</li>
0171: * </ol>
0172: * </p>
0173: * @since 2.0
0174: */
0175: public static final String JRE_CONTAINER = LaunchingPlugin
0176: .getUniqueIdentifier()
0177: + ".JRE_CONTAINER"; //$NON-NLS-1$
0178:
0179: /**
0180: * A status code indicating that a JRE could not be resolved for a project.
0181: * When a JRE cannot be resolved for a project by this plug-in's container
0182: * initializer, an exception is thrown with this status code. A status handler
0183: * may be registered for this status code. The <code>source</code> object provided
0184: * to the status handler is the Java project for which the path could not be
0185: * resolved. The status handler must return an <code>IVMInstall</code> or <code>null</code>.
0186: * The container resolver will re-set the project's classpath if required.
0187: *
0188: * @since 2.0
0189: */
0190: public static final int ERR_UNABLE_TO_RESOLVE_JRE = 160;
0191:
0192: /**
0193: * Preference key for launch/connect timeout. VM Runners should honor this timeout
0194: * value when attempting to launch and connect to a debuggable VM. The value is
0195: * an int, indicating a number of milliseconds.
0196: *
0197: * @since 2.0
0198: */
0199: public static final String PREF_CONNECT_TIMEOUT = LaunchingPlugin
0200: .getUniqueIdentifier()
0201: + ".PREF_CONNECT_TIMEOUT"; //$NON-NLS-1$
0202:
0203: /**
0204: * Preference key for the String of XML that defines all installed VMs.
0205: *
0206: * @since 2.1
0207: */
0208: public static final String PREF_VM_XML = LaunchingPlugin
0209: .getUniqueIdentifier()
0210: + ".PREF_VM_XML"; //$NON-NLS-1$
0211:
0212: /**
0213: * Default launch/connect timeout (ms).
0214: *
0215: * @since 2.0
0216: */
0217: public static final int DEF_CONNECT_TIMEOUT = 20000;
0218:
0219: /**
0220: * Attribute key for a process property. The class
0221: * <code>org.eclipse.debug.core.model.IProcess</code> allows attaching
0222: * String properties to processes.
0223: * The value of this attribute is the command line a process
0224: * was launched with. Implementers of <code>IVMRunner</code> should use
0225: * this attribute key to attach the command lines to the processes they create.
0226: *
0227: * @deprecated - use <code>IProcess.ATTR_CMDLINE</code>
0228: */
0229: public final static String ATTR_CMDLINE = LaunchingPlugin
0230: .getUniqueIdentifier()
0231: + ".launcher.cmdLine"; //$NON-NLS-1$
0232:
0233: /**
0234: * Attribute key for a classpath attribute referencing a
0235: * list of shared libraries that should appear on the
0236: * <code>-Djava.library.path</code> system property.
0237: * <p>
0238: * The factory methods <code>newLibraryPathsAttribute(String[])</code>
0239: * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
0240: * encode and decode the attribute value.
0241: * </p>
0242: * <p>
0243: * Each string is used to create an <code>IPath</code> using the constructor
0244: * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
0245: * Variable substitution is performed on the string prior to constructing
0246: * a path from the string.
0247: * If the resulting <code>IPath</code> is a relative path, it is interpreted
0248: * as relative to the workspace location. If the path is absolute, it is
0249: * interpreted as an absolute path in the local file system.
0250: * </p>
0251: * @since 3.1
0252: * @see org.eclipse.jdt.core.IClasspathAttribute
0253: */
0254: public static final String CLASSPATH_ATTR_LIBRARY_PATH_ENTRY = LaunchingPlugin
0255: .getUniqueIdentifier()
0256: + ".CLASSPATH_ATTR_LIBRARY_PATH_ENTRY"; //$NON-NLS-1$
0257:
0258: // lock for vm initialization
0259: private static Object fgVMLock = new Object();
0260: private static boolean fgInitializingVMs = false;
0261:
0262: private static HashSet fgVMTypes = null;
0263: private static String fgDefaultVMId = null;
0264: private static String fgDefaultVMConnectorId = null;
0265:
0266: /**
0267: * Resolvers keyed by variable name, container id,
0268: * and runtime classpath entry id.
0269: */
0270: private static Map fgVariableResolvers = null;
0271: private static Map fgContainerResolvers = null;
0272: private static Map fgRuntimeClasspathEntryResolvers = null;
0273:
0274: /**
0275: * Path providers keyed by id
0276: */
0277: private static Map fgPathProviders = null;
0278:
0279: /**
0280: * Default classpath and source path providers.
0281: */
0282: private static IRuntimeClasspathProvider fgDefaultClasspathProvider = new StandardClasspathProvider();
0283: private static IRuntimeClasspathProvider fgDefaultSourcePathProvider = new StandardSourcePathProvider();
0284:
0285: /**
0286: * VM change listeners
0287: */
0288: private static ListenerList fgVMListeners = new ListenerList(5);
0289:
0290: /**
0291: * Cache of already resolved projects in container entries. Used to avoid
0292: * cycles in project dependencies when resolving classpath container entries.
0293: * Counters used to know when entering/exiting to clear cache
0294: */
0295: private static ThreadLocal fgProjects = new ThreadLocal(); // Lists
0296: private static ThreadLocal fgEntryCount = new ThreadLocal(); // Integers
0297:
0298: /**
0299: * Set of IDs of VMs contributed via vmInstalls extension point.
0300: */
0301: private static Set fgContributedVMs = new HashSet();
0302:
0303: /**
0304: * This class contains only static methods, and is not intended
0305: * to be instantiated.
0306: */
0307: private JavaRuntime() {
0308: }
0309:
0310: /**
0311: * Initializes vm type extensions.
0312: */
0313: private static void initializeVMTypeExtensions() {
0314: IExtensionPoint extensionPoint = Platform
0315: .getExtensionRegistry().getExtensionPoint(
0316: LaunchingPlugin.ID_PLUGIN, "vmInstallTypes"); //$NON-NLS-1$
0317: if (extensionPoint != null) {
0318: IConfigurationElement[] configs = extensionPoint
0319: .getConfigurationElements();
0320: MultiStatus status = new MultiStatus(LaunchingPlugin
0321: .getUniqueIdentifier(), IStatus.OK,
0322: "Exceptions occurred", null); //$NON-NLS-1$
0323: fgVMTypes = new HashSet();
0324: for (int i = 0; i < configs.length; i++) {
0325: try {
0326: fgVMTypes.add(configs[i]
0327: .createExecutableExtension("class")); //$NON-NLS-1$
0328: } catch (CoreException e) {
0329: status.add(e.getStatus());
0330: }
0331: }
0332: if (!status.isOK()) {
0333: //only happens on a CoreException
0334: LaunchingPlugin.log(status);
0335: }
0336: } else {
0337: LaunchingPlugin.log(new Status(IStatus.ERROR,
0338: LaunchingPlugin.getUniqueIdentifier(),
0339: "VM Install extension point not found", null)); //$NON-NLS-1$
0340: }
0341: }
0342:
0343: /**
0344: * Returns the VM assigned to build the given Java project.
0345: * The project must exist. The VM assigned to a project is
0346: * determined from its build path.
0347: *
0348: * @param project the project to retrieve the VM from
0349: * @return the VM instance that is assigned to build the given Java project
0350: * Returns <code>null</code> if no VM is referenced on the project's build path.
0351: * @throws CoreException if unable to determine the project's VM install
0352: */
0353: public static IVMInstall getVMInstall(IJavaProject project)
0354: throws CoreException {
0355: // check the classpath
0356: IVMInstall vm = null;
0357: IClasspathEntry[] classpath = project.getRawClasspath();
0358: IRuntimeClasspathEntryResolver resolver = null;
0359: IClasspathEntry entry = null;
0360: for (int i = 0; i < classpath.length; i++) {
0361: entry = classpath[i];
0362: switch (entry.getEntryKind()) {
0363: case IClasspathEntry.CPE_VARIABLE:
0364: resolver = getVariableResolver(entry.getPath().segment(
0365: 0));
0366: if (resolver != null) {
0367: vm = resolver.resolveVMInstall(entry);
0368: }
0369: break;
0370: case IClasspathEntry.CPE_CONTAINER:
0371: resolver = getContainerResolver(entry.getPath()
0372: .segment(0));
0373: if (resolver != null) {
0374: vm = resolver.resolveVMInstall(entry);
0375: }
0376: break;
0377: }
0378: if (vm != null) {
0379: return vm;
0380: }
0381: }
0382: return null;
0383: }
0384:
0385: /**
0386: * Returns the VM install type with the given unique id.
0387: * @param id the VM install type unique id
0388: * @return The VM install type for the given id, or <code>null</code> if no
0389: * VM install type with the given id is registered.
0390: */
0391: public static IVMInstallType getVMInstallType(String id) {
0392: IVMInstallType[] vmTypes = getVMInstallTypes();
0393: for (int i = 0; i < vmTypes.length; i++) {
0394: if (vmTypes[i].getId().equals(id)) {
0395: return vmTypes[i];
0396: }
0397: }
0398: return null;
0399: }
0400:
0401: /**
0402: * Sets a VM as the system-wide default VM, and notifies registered VM install
0403: * change listeners of the change.
0404: *
0405: * @param vm The vm to make the default. May be <code>null</code> to clear
0406: * the default.
0407: * @param monitor progress monitor or <code>null</code>
0408: */
0409: public static void setDefaultVMInstall(IVMInstall vm,
0410: IProgressMonitor monitor) throws CoreException {
0411: setDefaultVMInstall(vm, monitor, true);
0412: }
0413:
0414: /**
0415: * Sets a VM as the system-wide default VM, and notifies registered VM install
0416: * change listeners of the change.
0417: *
0418: * @param vm The vm to make the default. May be <code>null</code> to clear
0419: * the default.
0420: * @param monitor progress monitor or <code>null</code>
0421: * @param savePreference If <code>true</code>, update workbench preferences to reflect
0422: * the new default VM.
0423: * @since 2.1
0424: */
0425: public static void setDefaultVMInstall(IVMInstall vm,
0426: IProgressMonitor monitor, boolean savePreference)
0427: throws CoreException {
0428: IVMInstall previous = null;
0429: if (fgDefaultVMId != null) {
0430: previous = getVMFromCompositeId(fgDefaultVMId);
0431: }
0432: fgDefaultVMId = getCompositeIdFromVM(vm);
0433: if (savePreference) {
0434: saveVMConfiguration();
0435: }
0436: IVMInstall current = null;
0437: if (fgDefaultVMId != null) {
0438: current = getVMFromCompositeId(fgDefaultVMId);
0439: }
0440: if (previous != current) {
0441: notifyDefaultVMChanged(previous, current);
0442: }
0443: }
0444:
0445: /**
0446: * Sets a VM connector as the system-wide default VM. This setting is persisted when
0447: * saveVMConfiguration is called.
0448: * @param connector The connector to make the default. May be <code>null</code> to clear
0449: * the default.
0450: * @param monitor The progress monitor to use
0451: * @since 2.0
0452: * @throws CoreException Thrown if saving the new default setting fails
0453: */
0454: public static void setDefaultVMConnector(IVMConnector connector,
0455: IProgressMonitor monitor) throws CoreException {
0456: fgDefaultVMConnectorId = connector.getIdentifier();
0457: saveVMConfiguration();
0458: }
0459:
0460: /**
0461: * Return the default VM set with <code>setDefaultVM()</code>.
0462: * @return Returns the default VM. May return <code>null</code> when no default
0463: * VM was set or when the default VM has been disposed.
0464: */
0465: public static IVMInstall getDefaultVMInstall() {
0466: IVMInstall install = getVMFromCompositeId(getDefaultVMId());
0467: if (install != null && install.getInstallLocation().exists()) {
0468: return install;
0469: }
0470: // if the default JRE goes missing, re-detect
0471: if (install != null) {
0472: install.getVMInstallType()
0473: .disposeVMInstall(install.getId());
0474: }
0475: synchronized (fgVMLock) {
0476: fgDefaultVMId = null;
0477: fgVMTypes = null;
0478: initializeVMs();
0479: }
0480: return getVMFromCompositeId(getDefaultVMId());
0481: }
0482:
0483: /**
0484: * Return the default VM connector.
0485: * @return Returns the default VM connector.
0486: * @since 2.0
0487: */
0488: public static IVMConnector getDefaultVMConnector() {
0489: String id = getDefaultVMConnectorId();
0490: IVMConnector connector = null;
0491: if (id != null) {
0492: connector = getVMConnector(id);
0493: }
0494: if (connector == null) {
0495: connector = new SocketAttachConnector();
0496: }
0497: return connector;
0498: }
0499:
0500: /**
0501: * Returns the list of registered VM types. VM types are registered via
0502: * <code>"org.eclipse.jdt.launching.vmTypes"</code> extension point.
0503: * Returns an empty list if there are no registered VM types.
0504: *
0505: * @return the list of registered VM types
0506: */
0507: public static IVMInstallType[] getVMInstallTypes() {
0508: initializeVMs();
0509: return (IVMInstallType[]) fgVMTypes
0510: .toArray(new IVMInstallType[fgVMTypes.size()]);
0511: }
0512:
0513: /**
0514: * Returns the default VM id determined during the initialization of the vm types
0515: * @return the id of the default VM
0516: */
0517: private static String getDefaultVMId() {
0518: initializeVMs();
0519: return fgDefaultVMId;
0520: }
0521:
0522: /**
0523: * Returns the default VM connector id determined during the initialization of the vm types
0524: * @return the id of the default VM connector
0525: */
0526: private static String getDefaultVMConnectorId() {
0527: initializeVMs();
0528: return fgDefaultVMConnectorId;
0529: }
0530:
0531: /**
0532: * Returns a String that uniquely identifies the specified VM across all VM types.
0533: *
0534: * @param vm the instance of IVMInstallType to be identified
0535: *
0536: * @since 2.1
0537: */
0538: public static String getCompositeIdFromVM(IVMInstall vm) {
0539: if (vm == null) {
0540: return null;
0541: }
0542: IVMInstallType vmType = vm.getVMInstallType();
0543: String typeID = vmType.getId();
0544: CompositeId id = new CompositeId(new String[] { typeID,
0545: vm.getId() });
0546: return id.toString();
0547: }
0548:
0549: /**
0550: * Return the VM corresponding to the specified composite Id. The id uniquely
0551: * identifies a VM across all vm types.
0552: *
0553: * @param idString the composite id that specifies an instance of IVMInstall
0554: *
0555: * @since 2.1
0556: */
0557: public static IVMInstall getVMFromCompositeId(String idString) {
0558: if (idString == null || idString.length() == 0) {
0559: return null;
0560: }
0561: CompositeId id = CompositeId.fromString(idString);
0562: if (id.getPartCount() == 2) {
0563: IVMInstallType vmType = getVMInstallType(id.get(0));
0564: if (vmType != null) {
0565: return vmType.findVMInstall(id.get(1));
0566: }
0567: }
0568: return null;
0569: }
0570:
0571: /**
0572: * Returns a new runtime classpath entry for the given expression that
0573: * may contain string substitution variable references. The resulting expression
0574: * refers to an archive (jar or directory) containing class files.
0575: *
0576: * @param expression an expression that resolves to the location of an archive
0577: * @return runtime classpath entry
0578: * @since 3.0
0579: */
0580: public static IRuntimeClasspathEntry newStringVariableClasspathEntry(
0581: String expression) {
0582: return new VariableClasspathEntry(expression);
0583: }
0584:
0585: /**
0586: * Returns a new runtime classpath entry containing the default classpath
0587: * for the specified Java project.
0588: *
0589: * @param project Java project
0590: * @return runtime classpath entry
0591: * @since 3.0
0592: */
0593: public static IRuntimeClasspathEntry newDefaultProjectClasspathEntry(
0594: IJavaProject project) {
0595: return new DefaultProjectClasspathEntry(project);
0596: }
0597:
0598: /**
0599: * Returns a new runtime classpath entry for the given project.
0600: *
0601: * @param project Java project
0602: * @return runtime classpath entry
0603: * @since 2.0
0604: */
0605: public static IRuntimeClasspathEntry newProjectRuntimeClasspathEntry(
0606: IJavaProject project) {
0607: return newRuntimeClasspathEntry(JavaCore
0608: .newProjectEntry(project.getProject().getFullPath()));
0609: }
0610:
0611: /**
0612: * Returns a new runtime classpath entry for the given archive.
0613: *
0614: * @param resource archive resource
0615: * @return runtime classpath entry
0616: * @since 2.0
0617: */
0618: public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(
0619: IResource resource) {
0620: return newRuntimeClasspathEntry(JavaCore.newLibraryEntry(
0621: resource.getFullPath(), null, null));
0622: }
0623:
0624: /**
0625: * Returns a new runtime classpath entry for the given archive (possibly
0626: * external).
0627: *
0628: * @param path absolute path to an archive
0629: * @return runtime classpath entry
0630: * @since 2.0
0631: */
0632: public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(
0633: IPath path) {
0634: return newRuntimeClasspathEntry(JavaCore.newLibraryEntry(path,
0635: null, null));
0636: }
0637:
0638: /**
0639: * Returns a new runtime classpath entry for the classpath
0640: * variable with the given path.
0641: *
0642: * @param path variable path; first segment is the name of the variable;
0643: * trailing segments are appended to the resolved variable value
0644: * @return runtime classpath entry
0645: * @since 2.0
0646: */
0647: public static IRuntimeClasspathEntry newVariableRuntimeClasspathEntry(
0648: IPath path) {
0649: return newRuntimeClasspathEntry(JavaCore.newVariableEntry(path,
0650: null, null));
0651: }
0652:
0653: /**
0654: * Returns a runtime classpath entry for the given container path with the given
0655: * classpath property.
0656: *
0657: * @param path container path
0658: * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,
0659: * <code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>
0660: * @return runtime classpath entry
0661: * @exception CoreException if unable to construct a runtime classpath entry
0662: * @since 2.0
0663: */
0664: public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(
0665: IPath path, int classpathProperty) throws CoreException {
0666: return newRuntimeContainerClasspathEntry(path,
0667: classpathProperty, null);
0668: }
0669:
0670: /**
0671: * Returns a runtime classpath entry for the given container path with the given
0672: * classpath property to be resolved in the context of the given Java project.
0673: *
0674: * @param path container path
0675: * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,
0676: * <code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>
0677: * @param project Java project context used for resolution, or <code>null</code>
0678: * if to be resolved in the context of the launch configuration this entry
0679: * is referenced in
0680: * @return runtime classpath entry
0681: * @exception CoreException if unable to construct a runtime classpath entry
0682: * @since 3.0
0683: */
0684: public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(
0685: IPath path, int classpathProperty, IJavaProject project)
0686: throws CoreException {
0687: RuntimeClasspathEntry entry = new RuntimeClasspathEntry(
0688: JavaCore.newContainerEntry(path), classpathProperty);
0689: entry.setJavaProject(project);
0690: return entry;
0691: }
0692:
0693: /**
0694: * Returns a runtime classpath entry constructed from the given memento.
0695: *
0696: * @param memento a memento for a runtime classpath entry
0697: * @return runtime classpath entry
0698: * @exception CoreException if unable to construct a runtime classpath entry
0699: * @since 2.0
0700: */
0701: public static IRuntimeClasspathEntry newRuntimeClasspathEntry(
0702: String memento) throws CoreException {
0703: try {
0704: Element root = null;
0705: DocumentBuilder parser = LaunchingPlugin.getParser();
0706: StringReader reader = new StringReader(memento);
0707: InputSource source = new InputSource(reader);
0708: root = parser.parse(source).getDocumentElement();
0709:
0710: String id = root.getAttribute("id"); //$NON-NLS-1$
0711: if (id == null || id.length() == 0) {
0712: // assume an old format
0713: return new RuntimeClasspathEntry(root);
0714: }
0715: // get the extension & create a new one
0716: IRuntimeClasspathEntry2 entry = LaunchingPlugin
0717: .getDefault().newRuntimeClasspathEntry(id);
0718: NodeList list = root.getChildNodes();
0719: Node node = null;
0720: Element element = null;
0721: for (int i = 0; i < list.getLength(); i++) {
0722: node = list.item(i);
0723: if (node.getNodeType() == Node.ELEMENT_NODE) {
0724: element = (Element) node;
0725: if ("memento".equals(element.getNodeName())) { //$NON-NLS-1$
0726: entry.initializeFrom(element);
0727: }
0728: }
0729: }
0730: return entry;
0731: } catch (SAXException e) {
0732: abort(LaunchingMessages.JavaRuntime_31, e);
0733: } catch (IOException e) {
0734: abort(LaunchingMessages.JavaRuntime_32, e);
0735: }
0736: return null;
0737: }
0738:
0739: /**
0740: * Returns a runtime classpath entry that corresponds to the given
0741: * classpath entry. The classpath entry may not be of type <code>CPE_SOURCE</code>
0742: * or <code>CPE_CONTAINER</code>.
0743: *
0744: * @param entry a classpath entry
0745: * @return runtime classpath entry
0746: * @since 2.0
0747: */
0748: private static IRuntimeClasspathEntry newRuntimeClasspathEntry(
0749: IClasspathEntry entry) {
0750: return new RuntimeClasspathEntry(entry);
0751: }
0752:
0753: /**
0754: * Computes and returns the default unresolved runtime classpath for the
0755: * given project.
0756: *
0757: * @return runtime classpath entries
0758: * @exception CoreException if unable to compute the runtime classpath
0759: * @see IRuntimeClasspathEntry
0760: * @since 2.0
0761: */
0762: public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(
0763: IJavaProject project) throws CoreException {
0764: IClasspathEntry[] entries = project.getRawClasspath();
0765: List classpathEntries = new ArrayList(3);
0766: for (int i = 0; i < entries.length; i++) {
0767: IClasspathEntry entry = entries[i];
0768: switch (entry.getEntryKind()) {
0769: case IClasspathEntry.CPE_CONTAINER:
0770: IClasspathContainer container = JavaCore
0771: .getClasspathContainer(entry.getPath(), project);
0772: if (container != null) {
0773: switch (container.getKind()) {
0774: case IClasspathContainer.K_APPLICATION:
0775: // don't look at application entries
0776: break;
0777: case IClasspathContainer.K_DEFAULT_SYSTEM:
0778: classpathEntries
0779: .add(newRuntimeContainerClasspathEntry(
0780: container.getPath(),
0781: IRuntimeClasspathEntry.STANDARD_CLASSES,
0782: project));
0783: break;
0784: case IClasspathContainer.K_SYSTEM:
0785: classpathEntries
0786: .add(newRuntimeContainerClasspathEntry(
0787: container.getPath(),
0788: IRuntimeClasspathEntry.BOOTSTRAP_CLASSES,
0789: project));
0790: break;
0791: }
0792: }
0793: break;
0794: case IClasspathEntry.CPE_VARIABLE:
0795: if (JRELIB_VARIABLE.equals(entry.getPath().segment(0))) {
0796: IRuntimeClasspathEntry jre = newVariableRuntimeClasspathEntry(entry
0797: .getPath());
0798: jre
0799: .setClasspathProperty(IRuntimeClasspathEntry.STANDARD_CLASSES);
0800: classpathEntries.add(jre);
0801: }
0802: break;
0803: default:
0804: break;
0805: }
0806: }
0807: classpathEntries.add(newDefaultProjectClasspathEntry(project));
0808: return (IRuntimeClasspathEntry[]) classpathEntries
0809: .toArray(new IRuntimeClasspathEntry[classpathEntries
0810: .size()]);
0811: }
0812:
0813: /**
0814: * Computes and returns the unresolved source lookup path for the given launch
0815: * configuration.
0816: *
0817: * @param configuration launch configuration
0818: * @return runtime classpath entries
0819: * @exception CoreException if unable to compute the source lookup path
0820: * @since 2.0
0821: */
0822: public static IRuntimeClasspathEntry[] computeUnresolvedSourceLookupPath(
0823: ILaunchConfiguration configuration) throws CoreException {
0824: return getSourceLookupPathProvider(configuration)
0825: .computeUnresolvedClasspath(configuration);
0826: }
0827:
0828: /**
0829: * Resolves the given source lookup path, returning the resolved source lookup path
0830: * in the context of the given launch configuration.
0831: *
0832: * @param entries unresolved entries
0833: * @param configuration launch configuration
0834: * @return resolved entries
0835: * @exception CoreException if unable to resolve the source lookup path
0836: * @since 2.0
0837: */
0838: public static IRuntimeClasspathEntry[] resolveSourceLookupPath(
0839: IRuntimeClasspathEntry[] entries,
0840: ILaunchConfiguration configuration) throws CoreException {
0841: return getSourceLookupPathProvider(configuration)
0842: .resolveClasspath(entries, configuration);
0843: }
0844:
0845: /**
0846: * Returns the classpath provider for the given launch configuration.
0847: *
0848: * @param configuration launch configuration
0849: * @return classpath provider
0850: * @exception CoreException if unable to resolve the path provider
0851: * @since 2.0
0852: */
0853: public static IRuntimeClasspathProvider getClasspathProvider(
0854: ILaunchConfiguration configuration) throws CoreException {
0855: String providerId = configuration
0856: .getAttribute(
0857: IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER,
0858: (String) null);
0859: IRuntimeClasspathProvider provider = null;
0860: if (providerId == null) {
0861: provider = fgDefaultClasspathProvider;
0862: } else {
0863: provider = (IRuntimeClasspathProvider) getClasspathProviders()
0864: .get(providerId);
0865: if (provider == null) {
0866: abort(MessageFormat.format(
0867: LaunchingMessages.JavaRuntime_26,
0868: new String[] { providerId }), null);
0869: }
0870: }
0871: return provider;
0872: }
0873:
0874: /**
0875: * Returns the source lookup path provider for the given launch configuration.
0876: *
0877: * @param configuration launch configuration
0878: * @return source lookup path provider
0879: * @exception CoreException if unable to resolve the path provider
0880: * @since 2.0
0881: */
0882: public static IRuntimeClasspathProvider getSourceLookupPathProvider(
0883: ILaunchConfiguration configuration) throws CoreException {
0884: String providerId = configuration
0885: .getAttribute(
0886: IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER,
0887: (String) null);
0888: IRuntimeClasspathProvider provider = null;
0889: if (providerId == null) {
0890: provider = fgDefaultSourcePathProvider;
0891: } else {
0892: provider = (IRuntimeClasspathProvider) getClasspathProviders()
0893: .get(providerId);
0894: if (provider == null) {
0895: abort(MessageFormat.format(
0896: LaunchingMessages.JavaRuntime_27,
0897: new String[] { providerId }), null);
0898: }
0899: }
0900: return provider;
0901: }
0902:
0903: /**
0904: * Returns resolved entries for the given entry in the context of the given
0905: * launch configuration. If the entry is of kind
0906: * <code>VARIABLE</code> or <code>CONTAINER</code>, variable and container
0907: * resolvers are consulted. If the entry is of kind <code>PROJECT</code>,
0908: * and the associated Java project specifies non-default output locations,
0909: * the corresponding output locations are returned. Otherwise, the given
0910: * entry is returned.
0911: * <p>
0912: * If the given entry is a variable entry, and a resolver is not registered,
0913: * the entry itself is returned. If the given entry is a container, and a
0914: * resolver is not registered, resolved runtime classpath entries are calculated
0915: * from the associated container classpath entries, in the context of the project
0916: * associated with the given launch configuration.
0917: * </p>
0918: * @param entry runtime classpath entry
0919: * @param configuration launch configuration
0920: * @return resolved runtime classpath entry
0921: * @exception CoreException if unable to resolve
0922: * @see IRuntimeClasspathEntryResolver
0923: * @since 2.0
0924: */
0925: public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(
0926: IRuntimeClasspathEntry entry,
0927: ILaunchConfiguration configuration) throws CoreException {
0928: switch (entry.getType()) {
0929: case IRuntimeClasspathEntry.PROJECT:
0930: // if the project has multiple output locations, they must be returned
0931: IResource resource = entry.getResource();
0932: if (resource instanceof IProject) {
0933: IProject p = (IProject) resource;
0934: IJavaProject project = JavaCore.create(p);
0935: if (project == null || !p.isOpen() || !project.exists()) {
0936: return new IRuntimeClasspathEntry[0];
0937: }
0938: IRuntimeClasspathEntry[] entries = resolveOutputLocations(
0939: project, entry.getClasspathProperty());
0940: if (entries != null) {
0941: return entries;
0942: }
0943: } else {
0944: // could not resolve project
0945: abort(
0946: MessageFormat
0947: .format(
0948: LaunchingMessages.JavaRuntime_Classpath_references_non_existant_project___0__3,
0949: new String[] { entry.getPath()
0950: .lastSegment() }), null);
0951: }
0952: break;
0953: case IRuntimeClasspathEntry.VARIABLE:
0954: IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry
0955: .getVariableName());
0956: if (resolver == null) {
0957: IRuntimeClasspathEntry[] resolved = resolveVariableEntry(
0958: entry, null, configuration);
0959: if (resolved != null) {
0960: return resolved;
0961: }
0962: break;
0963: }
0964: return resolver.resolveRuntimeClasspathEntry(entry,
0965: configuration);
0966: case IRuntimeClasspathEntry.CONTAINER:
0967: resolver = getContainerResolver(entry.getVariableName());
0968: if (resolver == null) {
0969: return computeDefaultContainerEntries(entry,
0970: configuration);
0971: }
0972: return resolver.resolveRuntimeClasspathEntry(entry,
0973: configuration);
0974: case IRuntimeClasspathEntry.ARCHIVE:
0975: // verify the archive exists
0976: String location = entry.getLocation();
0977: if (location == null) {
0978: abort(
0979: MessageFormat
0980: .format(
0981: LaunchingMessages.JavaRuntime_Classpath_references_non_existant_archive___0__4,
0982: new String[] { entry.getPath()
0983: .toString() }), null);
0984: }
0985: File file = new File(location);
0986: if (!file.exists()) {
0987: abort(
0988: MessageFormat
0989: .format(
0990: LaunchingMessages.JavaRuntime_Classpath_references_non_existant_archive___0__4,
0991: new String[] { entry.getPath()
0992: .toString() }), null);
0993: }
0994: break;
0995: case IRuntimeClasspathEntry.OTHER:
0996: resolver = getContributedResolver(((IRuntimeClasspathEntry2) entry)
0997: .getTypeId());
0998: return resolver.resolveRuntimeClasspathEntry(entry,
0999: configuration);
1000: default:
1001: break;
1002: }
1003: return new IRuntimeClasspathEntry[] { entry };
1004: }
1005:
1006: /**
1007: * Default resolution for a classpath variable - resolve to an archive. Only
1008: * one of project/configuration can be non-null.
1009: *
1010: * @param entry
1011: * @param project the project context or <code>null</code>
1012: * @param configuration configuration context or <code>null</code>
1013: * @return IRuntimeClasspathEntry[]
1014: * @throws CoreException
1015: */
1016: private static IRuntimeClasspathEntry[] resolveVariableEntry(
1017: IRuntimeClasspathEntry entry, IJavaProject project,
1018: ILaunchConfiguration configuration) throws CoreException {
1019: // default resolution - an archive
1020: IPath archPath = JavaCore.getClasspathVariable(entry
1021: .getVariableName());
1022: if (archPath != null) {
1023: if (entry.getPath().segmentCount() > 1) {
1024: archPath = archPath.append(entry.getPath()
1025: .removeFirstSegments(1));
1026: }
1027: IPath srcPath = null;
1028: IPath srcVar = entry.getSourceAttachmentPath();
1029: IPath srcRootPath = null;
1030: IPath srcRootVar = entry.getSourceAttachmentRootPath();
1031: if (archPath != null && !archPath.isEmpty()) {
1032: if (srcVar != null && !srcVar.isEmpty()) {
1033: srcPath = JavaCore.getClasspathVariable(srcVar
1034: .segment(0));
1035: if (srcPath != null) {
1036: if (srcVar.segmentCount() > 1) {
1037: srcPath = srcPath.append(srcVar
1038: .removeFirstSegments(1));
1039: }
1040: if (srcRootVar != null && !srcRootVar.isEmpty()) {
1041: srcRootPath = JavaCore
1042: .getClasspathVariable(srcRootVar
1043: .segment(0));
1044: if (srcRootPath != null) {
1045: if (srcRootVar.segmentCount() > 1) {
1046: srcRootPath = srcRootPath
1047: .append(srcRootVar
1048: .removeFirstSegments(1));
1049: }
1050: }
1051: }
1052: }
1053: }
1054: // now resolve the archive (recursively)
1055: IClasspathEntry archEntry = JavaCore.newLibraryEntry(
1056: archPath, srcPath, srcRootPath, entry
1057: .getClasspathEntry().isExported());
1058: IRuntimeClasspathEntry runtimeArchEntry = newRuntimeClasspathEntry(archEntry);
1059: runtimeArchEntry.setClasspathProperty(entry
1060: .getClasspathProperty());
1061: if (configuration == null) {
1062: return resolveRuntimeClasspathEntry(
1063: runtimeArchEntry, project);
1064: }
1065: return resolveRuntimeClasspathEntry(runtimeArchEntry,
1066: configuration);
1067: }
1068: }
1069: return null;
1070: }
1071:
1072: /**
1073: * Returns runtime classpath entries corresponding to the output locations
1074: * of the given project, or null if the project only uses the default
1075: * output location.
1076: *
1077: * @param project
1078: * @param classpathProperty the type of classpath entries to create
1079: * @return IRuntimeClasspathEntry[] or <code>null</code>
1080: * @throws CoreException
1081: */
1082: private static IRuntimeClasspathEntry[] resolveOutputLocations(
1083: IJavaProject project, int classpathProperty)
1084: throws CoreException {
1085: List nonDefault = new ArrayList();
1086: if (project.exists() && project.getProject().isOpen()) {
1087: IClasspathEntry entries[] = project.getRawClasspath();
1088: for (int i = 0; i < entries.length; i++) {
1089: IClasspathEntry classpathEntry = entries[i];
1090: if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
1091: IPath path = classpathEntry.getOutputLocation();
1092: if (path != null) {
1093: nonDefault.add(path);
1094: }
1095: }
1096: }
1097: }
1098: if (nonDefault.isEmpty()) {
1099: return null;
1100: }
1101: // add the default location if not already included
1102: IPath def = project.getOutputLocation();
1103: if (!nonDefault.contains(def)) {
1104: nonDefault.add(def);
1105: }
1106: IRuntimeClasspathEntry[] locations = new IRuntimeClasspathEntry[nonDefault
1107: .size()];
1108: for (int i = 0; i < locations.length; i++) {
1109: IClasspathEntry newEntry = JavaCore.newLibraryEntry(
1110: (IPath) nonDefault.get(i), null, null);
1111: locations[i] = new RuntimeClasspathEntry(newEntry);
1112: locations[i].setClasspathProperty(classpathProperty);
1113: }
1114: return locations;
1115: }
1116:
1117: /**
1118: * Returns resolved entries for the given entry in the context of the given
1119: * Java project. If the entry is of kind
1120: * <code>VARIABLE</code> or <code>CONTAINER</code>, variable and container
1121: * resolvers are consulted. If the entry is of kind <code>PROJECT</code>,
1122: * and the associated Java project specifies non-default output locations,
1123: * the corresponding output locations are returned. Otherwise, the given
1124: * entry is returned.
1125: * <p>
1126: * If the given entry is a variable entry, and a resolver is not registered,
1127: * the entry itself is returned. If the given entry is a container, and a
1128: * resolver is not registered, resolved runtime classpath entries are calculated
1129: * from the associated container classpath entries, in the context of the
1130: * given project.
1131: * </p>
1132: * @param entry runtime classpath entry
1133: * @param project Java project context
1134: * @return resolved runtime classpath entry
1135: * @exception CoreException if unable to resolve
1136: * @see IRuntimeClasspathEntryResolver
1137: * @since 2.0
1138: */
1139: public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(
1140: IRuntimeClasspathEntry entry, IJavaProject project)
1141: throws CoreException {
1142: switch (entry.getType()) {
1143: case IRuntimeClasspathEntry.PROJECT:
1144: // if the project has multiple output locations, they must be returned
1145: IResource resource = entry.getResource();
1146: if (resource instanceof IProject) {
1147: IProject p = (IProject) resource;
1148: IJavaProject jp = JavaCore.create(p);
1149: if (jp != null && p.isOpen() && jp.exists()) {
1150: IRuntimeClasspathEntry[] entries = resolveOutputLocations(
1151: jp, entry.getClasspathProperty());
1152: if (entries != null) {
1153: return entries;
1154: }
1155: } else {
1156: return new IRuntimeClasspathEntry[0];
1157: }
1158: }
1159: break;
1160: case IRuntimeClasspathEntry.VARIABLE:
1161: IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry
1162: .getVariableName());
1163: if (resolver == null) {
1164: IRuntimeClasspathEntry[] resolved = resolveVariableEntry(
1165: entry, project, null);
1166: if (resolved != null) {
1167: return resolved;
1168: }
1169: break;
1170: }
1171: return resolver
1172: .resolveRuntimeClasspathEntry(entry, project);
1173: case IRuntimeClasspathEntry.CONTAINER:
1174: resolver = getContainerResolver(entry.getVariableName());
1175: if (resolver == null) {
1176: return computeDefaultContainerEntries(entry, project);
1177: }
1178: return resolver
1179: .resolveRuntimeClasspathEntry(entry, project);
1180: case IRuntimeClasspathEntry.OTHER:
1181: resolver = getContributedResolver(((IRuntimeClasspathEntry2) entry)
1182: .getTypeId());
1183: return resolver
1184: .resolveRuntimeClasspathEntry(entry, project);
1185: default:
1186: break;
1187: }
1188: return new IRuntimeClasspathEntry[] { entry };
1189: }
1190:
1191: /**
1192: * Performs default resolution for a container entry.
1193: * Delegates to the Java model.
1194: */
1195: private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(
1196: IRuntimeClasspathEntry entry, ILaunchConfiguration config)
1197: throws CoreException {
1198: IJavaProject project = entry.getJavaProject();
1199: if (project == null) {
1200: project = getJavaProject(config);
1201: }
1202: return computeDefaultContainerEntries(entry, project);
1203: }
1204:
1205: /**
1206: * Performs default resolution for a container entry.
1207: * Delegates to the Java model.
1208: */
1209: private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(
1210: IRuntimeClasspathEntry entry, IJavaProject project)
1211: throws CoreException {
1212: if (project == null || entry == null) {
1213: // cannot resolve without entry or project context
1214: return new IRuntimeClasspathEntry[0];
1215: }
1216: IClasspathContainer container = JavaCore.getClasspathContainer(
1217: entry.getPath(), project);
1218: if (container == null) {
1219: abort(
1220: MessageFormat
1221: .format(
1222: LaunchingMessages.JavaRuntime_Could_not_resolve_classpath_container___0__1,
1223: new String[] { entry.getPath()
1224: .toString() }), null);
1225: // execution will not reach here - exception will be thrown
1226: return null;
1227: }
1228: IClasspathEntry[] cpes = container.getClasspathEntries();
1229: int property = -1;
1230: switch (container.getKind()) {
1231: case IClasspathContainer.K_APPLICATION:
1232: property = IRuntimeClasspathEntry.USER_CLASSES;
1233: break;
1234: case IClasspathContainer.K_DEFAULT_SYSTEM:
1235: property = IRuntimeClasspathEntry.STANDARD_CLASSES;
1236: break;
1237: case IClasspathContainer.K_SYSTEM:
1238: property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;
1239: break;
1240: }
1241: List resolved = new ArrayList(cpes.length);
1242: List projects = (List) fgProjects.get();
1243: Integer count = (Integer) fgEntryCount.get();
1244: if (projects == null) {
1245: projects = new ArrayList();
1246: fgProjects.set(projects);
1247: count = new Integer(0);
1248: }
1249: int intCount = count.intValue();
1250: intCount++;
1251: fgEntryCount.set(new Integer(intCount));
1252: try {
1253: for (int i = 0; i < cpes.length; i++) {
1254: IClasspathEntry cpe = cpes[i];
1255: if (cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
1256: IProject p = ResourcesPlugin.getWorkspace()
1257: .getRoot().getProject(
1258: cpe.getPath().segment(0));
1259: IJavaProject jp = JavaCore.create(p);
1260: if (!projects.contains(jp)) {
1261: projects.add(jp);
1262: IRuntimeClasspathEntry classpath = newDefaultProjectClasspathEntry(jp);
1263: IRuntimeClasspathEntry[] entries = resolveRuntimeClasspathEntry(
1264: classpath, jp);
1265: for (int j = 0; j < entries.length; j++) {
1266: IRuntimeClasspathEntry e = entries[j];
1267: if (!resolved.contains(e)) {
1268: resolved.add(entries[j]);
1269: }
1270: }
1271: }
1272: } else {
1273: IRuntimeClasspathEntry e = newRuntimeClasspathEntry(cpe);
1274: if (!resolved.contains(e)) {
1275: resolved.add(e);
1276: }
1277: }
1278: }
1279: } finally {
1280: intCount--;
1281: if (intCount == 0) {
1282: fgProjects.set(null);
1283: fgEntryCount.set(null);
1284: } else {
1285: fgEntryCount.set(new Integer(intCount));
1286: }
1287: }
1288: // set classpath property
1289: IRuntimeClasspathEntry[] result = new IRuntimeClasspathEntry[resolved
1290: .size()];
1291: for (int i = 0; i < result.length; i++) {
1292: result[i] = (IRuntimeClasspathEntry) resolved.get(i);
1293: result[i].setClasspathProperty(property);
1294: }
1295: return result;
1296: }
1297:
1298: /**
1299: * Computes and returns the unresolved class path for the given launch configuration.
1300: * Variable and container entries are unresolved.
1301: *
1302: * @param configuration launch configuration
1303: * @return unresolved runtime classpath entries
1304: * @exception CoreException if unable to compute the classpath
1305: * @since 2.0
1306: */
1307: public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(
1308: ILaunchConfiguration configuration) throws CoreException {
1309: return getClasspathProvider(configuration)
1310: .computeUnresolvedClasspath(configuration);
1311: }
1312:
1313: /**
1314: * Resolves the given classpath, returning the resolved classpath
1315: * in the context of the given launch configuration.
1316: *
1317: * @param entries unresolved classpath
1318: * @param configuration launch configuration
1319: * @return resolved runtime classpath entries
1320: * @exception CoreException if unable to compute the classpath
1321: * @since 2.0
1322: */
1323: public static IRuntimeClasspathEntry[] resolveRuntimeClasspath(
1324: IRuntimeClasspathEntry[] entries,
1325: ILaunchConfiguration configuration) throws CoreException {
1326: return getClasspathProvider(configuration).resolveClasspath(
1327: entries, configuration);
1328: }
1329:
1330: /**
1331: * Return the <code>IJavaProject</code> referenced in the specified configuration or
1332: * <code>null</code> if none.
1333: *
1334: * @exception CoreException if the referenced Java project does not exist
1335: * @since 2.0
1336: */
1337: public static IJavaProject getJavaProject(
1338: ILaunchConfiguration configuration) throws CoreException {
1339: String projectName = configuration.getAttribute(
1340: IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME,
1341: (String) null);
1342: if ((projectName == null) || (projectName.trim().length() < 1)) {
1343: return null;
1344: }
1345: IJavaProject javaProject = getJavaModel().getJavaProject(
1346: projectName);
1347: if (javaProject != null && javaProject.getProject().exists()
1348: && !javaProject.getProject().isOpen()) {
1349: abort(
1350: MessageFormat.format(
1351: LaunchingMessages.JavaRuntime_28,
1352: new String[] { configuration.getName(),
1353: projectName }),
1354: IJavaLaunchConfigurationConstants.ERR_PROJECT_CLOSED,
1355: null);
1356: }
1357: if ((javaProject == null) || !javaProject.exists()) {
1358: abort(
1359: MessageFormat
1360: .format(
1361: LaunchingMessages.JavaRuntime_Launch_configuration__0__references_non_existing_project__1___1,
1362: new String[] {
1363: configuration.getName(),
1364: projectName }),
1365: IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT,
1366: null);
1367: }
1368: return javaProject;
1369: }
1370:
1371: /**
1372: * Convenience method to get the java model.
1373: */
1374: private static IJavaModel getJavaModel() {
1375: return JavaCore
1376: .create(ResourcesPlugin.getWorkspace().getRoot());
1377: }
1378:
1379: /**
1380: * Returns the VM install for the given launch configuration.
1381: * The VM install is determined in the following prioritized way:
1382: * <ol>
1383: * <li>The VM install is explicitly specified on the launch configuration
1384: * via the <code>ATTR_JRE_CONTAINER_PATH</code> attribute (since 3.2).</li>
1385: * <li>The VM install is explicitly specified on the launch configuration
1386: * via the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_ID</code>
1387: * attributes.</li>
1388: * <li>If no explicit VM install is specified, the VM install associated with
1389: * the launch configuration's project is returned.</li>
1390: * <li>If no project is specified, or the project does not specify a custom
1391: * VM install, the workspace default VM install is returned.</li>
1392: * </ol>
1393: *
1394: * @param configuration launch configuration
1395: * @return vm install
1396: * @exception CoreException if unable to compute a vm install
1397: * @since 2.0
1398: */
1399: public static IVMInstall computeVMInstall(
1400: ILaunchConfiguration configuration) throws CoreException {
1401: String jreAttr = configuration
1402: .getAttribute(
1403: IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH,
1404: (String) null);
1405: if (jreAttr == null) {
1406: String type = configuration
1407: .getAttribute(
1408: IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE,
1409: (String) null);
1410: if (type == null) {
1411: IJavaProject proj = getJavaProject(configuration);
1412: if (proj != null) {
1413: IVMInstall vm = getVMInstall(proj);
1414: if (vm != null) {
1415: return vm;
1416: }
1417: }
1418: } else {
1419: String name = configuration
1420: .getAttribute(
1421: IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME,
1422: (String) null);
1423: return resolveVM(type, name, configuration);
1424: }
1425: } else {
1426: IPath jrePath = Path.fromPortableString(jreAttr);
1427: IClasspathEntry entry = JavaCore.newContainerEntry(jrePath);
1428: IRuntimeClasspathEntryResolver2 resolver = getVariableResolver(jrePath
1429: .segment(0));
1430: if (resolver != null) {
1431: return resolver.resolveVMInstall(entry);
1432: } else {
1433: resolver = getContainerResolver(jrePath.segment(0));
1434: if (resolver != null) {
1435: return resolver.resolveVMInstall(entry);
1436: }
1437: }
1438: }
1439:
1440: return getDefaultVMInstall();
1441: }
1442:
1443: /**
1444: * Returns the VM of the given type with the specified name.
1445: *
1446: * @param type vm type identifier
1447: * @param name vm name
1448: * @return vm install
1449: * @exception CoreException if unable to resolve
1450: * @since 3.2
1451: */
1452: private static IVMInstall resolveVM(String type, String name,
1453: ILaunchConfiguration configuration) throws CoreException {
1454: IVMInstallType vt = getVMInstallType(type);
1455: if (vt == null) {
1456: // error type does not exist
1457: abort(
1458: MessageFormat
1459: .format(
1460: LaunchingMessages.JavaRuntime_Specified_VM_install_type_does_not_exist___0__2,
1461: new String[] { type }), null);
1462: }
1463: IVMInstall vm = null;
1464: // look for a name
1465: if (name == null) {
1466: // error - type specified without a specific install (could be an old config that specified a VM ID)
1467: // log the error, but choose the default VM.
1468: LaunchingPlugin
1469: .log(new Status(
1470: IStatus.WARNING,
1471: LaunchingPlugin.getUniqueIdentifier(),
1472: IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_VM_INSTALL,
1473: MessageFormat
1474: .format(
1475: "VM not fully specified in launch configuration {0} - missing VM name. Reverting to default VM.", new String[] { configuration.getName() }), null)); //$NON-NLS-1$
1476: return getDefaultVMInstall();
1477: }
1478: vm = vt.findVMInstallByName(name);
1479: if (vm == null) {
1480: // error - install not found
1481: abort(
1482: MessageFormat
1483: .format(
1484: LaunchingMessages.JavaRuntime_Specified_VM_install_not_found__type__0___name__1__2,
1485: new String[] { vt.getName(), name }),
1486: null);
1487: } else {
1488: return vm;
1489: }
1490: // won't reach here
1491: return null;
1492: }
1493:
1494: /**
1495: * Throws a core exception with an internal error status.
1496: *
1497: * @param message the status message
1498: * @param exception lower level exception associated with the
1499: * error, or <code>null</code> if none
1500: */
1501: private static void abort(String message, Throwable exception)
1502: throws CoreException {
1503: abort(message,
1504: IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR,
1505: exception);
1506: }
1507:
1508: /**
1509: * Throws a core exception with an internal error status.
1510: *
1511: * @param message the status message
1512: * @param code status code
1513: * @param exception lower level exception associated with the
1514: *
1515: * error, or <code>null</code> if none
1516: */
1517: private static void abort(String message, int code,
1518: Throwable exception) throws CoreException {
1519: throw new CoreException(new Status(IStatus.ERROR,
1520: LaunchingPlugin.getUniqueIdentifier(), code, message,
1521: exception));
1522: }
1523:
1524: /**
1525: * Computes the default application classpath entries for the given
1526: * project.
1527: *
1528: * @param jproject The project to compute the classpath for
1529: * @return The computed classpath. May be empty, but not null.
1530: * @throws CoreException if unable to compute the default classpath
1531: */
1532: public static String[] computeDefaultRuntimeClassPath(
1533: IJavaProject jproject) throws CoreException {
1534: IRuntimeClasspathEntry[] unresolved = computeUnresolvedRuntimeClasspath(jproject);
1535: // 1. remove bootpath entries
1536: // 2. resolve & translate to local file system paths
1537: List resolved = new ArrayList(unresolved.length);
1538: for (int i = 0; i < unresolved.length; i++) {
1539: IRuntimeClasspathEntry entry = unresolved[i];
1540: if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
1541: IRuntimeClasspathEntry[] entries = resolveRuntimeClasspathEntry(
1542: entry, jproject);
1543: for (int j = 0; j < entries.length; j++) {
1544: String location = entries[j].getLocation();
1545: if (location != null) {
1546: resolved.add(location);
1547: }
1548: }
1549: }
1550: }
1551: return (String[]) resolved.toArray(new String[resolved.size()]);
1552: }
1553:
1554: /**
1555: * Saves the VM configuration information to the preferences. This includes
1556: * the following information:
1557: * <ul>
1558: * <li>The list of all defined IVMInstall instances.</li>
1559: * <li>The default VM</li>
1560: * <ul>
1561: * This state will be read again upon first access to VM
1562: * configuration information.
1563: */
1564: public static void saveVMConfiguration() throws CoreException {
1565: if (fgVMTypes == null) {
1566: // if the VM types have not been instantiated, there can be no changes.
1567: return;
1568: }
1569: String xml = getVMsAsXML();
1570: getPreferences().setValue(PREF_VM_XML, xml);
1571: savePreferences();
1572: }
1573:
1574: /**
1575: * Returns the listing of currently installed VMs as a single XML file
1576: * @return an XML representation of all of the currently installed VMs
1577: * @throws CoreException
1578: */
1579: private static String getVMsAsXML() throws CoreException {
1580: VMDefinitionsContainer container = new VMDefinitionsContainer();
1581: container.setDefaultVMInstallCompositeID(getDefaultVMId());
1582: container
1583: .setDefaultVMInstallConnectorTypeID(getDefaultVMConnectorId());
1584: IVMInstallType[] vmTypes = getVMInstallTypes();
1585: IVMInstall[] vms = null;
1586: for (int i = 0; i < vmTypes.length; ++i) {
1587: vms = vmTypes[i].getVMInstalls();
1588: for (int j = 0; j < vms.length; j++) {
1589: container.addVM(vms[j]);
1590: }
1591: }
1592: return container.getAsXML();
1593: }
1594:
1595: /**
1596: * This method loads installed JREs based an existing user preference
1597: * or old vm configurations file. The VMs found in the preference
1598: * or vm configurations file are added to the given VM definitions container.
1599: *
1600: * Returns whether the user preferences should be set - i.e. if it was
1601: * not already set when initialized.
1602: */
1603: private static boolean addPersistedVMs(VMDefinitionsContainer vmDefs)
1604: throws IOException {
1605: // Try retrieving the VM preferences from the preference store
1606: String vmXMLString = getPreferences().getString(PREF_VM_XML);
1607:
1608: // If the preference was found, load VMs from it into memory
1609: if (vmXMLString.length() > 0) {
1610: try {
1611: ByteArrayInputStream inputStream = new ByteArrayInputStream(
1612: vmXMLString.getBytes("UTF8")); //$NON-NLS-1$
1613: VMDefinitionsContainer.parseXMLIntoContainer(
1614: inputStream, vmDefs);
1615: return false;
1616: } catch (IOException ioe) {
1617: LaunchingPlugin.log(ioe);
1618: }
1619: } else {
1620: // Otherwise, look for the old file that previously held the VM definitions
1621: IPath stateLocation = LaunchingPlugin.getDefault()
1622: .getStateLocation();
1623: IPath stateFile = stateLocation
1624: .append("vmConfiguration.xml"); //$NON-NLS-1$
1625: File file = new File(stateFile.toOSString());
1626:
1627: if (file.exists()) {
1628: // If file exists, load VM definitions from it into memory and write the definitions to
1629: // the preference store WITHOUT triggering any processing of the new value
1630: InputStream fileInputStream = new BufferedInputStream(
1631: new FileInputStream(file));
1632: VMDefinitionsContainer.parseXMLIntoContainer(
1633: fileInputStream, vmDefs);
1634: }
1635: }
1636: return true;
1637: }
1638:
1639: /**
1640: * Loads contributed VM installs
1641: * @since 3.2
1642: */
1643: private static void addVMExtensions(VMDefinitionsContainer vmDefs) {
1644: IExtensionPoint extensionPoint = Platform
1645: .getExtensionRegistry().getExtensionPoint(
1646: LaunchingPlugin.ID_PLUGIN,
1647: JavaRuntime.EXTENSION_POINT_VM_INSTALLS);
1648: IConfigurationElement[] configs = extensionPoint
1649: .getConfigurationElements();
1650: for (int i = 0; i < configs.length; i++) {
1651: IConfigurationElement element = configs[i];
1652: try {
1653: if ("vmInstall".equals(element.getName())) { //$NON-NLS-1$
1654: String vmType = element
1655: .getAttribute("vmInstallType"); //$NON-NLS-1$
1656: if (vmType == null) {
1657: abort(
1658: MessageFormat
1659: .format(
1660: "Missing required vmInstallType attribute for vmInstall contributed by {0}", //$NON-NLS-1$
1661: new String[] { element
1662: .getContributor()
1663: .getName() }),
1664: null);
1665: }
1666: String id = element.getAttribute("id"); //$NON-NLS-1$
1667: if (id == null) {
1668: abort(
1669: MessageFormat
1670: .format(
1671: "Missing required id attribute for vmInstall contributed by {0}", //$NON-NLS-1$
1672: new String[] { element
1673: .getContributor()
1674: .getName() }),
1675: null);
1676: }
1677: IVMInstallType installType = getVMInstallType(vmType);
1678: if (installType == null) {
1679: abort(
1680: MessageFormat
1681: .format(
1682: "vmInstall {0} contributed by {1} references undefined VM install type {2}", //$NON-NLS-1$
1683: new String[] {
1684: id,
1685: element
1686: .getContributor()
1687: .getName(),
1688: vmType }), null);
1689: }
1690: IVMInstall install = installType.findVMInstall(id);
1691: if (install == null) {
1692: // only load/create if first time we've seen this VM install
1693: String name = element.getAttribute("name"); //$NON-NLS-1$
1694: if (name == null) {
1695: abort(
1696: MessageFormat
1697: .format(
1698: "vmInstall {0} contributed by {1} missing required attribute name", //$NON-NLS-1$
1699: new String[] {
1700: id,
1701: element
1702: .getContributor()
1703: .getName() }),
1704: null);
1705: }
1706: String home = element.getAttribute("home"); //$NON-NLS-1$
1707: if (home == null) {
1708: abort(
1709: MessageFormat
1710: .format(
1711: "vmInstall {0} contributed by {1} missing required attribute home", //$NON-NLS-1$
1712: new String[] {
1713: id,
1714: element
1715: .getContributor()
1716: .getName() }),
1717: null);
1718: }
1719: String javadoc = element
1720: .getAttribute("javadocURL"); //$NON-NLS-1$
1721: String vmArgs = element.getAttribute("vmArgs"); //$NON-NLS-1$
1722: VMStandin standin = new VMStandin(installType,
1723: id);
1724: standin.setName(name);
1725: home = substitute(home);
1726: File homeDir = new File(home);
1727: if (homeDir.exists()) {
1728: try {
1729: // adjust for relative path names
1730: home = homeDir.getCanonicalPath();
1731: homeDir = new File(home);
1732: } catch (IOException e) {
1733: }
1734: }
1735: IStatus status = installType
1736: .validateInstallLocation(homeDir);
1737: if (!status.isOK()) {
1738: abort(
1739: MessageFormat
1740: .format(
1741: "Illegal install location {0} for vmInstall {1} contributed by {2}: {3}", //$NON-NLS-1$
1742: new String[] {
1743: home,
1744: id,
1745: element
1746: .getContributor()
1747: .getName(),
1748: status
1749: .getMessage() }),
1750: null);
1751: }
1752: standin.setInstallLocation(homeDir);
1753: if (javadoc != null) {
1754: try {
1755: standin.setJavadocLocation(new URL(
1756: javadoc));
1757: } catch (MalformedURLException e) {
1758: abort(
1759: MessageFormat
1760: .format(
1761: "Illegal javadocURL attribute for vmInstall {0} contributed by {1}", //$NON-NLS-1$
1762: new String[] {
1763: id,
1764: element
1765: .getContributor()
1766: .getName() }),
1767: e);
1768: }
1769: }
1770: // allow default arguments to be specified by vm install type if no explicit arguments
1771: if (vmArgs == null) {
1772: if (installType instanceof AbstractVMInstallType) {
1773: AbstractVMInstallType type = (AbstractVMInstallType) installType;
1774: vmArgs = type
1775: .getDefaultVMArguments(homeDir);
1776: }
1777: }
1778: if (vmArgs != null) {
1779: standin.setVMArgs(vmArgs);
1780: }
1781: IConfigurationElement[] libraries = element
1782: .getChildren("library"); //$NON-NLS-1$
1783: LibraryLocation[] locations = null;
1784: if (libraries.length > 0) {
1785: locations = new LibraryLocation[libraries.length];
1786: for (int j = 0; j < libraries.length; j++) {
1787: IConfigurationElement library = libraries[j];
1788: String libPathStr = library
1789: .getAttribute("path"); //$NON-NLS-1$
1790: if (libPathStr == null) {
1791: abort(
1792: MessageFormat
1793: .format(
1794: "library for vmInstall {0} contributed by {1} missing required attribute libPath", //$NON-NLS-1$
1795: new String[] {
1796: id,
1797: element
1798: .getContributor()
1799: .getName() }),
1800: null);
1801: }
1802: String sourcePathStr = library
1803: .getAttribute("sourcePath"); //$NON-NLS-1$
1804: String packageRootStr = library
1805: .getAttribute("packageRootPath"); //$NON-NLS-1$
1806: String javadocOverride = library
1807: .getAttribute("javadocURL"); //$NON-NLS-1$
1808: URL url = null;
1809: if (javadocOverride != null) {
1810: try {
1811: url = new URL(javadocOverride);
1812: } catch (MalformedURLException e) {
1813: abort(
1814: MessageFormat
1815: .format(
1816: "Illegal javadocURL attribute specified for library {0} for vmInstall {1} contributed by {2}" //$NON-NLS-1$
1817: ,
1818: new String[] {
1819: libPathStr,
1820: id,
1821: element
1822: .getContributor()
1823: .getName() }),
1824: e);
1825: }
1826: }
1827: IPath homePath = new Path(home);
1828: IPath libPath = homePath
1829: .append(substitute(libPathStr));
1830: IPath sourcePath = Path.EMPTY;
1831: if (sourcePathStr != null) {
1832: sourcePath = homePath
1833: .append(substitute(sourcePathStr));
1834: }
1835: IPath packageRootPath = Path.EMPTY;
1836: if (packageRootStr != null) {
1837: packageRootPath = new Path(
1838: substitute(packageRootStr));
1839: }
1840: locations[j] = new LibraryLocation(
1841: libPath, sourcePath,
1842: packageRootPath, url);
1843: }
1844: }
1845: standin.setLibraryLocations(locations);
1846: // in case the contributed JRE attributes changed, remove it first, then add
1847: vmDefs.removeVM(standin);
1848: vmDefs.addVM(standin);
1849: }
1850: fgContributedVMs.add(id);
1851: } else {
1852: abort(
1853: MessageFormat
1854: .format(
1855: "Illegal element {0} in vmInstalls extension contributed by {1}", //$NON-NLS-1$
1856: new String[] {
1857: element.getName(),
1858: element
1859: .getContributor()
1860: .getName() }),
1861: null);
1862: }
1863: } catch (CoreException e) {
1864: LaunchingPlugin.log(e);
1865: }
1866: }
1867: }
1868:
1869: /**
1870: * Performs string substitution on the given expression.
1871: *
1872: * @param expression
1873: * @return expression after string substitution
1874: * @throws CoreException
1875: * @since 3.2
1876: */
1877: private static String substitute(String expression)
1878: throws CoreException {
1879: return VariablesPlugin.getDefault().getStringVariableManager()
1880: .performStringSubstitution(expression);
1881: }
1882:
1883: /**
1884: * Returns whether the VM install with the specified id was contributed via
1885: * the vmInstalls extension point.
1886: *
1887: * @param id vm id
1888: * @return whether the vm install was contributed via extension point
1889: * @since 3.2
1890: */
1891: public static boolean isContributedVMInstall(String id) {
1892: getVMInstallTypes(); // ensure VMs are initialized
1893: return fgContributedVMs.contains(id);
1894: }
1895:
1896: /**
1897: * Evaluates library locations for a IVMInstall. If no library locations are set on the install, a default
1898: * location is evaluated and checked if it exists.
1899: * @return library locations with paths that exist or are empty
1900: * @since 2.0
1901: */
1902: public static LibraryLocation[] getLibraryLocations(IVMInstall vm) {
1903: IPath[] libraryPaths;
1904: IPath[] sourcePaths;
1905: IPath[] sourceRootPaths;
1906: URL[] javadocLocations;
1907: LibraryLocation[] locations = vm.getLibraryLocations();
1908: if (locations == null) {
1909: URL defJavaDocLocation = vm.getJavadocLocation();
1910: LibraryLocation[] dflts = vm
1911: .getVMInstallType()
1912: .getDefaultLibraryLocations(vm.getInstallLocation());
1913: libraryPaths = new IPath[dflts.length];
1914: sourcePaths = new IPath[dflts.length];
1915: sourceRootPaths = new IPath[dflts.length];
1916: javadocLocations = new URL[dflts.length];
1917: for (int i = 0; i < dflts.length; i++) {
1918: libraryPaths[i] = dflts[i].getSystemLibraryPath();
1919: if (defJavaDocLocation == null) {
1920: javadocLocations[i] = dflts[i].getJavadocLocation();
1921: } else {
1922: javadocLocations[i] = defJavaDocLocation;
1923: }
1924: if (!libraryPaths[i].toFile().isFile()) {
1925: libraryPaths[i] = Path.EMPTY;
1926: }
1927:
1928: sourcePaths[i] = dflts[i].getSystemLibrarySourcePath();
1929: if (sourcePaths[i].toFile().isFile()) {
1930: sourceRootPaths[i] = dflts[i].getPackageRootPath();
1931: } else {
1932: sourcePaths[i] = Path.EMPTY;
1933: sourceRootPaths[i] = Path.EMPTY;
1934: }
1935: }
1936: } else {
1937: libraryPaths = new IPath[locations.length];
1938: sourcePaths = new IPath[locations.length];
1939: sourceRootPaths = new IPath[locations.length];
1940: javadocLocations = new URL[locations.length];
1941: for (int i = 0; i < locations.length; i++) {
1942: libraryPaths[i] = locations[i].getSystemLibraryPath();
1943: sourcePaths[i] = locations[i]
1944: .getSystemLibrarySourcePath();
1945: sourceRootPaths[i] = locations[i].getPackageRootPath();
1946: javadocLocations[i] = locations[i].getJavadocLocation();
1947: }
1948: }
1949: locations = new LibraryLocation[sourcePaths.length];
1950: for (int i = 0; i < sourcePaths.length; i++) {
1951: locations[i] = new LibraryLocation(libraryPaths[i],
1952: sourcePaths[i], sourceRootPaths[i],
1953: javadocLocations[i]);
1954: }
1955: return locations;
1956: }
1957:
1958: /**
1959: * Detect the VM that Eclipse is running on.
1960: *
1961: * @return a VM standin representing the VM that Eclipse is running on, or
1962: * <code>null</code> if unable to detect the runtime VM
1963: */
1964: private static VMStandin detectEclipseRuntime() {
1965: VMStandin detectedVMStandin = null;
1966: // Try to detect a VM for each declared VM type
1967: IVMInstallType[] vmTypes = getVMInstallTypes();
1968: for (int i = 0; i < vmTypes.length; i++) {
1969:
1970: File detectedLocation = vmTypes[i].detectInstallLocation();
1971: if (detectedLocation != null && detectedVMStandin == null) {
1972:
1973: // Make sure the VM id is unique
1974: long unique = System.currentTimeMillis();
1975: IVMInstallType vmType = vmTypes[i];
1976: while (vmType.findVMInstall(String.valueOf(unique)) != null) {
1977: unique++;
1978: }
1979:
1980: // Create a standin for the detected VM and add it to the result collector
1981: String vmID = String.valueOf(unique);
1982: detectedVMStandin = new VMStandin(vmType, vmID);
1983: detectedVMStandin.setInstallLocation(detectedLocation);
1984: detectedVMStandin
1985: .setName(generateDetectedVMName(detectedVMStandin));
1986: if (vmType instanceof AbstractVMInstallType) {
1987: AbstractVMInstallType abs = (AbstractVMInstallType) vmType;
1988: URL url = abs
1989: .getDefaultJavadocLocation(detectedLocation);
1990: detectedVMStandin.setJavadocLocation(url);
1991: String arguments = abs
1992: .getDefaultVMArguments(detectedLocation);
1993: if (arguments != null) {
1994: detectedVMStandin.setVMArgs(arguments);
1995: }
1996: }
1997: }
1998: }
1999: return detectedVMStandin;
2000: }
2001:
2002: /**
2003: * Returns whether the specified option is the same in both option maps.
2004: *
2005: * @param optionName name of option to test
2006: * @param defaultOptions map of default options
2007: * @param options map of other options
2008: * @return whether the options are the same in both maps
2009: */
2010: private static boolean equals(String optionName,
2011: Map defaultOptions, Map options) {
2012: if (defaultOptions.containsKey(optionName)) {
2013: return options.containsKey(optionName)
2014: && equals(defaultOptions.get(optionName), options
2015: .get(optionName));
2016: } else {
2017: return !options.containsKey(optionName);
2018: }
2019: }
2020:
2021: /**
2022: * Returns whether the objects are equal or both <code>null</code>
2023: *
2024: * @param o1 an object
2025: * @param o2 an object
2026: * @return whether the objects are equal or both <code>null</code>
2027: */
2028: private static boolean equals(Object o1, Object o2) {
2029: if (o1 == null) {
2030: return o2 == null;
2031: } else {
2032: return o1.equals(o2);
2033: }
2034: }
2035:
2036: /**
2037: * Make the name of a detected VM stand out.
2038: */
2039: private static String generateDetectedVMName(IVMInstall vm) {
2040: String name = vm.getInstallLocation().getName();
2041: name = name.trim();
2042: if (name.length() == 0) {
2043: name = LaunchingMessages.JavaRuntime_25;
2044: }
2045: return name;
2046: }
2047:
2048: /**
2049: * Creates and returns a classpath entry describing
2050: * the JRE_LIB classpath variable.
2051: *
2052: * @return a new IClasspathEntry that describes the JRE_LIB classpath variable
2053: */
2054: public static IClasspathEntry getJREVariableEntry() {
2055: return JavaCore.newVariableEntry(new Path(JRELIB_VARIABLE),
2056: new Path(JRESRC_VARIABLE),
2057: new Path(JRESRCROOT_VARIABLE));
2058: }
2059:
2060: /**
2061: * Creates and returns a classpath entry describing
2062: * the default JRE container entry.
2063: *
2064: * @return a new IClasspathEntry that describes the default JRE container entry
2065: * @since 2.0
2066: */
2067: public static IClasspathEntry getDefaultJREContainerEntry() {
2068: return JavaCore.newContainerEntry(newDefaultJREContainerPath());
2069: }
2070:
2071: /**
2072: * Returns a path for the JRE classpath container identifying the
2073: * default VM install.
2074: *
2075: * @return classpath container path
2076: * @since 3.2
2077: */
2078: public static IPath newDefaultJREContainerPath() {
2079: return new Path(JRE_CONTAINER);
2080: }
2081:
2082: /**
2083: * Returns a path for the JRE classpath container identifying the
2084: * specified VM install by type and name.
2085: *
2086: * @param vm vm install
2087: * @return classpath container path
2088: * @since 3.2
2089: */
2090: public static IPath newJREContainerPath(IVMInstall vm) {
2091: return newJREContainerPath(vm.getVMInstallType().getId(), vm
2092: .getName());
2093: }
2094:
2095: /**
2096: * Returns a path for the JRE classpath container identifying the
2097: * specified VM install by type and name.
2098: *
2099: * @param typeId vm install type identifier
2100: * @param name vm install name
2101: * @return classpath container path
2102: * @since 3.2
2103: */
2104: public static IPath newJREContainerPath(String typeId, String name) {
2105: IPath path = newDefaultJREContainerPath();
2106: path = path.append(typeId);
2107: path = path.append(name);
2108: return path;
2109: }
2110:
2111: /**
2112: * Returns a path for the JRE classpath container identifying the
2113: * specified execution environment.
2114: *
2115: * @param environment execution environment
2116: * @return classpath container path
2117: * @since 3.2
2118: */
2119: public static IPath newJREContainerPath(
2120: IExecutionEnvironment environment) {
2121: IPath path = newDefaultJREContainerPath();
2122: path = path.append(StandardVMType.ID_STANDARD_VM_TYPE);
2123: path = path.append(JREContainerInitializer
2124: .encodeEnvironmentId(environment.getId()));
2125: return path;
2126: }
2127:
2128: /**
2129: * Returns the JRE referenced by the specified JRE classpath container
2130: * path or <code>null</code> if none.
2131: *
2132: * @param jreContainerPath
2133: * @return JRE referenced by the specified JRE classpath container
2134: * path or <code>null</code>
2135: * @since 3.2
2136: */
2137: public static IVMInstall getVMInstall(IPath jreContainerPath) {
2138: return JREContainerInitializer.resolveVM(jreContainerPath);
2139: }
2140:
2141: /**
2142: * Returns the identifier of the VM install type referenced by the
2143: * given JRE classpath container path, or <code>null</code> if none.
2144: *
2145: * @param jreContainerPath
2146: * @return vm install type identifier or <code>null</code>
2147: * @since 3.2
2148: */
2149: public static String getVMInstallTypeId(IPath jreContainerPath) {
2150: if (JREContainerInitializer
2151: .isExecutionEnvironment(jreContainerPath)) {
2152: return null;
2153: }
2154: return JREContainerInitializer.getVMTypeId(jreContainerPath);
2155: }
2156:
2157: /**
2158: * Returns the name of the VM install referenced by the
2159: * given JRE classpath container path, or <code>null</code> if none.
2160: *
2161: * @param jreContainerPath
2162: * @return vm name or <code>null</code>
2163: * @since 3.2
2164: */
2165: public static String getVMInstallName(IPath jreContainerPath) {
2166: if (JREContainerInitializer
2167: .isExecutionEnvironment(jreContainerPath)) {
2168: return null;
2169: }
2170: return JREContainerInitializer.getVMName(jreContainerPath);
2171: }
2172:
2173: /**
2174: * Returns the execution environment identifier in the following JRE
2175: * classpath container path, or <code>null</code> if none.
2176: *
2177: * @param jreContainerPath classpath container path
2178: * @return execution environment identifier or <code>null</code>
2179: * @since 3.2
2180: */
2181: public static String getExecutionEnvironmentId(
2182: IPath jreContainerPath) {
2183: return JREContainerInitializer
2184: .getExecutionEnvironmentId(jreContainerPath);
2185: }
2186:
2187: /**
2188: * Returns a runtime classpath entry identifying the JRE to use when launching the specified
2189: * configuration or <code>null</code> if none is specified. The entry returned represents a
2190: * either a classpath variable or classpath container that resolves to a JRE.
2191: * <p>
2192: * The entry is resolved as follows:
2193: * <ol>
2194: * <li>If the <code>ATTR_JRE_CONTAINER_PATH</code> is present, it is used to create
2195: * a classpath container referring to a JRE.</li>
2196: * <li>Next, if the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_NAME</code>
2197: * attributes are present, they are used to create a classpath container.</li>
2198: * <li>When none of the above attributes are specified, a default entry is
2199: * created which refers to the JRE referenced by the build path of the configuration's
2200: * associated Java project. This could be a classpath variable or classpath container.</li>
2201: * <li>When there is no Java project associated with a configuration, the workspace
2202: * default JRE is used to create a container path.</li>
2203: * </ol>
2204: * </p>
2205: * @param configuration
2206: * @return classpath container path identifying a JRE or <code>null</code>
2207: * @exception org.eclipse.core.runtime.CoreException if an exception occurs retrieving
2208: * attributes from the specified launch configuration
2209: * @since 3.2
2210: */
2211: public static IRuntimeClasspathEntry computeJREEntry(
2212: ILaunchConfiguration configuration) throws CoreException {
2213: String jreAttr = configuration
2214: .getAttribute(
2215: IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH,
2216: (String) null);
2217: IPath containerPath = null;
2218: if (jreAttr == null) {
2219: String type = configuration
2220: .getAttribute(
2221: IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE,
2222: (String) null);
2223: if (type == null) {
2224: // default JRE for the launch configuration
2225: IJavaProject proj = getJavaProject(configuration);
2226: if (proj == null) {
2227: containerPath = newDefaultJREContainerPath();
2228: } else {
2229: return computeJREEntry(proj);
2230: }
2231: } else {
2232: String name = configuration
2233: .getAttribute(
2234: IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME,
2235: (String) null);
2236: if (name != null) {
2237: containerPath = newDefaultJREContainerPath()
2238: .append(type).append(name);
2239: }
2240: }
2241: } else {
2242: containerPath = Path.fromPortableString(jreAttr);
2243: }
2244: if (containerPath != null) {
2245: return newRuntimeContainerClasspathEntry(containerPath,
2246: IRuntimeClasspathEntry.STANDARD_CLASSES);
2247: }
2248: return null;
2249: }
2250:
2251: /**
2252: * Returns a runtime classpath entry identifying the JRE referenced by the specified
2253: * project, or <code>null</code> if none. The entry returned represents a either a
2254: * classpath variable or classpath container that resolves to a JRE.
2255: *
2256: * @param project Java project
2257: * @return JRE runtime classpath entry or <code>null</code>
2258: * @exception org.eclipse.core.runtime.CoreException if an exception occurs
2259: * accessing the project's classpath
2260: * @since 3.2
2261: */
2262: public static IRuntimeClasspathEntry computeJREEntry(
2263: IJavaProject project) throws CoreException {
2264: IClasspathEntry[] rawClasspath = project.getRawClasspath();
2265: IRuntimeClasspathEntryResolver2 resolver = null;
2266: for (int i = 0; i < rawClasspath.length; i++) {
2267: IClasspathEntry entry = rawClasspath[i];
2268: switch (entry.getEntryKind()) {
2269: case IClasspathEntry.CPE_VARIABLE:
2270: resolver = getVariableResolver(entry.getPath().segment(
2271: 0));
2272: if (resolver != null) {
2273: if (resolver.isVMInstallReference(entry)) {
2274: return newRuntimeClasspathEntry(entry);
2275: }
2276: }
2277: break;
2278: case IClasspathEntry.CPE_CONTAINER:
2279: resolver = getContainerResolver(entry.getPath()
2280: .segment(0));
2281: if (resolver != null) {
2282: if (resolver.isVMInstallReference(entry)) {
2283: IClasspathContainer container = JavaCore
2284: .getClasspathContainer(entry.getPath(),
2285: project);
2286: if (container != null) {
2287: switch (container.getKind()) {
2288: case IClasspathContainer.K_APPLICATION:
2289: break;
2290: case IClasspathContainer.K_DEFAULT_SYSTEM:
2291: return newRuntimeContainerClasspathEntry(
2292: entry.getPath(),
2293: IRuntimeClasspathEntry.STANDARD_CLASSES);
2294: case IClasspathContainer.K_SYSTEM:
2295: return newRuntimeContainerClasspathEntry(
2296: entry.getPath(),
2297: IRuntimeClasspathEntry.BOOTSTRAP_CLASSES);
2298: }
2299: }
2300: }
2301: }
2302: break;
2303: }
2304:
2305: }
2306: return null;
2307: }
2308:
2309: /**
2310: * Returns whether the given runtime classpath entry refers to a vm install.
2311: *
2312: * @param entry
2313: * @return whether the given runtime classpath entry refers to a vm install
2314: * @since 3.2
2315: */
2316: public static boolean isVMInstallReference(
2317: IRuntimeClasspathEntry entry) {
2318: IClasspathEntry classpathEntry = entry.getClasspathEntry();
2319: if (classpathEntry != null) {
2320: switch (classpathEntry.getEntryKind()) {
2321: case IClasspathEntry.CPE_VARIABLE:
2322: IRuntimeClasspathEntryResolver2 resolver = getVariableResolver(classpathEntry
2323: .getPath().segment(0));
2324: if (resolver != null) {
2325: return resolver
2326: .isVMInstallReference(classpathEntry);
2327: }
2328: break;
2329: case IClasspathEntry.CPE_CONTAINER:
2330: resolver = getContainerResolver(classpathEntry
2331: .getPath().segment(0));
2332: if (resolver != null) {
2333: return resolver
2334: .isVMInstallReference(classpathEntry);
2335: }
2336: break;
2337: }
2338: }
2339: return false;
2340: }
2341:
2342: /**
2343: * Returns the VM connector defined with the specified identifier,
2344: * or <code>null</code> if none.
2345: *
2346: * @param id VM connector identifier
2347: * @return VM connector or <code>null</code> if none
2348: * @since 2.0
2349: */
2350: public static IVMConnector getVMConnector(String id) {
2351: return LaunchingPlugin.getDefault().getVMConnector(id);
2352: }
2353:
2354: /**
2355: * Returns all VM connector extensions.
2356: *
2357: * @return VM connectors
2358: * @since 2.0
2359: */
2360: public static IVMConnector[] getVMConnectors() {
2361: return LaunchingPlugin.getDefault().getVMConnectors();
2362: }
2363:
2364: /**
2365: * Returns the preference store for the launching plug-in.
2366: *
2367: * @return the preference store for the launching plug-in
2368: * @since 2.0
2369: */
2370: public static Preferences getPreferences() {
2371: return LaunchingPlugin.getDefault().getPluginPreferences();
2372: }
2373:
2374: /**
2375: * Saves the preferences for the launching plug-in.
2376: *
2377: * @since 2.0
2378: */
2379: public static void savePreferences() {
2380: LaunchingPlugin.getDefault().savePluginPreferences();
2381: }
2382:
2383: /**
2384: * Registers the given resolver for the specified variable.
2385: *
2386: * @param resolver runtime classpath entry resolver
2387: * @param variableName variable name to register for
2388: * @since 2.0
2389: */
2390: public static void addVariableResolver(
2391: IRuntimeClasspathEntryResolver resolver, String variableName) {
2392: Map map = getVariableResolvers();
2393: map.put(variableName, resolver);
2394: }
2395:
2396: /**
2397: * Registers the given resolver for the specified container.
2398: *
2399: * @param resolver runtime classpath entry resolver
2400: * @param containerIdentifier identifier of the classpath container to register for
2401: * @since 2.0
2402: */
2403: public static void addContainerResolver(
2404: IRuntimeClasspathEntryResolver resolver,
2405: String containerIdentifier) {
2406: Map map = getContainerResolvers();
2407: map.put(containerIdentifier, resolver);
2408: }
2409:
2410: /**
2411: * Returns all registered variable resolvers.
2412: */
2413: private static Map getVariableResolvers() {
2414: if (fgVariableResolvers == null) {
2415: initializeResolvers();
2416: }
2417: return fgVariableResolvers;
2418: }
2419:
2420: /**
2421: * Returns all registered container resolvers.
2422: */
2423: private static Map getContainerResolvers() {
2424: if (fgContainerResolvers == null) {
2425: initializeResolvers();
2426: }
2427: return fgContainerResolvers;
2428: }
2429:
2430: /**
2431: * Returns all registered runtime classpath entry resolvers.
2432: */
2433: private static Map getEntryResolvers() {
2434: if (fgRuntimeClasspathEntryResolvers == null) {
2435: initializeResolvers();
2436: }
2437: return fgRuntimeClasspathEntryResolvers;
2438: }
2439:
2440: /**
2441: * Initializes the listing of runtime classpath entry resolvers
2442: */
2443: private static void initializeResolvers() {
2444: IExtensionPoint point = Platform
2445: .getExtensionRegistry()
2446: .getExtensionPoint(LaunchingPlugin.ID_PLUGIN,
2447: EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS);
2448: IConfigurationElement[] extensions = point
2449: .getConfigurationElements();
2450: fgVariableResolvers = new HashMap(extensions.length);
2451: fgContainerResolvers = new HashMap(extensions.length);
2452: fgRuntimeClasspathEntryResolvers = new HashMap(
2453: extensions.length);
2454: for (int i = 0; i < extensions.length; i++) {
2455: RuntimeClasspathEntryResolver res = new RuntimeClasspathEntryResolver(
2456: extensions[i]);
2457: String variable = res.getVariableName();
2458: String container = res.getContainerId();
2459: String entryId = res.getRuntimeClasspathEntryId();
2460: if (variable != null) {
2461: fgVariableResolvers.put(variable, res);
2462: }
2463: if (container != null) {
2464: fgContainerResolvers.put(container, res);
2465: }
2466: if (entryId != null) {
2467: fgRuntimeClasspathEntryResolvers.put(entryId, res);
2468: }
2469: }
2470: }
2471:
2472: /**
2473: * Returns all registered classpath providers.
2474: */
2475: private static Map getClasspathProviders() {
2476: if (fgPathProviders == null) {
2477: initializeProviders();
2478: }
2479: return fgPathProviders;
2480: }
2481:
2482: /**
2483: * Initializes the listing of classpath providers
2484: */
2485: private static void initializeProviders() {
2486: IExtensionPoint point = Platform.getExtensionRegistry()
2487: .getExtensionPoint(LaunchingPlugin.ID_PLUGIN,
2488: EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS);
2489: IConfigurationElement[] extensions = point
2490: .getConfigurationElements();
2491: fgPathProviders = new HashMap(extensions.length);
2492: for (int i = 0; i < extensions.length; i++) {
2493: RuntimeClasspathProvider res = new RuntimeClasspathProvider(
2494: extensions[i]);
2495: fgPathProviders.put(res.getIdentifier(), res);
2496: }
2497: }
2498:
2499: /**
2500: * Returns the resolver registered for the given variable, or
2501: * <code>null</code> if none.
2502: *
2503: * @param variableName the variable to determine the resolver for
2504: * @return the resolver registered for the given variable, or
2505: * <code>null</code> if none
2506: */
2507: private static IRuntimeClasspathEntryResolver2 getVariableResolver(
2508: String variableName) {
2509: return (IRuntimeClasspathEntryResolver2) getVariableResolvers()
2510: .get(variableName);
2511: }
2512:
2513: /**
2514: * Returns the resolver registered for the given container id, or
2515: * <code>null</code> if none.
2516: *
2517: * @param containerId the container to determine the resolver for
2518: * @return the resolver registered for the given container id, or
2519: * <code>null</code> if none
2520: */
2521: private static IRuntimeClasspathEntryResolver2 getContainerResolver(
2522: String containerId) {
2523: return (IRuntimeClasspathEntryResolver2) getContainerResolvers()
2524: .get(containerId);
2525: }
2526:
2527: /**
2528: * Returns the resolver registered for the given contributed classpath
2529: * entry type.
2530: *
2531: * @param typeId the id of the contributed classpath entry
2532: * @return the resolver registered for the given classpath entry
2533: */
2534: private static IRuntimeClasspathEntryResolver getContributedResolver(
2535: String typeId) {
2536: IRuntimeClasspathEntryResolver resolver = (IRuntimeClasspathEntryResolver) getEntryResolvers()
2537: .get(typeId);
2538: if (resolver == null) {
2539: return new DefaultEntryResolver();
2540: }
2541: return resolver;
2542: }
2543:
2544: /**
2545: * Adds the given listener to the list of registered VM install changed
2546: * listeners. Has no effect if an identical listener is already registered.
2547: *
2548: * @param listener the listener to add
2549: * @since 2.0
2550: */
2551: public static void addVMInstallChangedListener(
2552: IVMInstallChangedListener listener) {
2553: fgVMListeners.add(listener);
2554: }
2555:
2556: /**
2557: * Removes the given listener from the list of registered VM install changed
2558: * listeners. Has no effect if an identical listener is not already registered.
2559: *
2560: * @param listener the listener to remove
2561: * @since 2.0
2562: */
2563: public static void removeVMInstallChangedListener(
2564: IVMInstallChangedListener listener) {
2565: fgVMListeners.remove(listener);
2566: }
2567:
2568: /**
2569: * Notifies registered listeners that the default VM has changed
2570: * @param previous the previous VM
2571: * @param current the new current default VM
2572: */
2573: private static void notifyDefaultVMChanged(IVMInstall previous,
2574: IVMInstall current) {
2575: Object[] listeners = fgVMListeners.getListeners();
2576: for (int i = 0; i < listeners.length; i++) {
2577: IVMInstallChangedListener listener = (IVMInstallChangedListener) listeners[i];
2578: listener.defaultVMInstallChanged(previous, current);
2579: }
2580: }
2581:
2582: /**
2583: * Notifies all VM install changed listeners of the given property change.
2584: *
2585: * @param event event describing the change.
2586: * @since 2.0
2587: */
2588: public static void fireVMChanged(PropertyChangeEvent event) {
2589: Object[] listeners = fgVMListeners.getListeners();
2590: for (int i = 0; i < listeners.length; i++) {
2591: IVMInstallChangedListener listener = (IVMInstallChangedListener) listeners[i];
2592: listener.vmChanged(event);
2593: }
2594: }
2595:
2596: /**
2597: * Notifies all VM install changed listeners of the VM addition
2598: *
2599: * @param vm the VM that has been added
2600: * @since 2.0
2601: */
2602: public static void fireVMAdded(IVMInstall vm) {
2603: if (!fgInitializingVMs) {
2604: Object[] listeners = fgVMListeners.getListeners();
2605: for (int i = 0; i < listeners.length; i++) {
2606: IVMInstallChangedListener listener = (IVMInstallChangedListener) listeners[i];
2607: listener.vmAdded(vm);
2608: }
2609: }
2610: }
2611:
2612: /**
2613: * Notifies all VM install changed listeners of the VM removal
2614: *
2615: * @param vm the VM that has been removed
2616: * @since 2.0
2617: */
2618: public static void fireVMRemoved(IVMInstall vm) {
2619: Object[] listeners = fgVMListeners.getListeners();
2620: for (int i = 0; i < listeners.length; i++) {
2621: IVMInstallChangedListener listener = (IVMInstallChangedListener) listeners[i];
2622: listener.vmRemoved(vm);
2623: }
2624: }
2625:
2626: /**
2627: * Return the String representation of the default output directory of the
2628: * launch config's project or <code>null</code> if there is no config, no
2629: * project or some sort of problem.
2630: *
2631: * @return the default output directory for the specified launch
2632: * configuration's project
2633: * @since 2.1
2634: */
2635: public static String getProjectOutputDirectory(
2636: ILaunchConfiguration config) {
2637: try {
2638: if (config != null) {
2639: IJavaProject javaProject = JavaRuntime
2640: .getJavaProject(config);
2641: if (javaProject != null) {
2642: IWorkspaceRoot root = ResourcesPlugin
2643: .getWorkspace().getRoot();
2644: IPath outputLocation = javaProject
2645: .getOutputLocation();
2646: IResource resource = root
2647: .findMember(outputLocation);
2648: if (resource != null) {
2649: IPath path = resource.getFullPath();
2650: if (path != null) {
2651: return path.makeRelative().toString();
2652: }
2653: }
2654: }
2655: }
2656: } catch (CoreException ce) {
2657: }
2658: return null;
2659: }
2660:
2661: /**
2662: * Returns a collection of source containers corresponding to the given
2663: * resolved runtime classpath entries.
2664: * <p>
2665: * Note that the entries must be resolved to ARCHIVE and PROJECT entries,
2666: * as source containers cannot be determined for unresolved entries.
2667: * </p>
2668: * @param entries entries to translate
2669: * @return source containers corresponding to the given runtime classpath entries
2670: * @since 3.1
2671: */
2672: public static ISourceContainer[] getSourceContainers(
2673: IRuntimeClasspathEntry[] entries) {
2674: return JavaSourceLookupUtil.translate(entries);
2675: }
2676:
2677: /**
2678: * Returns a collection of paths that should be appended to the given project's
2679: * <code>java.library.path</code> system property when launched. Entries are
2680: * searched for on the project's build path as extra classpath attributes.
2681: * Each entry represents an absolute path in the local file system.
2682: *
2683: * @param project the project to compute the <code>java.library.path</code> for
2684: * @param requiredProjects whether to consider entries in required projects
2685: * @return a collection of paths representing entries that should be appended
2686: * to the given project's <code>java.library.path</code>
2687: * @throws CoreException if unable to compute the Java library path
2688: * @since 3.1
2689: * @see org.eclipse.jdt.core.IClasspathAttribute
2690: * @see JavaRuntime#CLASSPATH_ATTR_LIBRARY_PATH_ENTRY
2691: */
2692: public static String[] computeJavaLibraryPath(IJavaProject project,
2693: boolean requiredProjects) throws CoreException {
2694: Set visited = new HashSet();
2695: List entries = new ArrayList();
2696: gatherJavaLibraryPathEntries(project, requiredProjects,
2697: visited, entries);
2698: List resolved = new ArrayList(entries.size());
2699: Iterator iterator = entries.iterator();
2700: IStringVariableManager manager = VariablesPlugin.getDefault()
2701: .getStringVariableManager();
2702: IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2703: while (iterator.hasNext()) {
2704: String entry = (String) iterator.next();
2705: String resolvedEntry = manager
2706: .performStringSubstitution(entry);
2707: IPath path = new Path(resolvedEntry);
2708: if (path.isAbsolute()) {
2709: File file = path.toFile();
2710: resolved.add(file.getAbsolutePath());
2711: } else {
2712: IResource resource = root.findMember(path);
2713: if (resource != null) {
2714: IPath location = resource.getLocation();
2715: if (location != null) {
2716: resolved.add(location.toFile()
2717: .getAbsolutePath());
2718: }
2719: }
2720: }
2721: }
2722: return (String[]) resolved.toArray(new String[resolved.size()]);
2723: }
2724:
2725: /**
2726: * Gathers all Java library entries for the given project and optionally its required
2727: * projects.
2728: *
2729: * @param project project to gather entries for
2730: * @param requiredProjects whether to consider required projects
2731: * @param visited projects already considered
2732: * @param entries collection to add library entries to
2733: * @throws CoreException if unable to gather classpath entries
2734: * @since 3.1
2735: */
2736: private static void gatherJavaLibraryPathEntries(
2737: IJavaProject project, boolean requiredProjects,
2738: Set visited, List entries) throws CoreException {
2739: if (visited.contains(project)) {
2740: return;
2741: }
2742: visited.add(project);
2743: IClasspathEntry[] rawClasspath = project.getRawClasspath();
2744: IClasspathEntry[] required = processJavaLibraryPathEntries(
2745: project, requiredProjects, rawClasspath, entries);
2746: if (required != null) {
2747: IWorkspaceRoot root = ResourcesPlugin.getWorkspace()
2748: .getRoot();
2749: for (int i = 0; i < required.length; i++) {
2750: IClasspathEntry entry = required[i];
2751: String projectName = entry.getPath().segment(0);
2752: IProject p = root.getProject(projectName);
2753: if (p.exists()) {
2754: IJavaProject requiredProject = JavaCore.create(p);
2755: if (requiredProject != null) {
2756: gatherJavaLibraryPathEntries(requiredProject,
2757: requiredProjects, visited, entries);
2758: }
2759: }
2760: }
2761: }
2762: }
2763:
2764: /**
2765: * Adds all java library path extra classpath entry values to the given entries collection
2766: * specified on the given project's classpath, and returns a collection of required
2767: * projects, or <code>null</code>.
2768: *
2769: * @param project project being processed
2770: * @param collectRequired whether to collect required projects
2771: * @param classpathEntries the project's raw classpath
2772: * @param entries collection to add java library path entries to
2773: * @return required project classpath entries or <code>null</code>
2774: * @throws CoreException
2775: * @since 3.1
2776: */
2777: private static IClasspathEntry[] processJavaLibraryPathEntries(
2778: IJavaProject project, boolean collectRequired,
2779: IClasspathEntry[] classpathEntries, List entries)
2780: throws CoreException {
2781: List req = null;
2782: for (int i = 0; i < classpathEntries.length; i++) {
2783: IClasspathEntry entry = classpathEntries[i];
2784: IClasspathAttribute[] extraAttributes = entry
2785: .getExtraAttributes();
2786: for (int j = 0; j < extraAttributes.length; j++) {
2787: String[] paths = getLibraryPaths(extraAttributes[j]);
2788: if (paths != null) {
2789: for (int k = 0; k < paths.length; k++) {
2790: entries.add(paths[k]);
2791: }
2792: }
2793: }
2794: if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
2795: IClasspathContainer container = JavaCore
2796: .getClasspathContainer(entry.getPath(), project);
2797: if (container != null) {
2798: IClasspathEntry[] requiredProjects = processJavaLibraryPathEntries(
2799: project, collectRequired, container
2800: .getClasspathEntries(), entries);
2801: if (requiredProjects != null) {
2802: if (req == null) {
2803: req = new ArrayList();
2804: }
2805: for (int j = 0; j < requiredProjects.length; j++) {
2806: req.add(requiredProjects[j]);
2807: }
2808: }
2809: }
2810: } else if (collectRequired
2811: && entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2812: if (req == null) {
2813: req = new ArrayList();
2814: }
2815: req.add(entry);
2816: }
2817: }
2818: if (req != null) {
2819: return (IClasspathEntry[]) req
2820: .toArray(new IClasspathEntry[req.size()]);
2821: }
2822: return null;
2823: }
2824:
2825: /**
2826: * Creates a new classpath attribute referencing a list of shared libraries that should
2827: * appear on the <code>-Djava.library.path</code> system property at runtime
2828: * for an associated {@link IClasspathEntry}.
2829: * <p>
2830: * The factory methods <code>newLibraryPathsAttribute(String[])</code>
2831: * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
2832: * encode and decode the attribute value.
2833: * </p>
2834: * @param paths an array of strings representing paths of shared libraries.
2835: * Each string is used to create an <code>IPath</code> using the constructor
2836: * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2837: * Variable substitution is performed on each string before a path is constructed
2838: * from a string.
2839: * @return a classpath attribute with the name <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>
2840: * and an value encoded to the specified paths.
2841: * @since 3.1
2842: */
2843: public static IClasspathAttribute newLibraryPathsAttribute(
2844: String[] paths) {
2845: StringBuffer value = new StringBuffer();
2846: for (int i = 0; i < paths.length; i++) {
2847: value.append(paths[i]);
2848: if (i < (paths.length - 1)) {
2849: value.append("|"); //$NON-NLS-1$
2850: }
2851: }
2852: return JavaCore.newClasspathAttribute(
2853: CLASSPATH_ATTR_LIBRARY_PATH_ENTRY, value.toString());
2854: }
2855:
2856: /**
2857: * Returns an array of strings referencing shared libraries that should
2858: * appear on the <code>-Djava.library.path</code> system property at runtime
2859: * for an associated {@link IClasspathEntry}, or <code>null</code> if the
2860: * given attribute is not a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>.
2861: * Each string is used to create an <code>IPath</code> using the constructor
2862: * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2863: * <p>
2864: * The factory methods <code>newLibraryPathsAttribute(String[])</code>
2865: * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
2866: * encode and decode the attribute value.
2867: * </p>
2868: * @param attribute a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code> classpath attribute
2869: * @return an array of strings referencing shared libraries that should
2870: * appear on the <code>-Djava.library.path</code> system property at runtime
2871: * for an associated {@link IClasspathEntry}, or <code>null</code> if the
2872: * given attribute is not a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>.
2873: * Each string is used to create an <code>IPath</code> using the constructor
2874: * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2875: * @since 3.1
2876: */
2877: public static String[] getLibraryPaths(IClasspathAttribute attribute) {
2878: if (CLASSPATH_ATTR_LIBRARY_PATH_ENTRY.equals(attribute
2879: .getName())) {
2880: String value = attribute.getValue();
2881: return value.split("\\|"); //$NON-NLS-1$
2882: }
2883: return null;
2884: }
2885:
2886: /**
2887: * Returns the execution environments manager.
2888: *
2889: * @return execution environments manager
2890: * @since 3.2
2891: */
2892: public static IExecutionEnvironmentsManager getExecutionEnvironmentsManager() {
2893: return EnvironmentsManager.getDefault();
2894: }
2895:
2896: /**
2897: * Perform VM type and VM install initialization. Does not hold locks
2898: * while performing change notification.
2899: *
2900: * @since 3.2
2901: */
2902: private static void initializeVMs() {
2903: VMDefinitionsContainer vmDefs = null;
2904: boolean setPref = false;
2905: boolean updateCompliance = false;
2906: synchronized (fgVMLock) {
2907: if (fgVMTypes == null) {
2908: try {
2909: fgInitializingVMs = true;
2910: // 1. load VM type extensions
2911: initializeVMTypeExtensions();
2912: try {
2913: vmDefs = new VMDefinitionsContainer();
2914: // 2. add persisted VMs
2915: setPref = addPersistedVMs(vmDefs);
2916: IStatus status = vmDefs.getStatus();
2917: if (status != null) {
2918: if (status.isMultiStatus()) {
2919: MultiStatus multi = (MultiStatus) status;
2920: IStatus[] children = multi
2921: .getChildren();
2922: for (int i = 0; i < children.length; i++) {
2923: IStatus child = children[i];
2924: if (!child.isOK()) {
2925: LaunchingPlugin.log(child);
2926: }
2927: }
2928: } else if (!status.isOK()) {
2929: LaunchingPlugin.log(status);
2930: }
2931: }
2932:
2933: // 3. if there are none, detect the eclipse runtime
2934: if (vmDefs.getValidVMList().isEmpty()) {
2935: // calling out to detectEclipseRuntime() could allow clients to change
2936: // VM settings (i.e. call back into change VM settings).
2937: VMListener listener = new VMListener();
2938: addVMInstallChangedListener(listener);
2939: setPref = true;
2940: VMStandin runtime = detectEclipseRuntime();
2941: removeVMInstallChangedListener(listener);
2942: if (!listener.isChanged()) {
2943: if (runtime != null) {
2944: updateCompliance = true;
2945: vmDefs.addVM(runtime);
2946: vmDefs
2947: .setDefaultVMInstallCompositeID(getCompositeIdFromVM(runtime));
2948: }
2949: } else {
2950: // VMs were changed - reflect current settings
2951: addPersistedVMs(vmDefs);
2952: vmDefs
2953: .setDefaultVMInstallCompositeID(fgDefaultVMId);
2954: updateCompliance = fgDefaultVMId != null;
2955: }
2956: }
2957: // 4. load contributed VM installs
2958: addVMExtensions(vmDefs);
2959: // 5. verify default VM is valid
2960: String defId = vmDefs
2961: .getDefaultVMInstallCompositeID();
2962: boolean validDef = false;
2963: if (defId != null) {
2964: Iterator iterator = vmDefs.getValidVMList()
2965: .iterator();
2966: while (iterator.hasNext()) {
2967: IVMInstall vm = (IVMInstall) iterator
2968: .next();
2969: if (getCompositeIdFromVM(vm).equals(
2970: defId)) {
2971: validDef = true;
2972: break;
2973: }
2974: }
2975: }
2976: if (!validDef) {
2977: // use the first as the default
2978: setPref = true;
2979: List list = vmDefs.getValidVMList();
2980: if (!list.isEmpty()) {
2981: IVMInstall vm = (IVMInstall) list
2982: .get(0);
2983: vmDefs
2984: .setDefaultVMInstallCompositeID(getCompositeIdFromVM(vm));
2985: }
2986: }
2987: fgDefaultVMId = vmDefs
2988: .getDefaultVMInstallCompositeID();
2989: fgDefaultVMConnectorId = vmDefs
2990: .getDefaultVMInstallConnectorTypeID();
2991:
2992: // Create the underlying VMs for each valid VM
2993: List vmList = vmDefs.getValidVMList();
2994: Iterator vmListIterator = vmList.iterator();
2995: while (vmListIterator.hasNext()) {
2996: VMStandin vmStandin = (VMStandin) vmListIterator
2997: .next();
2998: vmStandin.convertToRealVM();
2999: }
3000:
3001: } catch (IOException e) {
3002: LaunchingPlugin.log(e);
3003: }
3004: } finally {
3005: fgInitializingVMs = false;
3006: }
3007: }
3008: }
3009: if (vmDefs != null) {
3010: // notify of initial VMs for backwards compatibility
3011: IVMInstallType[] installTypes = getVMInstallTypes();
3012: for (int i = 0; i < installTypes.length; i++) {
3013: IVMInstallType type = installTypes[i];
3014: IVMInstall[] installs = type.getVMInstalls();
3015: for (int j = 0; j < installs.length; j++) {
3016: fireVMAdded(installs[j]);
3017: }
3018: }
3019:
3020: // save settings if required
3021: if (setPref) {
3022: try {
3023: String xml = vmDefs.getAsXML();
3024: LaunchingPlugin.getDefault().getPluginPreferences()
3025: .setValue(PREF_VM_XML, xml);
3026: } catch (CoreException e) {
3027: LaunchingPlugin.log(e);
3028: }
3029:
3030: }
3031:
3032: // update compliance if required
3033: if (updateCompliance) {
3034: updateCompliance(getDefaultVMInstall());
3035: }
3036: }
3037: }
3038:
3039: /**
3040: * Update compiler compliance settings based on the given vm.
3041: *
3042: * @param vm
3043: */
3044: private static void updateCompliance(IVMInstall vm) {
3045: if (vm instanceof IVMInstall2) {
3046: String javaVersion = ((IVMInstall2) vm).getJavaVersion();
3047: if (javaVersion != null) {
3048: String compliance = null;
3049: if (javaVersion.startsWith(JavaCore.VERSION_1_5)) {
3050: compliance = JavaCore.VERSION_1_5;
3051: } else if (javaVersion.startsWith(JavaCore.VERSION_1_6)) {
3052: compliance = JavaCore.VERSION_1_6;
3053: } else if (javaVersion.startsWith(JavaCore.VERSION_1_7)) {
3054: compliance = JavaCore.VERSION_1_7;
3055: }
3056: if (compliance != null) {
3057: Hashtable defaultOptions = JavaCore
3058: .getDefaultOptions();
3059: Hashtable options = JavaCore.getOptions();
3060: boolean isDefault = equals(
3061: JavaCore.COMPILER_COMPLIANCE,
3062: defaultOptions, options)
3063: && equals(JavaCore.COMPILER_SOURCE,
3064: defaultOptions, options)
3065: && equals(
3066: JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM,
3067: defaultOptions, options)
3068: && equals(
3069: JavaCore.COMPILER_PB_ASSERT_IDENTIFIER,
3070: defaultOptions, options)
3071: && equals(
3072: JavaCore.COMPILER_PB_ENUM_IDENTIFIER,
3073: defaultOptions, options);
3074: // only update the compliance settings if they are default settings, otherwise the
3075: // settings have already been modified by a tool or user
3076: if (isDefault) {
3077: JavaCore.setComplianceOptions(compliance,
3078: options);
3079: JavaCore.setOptions(options);
3080: }
3081: }
3082: }
3083: }
3084: }
3085:
3086: }
|