KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > launching > JavaRuntime


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.launching;
12
13
14 import java.io.BufferedInputStream JavaDoc;
15 import java.io.ByteArrayInputStream JavaDoc;
16 import java.io.File JavaDoc;
17 import java.io.FileInputStream JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.io.StringReader JavaDoc;
21 import java.net.MalformedURLException JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31
32 import javax.xml.parsers.DocumentBuilder JavaDoc;
33 import javax.xml.parsers.ParserConfigurationException JavaDoc;
34 import javax.xml.transform.TransformerException JavaDoc;
35
36 import org.eclipse.core.resources.IProject;
37 import org.eclipse.core.resources.IResource;
38 import org.eclipse.core.resources.IWorkspaceRoot;
39 import org.eclipse.core.resources.ResourcesPlugin;
40 import org.eclipse.core.runtime.CoreException;
41 import org.eclipse.core.runtime.IConfigurationElement;
42 import org.eclipse.core.runtime.IExtensionPoint;
43 import org.eclipse.core.runtime.IPath;
44 import org.eclipse.core.runtime.IProgressMonitor;
45 import org.eclipse.core.runtime.IStatus;
46 import org.eclipse.core.runtime.MultiStatus;
47 import org.eclipse.core.runtime.Path;
48 import org.eclipse.core.runtime.Platform;
49 import org.eclipse.core.runtime.Preferences;
50 import org.eclipse.core.runtime.Status;
51 import org.eclipse.core.variables.IStringVariableManager;
52 import org.eclipse.core.variables.VariablesPlugin;
53 import org.eclipse.debug.core.ILaunchConfiguration;
54 import org.eclipse.debug.core.sourcelookup.ISourceContainer;
55 import org.eclipse.jdt.core.IClasspathAttribute;
56 import org.eclipse.jdt.core.IClasspathContainer;
57 import org.eclipse.jdt.core.IClasspathEntry;
58 import org.eclipse.jdt.core.IJavaModel;
59 import org.eclipse.jdt.core.IJavaProject;
60 import org.eclipse.jdt.core.JavaCore;
61 import org.eclipse.jdt.internal.launching.CompositeId;
62 import org.eclipse.jdt.internal.launching.DefaultEntryResolver;
63 import org.eclipse.jdt.internal.launching.DefaultProjectClasspathEntry;
64 import org.eclipse.jdt.internal.launching.JREContainerInitializer;
65 import org.eclipse.jdt.internal.launching.JavaSourceLookupUtil;
66 import org.eclipse.jdt.internal.launching.LaunchingMessages;
67 import org.eclipse.jdt.internal.launching.LaunchingPlugin;
68 import org.eclipse.jdt.internal.launching.ListenerList;
69 import org.eclipse.jdt.internal.launching.RuntimeClasspathEntry;
70 import org.eclipse.jdt.internal.launching.RuntimeClasspathEntryResolver;
71 import org.eclipse.jdt.internal.launching.RuntimeClasspathProvider;
72 import org.eclipse.jdt.internal.launching.SocketAttachConnector;
73 import org.eclipse.jdt.internal.launching.StandardVMType;
74 import org.eclipse.jdt.internal.launching.VMDefinitionsContainer;
75 import org.eclipse.jdt.internal.launching.VMListener;
76 import org.eclipse.jdt.internal.launching.VariableClasspathEntry;
77 import org.eclipse.jdt.internal.launching.environments.EnvironmentsManager;
78 import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
79 import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
80 import org.w3c.dom.Element JavaDoc;
81 import org.w3c.dom.Node JavaDoc;
82 import org.w3c.dom.NodeList JavaDoc;
83 import org.xml.sax.InputSource JavaDoc;
84 import org.xml.sax.SAXException JavaDoc;
85
86 import com.ibm.icu.text.MessageFormat;
87
88 /**
89  * The central access point for launching support. This class manages
90  * the registered VM types contributed through the
91  * <code>"org.eclipse.jdt.launching.vmType"</code> extension point.
92  * As well, this class provides VM install change notification,
93  * and computes class paths and source lookup paths for launch
94  * configurations.
95  * <p>
96  * This class provides static methods only; it is not intended to be
97  * instantiated or sub-classed by clients.
98  * </p>
99  */

100 public final class JavaRuntime {
101     
102     /**
103      * Classpath variable name used for the default JRE's library
104      * (value <code>"JRE_LIB"</code>).
105      */

106     public static final String JavaDoc JRELIB_VARIABLE= "JRE_LIB"; //$NON-NLS-1$
107

108     /**
109      * Classpath variable name used for the default JRE's library source
110      * (value <code>"JRE_SRC"</code>).
111      */

112     public static final String JavaDoc JRESRC_VARIABLE= "JRE_SRC"; //$NON-NLS-1$
113

114     /**
115      * Classpath variable name used for the default JRE's library source root
116      * (value <code>"JRE_SRCROOT"</code>).
117      */

118     public static final String JavaDoc JRESRCROOT_VARIABLE= "JRE_SRCROOT"; //$NON-NLS-1$
119

120     /**
121      * Simple identifier constant (value <code>"runtimeClasspathEntryResolvers"</code>) for the
122      * runtime classpath entry resolvers extension point.
123      *
124      * @since 2.0
125      */

126     public static final String JavaDoc EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS= "runtimeClasspathEntryResolvers"; //$NON-NLS-1$
127

128     /**
129      * Simple identifier constant (value <code>"classpathProviders"</code>) for the
130      * runtime classpath providers extension point.
131      *
132      * @since 2.0
133      */

134     public static final String JavaDoc EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS= "classpathProviders"; //$NON-NLS-1$
135

136     /**
137      * Simple identifier constant (value <code>"executionEnvironments"</code>) for the
138      * execution environments extension point.
139      *
140      * @since 3.2
141      */

142     public static final String JavaDoc EXTENSION_POINT_EXECUTION_ENVIRONMENTS= "executionEnvironments"; //$NON-NLS-1$
143

144     /**
145      * Simple identifier constant (value <code>"vmInstalls"</code>) for the
146      * VM installs extension point.
147      *
148      * @since 3.2
149      */

150     public static final String JavaDoc EXTENSION_POINT_VM_INSTALLS = "vmInstalls"; //$NON-NLS-1$
151

152     /**
153      * Classpath container used for a project's JRE
154      * (value <code>"org.eclipse.jdt.launching.JRE_CONTAINER"</code>). A
155      * container is resolved in the context of a specific Java project, to one
156      * or more system libraries contained in a JRE. The container can have zero
157      * or two path segments following the container name. When no segments
158      * follow the container name, the workspace default JRE is used to build a
159      * project. Otherwise the segments identify a specific JRE used to build a
160      * project:
161      * <ol>
162      * <li>VM Install Type Identifier - identifies the type of JRE used to build the
163      * project. For example, the standard VM.</li>
164      * <li>VM Install Name - a user defined name that identifies that a specific VM
165      * of the above kind. For example, <code>IBM 1.3.1</code>. This information is
166      * shared in a projects classpath file, so teams must agree on JRE naming
167      * conventions.</li>
168      * </ol>
169      * <p>
170      * Since 3.2, the path may also identify an execution environment as follows:
171      * <ol>
172      * <li>Execution environment extension point name
173      * (value <code>executionEnvironments</code>)</li>
174      * <li>Identifier of a contributed execution environment</li>
175      * </ol>
176      * </p>
177      * @since 2.0
178      */

179     public static final String JavaDoc JRE_CONTAINER = LaunchingPlugin.getUniqueIdentifier() + ".JRE_CONTAINER"; //$NON-NLS-1$
180

181     /**
182      * A status code indicating that a JRE could not be resolved for a project.
183      * When a JRE cannot be resolved for a project by this plug-in's container
184      * initializer, an exception is thrown with this status code. A status handler
185      * may be registered for this status code. The <code>source</code> object provided
186      * to the status handler is the Java project for which the path could not be
187      * resolved. The status handler must return an <code>IVMInstall</code> or <code>null</code>.
188      * The container resolver will re-set the project's classpath if required.
189      *
190      * @since 2.0
191      */

192     public static final int ERR_UNABLE_TO_RESOLVE_JRE = 160;
193     
194     /**
195      * Preference key for launch/connect timeout. VM Runners should honor this timeout
196      * value when attempting to launch and connect to a debuggable VM. The value is
197      * an int, indicating a number of milliseconds.
198      *
199      * @since 2.0
200      */

201     public static final String JavaDoc PREF_CONNECT_TIMEOUT = LaunchingPlugin.getUniqueIdentifier() + ".PREF_CONNECT_TIMEOUT"; //$NON-NLS-1$
202

203     /**
204      * Preference key for the String of XML that defines all installed VMs.
205      *
206      * @since 2.1
207      */

208     public static final String JavaDoc PREF_VM_XML = LaunchingPlugin.getUniqueIdentifier() + ".PREF_VM_XML"; //$NON-NLS-1$
209

210     /**
211      * Default launch/connect timeout (ms).
212      *
213      * @since 2.0
214      */

215     public static final int DEF_CONNECT_TIMEOUT = 20000;
216     
217     /**
218      * Attribute key for a process property. The class
219      * <code>org.eclipse.debug.core.model.IProcess</code> allows attaching
220      * String properties to processes.
221      * The value of this attribute is the command line a process
222      * was launched with. Implementers of <code>IVMRunner</code> should use
223      * this attribute key to attach the command lines to the processes they create.
224      *
225      * @deprecated - use <code>IProcess.ATTR_CMDLINE</code>
226      */

227     public final static String JavaDoc ATTR_CMDLINE= LaunchingPlugin.getUniqueIdentifier() + ".launcher.cmdLine"; //$NON-NLS-1$
228

229     /**
230      * Attribute key for a classpath attribute referencing a
231      * list of shared libraries that should appear on the
232      * <code>-Djava.library.path</code> system property.
233      * <p>
234      * The factory methods <code>newLibraryPathsAttribute(String[])</code>
235      * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
236      * encode and decode the attribute value.
237      * </p>
238      * <p>
239      * Each string is used to create an <code>IPath</code> using the constructor
240      * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
241      * Variable substitution is performed on the string prior to constructing
242      * a path from the string.
243      * If the resulting <code>IPath</code> is a relative path, it is interpreted
244      * as relative to the workspace location. If the path is absolute, it is
245      * interpreted as an absolute path in the local file system.
246      * </p>
247      * @since 3.1
248      * @see org.eclipse.jdt.core.IClasspathAttribute
249      */

250     public static final String JavaDoc CLASSPATH_ATTR_LIBRARY_PATH_ENTRY = LaunchingPlugin.getUniqueIdentifier() + ".CLASSPATH_ATTR_LIBRARY_PATH_ENTRY"; //$NON-NLS-1$
251

252     // lock for vm initialization
253
private static Object JavaDoc fgVMLock = new Object JavaDoc();
254     private static boolean fgInitializingVMs = false;
255     
256     private static HashSet JavaDoc fgVMTypes = null;
257     private static String JavaDoc fgDefaultVMId = null;
258     private static String JavaDoc fgDefaultVMConnectorId = null;
259     
260     /**
261      * Resolvers keyed by variable name, container id,
262      * and runtime classpath entry id.
263      */

264     private static Map JavaDoc fgVariableResolvers = null;
265     private static Map JavaDoc fgContainerResolvers = null;
266     private static Map JavaDoc fgRuntimeClasspathEntryResolvers = null;
267     
268     /**
269      * Path providers keyed by id
270      */

271     private static Map JavaDoc fgPathProviders = null;
272     
273     /**
274      * Default classpath and source path providers.
275      */

276     private static IRuntimeClasspathProvider fgDefaultClasspathProvider = new StandardClasspathProvider();
277     private static IRuntimeClasspathProvider fgDefaultSourcePathProvider = new StandardSourcePathProvider();
278     
279     /**
280      * VM change listeners
281      */

282     private static ListenerList fgVMListeners = new ListenerList(5);
283     
284     /**
285      * Cache of already resolved projects in container entries. Used to avoid
286      * cycles in project dependencies when resolving classpath container entries.
287      * Counters used to know when entering/exiting to clear cache
288      */

289     private static ThreadLocal JavaDoc fgProjects = new ThreadLocal JavaDoc(); // Lists
290
private static ThreadLocal JavaDoc fgEntryCount = new ThreadLocal JavaDoc(); // Integers
291

292     /**
293      * Set of IDs of VMs contributed via vmInstalls extension point.
294      */

295     private static Set JavaDoc fgContributedVMs = new HashSet JavaDoc();
296     
297     /**
298      * This class contains only static methods, and is not intended
299      * to be instantiated.
300      */

301     private JavaRuntime() {
302     }
303
304     /**
305      * Initializes vm type extensions.
306      */

307     private static void initializeVMTypeExtensions() {
308         IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(LaunchingPlugin.ID_PLUGIN, "vmInstallTypes"); //$NON-NLS-1$
309
if(extensionPoint != null) {
310             IConfigurationElement[] configs = extensionPoint.getConfigurationElements();
311             MultiStatus status = new MultiStatus(LaunchingPlugin.getUniqueIdentifier(), IStatus.OK, "Exceptions occurred", null); //$NON-NLS-1$
312
fgVMTypes = new HashSet JavaDoc();
313             for (int i= 0; i < configs.length; i++) {
314                 try {
315                     fgVMTypes.add(configs[i].createExecutableExtension("class")); //$NON-NLS-1$
316
}
317                 catch (CoreException e) {status.add(e.getStatus());}
318             }
319             if (!status.isOK()) {
320                 //only happens on a CoreException
321
LaunchingPlugin.log(status);
322             }
323         }
324         else {
325             LaunchingPlugin.log(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), "VM Install extension point not found", null)); //$NON-NLS-1$
326
}
327     }
328
329     /**
330      * Returns the VM assigned to build the given Java project.
331      * The project must exist. The VM assigned to a project is
332      * determined from its build path.
333      *
334      * @param project the project to retrieve the VM from
335      * @return the VM instance that is assigned to build the given Java project
336      * Returns <code>null</code> if no VM is referenced on the project's build path.
337      * @throws CoreException if unable to determine the project's VM install
338      */

339     public static IVMInstall getVMInstall(IJavaProject project) throws CoreException {
340         // check the classpath
341
IVMInstall vm = null;
342         IClasspathEntry[] classpath = project.getRawClasspath();
343         IRuntimeClasspathEntryResolver resolver = null;
344         IClasspathEntry entry = null;
345         for (int i = 0; i < classpath.length; i++) {
346             entry = classpath[i];
347             switch (entry.getEntryKind()) {
348                 case IClasspathEntry.CPE_VARIABLE:
349                     resolver = getVariableResolver(entry.getPath().segment(0));
350                     if (resolver != null) {
351                         vm = resolver.resolveVMInstall(entry);
352                     }
353                     break;
354                 case IClasspathEntry.CPE_CONTAINER:
355                     resolver = getContainerResolver(entry.getPath().segment(0));
356                     if (resolver != null) {
357                         vm = resolver.resolveVMInstall(entry);
358                     }
359                     break;
360             }
361             if (vm != null) {
362                 return vm;
363             }
364         }
365         return null;
366     }
367     
368     /**
369      * Returns the VM install type with the given unique id.
370      * @param id the VM install type unique id
371      * @return The VM install type for the given id, or <code>null</code> if no
372      * VM install type with the given id is registered.
373      */

374     public static IVMInstallType getVMInstallType(String JavaDoc id) {
375         IVMInstallType[] vmTypes= getVMInstallTypes();
376         for (int i= 0; i < vmTypes.length; i++) {
377             if (vmTypes[i].getId().equals(id)) {
378                 return vmTypes[i];
379             }
380         }
381         return null;
382     }
383     
384     /**
385      * Sets a VM as the system-wide default VM, and notifies registered VM install
386      * change listeners of the change.
387      *
388      * @param vm The vm to make the default. May be <code>null</code> to clear
389      * the default.
390      * @param monitor progress monitor or <code>null</code>
391      */

392     public static void setDefaultVMInstall(IVMInstall vm, IProgressMonitor monitor) throws CoreException {
393         setDefaultVMInstall(vm, monitor, true);
394     }
395     
396     /**
397      * Sets a VM as the system-wide default VM, and notifies registered VM install
398      * change listeners of the change.
399      *
400      * @param vm The vm to make the default. May be <code>null</code> to clear
401      * the default.
402      * @param monitor progress monitor or <code>null</code>
403      * @param savePreference If <code>true</code>, update workbench preferences to reflect
404      * the new default VM.
405      * @since 2.1
406      */

407     public static void setDefaultVMInstall(IVMInstall vm, IProgressMonitor monitor, boolean savePreference) throws CoreException {
408         IVMInstall previous = null;
409         if (fgDefaultVMId != null) {
410             previous = getVMFromCompositeId(fgDefaultVMId);
411         }
412         fgDefaultVMId= getCompositeIdFromVM(vm);
413         if (savePreference) {
414             saveVMConfiguration();
415         }
416         IVMInstall current = null;
417         if (fgDefaultVMId != null) {
418             current = getVMFromCompositeId(fgDefaultVMId);
419         }
420         if (previous != current) {
421             notifyDefaultVMChanged(previous, current);
422         }
423     }
424     
425     /**
426      * Sets a VM connector as the system-wide default VM. This setting is persisted when
427      * saveVMConfiguration is called.
428      * @param connector The connector to make the default. May be <code>null</code> to clear
429      * the default.
430      * @param monitor The progress monitor to use
431      * @since 2.0
432      * @throws CoreException Thrown if saving the new default setting fails
433      */

434     public static void setDefaultVMConnector(IVMConnector connector, IProgressMonitor monitor) throws CoreException {
435         fgDefaultVMConnectorId= connector.getIdentifier();
436         saveVMConfiguration();
437     }
438     
439     /**
440      * Return the default VM set with <code>setDefaultVM()</code>.
441      * @return Returns the default VM. May return <code>null</code> when no default
442      * VM was set or when the default VM has been disposed.
443      */

444     public static IVMInstall getDefaultVMInstall() {
445         IVMInstall install= getVMFromCompositeId(getDefaultVMId());
446         if (install != null && install.getInstallLocation().exists()) {
447             return install;
448         }
449         // if the default JRE goes missing, re-detect
450
if (install != null) {
451             install.getVMInstallType().disposeVMInstall(install.getId());
452         }
453         synchronized (fgVMLock) {
454             fgDefaultVMId = null;
455             fgVMTypes = null;
456             initializeVMs();
457         }
458         return getVMFromCompositeId(getDefaultVMId());
459     }
460     
461     /**
462      * Return the default VM connector.
463      * @return Returns the default VM connector.
464      * @since 2.0
465      */

466     public static IVMConnector getDefaultVMConnector() {
467         String JavaDoc id = getDefaultVMConnectorId();
468         IVMConnector connector = null;
469         if (id != null) {
470             connector = getVMConnector(id);
471         }
472         if (connector == null) {
473             connector = new SocketAttachConnector();
474         }
475         return connector;
476     }
477     
478     /**
479      * Returns the list of registered VM types. VM types are registered via
480      * <code>"org.eclipse.jdt.launching.vmTypes"</code> extension point.
481      * Returns an empty list if there are no registered VM types.
482      *
483      * @return the list of registered VM types
484      */

485     public static IVMInstallType[] getVMInstallTypes() {
486         initializeVMs();
487         return (IVMInstallType[]) fgVMTypes.toArray(new IVMInstallType[fgVMTypes.size()]);
488     }
489     
490     /**
491      * Returns the default VM id determined during the initialization of the vm types
492      * @return the id of the default VM
493      */

494     private static String JavaDoc getDefaultVMId() {
495         initializeVMs();
496         return fgDefaultVMId;
497     }
498     
499     /**
500      * Returns the default VM connector id determined during the initialization of the vm types
501      * @return the id of the default VM connector
502      */

503     private static String JavaDoc getDefaultVMConnectorId() {
504         initializeVMs();
505         return fgDefaultVMConnectorId;
506     }
507     
508     /**
509      * Returns a String that uniquely identifies the specified VM across all VM types.
510      *
511      * @param vm the instance of IVMInstallType to be identified
512      *
513      * @since 2.1
514      */

515     public static String JavaDoc getCompositeIdFromVM(IVMInstall vm) {
516         if (vm == null) {
517             return null;
518         }
519         IVMInstallType vmType = vm.getVMInstallType();
520         String JavaDoc typeID = vmType.getId();
521         CompositeId id = new CompositeId(new String JavaDoc[] { typeID, vm.getId() });
522         return id.toString();
523     }
524     
525     /**
526      * Return the VM corresponding to the specified composite Id. The id uniquely
527      * identifies a VM across all vm types.
528      *
529      * @param idString the composite id that specifies an instance of IVMInstall
530      *
531      * @since 2.1
532      */

533     public static IVMInstall getVMFromCompositeId(String JavaDoc idString) {
534         if (idString == null || idString.length() == 0) {
535             return null;
536         }
537         CompositeId id= CompositeId.fromString(idString);
538         if (id.getPartCount() == 2) {
539             IVMInstallType vmType= getVMInstallType(id.get(0));
540             if (vmType != null) {
541                 return vmType.findVMInstall(id.get(1));
542             }
543         }
544         return null;
545     }
546
547     /**
548      * Returns a new runtime classpath entry for the given expression that
549      * may contain string substitution variable references. The resulting expression
550      * refers to an archive (jar or directory) containing class files.
551      *
552      * @param expression an expression that resolves to the location of an archive
553      * @return runtime classpath entry
554      * @since 3.0
555      */

556     public static IRuntimeClasspathEntry newStringVariableClasspathEntry(String JavaDoc expression) {
557         return new VariableClasspathEntry(expression);
558     }
559     
560     /**
561      * Returns a new runtime classpath entry containing the default classpath
562      * for the specified Java project.
563      *
564      * @param project Java project
565      * @return runtime classpath entry
566      * @since 3.0
567      */

568     public static IRuntimeClasspathEntry newDefaultProjectClasspathEntry(IJavaProject project) {
569         return new DefaultProjectClasspathEntry(project);
570     }
571     
572     /**
573      * Returns a new runtime classpath entry for the given project.
574      *
575      * @param project Java project
576      * @return runtime classpath entry
577      * @since 2.0
578      */

579     public static IRuntimeClasspathEntry newProjectRuntimeClasspathEntry(IJavaProject project) {
580         return newRuntimeClasspathEntry(JavaCore.newProjectEntry(project.getProject().getFullPath()));
581     }
582     
583     
584     /**
585      * Returns a new runtime classpath entry for the given archive.
586      *
587      * @param resource archive resource
588      * @return runtime classpath entry
589      * @since 2.0
590      */

591     public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IResource resource) {
592         return newRuntimeClasspathEntry(JavaCore.newLibraryEntry(resource.getFullPath(), null, null));
593     }
594     
595     /**
596      * Returns a new runtime classpath entry for the given archive (possibly
597      * external).
598      *
599      * @param path absolute path to an archive
600      * @return runtime classpath entry
601      * @since 2.0
602      */

603     public static IRuntimeClasspathEntry newArchiveRuntimeClasspathEntry(IPath path) {
604         return newRuntimeClasspathEntry(JavaCore.newLibraryEntry(path, null, null));
605     }
606
607     /**
608      * Returns a new runtime classpath entry for the classpath
609      * variable with the given path.
610      *
611      * @param path variable path; first segment is the name of the variable;
612      * trailing segments are appended to the resolved variable value
613      * @return runtime classpath entry
614      * @since 2.0
615      */

616     public static IRuntimeClasspathEntry newVariableRuntimeClasspathEntry(IPath path) {
617         return newRuntimeClasspathEntry(JavaCore.newVariableEntry(path, null, null));
618     }
619
620     /**
621      * Returns a runtime classpath entry for the given container path with the given
622      * classpath property.
623      *
624      * @param path container path
625      * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,
626      * <code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>
627      * @return runtime classpath entry
628      * @exception CoreException if unable to construct a runtime classpath entry
629      * @since 2.0
630      */

631     public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(IPath path, int classpathProperty) throws CoreException {
632         return newRuntimeContainerClasspathEntry(path, classpathProperty, null);
633     }
634     
635     /**
636      * Returns a runtime classpath entry for the given container path with the given
637      * classpath property to be resolved in the context of the given Java project.
638      *
639      * @param path container path
640      * @param classpathProperty the type of entry - one of <code>USER_CLASSES</code>,
641      * <code>BOOTSTRAP_CLASSES</code>, or <code>STANDARD_CLASSES</code>
642      * @param project Java project context used for resolution, or <code>null</code>
643      * if to be resolved in the context of the launch configuration this entry
644      * is referenced in
645      * @return runtime classpath entry
646      * @exception CoreException if unable to construct a runtime classpath entry
647      * @since 3.0
648      */

649     public static IRuntimeClasspathEntry newRuntimeContainerClasspathEntry(IPath path, int classpathProperty, IJavaProject project) throws CoreException {
650         RuntimeClasspathEntry entry = new RuntimeClasspathEntry(JavaCore.newContainerEntry(path), classpathProperty);
651         entry.setJavaProject(project);
652         return entry;
653     }
654         
655     /**
656      * Returns a runtime classpath entry constructed from the given memento.
657      *
658      * @param memento a memento for a runtime classpath entry
659      * @return runtime classpath entry
660      * @exception CoreException if unable to construct a runtime classpath entry
661      * @since 2.0
662      */

663     public static IRuntimeClasspathEntry newRuntimeClasspathEntry(String JavaDoc memento) throws CoreException {
664         try {
665             Element root = null;
666             DocumentBuilder JavaDoc parser = LaunchingPlugin.getParser();
667             StringReader JavaDoc reader = new StringReader JavaDoc(memento);
668             InputSource JavaDoc source = new InputSource JavaDoc(reader);
669             root = parser.parse(source).getDocumentElement();
670                                                 
671             String JavaDoc id = root.getAttribute("id"); //$NON-NLS-1$
672
if (id == null || id.length() == 0) {
673                 // assume an old format
674
return new RuntimeClasspathEntry(root);
675             }
676             // get the extension & create a new one
677
IRuntimeClasspathEntry2 entry = LaunchingPlugin.getDefault().newRuntimeClasspathEntry(id);
678             NodeList JavaDoc list = root.getChildNodes();
679             Node JavaDoc node = null;
680             Element element = null;
681             for (int i = 0; i < list.getLength(); i++) {
682                 node = list.item(i);
683                 if (node.getNodeType() == Node.ELEMENT_NODE) {
684                     element = (Element)node;
685                     if ("memento".equals(element.getNodeName())) { //$NON-NLS-1$
686
entry.initializeFrom(element);
687                     }
688                 }
689             }
690             return entry;
691         } catch (SAXException JavaDoc e) {
692             abort(LaunchingMessages.JavaRuntime_31, e);
693         } catch (IOException JavaDoc e) {
694             abort(LaunchingMessages.JavaRuntime_32, e);
695         }
696         return null;
697     }
698     
699     /**
700      * Returns a runtime classpath entry that corresponds to the given
701      * classpath entry. The classpath entry may not be of type <code>CPE_SOURCE</code>
702      * or <code>CPE_CONTAINER</code>.
703      *
704      * @param entry a classpath entry
705      * @return runtime classpath entry
706      * @since 2.0
707      */

708     private static IRuntimeClasspathEntry newRuntimeClasspathEntry(IClasspathEntry entry) {
709         return new RuntimeClasspathEntry(entry);
710     }
711             
712     /**
713      * Computes and returns the default unresolved runtime classpath for the
714      * given project.
715      *
716      * @return runtime classpath entries
717      * @exception CoreException if unable to compute the runtime classpath
718      * @see IRuntimeClasspathEntry
719      * @since 2.0
720      */

721     public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(IJavaProject project) throws CoreException {
722         IClasspathEntry[] entries = project.getRawClasspath();
723         List JavaDoc classpathEntries = new ArrayList JavaDoc(3);
724         for (int i = 0; i < entries.length; i++) {
725             IClasspathEntry entry = entries[i];
726             switch (entry.getEntryKind()) {
727                 case IClasspathEntry.CPE_CONTAINER:
728                     IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
729                     if (container != null) {
730                         switch (container.getKind()) {
731                             case IClasspathContainer.K_APPLICATION:
732                                 // don't look at application entries
733
break;
734                             case IClasspathContainer.K_DEFAULT_SYSTEM:
735                                 classpathEntries.add(newRuntimeContainerClasspathEntry(container.getPath(), IRuntimeClasspathEntry.STANDARD_CLASSES, project));
736                                 break;
737                             case IClasspathContainer.K_SYSTEM:
738                                 classpathEntries.add(newRuntimeContainerClasspathEntry(container.getPath(), IRuntimeClasspathEntry.BOOTSTRAP_CLASSES, project));
739                                 break;
740                         }
741                     }
742                     break;
743                 case IClasspathEntry.CPE_VARIABLE:
744                     if (JRELIB_VARIABLE.equals(entry.getPath().segment(0))) {
745                         IRuntimeClasspathEntry jre = newVariableRuntimeClasspathEntry(entry.getPath());
746                         jre.setClasspathProperty(IRuntimeClasspathEntry.STANDARD_CLASSES);
747                         classpathEntries.add(jre);
748                     }
749                     break;
750                 default:
751                     break;
752             }
753         }
754         classpathEntries.add(newDefaultProjectClasspathEntry(project));
755         return (IRuntimeClasspathEntry[]) classpathEntries.toArray(new IRuntimeClasspathEntry[classpathEntries.size()]);
756     }
757     
758     /**
759      * Computes and returns the unresolved source lookup path for the given launch
760      * configuration.
761      *
762      * @param configuration launch configuration
763      * @return runtime classpath entries
764      * @exception CoreException if unable to compute the source lookup path
765      * @since 2.0
766      */

767     public static IRuntimeClasspathEntry[] computeUnresolvedSourceLookupPath(ILaunchConfiguration configuration) throws CoreException {
768         return getSourceLookupPathProvider(configuration).computeUnresolvedClasspath(configuration);
769     }
770     
771     /**
772      * Resolves the given source lookup path, returning the resolved source lookup path
773      * in the context of the given launch configuration.
774      *
775      * @param entries unresolved entries
776      * @param configuration launch configuration
777      * @return resolved entries
778      * @exception CoreException if unable to resolve the source lookup path
779      * @since 2.0
780      */

781     public static IRuntimeClasspathEntry[] resolveSourceLookupPath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {
782         return getSourceLookupPathProvider(configuration).resolveClasspath(entries, configuration);
783     }
784     
785     /**
786      * Returns the classpath provider for the given launch configuration.
787      *
788      * @param configuration launch configuration
789      * @return classpath provider
790      * @exception CoreException if unable to resolve the path provider
791      * @since 2.0
792      */

793     public static IRuntimeClasspathProvider getClasspathProvider(ILaunchConfiguration configuration) throws CoreException {
794         String JavaDoc providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH_PROVIDER, (String JavaDoc)null);
795         IRuntimeClasspathProvider provider = null;
796         if (providerId == null) {
797             provider = fgDefaultClasspathProvider;
798         } else {
799             provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);
800             if (provider == null) {
801                 abort(MessageFormat.format(LaunchingMessages.JavaRuntime_26, new String JavaDoc[]{providerId}), null);
802             }
803         }
804         return provider;
805     }
806         
807     /**
808      * Returns the source lookup path provider for the given launch configuration.
809      *
810      * @param configuration launch configuration
811      * @return source lookup path provider
812      * @exception CoreException if unable to resolve the path provider
813      * @since 2.0
814      */

815     public static IRuntimeClasspathProvider getSourceLookupPathProvider(ILaunchConfiguration configuration) throws CoreException {
816         String JavaDoc providerId = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_SOURCE_PATH_PROVIDER, (String JavaDoc)null);
817         IRuntimeClasspathProvider provider = null;
818         if (providerId == null) {
819             provider = fgDefaultSourcePathProvider;
820         } else {
821             provider = (IRuntimeClasspathProvider)getClasspathProviders().get(providerId);
822             if (provider == null) {
823                 abort(MessageFormat.format(LaunchingMessages.JavaRuntime_27, new String JavaDoc[]{providerId}), null);
824             }
825         }
826         return provider;
827     }
828         
829     /**
830      * Returns resolved entries for the given entry in the context of the given
831      * launch configuration. If the entry is of kind
832      * <code>VARIABLE</code> or <code>CONTAINER</code>, variable and container
833      * resolvers are consulted. If the entry is of kind <code>PROJECT</code>,
834      * and the associated Java project specifies non-default output locations,
835      * the corresponding output locations are returned. Otherwise, the given
836      * entry is returned.
837      * <p>
838      * If the given entry is a variable entry, and a resolver is not registered,
839      * the entry itself is returned. If the given entry is a container, and a
840      * resolver is not registered, resolved runtime classpath entries are calculated
841      * from the associated container classpath entries, in the context of the project
842      * associated with the given launch configuration.
843      * </p>
844      * @param entry runtime classpath entry
845      * @param configuration launch configuration
846      * @return resolved runtime classpath entry
847      * @exception CoreException if unable to resolve
848      * @see IRuntimeClasspathEntryResolver
849      * @since 2.0
850      */

851     public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, ILaunchConfiguration configuration) throws CoreException {
852         switch (entry.getType()) {
853             case IRuntimeClasspathEntry.PROJECT:
854                 // if the project has multiple output locations, they must be returned
855
IResource resource = entry.getResource();
856                 if (resource instanceof IProject) {
857                     IProject p = (IProject)resource;
858                     IJavaProject project = JavaCore.create(p);
859                     if (project == null || !p.isOpen() || !project.exists()) {
860                         return new IRuntimeClasspathEntry[0];
861                     }
862                     IRuntimeClasspathEntry[] entries = resolveOutputLocations(project, entry.getClasspathProperty());
863                     if (entries != null) {
864                         return entries;
865                     }
866                 } else {
867                     // could not resolve project
868
abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Classpath_references_non_existant_project___0__3, new String JavaDoc[]{entry.getPath().lastSegment()}), null);
869                 }
870                 break;
871             case IRuntimeClasspathEntry.VARIABLE:
872                 IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());
873                 if (resolver == null) {
874                     IRuntimeClasspathEntry[] resolved = resolveVariableEntry(entry, null, configuration);
875                     if (resolved != null) {
876                         return resolved;
877                     }
878                     break;
879                 }
880                 return resolver.resolveRuntimeClasspathEntry(entry, configuration);
881             case IRuntimeClasspathEntry.CONTAINER:
882                 resolver = getContainerResolver(entry.getVariableName());
883                 if (resolver == null) {
884                     return computeDefaultContainerEntries(entry, configuration);
885                 }
886                 return resolver.resolveRuntimeClasspathEntry(entry, configuration);
887             case IRuntimeClasspathEntry.ARCHIVE:
888                 // verify the archive exists
889
String JavaDoc location = entry.getLocation();
890                 if (location == null) {
891                     abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Classpath_references_non_existant_archive___0__4, new String JavaDoc[]{entry.getPath().toString()}), null);
892                 }
893                 File JavaDoc file = new File JavaDoc(location);
894                 if (!file.exists()) {
895                     abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Classpath_references_non_existant_archive___0__4, new String JavaDoc[]{entry.getPath().toString()}), null);
896                 }
897                 break;
898             case IRuntimeClasspathEntry.OTHER:
899                 resolver = getContributedResolver(((IRuntimeClasspathEntry2)entry).getTypeId());
900                 return resolver.resolveRuntimeClasspathEntry(entry, configuration);
901             default:
902                 break;
903         }
904         return new IRuntimeClasspathEntry[] {entry};
905     }
906     
907     /**
908      * Default resolution for a classpath variable - resolve to an archive. Only
909      * one of project/configuration can be non-null.
910      *
911      * @param entry
912      * @param project the project context or <code>null</code>
913      * @param configuration configuration context or <code>null</code>
914      * @return IRuntimeClasspathEntry[]
915      * @throws CoreException
916      */

917     private static IRuntimeClasspathEntry[] resolveVariableEntry(IRuntimeClasspathEntry entry, IJavaProject project, ILaunchConfiguration configuration) throws CoreException {
918         // default resolution - an archive
919
IPath archPath = JavaCore.getClasspathVariable(entry.getVariableName());
920         if (archPath != null) {
921             if (entry.getPath().segmentCount() > 1) {
922                 archPath = archPath.append(entry.getPath().removeFirstSegments(1));
923             }
924             IPath srcPath = null;
925             IPath srcVar = entry.getSourceAttachmentPath();
926             IPath srcRootPath = null;
927             IPath srcRootVar = entry.getSourceAttachmentRootPath();
928             if (archPath != null && !archPath.isEmpty()) {
929                 if (srcVar != null && !srcVar.isEmpty()) {
930                     srcPath = JavaCore.getClasspathVariable(srcVar.segment(0));
931                     if (srcPath != null) {
932                         if (srcVar.segmentCount() > 1) {
933                             srcPath = srcPath.append(srcVar.removeFirstSegments(1));
934                         }
935                         if (srcRootVar != null && !srcRootVar.isEmpty()) {
936                             srcRootPath = JavaCore.getClasspathVariable(srcRootVar.segment(0));
937                             if (srcRootPath != null) {
938                                 if (srcRootVar.segmentCount() > 1) {
939                                     srcRootPath = srcRootPath.append(srcRootVar.removeFirstSegments(1));
940                                 }
941                             }
942                         }
943                     }
944                 }
945                 // now resolve the archive (recursively)
946
IClasspathEntry archEntry = JavaCore.newLibraryEntry(archPath, srcPath, srcRootPath, entry.getClasspathEntry().isExported());
947                 IRuntimeClasspathEntry runtimeArchEntry = newRuntimeClasspathEntry(archEntry);
948                 runtimeArchEntry.setClasspathProperty(entry.getClasspathProperty());
949                 if (configuration == null) {
950                     return resolveRuntimeClasspathEntry(runtimeArchEntry, project);
951                 }
952                 return resolveRuntimeClasspathEntry(runtimeArchEntry, configuration);
953             }
954         }
955         return null;
956     }
957     
958     /**
959      * Returns runtime classpath entries corresponding to the output locations
960      * of the given project, or null if the project only uses the default
961      * output location.
962      *
963      * @param project
964      * @param classpathProperty the type of classpath entries to create
965      * @return IRuntimeClasspathEntry[] or <code>null</code>
966      * @throws CoreException
967      */

968     private static IRuntimeClasspathEntry[] resolveOutputLocations(IJavaProject project, int classpathProperty) throws CoreException {
969         List JavaDoc nonDefault = new ArrayList JavaDoc();
970         if (project.exists() && project.getProject().isOpen()) {
971             IClasspathEntry entries[] = project.getRawClasspath();
972             for (int i = 0; i < entries.length; i++) {
973                 IClasspathEntry classpathEntry = entries[i];
974                 if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
975                     IPath path = classpathEntry.getOutputLocation();
976                     if (path != null) {
977                         nonDefault.add(path);
978                     }
979                 }
980             }
981         }
982         if (nonDefault.isEmpty()) {
983             return null;
984         }
985         // add the default location if not already included
986
IPath def = project.getOutputLocation();
987         if (!nonDefault.contains(def)) {
988             nonDefault.add(def);
989         }
990         IRuntimeClasspathEntry[] locations = new IRuntimeClasspathEntry[nonDefault.size()];
991         for (int i = 0; i < locations.length; i++) {
992             IClasspathEntry newEntry = JavaCore.newLibraryEntry((IPath)nonDefault.get(i), null, null);
993             locations[i] = new RuntimeClasspathEntry(newEntry);
994             locations[i].setClasspathProperty(classpathProperty);
995         }
996         return locations;
997     }
998     
999     /**
1000     * Returns resolved entries for the given entry in the context of the given
1001     * Java project. If the entry is of kind
1002     * <code>VARIABLE</code> or <code>CONTAINER</code>, variable and container
1003     * resolvers are consulted. If the entry is of kind <code>PROJECT</code>,
1004     * and the associated Java project specifies non-default output locations,
1005     * the corresponding output locations are returned. Otherwise, the given
1006     * entry is returned.
1007     * <p>
1008     * If the given entry is a variable entry, and a resolver is not registered,
1009     * the entry itself is returned. If the given entry is a container, and a
1010     * resolver is not registered, resolved runtime classpath entries are calculated
1011     * from the associated container classpath entries, in the context of the
1012     * given project.
1013     * </p>
1014     * @param entry runtime classpath entry
1015     * @param project Java project context
1016     * @return resolved runtime classpath entry
1017     * @exception CoreException if unable to resolve
1018     * @see IRuntimeClasspathEntryResolver
1019     * @since 2.0
1020     */

1021    public static IRuntimeClasspathEntry[] resolveRuntimeClasspathEntry(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {
1022        switch (entry.getType()) {
1023            case IRuntimeClasspathEntry.PROJECT:
1024                // if the project has multiple output locations, they must be returned
1025
IResource resource = entry.getResource();
1026                if (resource instanceof IProject) {
1027                    IProject p = (IProject)resource;
1028                    IJavaProject jp = JavaCore.create(p);
1029                    if (jp != null && p.isOpen() && jp.exists()) {
1030                        IRuntimeClasspathEntry[] entries = resolveOutputLocations(jp, entry.getClasspathProperty());
1031                        if (entries != null) {
1032                            return entries;
1033                        }
1034                    } else {
1035                        return new IRuntimeClasspathEntry[0];
1036                    }
1037                }
1038                break;
1039            case IRuntimeClasspathEntry.VARIABLE:
1040                IRuntimeClasspathEntryResolver resolver = getVariableResolver(entry.getVariableName());
1041                if (resolver == null) {
1042                    IRuntimeClasspathEntry[] resolved = resolveVariableEntry(entry, project, null);
1043                    if (resolved != null) {
1044                        return resolved;
1045                    }
1046                    break;
1047                }
1048                return resolver.resolveRuntimeClasspathEntry(entry, project);
1049            case IRuntimeClasspathEntry.CONTAINER:
1050                resolver = getContainerResolver(entry.getVariableName());
1051                if (resolver == null) {
1052                    return computeDefaultContainerEntries(entry, project);
1053                }
1054                return resolver.resolveRuntimeClasspathEntry(entry, project);
1055            case IRuntimeClasspathEntry.OTHER:
1056                resolver = getContributedResolver(((IRuntimeClasspathEntry2)entry).getTypeId());
1057                return resolver.resolveRuntimeClasspathEntry(entry, project);
1058            default:
1059                break;
1060        }
1061        return new IRuntimeClasspathEntry[] {entry};
1062    }
1063        
1064    /**
1065     * Performs default resolution for a container entry.
1066     * Delegates to the Java model.
1067     */

1068    private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, ILaunchConfiguration config) throws CoreException {
1069        IJavaProject project = entry.getJavaProject();
1070        if (project == null) {
1071            project = getJavaProject(config);
1072        }
1073        return computeDefaultContainerEntries(entry, project);
1074    }
1075    
1076    /**
1077     * Performs default resolution for a container entry.
1078     * Delegates to the Java model.
1079     */

1080    private static IRuntimeClasspathEntry[] computeDefaultContainerEntries(IRuntimeClasspathEntry entry, IJavaProject project) throws CoreException {
1081        if (project == null || entry == null) {
1082            // cannot resolve without entry or project context
1083
return new IRuntimeClasspathEntry[0];
1084        }
1085        IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
1086        if (container == null) {
1087            abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Could_not_resolve_classpath_container___0__1, new String JavaDoc[]{entry.getPath().toString()}), null);
1088            // execution will not reach here - exception will be thrown
1089
return null;
1090        }
1091        IClasspathEntry[] cpes = container.getClasspathEntries();
1092        int property = -1;
1093        switch (container.getKind()) {
1094            case IClasspathContainer.K_APPLICATION:
1095                property = IRuntimeClasspathEntry.USER_CLASSES;
1096                break;
1097            case IClasspathContainer.K_DEFAULT_SYSTEM:
1098                property = IRuntimeClasspathEntry.STANDARD_CLASSES;
1099                break;
1100            case IClasspathContainer.K_SYSTEM:
1101                property = IRuntimeClasspathEntry.BOOTSTRAP_CLASSES;
1102                break;
1103        }
1104        List JavaDoc resolved = new ArrayList JavaDoc(cpes.length);
1105        List JavaDoc projects = (List JavaDoc) fgProjects.get();
1106        Integer JavaDoc count = (Integer JavaDoc) fgEntryCount.get();
1107        if (projects == null) {
1108            projects = new ArrayList JavaDoc();
1109            fgProjects.set(projects);
1110            count = new Integer JavaDoc(0);
1111        }
1112        int intCount = count.intValue();
1113        intCount++;
1114        fgEntryCount.set(new Integer JavaDoc(intCount));
1115        try {
1116            for (int i = 0; i < cpes.length; i++) {
1117                IClasspathEntry cpe = cpes[i];
1118                if (cpe.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
1119                    IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(cpe.getPath().segment(0));
1120                    IJavaProject jp = JavaCore.create(p);
1121                    if (!projects.contains(jp)) {
1122                        projects.add(jp);
1123                        IRuntimeClasspathEntry classpath = newDefaultProjectClasspathEntry(jp);
1124                        IRuntimeClasspathEntry[] entries = resolveRuntimeClasspathEntry(classpath, jp);
1125                        for (int j = 0; j < entries.length; j++) {
1126                            IRuntimeClasspathEntry e = entries[j];
1127                            if (!resolved.contains(e)) {
1128                                resolved.add(entries[j]);
1129                            }
1130                        }
1131                    }
1132                } else {
1133                    IRuntimeClasspathEntry e = newRuntimeClasspathEntry(cpe);
1134                    if (!resolved.contains(e)) {
1135                        resolved.add(e);
1136                    }
1137                }
1138            }
1139        } finally {
1140            intCount--;
1141            if (intCount == 0) {
1142                fgProjects.set(null);
1143                fgEntryCount.set(null);
1144            } else {
1145                fgEntryCount.set(new Integer JavaDoc(intCount));
1146            }
1147        }
1148        // set classpath property
1149
IRuntimeClasspathEntry[] result = new IRuntimeClasspathEntry[resolved.size()];
1150        for (int i = 0; i < result.length; i++) {
1151            result[i] = (IRuntimeClasspathEntry) resolved.get(i);
1152            result[i].setClasspathProperty(property);
1153        }
1154        return result;
1155    }
1156            
1157    /**
1158     * Computes and returns the unresolved class path for the given launch configuration.
1159     * Variable and container entries are unresolved.
1160     *
1161     * @param configuration launch configuration
1162     * @return unresolved runtime classpath entries
1163     * @exception CoreException if unable to compute the classpath
1164     * @since 2.0
1165     */

1166    public static IRuntimeClasspathEntry[] computeUnresolvedRuntimeClasspath(ILaunchConfiguration configuration) throws CoreException {
1167        return getClasspathProvider(configuration).computeUnresolvedClasspath(configuration);
1168    }
1169    
1170    /**
1171     * Resolves the given classpath, returning the resolved classpath
1172     * in the context of the given launch configuration.
1173     *
1174     * @param entries unresolved classpath
1175     * @param configuration launch configuration
1176     * @return resolved runtime classpath entries
1177     * @exception CoreException if unable to compute the classpath
1178     * @since 2.0
1179     */

1180    public static IRuntimeClasspathEntry[] resolveRuntimeClasspath(IRuntimeClasspathEntry[] entries, ILaunchConfiguration configuration) throws CoreException {
1181        return getClasspathProvider(configuration).resolveClasspath(entries, configuration);
1182    }
1183    
1184    /**
1185     * Return the <code>IJavaProject</code> referenced in the specified configuration or
1186     * <code>null</code> if none.
1187     *
1188     * @exception CoreException if the referenced Java project does not exist
1189     * @since 2.0
1190     */

1191    public static IJavaProject getJavaProject(ILaunchConfiguration configuration) throws CoreException {
1192        String JavaDoc projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String JavaDoc)null);
1193        if ((projectName == null) || (projectName.trim().length() < 1)) {
1194            return null;
1195        }
1196        IJavaProject javaProject = getJavaModel().getJavaProject(projectName);
1197        if (javaProject != null && javaProject.getProject().exists() && !javaProject.getProject().isOpen()) {
1198            abort(MessageFormat.format(LaunchingMessages.JavaRuntime_28, new String JavaDoc[] {configuration.getName(), projectName}), IJavaLaunchConfigurationConstants.ERR_PROJECT_CLOSED, null);
1199        }
1200        if ((javaProject == null) || !javaProject.exists()) {
1201            abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Launch_configuration__0__references_non_existing_project__1___1, new String JavaDoc[] {configuration.getName(), projectName}), IJavaLaunchConfigurationConstants.ERR_NOT_A_JAVA_PROJECT, null);
1202        }
1203        return javaProject;
1204    }
1205                
1206    /**
1207     * Convenience method to get the java model.
1208     */

1209    private static IJavaModel getJavaModel() {
1210        return JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());
1211    }
1212    
1213    /**
1214     * Returns the VM install for the given launch configuration.
1215     * The VM install is determined in the following prioritized way:
1216     * <ol>
1217     * <li>The VM install is explicitly specified on the launch configuration
1218     * via the <code>ATTR_JRE_CONTAINER_PATH</code> attribute (since 3.2).</li>
1219     * <li>The VM install is explicitly specified on the launch configuration
1220     * via the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_ID</code>
1221     * attributes.</li>
1222     * <li>If no explicit VM install is specified, the VM install associated with
1223     * the launch configuration's project is returned.</li>
1224     * <li>If no project is specified, or the project does not specify a custom
1225     * VM install, the workspace default VM install is returned.</li>
1226     * </ol>
1227     *
1228     * @param configuration launch configuration
1229     * @return vm install
1230     * @exception CoreException if unable to compute a vm install
1231     * @since 2.0
1232     */

1233    public static IVMInstall computeVMInstall(ILaunchConfiguration configuration) throws CoreException {
1234        String JavaDoc jreAttr = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, (String JavaDoc)null);
1235        if (jreAttr == null) {
1236            String JavaDoc type = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, (String JavaDoc)null);
1237            if (type == null) {
1238                IJavaProject proj = getJavaProject(configuration);
1239                if (proj != null) {
1240                    IVMInstall vm = getVMInstall(proj);
1241                    if (vm != null) {
1242                        return vm;
1243                    }
1244                }
1245            } else {
1246                String JavaDoc name = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, (String JavaDoc)null);
1247                return resolveVM(type, name, configuration);
1248            }
1249        } else {
1250            IPath jrePath = Path.fromPortableString(jreAttr);
1251            IClasspathEntry entry = JavaCore.newContainerEntry(jrePath);
1252            IRuntimeClasspathEntryResolver2 resolver = getVariableResolver(jrePath.segment(0));
1253            if (resolver != null) {
1254                return resolver.resolveVMInstall(entry);
1255            } else {
1256                resolver = getContainerResolver(jrePath.segment(0));
1257                if (resolver != null) {
1258                    return resolver.resolveVMInstall(entry);
1259                }
1260            }
1261        }
1262        
1263        return getDefaultVMInstall();
1264    }
1265    /**
1266     * Returns the VM of the given type with the specified name.
1267     *
1268     * @param type vm type identifier
1269     * @param name vm name
1270     * @return vm install
1271     * @exception CoreException if unable to resolve
1272     * @since 3.2
1273     */

1274    private static IVMInstall resolveVM(String JavaDoc type, String JavaDoc name, ILaunchConfiguration configuration) throws CoreException {
1275        IVMInstallType vt = getVMInstallType(type);
1276        if (vt == null) {
1277            // error type does not exist
1278
abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Specified_VM_install_type_does_not_exist___0__2, new String JavaDoc[] {type}), null);
1279        }
1280        IVMInstall vm = null;
1281        // look for a name
1282
if (name == null) {
1283            // error - type specified without a specific install (could be an old config that specified a VM ID)
1284
// log the error, but choose the default VM.
1285
LaunchingPlugin.log(new Status(IStatus.WARNING, LaunchingPlugin.getUniqueIdentifier(), IJavaLaunchConfigurationConstants.ERR_UNSPECIFIED_VM_INSTALL, MessageFormat.format("VM not fully specified in launch configuration {0} - missing VM name. Reverting to default VM.", new String JavaDoc[] {configuration.getName()}), null)); //$NON-NLS-1$
1286
return getDefaultVMInstall();
1287        }
1288        vm = vt.findVMInstallByName(name);
1289        if (vm == null) {
1290            // error - install not found
1291
abort(MessageFormat.format(LaunchingMessages.JavaRuntime_Specified_VM_install_not_found__type__0___name__1__2, new String JavaDoc[] {vt.getName(), name}), null);
1292        } else {
1293            return vm;
1294        }
1295        // won't reach here
1296
return null;
1297    }
1298    
1299    /**
1300     * Throws a core exception with an internal error status.
1301     *
1302     * @param message the status message
1303     * @param exception lower level exception associated with the
1304     * error, or <code>null</code> if none
1305     */

1306    private static void abort(String JavaDoc message, Throwable JavaDoc exception) throws CoreException {
1307        abort(message, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR, exception);
1308    }
1309        
1310        
1311    /**
1312     * Throws a core exception with an internal error status.
1313     *
1314     * @param message the status message
1315     * @param code status code
1316     * @param exception lower level exception associated with the
1317     *
1318     * error, or <code>null</code> if none
1319     */

1320    private static void abort(String JavaDoc message, int code, Throwable JavaDoc exception) throws CoreException {
1321        throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), code, message, exception));
1322    }
1323        
1324    /**
1325     * Computes the default application classpath entries for the given
1326     * project.
1327     *
1328     * @param jproject The project to compute the classpath for
1329     * @return The computed classpath. May be empty, but not null.
1330     * @throws CoreException if unable to compute the default classpath
1331     */

1332    public static String JavaDoc[] computeDefaultRuntimeClassPath(IJavaProject jproject) throws CoreException {
1333        IRuntimeClasspathEntry[] unresolved = computeUnresolvedRuntimeClasspath(jproject);
1334        // 1. remove bootpath entries
1335
// 2. resolve & translate to local file system paths
1336
List JavaDoc resolved = new ArrayList JavaDoc(unresolved.length);
1337        for (int i = 0; i < unresolved.length; i++) {
1338            IRuntimeClasspathEntry entry = unresolved[i];
1339            if (entry.getClasspathProperty() == IRuntimeClasspathEntry.USER_CLASSES) {
1340                IRuntimeClasspathEntry[] entries = resolveRuntimeClasspathEntry(entry, jproject);
1341                for (int j = 0; j < entries.length; j++) {
1342                    String JavaDoc location = entries[j].getLocation();
1343                    if (location != null) {
1344                        resolved.add(location);
1345                    }
1346                }
1347            }
1348        }
1349        return (String JavaDoc[])resolved.toArray(new String JavaDoc[resolved.size()]);
1350    }
1351        
1352    /**
1353     * Saves the VM configuration information to the preferences. This includes
1354     * the following information:
1355     * <ul>
1356     * <li>The list of all defined IVMInstall instances.</li>
1357     * <li>The default VM</li>
1358     * <ul>
1359     * This state will be read again upon first access to VM
1360     * configuration information.
1361     */

1362    public static void saveVMConfiguration() throws CoreException {
1363        if (fgVMTypes == null) {
1364            // if the VM types have not been instantiated, there can be no changes.
1365
return;
1366        }
1367        try {
1368            String JavaDoc xml = getVMsAsXML();
1369            getPreferences().setValue(PREF_VM_XML, xml);
1370            savePreferences();
1371        } catch (IOException JavaDoc e) {
1372            throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, LaunchingMessages.JavaRuntime_exceptionsOccurred, e));
1373        } catch (ParserConfigurationException JavaDoc e) {
1374            throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, LaunchingMessages.JavaRuntime_exceptionsOccurred, e));
1375        } catch (TransformerException JavaDoc e) {
1376            throw new CoreException(new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), IStatus.ERROR, LaunchingMessages.JavaRuntime_exceptionsOccurred, e));
1377        }
1378    }
1379    
1380    /**
1381     * Returns the listing of currently installed VMs as a single XML file
1382     * @return an XML representation of all of the currently installed VMs
1383     * @throws IOException
1384     * @throws ParserConfigurationException
1385     * @throws TransformerException
1386     */

1387    private static String JavaDoc getVMsAsXML() throws IOException JavaDoc, ParserConfigurationException JavaDoc, TransformerException JavaDoc {
1388        VMDefinitionsContainer container = new VMDefinitionsContainer();
1389        container.setDefaultVMInstallCompositeID(getDefaultVMId());
1390        container.setDefaultVMInstallConnectorTypeID(getDefaultVMConnectorId());
1391        IVMInstallType[] vmTypes = getVMInstallTypes();
1392        IVMInstall[] vms = null;
1393        for (int i = 0; i < vmTypes.length; ++i) {
1394            vms = vmTypes[i].getVMInstalls();
1395            for (int j = 0; j < vms.length; j++) {
1396                container.addVM(vms[j]);
1397            }
1398        }
1399        return container.getAsXML();
1400    }
1401    
1402    /**
1403     * This method loads installed JREs based an existing user preference
1404     * or old vm configurations file. The VMs found in the preference
1405     * or vm configurations file are added to the given VM definitions container.
1406     *
1407     * Returns whether the user preferences should be set - i.e. if it was
1408     * not already set when initialized.
1409     */

1410    private static boolean addPersistedVMs(VMDefinitionsContainer vmDefs) throws IOException JavaDoc {
1411        // Try retrieving the VM preferences from the preference store
1412
String JavaDoc vmXMLString = getPreferences().getString(PREF_VM_XML);
1413        
1414        // If the preference was found, load VMs from it into memory
1415
if (vmXMLString.length() > 0) {
1416            try {
1417                ByteArrayInputStream JavaDoc inputStream = new ByteArrayInputStream JavaDoc(vmXMLString.getBytes("UTF8")); //$NON-NLS-1$
1418
VMDefinitionsContainer.parseXMLIntoContainer(inputStream, vmDefs);
1419                return false;
1420            } catch (IOException JavaDoc ioe) {
1421                LaunchingPlugin.log(ioe);
1422            }
1423        } else {
1424            // Otherwise, look for the old file that previously held the VM definitions
1425
IPath stateLocation= LaunchingPlugin.getDefault().getStateLocation();
1426            IPath stateFile= stateLocation.append("vmConfiguration.xml"); //$NON-NLS-1$
1427
File JavaDoc file = new File JavaDoc(stateFile.toOSString());
1428            
1429            if (file.exists()) {
1430                // If file exists, load VM definitions from it into memory and write the definitions to
1431
// the preference store WITHOUT triggering any processing of the new value
1432
InputStream JavaDoc fileInputStream = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(file));
1433                VMDefinitionsContainer.parseXMLIntoContainer(fileInputStream, vmDefs);
1434            }
1435        }
1436        return true;
1437    }
1438    
1439    /**
1440     * Loads contributed VM installs
1441     * @since 3.2
1442     */

1443    private static void addVMExtensions(VMDefinitionsContainer vmDefs) {
1444        IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(LaunchingPlugin.ID_PLUGIN, JavaRuntime.EXTENSION_POINT_VM_INSTALLS);
1445        IConfigurationElement[] configs= extensionPoint.getConfigurationElements();
1446        for (int i = 0; i < configs.length; i++) {
1447            IConfigurationElement element = configs[i];
1448            try {
1449                if ("vmInstall".equals(element.getName())) { //$NON-NLS-1$
1450
String JavaDoc vmType = element.getAttribute("vmInstallType"); //$NON-NLS-1$
1451
if (vmType == null) {
1452                        abort(MessageFormat.format("Missing required vmInstallType attribute for vmInstall contributed by {0}", //$NON-NLS-1$
1453
new String JavaDoc[]{element.getContributor().getName()}), null);
1454                    }
1455                    String JavaDoc id = element.getAttribute("id"); //$NON-NLS-1$
1456
if (id == null) {
1457                        abort(MessageFormat.format("Missing required id attribute for vmInstall contributed by {0}", //$NON-NLS-1$
1458
new String JavaDoc[]{element.getContributor().getName()}), null);
1459                    }
1460                    IVMInstallType installType = getVMInstallType(vmType);
1461                    if (installType == null) {
1462                        abort(MessageFormat.format("vmInstall {0} contributed by {1} references undefined VM install type {2}", //$NON-NLS-1$
1463
new String JavaDoc[]{id, element.getContributor().getName(), vmType}), null);
1464                    }
1465                    IVMInstall install = installType.findVMInstall(id);
1466                    if (install == null) {
1467                        // only load/create if first time we've seen this VM install
1468
String JavaDoc name = element.getAttribute("name"); //$NON-NLS-1$
1469
if (name == null) {
1470                            abort(MessageFormat.format("vmInstall {0} contributed by {1} missing required attribute name", //$NON-NLS-1$
1471
new String JavaDoc[]{id, element.getContributor().getName()}), null);
1472                        }
1473                        String JavaDoc home = element.getAttribute("home"); //$NON-NLS-1$
1474
if (home == null) {
1475                            abort(MessageFormat.format("vmInstall {0} contributed by {1} missing required attribute home", //$NON-NLS-1$
1476
new String JavaDoc[]{id, element.getContributor().getName()}), null);
1477                        }
1478                        String JavaDoc javadoc = element.getAttribute("javadocURL"); //$NON-NLS-1$
1479
String JavaDoc vmArgs = element.getAttribute("vmArgs"); //$NON-NLS-1$
1480
VMStandin standin = new VMStandin(installType, id);
1481                        standin.setName(name);
1482                        home = substitute(home);
1483                        File JavaDoc homeDir = new File JavaDoc(home);
1484                        if (homeDir.exists()) {
1485                            try {
1486                                // adjust for relative path names
1487
home = homeDir.getCanonicalPath();
1488                                homeDir = new File JavaDoc(home);
1489                            } catch (IOException JavaDoc e) {
1490                            }
1491                        }
1492                        IStatus status = installType.validateInstallLocation(homeDir);
1493                        if (!status.isOK()) {
1494                            abort(MessageFormat.format("Illegal install location {0} for vmInstall {1} contributed by {2}: {3}", //$NON-NLS-1$
1495
new String JavaDoc[]{home, id, element.getContributor().getName(), status.getMessage()}), null);
1496                        }
1497                        standin.setInstallLocation(homeDir);
1498                        if (javadoc != null) {
1499                            try {
1500                                standin.setJavadocLocation(new URL JavaDoc(javadoc));
1501                            } catch (MalformedURLException JavaDoc e) {
1502                                abort(MessageFormat.format("Illegal javadocURL attribute for vmInstall {0} contributed by {1}", //$NON-NLS-1$
1503
new String JavaDoc[]{id, element.getContributor().getName()}), e);
1504                            }
1505                        }
1506                        if (vmArgs != null) {
1507                            standin.setVMArgs(vmArgs);
1508                        }
1509                        IConfigurationElement[] libraries = element.getChildren("library"); //$NON-NLS-1$
1510
LibraryLocation[] locations = null;
1511                        if (libraries.length > 0) {
1512                            locations = new LibraryLocation[libraries.length];
1513                            for (int j = 0; j < libraries.length; j++) {
1514                                IConfigurationElement library = libraries[j];
1515                                String JavaDoc libPathStr = library.getAttribute("path"); //$NON-NLS-1$
1516
if (libPathStr == null) {
1517                                    abort(MessageFormat.format("library for vmInstall {0} contributed by {1} missing required attribute libPath", //$NON-NLS-1$
1518
new String JavaDoc[]{id, element.getContributor().getName()}), null);
1519                                }
1520                                String JavaDoc sourcePathStr = library.getAttribute("sourcePath"); //$NON-NLS-1$
1521
String JavaDoc packageRootStr = library.getAttribute("packageRootPath"); //$NON-NLS-1$
1522
String JavaDoc javadocOverride = library.getAttribute("javadocURL"); //$NON-NLS-1$
1523
URL JavaDoc url = null;
1524                                if (javadocOverride != null) {
1525                                    try {
1526                                        url = new URL JavaDoc(javadocOverride);
1527                                    } catch (MalformedURLException JavaDoc e) {
1528                                        abort(MessageFormat.format("Illegal javadocURL attribute specified for library {0} for vmInstall {1} contributed by {2}" //$NON-NLS-1$
1529
,new String JavaDoc[]{libPathStr, id, element.getContributor().getName()}), e);
1530                                    }
1531                                }
1532                                IPath homePath = new Path(home);
1533                                IPath libPath = homePath.append(substitute(libPathStr));
1534                                IPath sourcePath = Path.EMPTY;
1535                                if (sourcePathStr != null) {
1536                                    sourcePath = homePath.append(substitute(sourcePathStr));
1537                                }
1538                                IPath packageRootPath = Path.EMPTY;
1539                                if (packageRootStr != null) {
1540                                    packageRootPath = new Path(substitute(packageRootStr));
1541                                }
1542                                locations[j] = new LibraryLocation(libPath, sourcePath, packageRootPath, url);
1543                            }
1544                        }
1545                        standin.setLibraryLocations(locations);
1546                        // in case the contributed JRE attributes changed, remove it first, then add
1547
vmDefs.removeVM(standin);
1548                        vmDefs.addVM(standin);
1549                    }
1550                    fgContributedVMs.add(id);
1551                } else {
1552                    abort(MessageFormat.format("Illegal element {0} in vmInstalls extension contributed by {1}", //$NON-NLS-1$
1553
new String JavaDoc[]{element.getName(), element.getContributor().getName()}), null);
1554                }
1555            } catch (CoreException e) {
1556                LaunchingPlugin.log(e);
1557            }
1558        }
1559    }
1560    
1561    /**
1562     * Performs string substitution on the given expression.
1563     *
1564     * @param expression
1565     * @return expression after string substitution
1566     * @throws CoreException
1567     * @since 3.2
1568     */

1569    private static String JavaDoc substitute(String JavaDoc expression) throws CoreException {
1570        return VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(expression);
1571    }
1572    
1573    /**
1574     * Returns whether the VM install with the specified id was contributed via
1575     * the vmInstalls extension point.
1576     *
1577     * @param id vm id
1578     * @return whether the vm install was contributed via extension point
1579     * @since 3.2
1580     */

1581    public static boolean isContributedVMInstall(String JavaDoc id) {
1582        getVMInstallTypes(); // ensure VMs are initialized
1583
return fgContributedVMs.contains(id);
1584    }
1585    
1586    /**
1587     * Evaluates library locations for a IVMInstall. If no library locations are set on the install, a default
1588     * location is evaluated and checked if it exists.
1589     * @return library locations with paths that exist or are empty
1590     * @since 2.0
1591     */

1592    public static LibraryLocation[] getLibraryLocations(IVMInstall vm) {
1593        IPath[] libraryPaths;
1594        IPath[] sourcePaths;
1595        IPath[] sourceRootPaths;
1596        URL JavaDoc[] javadocLocations;
1597        LibraryLocation[] locations= vm.getLibraryLocations();
1598        if (locations == null) {
1599            URL JavaDoc defJavaDocLocation = vm.getJavadocLocation();
1600            LibraryLocation[] dflts= vm.getVMInstallType().getDefaultLibraryLocations(vm.getInstallLocation());
1601            libraryPaths = new IPath[dflts.length];
1602            sourcePaths = new IPath[dflts.length];
1603            sourceRootPaths = new IPath[dflts.length];
1604            javadocLocations= new URL JavaDoc[dflts.length];
1605            for (int i = 0; i < dflts.length; i++) {
1606                libraryPaths[i]= dflts[i].getSystemLibraryPath();
1607                if (defJavaDocLocation == null) {
1608                    javadocLocations[i]= dflts[i].getJavadocLocation();
1609                } else {
1610                    javadocLocations[i]= defJavaDocLocation;
1611                }
1612                if (!libraryPaths[i].toFile().isFile()) {
1613                    libraryPaths[i]= Path.EMPTY;
1614                }
1615                
1616                sourcePaths[i]= dflts[i].getSystemLibrarySourcePath();
1617                if (sourcePaths[i].toFile().isFile()) {
1618                    sourceRootPaths[i]= dflts[i].getPackageRootPath();
1619                } else {
1620                    sourcePaths[i]= Path.EMPTY;
1621                    sourceRootPaths[i]= Path.EMPTY;
1622                }
1623            }
1624        } else {
1625            libraryPaths = new IPath[locations.length];
1626            sourcePaths = new IPath[locations.length];
1627            sourceRootPaths = new IPath[locations.length];
1628            javadocLocations= new URL JavaDoc[locations.length];
1629            for (int i = 0; i < locations.length; i++) {
1630                libraryPaths[i]= locations[i].getSystemLibraryPath();
1631                sourcePaths[i]= locations[i].getSystemLibrarySourcePath();
1632                sourceRootPaths[i]= locations[i].getPackageRootPath();
1633                javadocLocations[i]= locations[i].getJavadocLocation();
1634            }
1635        }
1636        locations = new LibraryLocation[sourcePaths.length];
1637        for (int i = 0; i < sourcePaths.length; i++) {
1638            locations[i] = new LibraryLocation(libraryPaths[i], sourcePaths[i], sourceRootPaths[i], javadocLocations[i]);
1639        }
1640        return locations;
1641    }
1642    
1643    /**
1644     * Detect the VM that Eclipse is running on.
1645     *
1646     * @return a VM standin representing the VM that Eclipse is running on, or
1647     * <code>null</code> if unable to detect the runtime VM
1648     */

1649    private static VMStandin detectEclipseRuntime() {
1650        VMStandin detectedVMStandin = null;
1651        // Try to detect a VM for each declared VM type
1652
IVMInstallType[] vmTypes= getVMInstallTypes();
1653        for (int i = 0; i < vmTypes.length; i++) {
1654            
1655            File JavaDoc detectedLocation= vmTypes[i].detectInstallLocation();
1656            if (detectedLocation != null && detectedVMStandin == null) {
1657                
1658                // Make sure the VM id is unique
1659
long unique = System.currentTimeMillis();
1660                IVMInstallType vmType = vmTypes[i];
1661                while (vmType.findVMInstall(String.valueOf(unique)) != null) {
1662                    unique++;
1663                }
1664
1665                // Create a standin for the detected VM and add it to the result collector
1666
String JavaDoc vmID = String.valueOf(unique);
1667                detectedVMStandin = new VMStandin(vmType, vmID);
1668                detectedVMStandin.setInstallLocation(detectedLocation);
1669                detectedVMStandin.setName(generateDetectedVMName(detectedVMStandin));
1670                if (vmType instanceof AbstractVMInstallType) {
1671                    AbstractVMInstallType abs = (AbstractVMInstallType)vmType;
1672                    URL JavaDoc url = abs.getDefaultJavadocLocation(detectedLocation);
1673                    detectedVMStandin.setJavadocLocation(url);
1674                }
1675            }
1676        }
1677        return detectedVMStandin;
1678    }
1679    
1680    /**
1681     * Returns whether the specified option is the same in both option maps.
1682     *
1683     * @param optionName name of option to test
1684     * @param defaultOptions map of default options
1685     * @param options map of other options
1686     * @return whether the options are the same in both maps
1687     */

1688    private static boolean equals(String JavaDoc optionName, Map JavaDoc defaultOptions, Map JavaDoc options) {
1689        if (defaultOptions.containsKey(optionName)) {
1690            return options.containsKey(optionName) &&
1691                equals(defaultOptions.get(optionName), options.get(optionName));
1692        } else {
1693            return !options.containsKey(optionName);
1694        }
1695    }
1696    
1697    /**
1698     * Returns whether the objects are equal or both <code>null</code>
1699     *
1700     * @param o1 an object
1701     * @param o2 an object
1702     * @return whether the objects are equal or both <code>null</code>
1703     */

1704    private static boolean equals(Object JavaDoc o1, Object JavaDoc o2) {
1705        if (o1 == null) {
1706            return o2 == null;
1707        } else {
1708            return o1.equals(o2);
1709        }
1710    }
1711    
1712    /**
1713     * Make the name of a detected VM stand out.
1714     */

1715    private static String JavaDoc generateDetectedVMName(IVMInstall vm) {
1716        String JavaDoc name = vm.getInstallLocation().getName();
1717        name = name.trim();
1718        if (name.length() == 0) {
1719            name = LaunchingMessages.JavaRuntime_25;
1720        }
1721        return name;
1722    }
1723    
1724    /**
1725     * Creates and returns a classpath entry describing
1726     * the JRE_LIB classpath variable.
1727     *
1728     * @return a new IClasspathEntry that describes the JRE_LIB classpath variable
1729     */

1730    public static IClasspathEntry getJREVariableEntry() {
1731        return JavaCore.newVariableEntry(
1732            new Path(JRELIB_VARIABLE),
1733            new Path(JRESRC_VARIABLE),
1734            new Path(JRESRCROOT_VARIABLE)
1735        );
1736    }
1737    
1738    /**
1739     * Creates and returns a classpath entry describing
1740     * the default JRE container entry.
1741     *
1742     * @return a new IClasspathEntry that describes the default JRE container entry
1743     * @since 2.0
1744     */

1745    public static IClasspathEntry getDefaultJREContainerEntry() {
1746        return JavaCore.newContainerEntry(newDefaultJREContainerPath());
1747    }
1748    
1749    /**
1750     * Returns a path for the JRE classpath container identifying the
1751     * default VM install.
1752     *
1753     * @return classpath container path
1754     * @since 3.2
1755     */

1756    public static IPath newDefaultJREContainerPath() {
1757        return new Path(JRE_CONTAINER);
1758    }
1759    
1760    /**
1761     * Returns a path for the JRE classpath container identifying the
1762     * specified VM install by type and name.
1763     *
1764     * @param vm vm install
1765     * @return classpath container path
1766     * @since 3.2
1767     */

1768    public static IPath newJREContainerPath(IVMInstall vm) {
1769        return newJREContainerPath(vm.getVMInstallType().getId(), vm.getName());
1770    }
1771    
1772    /**
1773     * Returns a path for the JRE classpath container identifying the
1774     * specified VM install by type and name.
1775     *
1776     * @param typeId vm install type identifier
1777     * @param name vm install name
1778     * @return classpath container path
1779     * @since 3.2
1780     */

1781    public static IPath newJREContainerPath(String JavaDoc typeId, String JavaDoc name) {
1782        IPath path = newDefaultJREContainerPath();
1783        path = path.append(typeId);
1784        path = path.append(name);
1785        return path;
1786    }
1787    
1788    /**
1789     * Returns a path for the JRE classpath container identifying the
1790     * specified execution environment.
1791     *
1792     * @param environment execution environment
1793     * @return classpath container path
1794     * @since 3.2
1795     */

1796    public static IPath newJREContainerPath(IExecutionEnvironment environment) {
1797        IPath path = newDefaultJREContainerPath();
1798        path = path.append(StandardVMType.ID_STANDARD_VM_TYPE);
1799        path = path.append(JREContainerInitializer.encodeEnvironmentId(environment.getId()));
1800        return path;
1801    }
1802    
1803    /**
1804     * Returns the JRE referenced by the specified JRE classpath container
1805     * path or <code>null</code> if none.
1806     *
1807     * @param jreContainerPath
1808     * @return JRE referenced by the specified JRE classpath container
1809     * path or <code>null</code>
1810     * @since 3.2
1811     */

1812    public static IVMInstall getVMInstall(IPath jreContainerPath) {
1813        return JREContainerInitializer.resolveVM(jreContainerPath);
1814    }
1815    
1816    /**
1817     * Returns the identifier of the VM install type referenced by the
1818     * given JRE classpath container path, or <code>null</code> if none.
1819     *
1820     * @param jreContainerPath
1821     * @return vm install type identifier or <code>null</code>
1822     * @since 3.2
1823     */

1824    public static String JavaDoc getVMInstallTypeId(IPath jreContainerPath) {
1825        if (JREContainerInitializer.isExecutionEnvironment(jreContainerPath)) {
1826            return null;
1827        }
1828        return JREContainerInitializer.getVMTypeId(jreContainerPath);
1829    }
1830
1831    /**
1832     * Returns the name of the VM install referenced by the
1833     * given JRE classpath container path, or <code>null</code> if none.
1834     *
1835     * @param jreContainerPath
1836     * @return vm name or <code>null</code>
1837     * @since 3.2
1838     */

1839    public static String JavaDoc getVMInstallName(IPath jreContainerPath) {
1840        if (JREContainerInitializer.isExecutionEnvironment(jreContainerPath)) {
1841            return null;
1842        }
1843        return JREContainerInitializer.getVMName(jreContainerPath);
1844    }
1845    
1846    /**
1847     * Returns the execution environment identifier in the following JRE
1848     * classpath container path, or <code>null</code> if none.
1849     *
1850     * @param jreContainerPath classpath container path
1851     * @return execution environment identifier or <code>null</code>
1852     * @since 3.2
1853     */

1854    public static String JavaDoc getExecutionEnvironmentId(IPath jreContainerPath) {
1855        return JREContainerInitializer.getExecutionEnvironmentId(jreContainerPath);
1856    }
1857    
1858    /**
1859     * Returns a runtime classpath entry identifying the JRE to use when launching the specified
1860     * configuration or <code>null</code> if none is specified. The entry returned represents a
1861     * either a classpath variable or classpath container that resolves to a JRE.
1862     * <p>
1863     * The entry is resolved as follows:
1864     * <ol>
1865     * <li>If the <code>ATTR_JRE_CONTAINER_PATH</code> is present, it is used to create
1866     * a classpath container referring to a JRE.</li>
1867     * <li>Next, if the <code>ATTR_VM_INSTALL_TYPE</code> and <code>ATTR_VM_INSTALL_NAME</code>
1868     * attributes are present, they are used to create a classpath container.</li>
1869     * <li>When none of the above attributes are specified, a default entry is
1870     * created which refers to the JRE referenced by the build path of the configuration's
1871     * associated Java project. This could be a classpath variable or classpath container.</li>
1872     * <li>When there is no Java project associated with a configuration, the workspace
1873     * default JRE is used to create a container path.</li>
1874     * </ol>
1875     * </p>
1876     * @param configuration
1877     * @return classpath container path identifying a JRE or <code>null</code>
1878     * @exception org.eclipse.core.runtime.CoreException if an exception occurs retrieving
1879     * attributes from the specified launch configuration
1880     * @since 3.2
1881     */

1882    public static IRuntimeClasspathEntry computeJREEntry(ILaunchConfiguration configuration) throws CoreException {
1883        String JavaDoc jreAttr = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, (String JavaDoc)null);
1884        IPath containerPath = null;
1885        if (jreAttr == null) {
1886            String JavaDoc type = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, (String JavaDoc)null);
1887            if (type == null) {
1888                // default JRE for the launch configuration
1889
IJavaProject proj = getJavaProject(configuration);
1890                if (proj == null) {
1891                    containerPath = newDefaultJREContainerPath();
1892                } else {
1893                    return computeJREEntry(proj);
1894                }
1895            } else {
1896                String JavaDoc name = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, (String JavaDoc)null);
1897                if (name != null) {
1898                    containerPath = newDefaultJREContainerPath().append(type).append(name);
1899                }
1900            }
1901        } else {
1902            containerPath = Path.fromPortableString(jreAttr);
1903        }
1904        if (containerPath != null) {
1905            return newRuntimeContainerClasspathEntry(containerPath, IRuntimeClasspathEntry.STANDARD_CLASSES);
1906        }
1907        return null;
1908    }
1909    
1910    /**
1911     * Returns a runtime classpath entry identifying the JRE referenced by the specified
1912     * project, or <code>null</code> if none. The entry returned represents a either a
1913     * classpath variable or classpath container that resolves to a JRE.
1914     *
1915     * @param project Java project
1916     * @return JRE runtime classpath entry or <code>null</code>
1917     * @exception org.eclipse.core.runtime.CoreException if an exception occurs
1918     * accessing the project's classpath
1919     * @since 3.2
1920     */

1921    public static IRuntimeClasspathEntry computeJREEntry(IJavaProject project) throws CoreException {
1922        IClasspathEntry[] rawClasspath = project.getRawClasspath();
1923        IRuntimeClasspathEntryResolver2 resolver = null;
1924        for (int i = 0; i < rawClasspath.length; i++) {
1925            IClasspathEntry entry = rawClasspath[i];
1926            switch (entry.getEntryKind()) {
1927                case IClasspathEntry.CPE_VARIABLE:
1928                    resolver = getVariableResolver(entry.getPath().segment(0));
1929                    if (resolver != null) {
1930                        if (resolver.isVMInstallReference(entry)) {
1931                            return newRuntimeClasspathEntry(entry);
1932                        }
1933                    }
1934                    break;
1935                case IClasspathEntry.CPE_CONTAINER:
1936                    resolver = getContainerResolver(entry.getPath().segment(0));
1937                    if (resolver != null) {
1938                        if (resolver.isVMInstallReference(entry)) {
1939                            IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
1940                            if (container != null) {
1941                                switch (container.getKind()) {
1942                                    case IClasspathContainer.K_APPLICATION:
1943                                        break;
1944                                    case IClasspathContainer.K_DEFAULT_SYSTEM:
1945                                        return newRuntimeContainerClasspathEntry(entry.getPath(), IRuntimeClasspathEntry.STANDARD_CLASSES);
1946                                    case IClasspathContainer.K_SYSTEM:
1947                                        return newRuntimeContainerClasspathEntry(entry.getPath(), IRuntimeClasspathEntry.BOOTSTRAP_CLASSES);
1948                                }
1949                            }
1950                        }
1951                    }
1952                    break;
1953            }
1954            
1955        }
1956        return null;
1957    }
1958    
1959    /**
1960     * Returns whether the given runtime classpath entry refers to a vm install.
1961     *
1962     * @param entry
1963     * @return whether the given runtime classpath entry refers to a vm install
1964     * @since 3.2
1965     */

1966    public static boolean isVMInstallReference(IRuntimeClasspathEntry entry) {
1967        IClasspathEntry classpathEntry = entry.getClasspathEntry();
1968        if (classpathEntry != null) {
1969            switch (classpathEntry.getEntryKind()) {
1970                case IClasspathEntry.CPE_VARIABLE:
1971                    IRuntimeClasspathEntryResolver2 resolver = getVariableResolver(classpathEntry.getPath().segment(0));
1972                    if (resolver != null) {
1973                        return resolver.isVMInstallReference(classpathEntry);
1974                    }
1975                    break;
1976                case IClasspathEntry.CPE_CONTAINER:
1977                    resolver = getContainerResolver(classpathEntry.getPath().segment(0));
1978                    if (resolver != null) {
1979                        return resolver.isVMInstallReference(classpathEntry);
1980                    }
1981                    break;
1982                }
1983        }
1984        return false;
1985    }
1986    
1987    /**
1988     * Returns the VM connector defined with the specified identifier,
1989     * or <code>null</code> if none.
1990     *
1991     * @param id VM connector identifier
1992     * @return VM connector or <code>null</code> if none
1993     * @since 2.0
1994     */

1995    public static IVMConnector getVMConnector(String JavaDoc id) {
1996        return LaunchingPlugin.getDefault().getVMConnector(id);
1997    }
1998    
1999    /**
2000     * Returns all VM connector extensions.
2001     *
2002     * @return VM connectors
2003     * @since 2.0
2004     */

2005    public static IVMConnector[] getVMConnectors() {
2006        return LaunchingPlugin.getDefault().getVMConnectors();
2007    }
2008    
2009    /**
2010     * Returns the preference store for the launching plug-in.
2011     *
2012     * @return the preference store for the launching plug-in
2013     * @since 2.0
2014     */

2015    public static Preferences getPreferences() {
2016        return LaunchingPlugin.getDefault().getPluginPreferences();
2017    }
2018    
2019    /**
2020     * Saves the preferences for the launching plug-in.
2021     *
2022     * @since 2.0
2023     */

2024    public static void savePreferences() {
2025        LaunchingPlugin.getDefault().savePluginPreferences();
2026    }
2027    
2028    /**
2029     * Registers the given resolver for the specified variable.
2030     *
2031     * @param resolver runtime classpath entry resolver
2032     * @param variableName variable name to register for
2033     * @since 2.0
2034     */

2035    public static void addVariableResolver(IRuntimeClasspathEntryResolver resolver, String JavaDoc variableName) {
2036        Map JavaDoc map = getVariableResolvers();
2037        map.put(variableName, resolver);
2038    }
2039    
2040    /**
2041     * Registers the given resolver for the specified container.
2042     *
2043     * @param resolver runtime classpath entry resolver
2044     * @param containerIdentifier identifier of the classpath container to register for
2045     * @since 2.0
2046     */

2047    public static void addContainerResolver(IRuntimeClasspathEntryResolver resolver, String JavaDoc containerIdentifier) {
2048        Map JavaDoc map = getContainerResolvers();
2049        map.put(containerIdentifier, resolver);
2050    }
2051    
2052    /**
2053     * Returns all registered variable resolvers.
2054     */

2055    private static Map JavaDoc getVariableResolvers() {
2056        if (fgVariableResolvers == null) {
2057            initializeResolvers();
2058        }
2059        return fgVariableResolvers;
2060    }
2061    
2062    /**
2063     * Returns all registered container resolvers.
2064     */

2065    private static Map JavaDoc getContainerResolvers() {
2066        if (fgContainerResolvers == null) {
2067            initializeResolvers();
2068        }
2069        return fgContainerResolvers;
2070    }
2071    
2072    /**
2073     * Returns all registered runtime classpath entry resolvers.
2074     */

2075    private static Map JavaDoc getEntryResolvers() {
2076        if (fgRuntimeClasspathEntryResolvers == null) {
2077            initializeResolvers();
2078        }
2079        return fgRuntimeClasspathEntryResolvers;
2080    }
2081
2082    /**
2083     * Initializes the listing of runtime classpath entry resolvers
2084     */

2085    private static void initializeResolvers() {
2086        IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(LaunchingPlugin.ID_PLUGIN, EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRY_RESOLVERS);
2087        IConfigurationElement[] extensions = point.getConfigurationElements();
2088        fgVariableResolvers = new HashMap JavaDoc(extensions.length);
2089        fgContainerResolvers = new HashMap JavaDoc(extensions.length);
2090        fgRuntimeClasspathEntryResolvers = new HashMap JavaDoc(extensions.length);
2091        for (int i = 0; i < extensions.length; i++) {
2092            RuntimeClasspathEntryResolver res = new RuntimeClasspathEntryResolver(extensions[i]);
2093            String JavaDoc variable = res.getVariableName();
2094            String JavaDoc container = res.getContainerId();
2095            String JavaDoc entryId = res.getRuntimeClasspathEntryId();
2096            if (variable != null) {
2097                fgVariableResolvers.put(variable, res);
2098            }
2099            if (container != null) {
2100                fgContainerResolvers.put(container, res);
2101            }
2102            if (entryId != null) {
2103                fgRuntimeClasspathEntryResolvers.put(entryId, res);
2104            }
2105        }
2106    }
2107
2108    /**
2109     * Returns all registered classpath providers.
2110     */

2111    private static Map JavaDoc getClasspathProviders() {
2112        if (fgPathProviders == null) {
2113            initializeProviders();
2114        }
2115        return fgPathProviders;
2116    }
2117        
2118    /**
2119     * Initializes the listing of classpath providers
2120     */

2121    private static void initializeProviders() {
2122        IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(LaunchingPlugin.ID_PLUGIN, EXTENSION_POINT_RUNTIME_CLASSPATH_PROVIDERS);
2123        IConfigurationElement[] extensions = point.getConfigurationElements();
2124        fgPathProviders = new HashMap JavaDoc(extensions.length);
2125        for (int i = 0; i < extensions.length; i++) {
2126            RuntimeClasspathProvider res = new RuntimeClasspathProvider(extensions[i]);
2127            fgPathProviders.put(res.getIdentifier(), res);
2128        }
2129    }
2130        
2131    /**
2132     * Returns the resolver registered for the given variable, or
2133     * <code>null</code> if none.
2134     *
2135     * @param variableName the variable to determine the resolver for
2136     * @return the resolver registered for the given variable, or
2137     * <code>null</code> if none
2138     */

2139    private static IRuntimeClasspathEntryResolver2 getVariableResolver(String JavaDoc variableName) {
2140        return (IRuntimeClasspathEntryResolver2)getVariableResolvers().get(variableName);
2141    }
2142    
2143    /**
2144     * Returns the resolver registered for the given container id, or
2145     * <code>null</code> if none.
2146     *
2147     * @param containerId the container to determine the resolver for
2148     * @return the resolver registered for the given container id, or
2149     * <code>null</code> if none
2150     */

2151    private static IRuntimeClasspathEntryResolver2 getContainerResolver(String JavaDoc containerId) {
2152        return (IRuntimeClasspathEntryResolver2)getContainerResolvers().get(containerId);
2153    }
2154    
2155    /**
2156     * Returns the resolver registered for the given contributed classpath
2157     * entry type.
2158     *
2159     * @param typeId the id of the contributed classpath entry
2160     * @return the resolver registered for the given classpath entry
2161     */

2162    private static IRuntimeClasspathEntryResolver getContributedResolver(String JavaDoc typeId) {
2163        IRuntimeClasspathEntryResolver resolver = (IRuntimeClasspathEntryResolver)getEntryResolvers().get(typeId);
2164        if (resolver == null) {
2165            return new DefaultEntryResolver();
2166        }
2167        return resolver;
2168    }
2169    
2170    /**
2171     * Adds the given listener to the list of registered VM install changed
2172     * listeners. Has no effect if an identical listener is already registered.
2173     *
2174     * @param listener the listener to add
2175     * @since 2.0
2176     */

2177    public static void addVMInstallChangedListener(IVMInstallChangedListener listener) {
2178        fgVMListeners.add(listener);
2179    }
2180    
2181    /**
2182     * Removes the given listener from the list of registered VM install changed
2183     * listeners. Has no effect if an identical listener is not already registered.
2184     *
2185     * @param listener the listener to remove
2186     * @since 2.0
2187     */

2188    public static void removeVMInstallChangedListener(IVMInstallChangedListener listener) {
2189        fgVMListeners.remove(listener);
2190    }
2191    
2192    /**
2193     * Notifies registered listeners that the default VM has changed
2194     * @param previous the previous VM
2195     * @param current the new current default VM
2196     */

2197    private static void notifyDefaultVMChanged(IVMInstall previous, IVMInstall current) {
2198        Object JavaDoc[] listeners = fgVMListeners.getListeners();
2199        for (int i = 0; i < listeners.length; i++) {
2200            IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
2201            listener.defaultVMInstallChanged(previous, current);
2202        }
2203    }
2204    
2205    /**
2206     * Notifies all VM install changed listeners of the given property change.
2207     *
2208     * @param event event describing the change.
2209     * @since 2.0
2210     */

2211    public static void fireVMChanged(PropertyChangeEvent event) {
2212        Object JavaDoc[] listeners = fgVMListeners.getListeners();
2213        for (int i = 0; i < listeners.length; i++) {
2214            IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
2215            listener.vmChanged(event);
2216        }
2217    }
2218    
2219    /**
2220     * Notifies all VM install changed listeners of the VM addition
2221     *
2222     * @param vm the VM that has been added
2223     * @since 2.0
2224     */

2225    public static void fireVMAdded(IVMInstall vm) {
2226        if (!fgInitializingVMs) {
2227            Object JavaDoc[] listeners = fgVMListeners.getListeners();
2228            for (int i = 0; i < listeners.length; i++) {
2229                IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
2230                listener.vmAdded(vm);
2231            }
2232        }
2233    }
2234    
2235    /**
2236     * Notifies all VM install changed listeners of the VM removal
2237     *
2238     * @param vm the VM that has been removed
2239     * @since 2.0
2240     */

2241    public static void fireVMRemoved(IVMInstall vm) {
2242        Object JavaDoc[] listeners = fgVMListeners.getListeners();
2243        for (int i = 0; i < listeners.length; i++) {
2244            IVMInstallChangedListener listener = (IVMInstallChangedListener)listeners[i];
2245            listener.vmRemoved(vm);
2246        }
2247    }
2248    
2249    /**
2250     * Return the String representation of the default output directory of the
2251     * launch config's project or <code>null</code> if there is no config, no
2252     * project or some sort of problem.
2253     *
2254     * @return the default output directory for the specified launch
2255     * configuration's project
2256     * @since 2.1
2257     */

2258    public static String JavaDoc getProjectOutputDirectory(ILaunchConfiguration config) {
2259        try {
2260            if (config != null) {
2261                IJavaProject javaProject = JavaRuntime.getJavaProject(config);
2262                if (javaProject != null) {
2263                    IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2264                    IPath outputLocation = javaProject.getOutputLocation();
2265                    IResource resource = root.findMember(outputLocation);
2266                    if (resource != null) {
2267                        IPath path = resource.getFullPath();
2268                        if (path != null) {
2269                            return path.makeRelative().toString();
2270                        }
2271                    }
2272                }
2273            }
2274        } catch (CoreException ce) {
2275        }
2276        return null;
2277    }
2278    
2279    /**
2280     * Returns a collection of source containers corresponding to the given
2281     * resolved runtime classpath entries.
2282     * <p>
2283     * Note that the entries must be resolved to ARCHIVE and PROJECT entries,
2284     * as source containers cannot be determined for unresolved entries.
2285     * </p>
2286     * @param entries entries to translate
2287     * @return source containers corresponding to the given runtime classpath entries
2288     * @since 3.1
2289     */

2290    public static ISourceContainer[] getSourceContainers(IRuntimeClasspathEntry[] entries) {
2291        return JavaSourceLookupUtil.translate(entries);
2292    }
2293    
2294    /**
2295     * Returns a collection of paths that should be appended to the given project's
2296     * <code>java.library.path</code> system property when launched. Entries are
2297     * searched for on the project's build path as extra classpath attributes.
2298     * Each entry represents an absolute path in the local file system.
2299     *
2300     * @param project the project to compute the <code>java.library.path</code> for
2301     * @param requiredProjects whether to consider entries in required projects
2302     * @return a collection of paths representing entries that should be appended
2303     * to the given project's <code>java.library.path</code>
2304     * @throws CoreException if unable to compute the Java library path
2305     * @since 3.1
2306     * @see org.eclipse.jdt.core.IClasspathAttribute
2307     * @see JavaRuntime#CLASSPATH_ATTR_LIBRARY_PATH_ENTRY
2308     */

2309    public static String JavaDoc[] computeJavaLibraryPath(IJavaProject project, boolean requiredProjects) throws CoreException {
2310        Set JavaDoc visited = new HashSet JavaDoc();
2311        List JavaDoc entries = new ArrayList JavaDoc();
2312        gatherJavaLibraryPathEntries(project, requiredProjects, visited, entries);
2313        List JavaDoc resolved = new ArrayList JavaDoc(entries.size());
2314        Iterator JavaDoc iterator = entries.iterator();
2315        IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
2316        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2317        while (iterator.hasNext()) {
2318            String JavaDoc entry = (String JavaDoc) iterator.next();
2319            String JavaDoc resolvedEntry = manager.performStringSubstitution(entry);
2320            IPath path = new Path(resolvedEntry);
2321            if (path.isAbsolute()) {
2322                File JavaDoc file = path.toFile();
2323                resolved.add(file.getAbsolutePath());
2324            } else {
2325                IResource resource = root.findMember(path);
2326                if (resource != null) {
2327                    IPath location = resource.getLocation();
2328                    if (location != null) {
2329                        resolved.add(location.toFile().getAbsolutePath());
2330                    }
2331                }
2332            }
2333        }
2334        return (String JavaDoc[])resolved.toArray(new String JavaDoc[resolved.size()]);
2335    }
2336
2337    /**
2338     * Gathers all Java library entries for the given project and optionally its required
2339     * projects.
2340     *
2341     * @param project project to gather entries for
2342     * @param requiredProjects whether to consider required projects
2343     * @param visited projects already considered
2344     * @param entries collection to add library entries to
2345     * @throws CoreException if unable to gather classpath entries
2346     * @since 3.1
2347     */

2348    private static void gatherJavaLibraryPathEntries(IJavaProject project, boolean requiredProjects, Set JavaDoc visited, List JavaDoc entries) throws CoreException {
2349        if (visited.contains(project)) {
2350            return;
2351        }
2352        visited.add(project);
2353        IClasspathEntry[] rawClasspath = project.getRawClasspath();
2354        IClasspathEntry[] required = processJavaLibraryPathEntries(project, requiredProjects, rawClasspath, entries);
2355        if (required != null) {
2356            IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2357            for (int i = 0; i < required.length; i++) {
2358                IClasspathEntry entry = required[i];
2359                String JavaDoc projectName = entry.getPath().segment(0);
2360                IProject p = root.getProject(projectName);
2361                if (p.exists()) {
2362                    IJavaProject requiredProject = JavaCore.create(p);
2363                    if (requiredProject != null) {
2364                        gatherJavaLibraryPathEntries(requiredProject, requiredProjects, visited, entries);
2365                    }
2366                }
2367            }
2368        }
2369    }
2370    
2371    /**
2372     * Adds all java library path extra classpath entry values to the given entries collection
2373     * specified on the given project's classpath, and returns a collection of required
2374     * projects, or <code>null</code>.
2375     *
2376     * @param project project being processed
2377     * @param collectRequired whether to collect required projects
2378     * @param classpathEntries the project's raw classpath
2379     * @param entries collection to add java library path entries to
2380     * @return required project classpath entries or <code>null</code>
2381     * @throws CoreException
2382     * @since 3.1
2383     */

2384    private static IClasspathEntry[] processJavaLibraryPathEntries(IJavaProject project, boolean collectRequired, IClasspathEntry[] classpathEntries, List JavaDoc entries) throws CoreException {
2385        List JavaDoc req = null;
2386        for (int i = 0; i < classpathEntries.length; i++) {
2387            IClasspathEntry entry = classpathEntries[i];
2388            IClasspathAttribute[] extraAttributes = entry.getExtraAttributes();
2389            for (int j = 0; j < extraAttributes.length; j++) {
2390                String JavaDoc[] paths = getLibraryPaths(extraAttributes[j]);
2391                if (paths != null) {
2392                    for (int k = 0; k < paths.length; k++) {
2393                        entries.add(paths[k]);
2394                    }
2395                }
2396            }
2397            if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
2398                IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
2399                if (container != null) {
2400                    IClasspathEntry[] requiredProjects = processJavaLibraryPathEntries(project, collectRequired, container.getClasspathEntries(), entries);
2401                    if (requiredProjects != null) {
2402                        if (req == null) {
2403                            req = new ArrayList JavaDoc();
2404                        }
2405                        for (int j = 0; j < requiredProjects.length; j++) {
2406                            req.add(requiredProjects[j]);
2407                        }
2408                    }
2409                }
2410            } else if (collectRequired && entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
2411                if (req == null) {
2412                    req = new ArrayList JavaDoc();
2413                }
2414                req.add(entry);
2415            }
2416        }
2417        if (req != null) {
2418            return (IClasspathEntry[]) req.toArray(new IClasspathEntry[req.size()]);
2419        }
2420        return null;
2421    }
2422    
2423    /**
2424     * Creates a new classpath attribute referencing a list of shared libraries that should
2425     * appear on the <code>-Djava.library.path</code> system property at runtime
2426     * for an associated {@link IClasspathEntry}.
2427     * <p>
2428     * The factory methods <code>newLibraryPathsAttribute(String[])</code>
2429     * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
2430     * encode and decode the attribute value.
2431     * </p>
2432     * @param paths an array of strings representing paths of shared libraries.
2433     * Each string is used to create an <code>IPath</code> using the constructor
2434     * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2435     * Variable substitution is performed on each string before a path is constructed
2436     * from a string.
2437     * @return a classpath attribute with the name <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>
2438     * and an value encoded to the specified paths.
2439     * @since 3.1
2440     */

2441    public static IClasspathAttribute newLibraryPathsAttribute(String JavaDoc[] paths) {
2442        StringBuffer JavaDoc value = new StringBuffer JavaDoc();
2443        for (int i = 0; i < paths.length; i++) {
2444            value.append(paths[i]);
2445            if (i < (paths.length - 1)) {
2446                value.append("|"); //$NON-NLS-1$
2447
}
2448        }
2449        return JavaCore.newClasspathAttribute(CLASSPATH_ATTR_LIBRARY_PATH_ENTRY, value.toString());
2450    }
2451    
2452    /**
2453     * Returns an array of strings referencing shared libraries that should
2454     * appear on the <code>-Djava.library.path</code> system property at runtime
2455     * for an associated {@link IClasspathEntry}, or <code>null</code> if the
2456     * given attribute is not a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>.
2457     * Each string is used to create an <code>IPath</code> using the constructor
2458     * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2459     * <p>
2460     * The factory methods <code>newLibraryPathsAttribute(String[])</code>
2461     * and <code>getLibraryPaths(IClasspathAttribute)</code> should be used to
2462     * encode and decode the attribute value.
2463     * </p>
2464     * @param attribute a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code> classpath attribute
2465     * @return an array of strings referencing shared libraries that should
2466     * appear on the <code>-Djava.library.path</code> system property at runtime
2467     * for an associated {@link IClasspathEntry}, or <code>null</code> if the
2468     * given attribute is not a <code>CLASSPATH_ATTR_LIBRARY_PATH_ENTRY</code>.
2469     * Each string is used to create an <code>IPath</code> using the constructor
2470     * <code>Path(String)</code>, and may contain <code>IStringVariable</code>'s.
2471     * @since 3.1
2472     */

2473    public static String JavaDoc[] getLibraryPaths(IClasspathAttribute attribute) {
2474        if (CLASSPATH_ATTR_LIBRARY_PATH_ENTRY.equals(attribute.getName())) {
2475            String JavaDoc value = attribute.getValue();
2476            return value.split("\\|"); //$NON-NLS-1$
2477
}
2478        return null;
2479    }
2480    
2481    /**
2482     * Returns the execution environments manager.
2483     *
2484     * @return execution environments manager
2485     * @since 3.2
2486     */

2487    public static IExecutionEnvironmentsManager getExecutionEnvironmentsManager() {
2488        return EnvironmentsManager.getDefault();
2489    }
2490    
2491    /**
2492     * Perform VM type and VM install initialization. Does not hold locks
2493     * while performing change notification.
2494     *
2495     * @since 3.2
2496     */

2497    private static void initializeVMs() {
2498        VMDefinitionsContainer vmDefs = null;
2499        boolean setPref = false;
2500        boolean updateCompliance = false;
2501        synchronized (fgVMLock) {
2502            if (fgVMTypes == null) {
2503                try {
2504                    fgInitializingVMs = true;
2505                    // 1. load VM type extensions
2506
initializeVMTypeExtensions();
2507                    try {
2508                        vmDefs = new VMDefinitionsContainer();
2509                        // 2. add persisted VMs
2510
setPref = addPersistedVMs(vmDefs);
2511                        
2512                        // 3. if there are none, detect the eclipse runtime
2513
if (vmDefs.getValidVMList().isEmpty()) {
2514                            // calling out to detectEclipseRuntime() could allow clients to change
2515
// VM settings (i.e. call back into change VM settings).
2516
VMListener listener = new VMListener();
2517                            addVMInstallChangedListener(listener);
2518                            setPref = true;
2519                            VMStandin runtime = detectEclipseRuntime();
2520                            removeVMInstallChangedListener(listener);
2521                            if (!listener.isChanged()) {
2522                                if (runtime != null) {
2523                                    updateCompliance = true;
2524                                    vmDefs.addVM(runtime);
2525                                    vmDefs.setDefaultVMInstallCompositeID(getCompositeIdFromVM(runtime));
2526                                }
2527                            } else {
2528                                // VMs were changed - reflect current settings
2529
addPersistedVMs(vmDefs);
2530                                vmDefs.setDefaultVMInstallCompositeID(fgDefaultVMId);
2531                                updateCompliance = fgDefaultVMId != null;
2532                            }
2533                        }
2534                        // 4. load contributed VM installs
2535
addVMExtensions(vmDefs);
2536                        // 5. verify default VM is valid
2537
String JavaDoc defId = vmDefs.getDefaultVMInstallCompositeID();
2538                        boolean validDef = false;
2539                        if (defId != null) {
2540                            Iterator JavaDoc iterator = vmDefs.getValidVMList().iterator();
2541                            while (iterator.hasNext()) {
2542                                IVMInstall vm = (IVMInstall) iterator.next();
2543                                if (getCompositeIdFromVM(vm).equals(defId)) {
2544                                    validDef = true;
2545                                    break;
2546                                }
2547                            }
2548                        }
2549                        if (!validDef) {
2550                            // use the first as the default
2551
setPref = true;
2552                            List JavaDoc list = vmDefs.getValidVMList();
2553                            if (!list.isEmpty()) {
2554                                IVMInstall vm = (IVMInstall) list.get(0);
2555                                vmDefs.setDefaultVMInstallCompositeID(getCompositeIdFromVM(vm));
2556                            }
2557                        }
2558                        fgDefaultVMId = vmDefs.getDefaultVMInstallCompositeID();
2559                        fgDefaultVMConnectorId = vmDefs.getDefaultVMInstallConnectorTypeID();
2560                        
2561                        // Create the underlying VMs for each valid VM
2562
List JavaDoc vmList = vmDefs.getValidVMList();
2563                        Iterator JavaDoc vmListIterator = vmList.iterator();
2564                        while (vmListIterator.hasNext()) {
2565                            VMStandin vmStandin = (VMStandin) vmListIterator.next();
2566                            vmStandin.convertToRealVM();
2567                        }
2568                        
2569
2570                    } catch (IOException JavaDoc e) {
2571                        LaunchingPlugin.log(e);
2572                    }
2573                } finally {
2574                    fgInitializingVMs = false;
2575                }
2576            }
2577        }
2578        if (vmDefs != null) {
2579            // notify of initial VMs for backwards compatibility
2580
IVMInstallType[] installTypes = getVMInstallTypes();
2581            for (int i = 0; i < installTypes.length; i++) {
2582                IVMInstallType type = installTypes[i];
2583                IVMInstall[] installs = type.getVMInstalls();
2584                for (int j = 0; j < installs.length; j++) {
2585                    fireVMAdded(installs[j]);
2586                }
2587            }
2588            
2589            // save settings if required
2590
if (setPref) {
2591                try {
2592                    String JavaDoc xml = vmDefs.getAsXML();
2593                    LaunchingPlugin.getDefault().getPluginPreferences().setValue(PREF_VM_XML, xml);
2594                } catch (ParserConfigurationException JavaDoc e) {
2595                    LaunchingPlugin.log(e);
2596                } catch (IOException JavaDoc e) {
2597                    LaunchingPlugin.log(e);
2598                } catch (TransformerException JavaDoc e) {
2599                    LaunchingPlugin.log(e);
2600                }
2601                
2602            }
2603            
2604            // update compliance if required
2605
if (updateCompliance) {
2606                updateCompliance(getDefaultVMInstall());
2607            }
2608        }
2609    }
2610    
2611    /**
2612     * Update compiler compliance settings based on the given vm.
2613     *
2614     * @param vm
2615     */

2616    private static void updateCompliance(IVMInstall vm) {
2617        if (vm instanceof IVMInstall2) {
2618            String JavaDoc javaVersion = ((IVMInstall2)vm).getJavaVersion();
2619            if (javaVersion != null) {
2620                String JavaDoc compliance = null;
2621                if (javaVersion.startsWith(JavaCore.VERSION_1_5)) {
2622                    compliance = JavaCore.VERSION_1_5;
2623                } else if (javaVersion.startsWith(JavaCore.VERSION_1_6)) {
2624                    compliance = JavaCore.VERSION_1_6;
2625                } else if (javaVersion.startsWith(JavaCore.VERSION_1_7)) {
2626                    compliance = JavaCore.VERSION_1_7;
2627                }
2628                if (compliance != null) {
2629                    Hashtable JavaDoc defaultOptions = JavaCore.getDefaultOptions();
2630                    Hashtable JavaDoc options = JavaCore.getOptions();
2631                    boolean isDefault =
2632                        equals(JavaCore.COMPILER_COMPLIANCE, defaultOptions, options) &&
2633                        equals(JavaCore.COMPILER_SOURCE, defaultOptions, options) &&
2634                        equals(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, defaultOptions, options) &&
2635                        equals(JavaCore.COMPILER_PB_ASSERT_IDENTIFIER, defaultOptions, options) &&
2636                        equals(JavaCore.COMPILER_PB_ENUM_IDENTIFIER, defaultOptions, options);
2637                    // only update the compliance settings if they are default settings, otherwise the
2638
// settings have already been modified by a tool or user
2639
if (isDefault) {
2640                        JavaCore.setComplianceOptions(compliance, options);
2641                        JavaCore.setOptions(options);
2642                    }
2643                }
2644            }
2645        }
2646    }
2647
2648}
2649
Popular Tags