KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > launching > LaunchingPlugin


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.internal.launching;
12
13
14 import java.io.BufferedInputStream JavaDoc;
15 import java.io.BufferedOutputStream JavaDoc;
16 import java.io.ByteArrayInputStream JavaDoc;
17 import java.io.ByteArrayOutputStream JavaDoc;
18 import java.io.File JavaDoc;
19 import java.io.FileInputStream JavaDoc;
20 import java.io.FileOutputStream JavaDoc;
21 import java.io.IOException JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.OutputStream JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.xml.parsers.DocumentBuilder JavaDoc;
33 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
34 import javax.xml.parsers.FactoryConfigurationError JavaDoc;
35 import javax.xml.parsers.ParserConfigurationException JavaDoc;
36 import javax.xml.transform.OutputKeys JavaDoc;
37 import javax.xml.transform.Transformer JavaDoc;
38 import javax.xml.transform.TransformerException JavaDoc;
39 import javax.xml.transform.TransformerFactory JavaDoc;
40 import javax.xml.transform.dom.DOMSource JavaDoc;
41 import javax.xml.transform.stream.StreamResult JavaDoc;
42
43 import org.eclipse.core.resources.IMarker;
44 import org.eclipse.core.resources.IResource;
45 import org.eclipse.core.resources.IResourceChangeEvent;
46 import org.eclipse.core.resources.IResourceChangeListener;
47 import org.eclipse.core.resources.IResourceDelta;
48 import org.eclipse.core.resources.ISaveContext;
49 import org.eclipse.core.resources.ISaveParticipant;
50 import org.eclipse.core.resources.IWorkspaceRunnable;
51 import org.eclipse.core.resources.ResourcesPlugin;
52 import org.eclipse.core.runtime.CoreException;
53 import org.eclipse.core.runtime.FileLocator;
54 import org.eclipse.core.runtime.IConfigurationElement;
55 import org.eclipse.core.runtime.IExtensionPoint;
56 import org.eclipse.core.runtime.IPath;
57 import org.eclipse.core.runtime.IProgressMonitor;
58 import org.eclipse.core.runtime.IStatus;
59 import org.eclipse.core.runtime.MultiStatus;
60 import org.eclipse.core.runtime.Path;
61 import org.eclipse.core.runtime.Platform;
62 import org.eclipse.core.runtime.Plugin;
63 import org.eclipse.core.runtime.Preferences;
64 import org.eclipse.core.runtime.Status;
65 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
66 import org.eclipse.core.runtime.jobs.Job;
67 import org.eclipse.debug.core.DebugEvent;
68 import org.eclipse.debug.core.DebugPlugin;
69 import org.eclipse.debug.core.IDebugEventSetListener;
70 import org.eclipse.debug.core.ILaunch;
71 import org.eclipse.debug.core.ILaunchConfiguration;
72 import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
73 import org.eclipse.debug.core.ILaunchesListener;
74 import org.eclipse.debug.core.model.IDebugTarget;
75 import org.eclipse.debug.core.model.IProcess;
76 import org.eclipse.jdt.core.IClasspathEntry;
77 import org.eclipse.jdt.core.IJavaProject;
78 import org.eclipse.jdt.core.JavaCore;
79 import org.eclipse.jdt.launching.IRuntimeClasspathEntry2;
80 import org.eclipse.jdt.launching.IVMConnector;
81 import org.eclipse.jdt.launching.IVMInstall;
82 import org.eclipse.jdt.launching.IVMInstallChangedListener;
83 import org.eclipse.jdt.launching.JavaRuntime;
84 import org.eclipse.jdt.launching.VMStandin;
85 import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
86 import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
87 import org.eclipse.jdt.launching.sourcelookup.ArchiveSourceLocation;
88 import org.osgi.framework.BundleContext;
89 import org.w3c.dom.Document JavaDoc;
90 import org.w3c.dom.Element JavaDoc;
91 import org.w3c.dom.Node JavaDoc;
92 import org.w3c.dom.NodeList JavaDoc;
93 import org.xml.sax.InputSource JavaDoc;
94 import org.xml.sax.SAXException JavaDoc;
95 import org.xml.sax.helpers.DefaultHandler JavaDoc;
96
97 import com.ibm.icu.text.MessageFormat;
98
99 public class LaunchingPlugin extends Plugin implements Preferences.IPropertyChangeListener, IVMInstallChangedListener, IResourceChangeListener, ILaunchesListener, IDebugEventSetListener {
100     
101     /**
102      * The id of the JDT launching plug-in (value <code>"org.eclipse.jdt.launching"</code>).
103      */

104     public static final String JavaDoc ID_PLUGIN= "org.eclipse.jdt.launching"; //$NON-NLS-1$
105

106     /**
107      * Identifier for 'vmConnectors' extension point
108      */

109     public static final String JavaDoc ID_EXTENSION_POINT_VM_CONNECTORS = "vmConnectors"; //$NON-NLS-1$
110

111     /**
112      * Identifier for 'runtimeClasspathEntries' extension point
113      */

114     public static final String JavaDoc ID_EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRIES = "runtimeClasspathEntries"; //$NON-NLS-1$
115

116     /**
117      * Marker type for JRE container problems.
118      *
119      * @since 3.2
120      */

121     public static final String JavaDoc ID_JRE_CONTAINER_MARKER = ID_PLUGIN + ".jreContainerMarker"; //$NON-NLS-1$
122

123     private static LaunchingPlugin fgLaunchingPlugin;
124     
125     private HashMap JavaDoc fVMConnectors = null;
126     
127     /**
128      * Runtime classpath extensions
129      */

130     private HashMap JavaDoc fClasspathEntryExtensions = null;
131
132     private String JavaDoc fOldVMPrefString = EMPTY_STRING;
133     
134     private boolean fIgnoreVMDefPropertyChangeEvents = false;
135         
136     private static final String JavaDoc EMPTY_STRING = ""; //$NON-NLS-1$
137

138     /**
139      * Mapping of top-level VM installation directories to library info for that
140      * VM.
141      */

142     private static Map JavaDoc fgLibraryInfoMap = null;
143     
144     /**
145      * Whether changes in VM preferences are being batched. When being batched
146      * the plug-in can ignore processing and changes.
147      */

148     private boolean fBatchingChanges = false;
149     
150     /**
151      * Shared XML parser
152      */

153     private static DocumentBuilder JavaDoc fgXMLParser = null;
154     
155     /**
156      * Whether debug options are turned on for this plug-in.
157      */

158     public static boolean DEBUG = false;
159     
160     /**
161      * Stores VM changes resulting from a JRE preference change.
162      */

163     class VMChanges implements IVMInstallChangedListener {
164         
165         // true if the default VM changes
166
private boolean fDefaultChanged = false;
167         
168         // old container ids to new
169
private HashMap JavaDoc fRenamedContainerIds = new HashMap JavaDoc();
170         
171         /**
172          * Returns the JRE container id that the given VM would map to, or
173          * <code>null</code> if none.
174          *
175          * @param vm
176          * @return container id or <code>null</code>
177          */

178         private IPath getContainerId(IVMInstall vm) {
179             if (vm != null) {
180                 String JavaDoc name = vm.getName();
181                 if (name != null) {
182                     IPath path = new Path(JavaRuntime.JRE_CONTAINER);
183                     path = path.append(new Path(vm.getVMInstallType().getId()));
184                     path = path.append(new Path(name));
185                     return path;
186                 }
187             }
188             return null;
189         }
190         
191         /**
192          * @see org.eclipse.jdt.launching.IVMInstallChangedListener#defaultVMInstallChanged(org.eclipse.jdt.launching.IVMInstall, org.eclipse.jdt.launching.IVMInstall)
193          */

194         public void defaultVMInstallChanged(IVMInstall previous, IVMInstall current) {
195             fDefaultChanged = true;
196         }
197
198         /**
199          * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmAdded(org.eclipse.jdt.launching.IVMInstall)
200          */

201         public void vmAdded(IVMInstall vm) {
202         }
203
204         /**
205          * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent)
206          */

207         public void vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent event) {
208             String JavaDoc property = event.getProperty();
209             IVMInstall vm = (IVMInstall)event.getSource();
210             if (property.equals(IVMInstallChangedListener.PROPERTY_NAME)) {
211                 IPath newId = getContainerId(vm);
212                 IPath oldId = new Path(JavaRuntime.JRE_CONTAINER);
213                 oldId = oldId.append(vm.getVMInstallType().getId());
214                 String JavaDoc oldName = (String JavaDoc)event.getOldValue();
215                 // bug 33746 - if there is no old name, then this is not a re-name.
216
if (oldName != null) {
217                     oldId = oldId.append(oldName);
218                     fRenamedContainerIds.put(oldId, newId);
219                     //bug 39222 update launch configurations that ref old name
220
try {
221                         ILaunchConfiguration[] configs = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurations();
222                         String JavaDoc container = null;
223                         ILaunchConfigurationWorkingCopy wc = null;
224                         IPath cpath = null;
225                         for(int i = 0; i < configs.length; i++) {
226                             container = configs[i].getAttribute(JavaRuntime.JRE_CONTAINER, (String JavaDoc)null);
227                             if(container != null) {
228                                 cpath = new Path(container);
229                                 if(cpath.lastSegment().equals(oldName)) {
230                                     cpath = cpath.removeLastSegments(1).append(newId.lastSegment()).addTrailingSeparator();
231                                     wc = configs[i].getWorkingCopy();
232                                     wc.setAttribute(JavaRuntime.JRE_CONTAINER, cpath.toString());
233                                     wc.doSave();
234                                 }
235                             }
236                         }
237                     } catch (CoreException e) {}
238                 }
239             }
240         }
241
242         /**
243          * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmRemoved(org.eclipse.jdt.launching.IVMInstall)
244          */

245         public void vmRemoved(IVMInstall vm) {
246         }
247     
248         /**
249          * Re-bind classpath variables and containers affected by the JRE
250          * changes.
251          */

252         public void process() {
253             JREUpdateJob job = new JREUpdateJob(this);
254             job.schedule();
255         }
256         
257         protected void doit(IProgressMonitor monitor) throws CoreException {
258             IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
259                 public void run(IProgressMonitor monitor1) throws CoreException {
260                     IJavaProject[] projects = JavaCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaProjects();
261                     monitor1.beginTask(LaunchingMessages.LaunchingPlugin_0, projects.length + 1);
262                     rebind(monitor1, projects);
263                     monitor1.done();
264                 }
265             };
266             JavaCore.run(runnable, null, monitor);
267         }
268                 
269         /**
270          * Re-bind classpath variables and containers affected by the JRE
271          * changes.
272          * @param monitor
273          */

274         private void rebind(IProgressMonitor monitor, IJavaProject[] projects) throws CoreException {
275              
276             if (fDefaultChanged) {
277                 // re-bind JRELIB if the default VM changed
278
JavaClasspathVariablesInitializer initializer = new JavaClasspathVariablesInitializer();
279                 initializer.initialize(JavaRuntime.JRELIB_VARIABLE);
280                 initializer.initialize(JavaRuntime.JRESRC_VARIABLE);
281                 initializer.initialize(JavaRuntime.JRESRCROOT_VARIABLE);
282             }
283             monitor.worked(1);
284                                                         
285             // re-bind all container entries
286
for (int i = 0; i < projects.length; i++) {
287                 IJavaProject project = projects[i];
288                 IClasspathEntry[] entries = project.getRawClasspath();
289                 boolean replace = false;
290                 for (int j = 0; j < entries.length; j++) {
291                     IClasspathEntry entry = entries[j];
292                     switch (entry.getEntryKind()) {
293                         case IClasspathEntry.CPE_CONTAINER:
294                             IPath reference = entry.getPath();
295                             IPath newBinding = null;
296                             String JavaDoc firstSegment = reference.segment(0);
297                             if (JavaRuntime.JRE_CONTAINER.equals(firstSegment)) {
298                                 if (reference.segmentCount() > 1) {
299                                     IPath renamed = (IPath)fRenamedContainerIds.get(reference);
300                                     if (renamed != null) {
301                                         // The JRE was re-named. This changes the identifier of
302
// the container entry.
303
newBinding = renamed;
304                                     }
305                                 }
306                                 JREContainerInitializer initializer = new JREContainerInitializer();
307                                 if (newBinding == null){
308                                     // re-bind old path
309
initializer.initialize(reference, project);
310                                 } else {
311                                     // replace old class path entry with a new one
312
IClasspathEntry newEntry = JavaCore.newContainerEntry(newBinding, entry.isExported());
313                                     entries[j] = newEntry;
314                                     replace = true;
315                                 }
316                             }
317                             break;
318                         default:
319                             break;
320                     }
321                 }
322                 if (replace) {
323                     project.setRawClasspath(entries, null);
324                 }
325                 monitor.worked(1);
326             }
327
328         }
329
330     }
331     
332     class JREUpdateJob extends Job {
333         private VMChanges fChanges;
334         
335         public JREUpdateJob(VMChanges changes) {
336             super(LaunchingMessages.LaunchingPlugin_1);
337             fChanges = changes;
338             setSystem(true);
339         }
340
341         /* (non-Javadoc)
342          * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
343          */

344         protected IStatus run(IProgressMonitor monitor) {
345             try {
346                 fChanges.doit(monitor);
347             } catch (CoreException e) {
348                 return e.getStatus();
349             }
350             return Status.OK_STATUS;
351         }
352         
353     }
354     
355     /**
356      * Constructor
357      */

358     public LaunchingPlugin() {
359         super();
360         fgLaunchingPlugin = this;
361     }
362     
363     /**
364      * Returns the library info that corresponds to the specified JRE install
365      * path, or <code>null</code> if none.
366      *
367      * @return the library info that corresponds to the specified JRE install
368      * path, or <code>null</code> if none
369      */

370     public static LibraryInfo getLibraryInfo(String JavaDoc javaInstallPath) {
371         if (fgLibraryInfoMap == null) {
372             restoreLibraryInfo();
373         }
374         return (LibraryInfo) fgLibraryInfoMap.get(javaInstallPath);
375     }
376     
377     /**
378      * Sets the library info that corresponds to the specified JRE install
379      * path.
380      *
381      * @param javaInstallPath home location for a JRE
382      * @param info the library information, or <code>null</code> to remove
383      */

384     public static void setLibraryInfo(String JavaDoc javaInstallPath, LibraryInfo info) {
385         if (fgLibraryInfoMap == null) {
386             restoreLibraryInfo();
387         }
388         if (info == null) {
389             fgLibraryInfoMap.remove(javaInstallPath);
390         } else {
391             fgLibraryInfoMap.put(javaInstallPath, info);
392         }
393         saveLibraryInfo();
394     }
395         
396     /**
397      * Return a <code>java.io.File</code> object that corresponds to the specified
398      * <code>IPath</code> in the plugin directory.
399      */

400     public static File JavaDoc getFileInPlugin(IPath path) {
401         try {
402             URL JavaDoc installURL =
403                 new URL JavaDoc(getDefault().getBundle().getEntry("/"), path.toString()); //$NON-NLS-1$
404
URL JavaDoc localURL = FileLocator.toFileURL(installURL);
405             return new File JavaDoc(localURL.getFile());
406         } catch (IOException JavaDoc ioe) {
407             return null;
408         }
409     }
410         
411     /**
412      * Convenience method which returns the unique identifier of this plugin.
413      */

414     public static String JavaDoc getUniqueIdentifier() {
415         return ID_PLUGIN;
416     }
417
418     /**
419      * Returns the singleton instance of <code>LaunchingPlugin</code>
420      * @return the singleton instance of <code>LaunchingPlugin</code>
421      */

422     public static LaunchingPlugin getDefault() {
423         if(fgLaunchingPlugin == null) {
424             fgLaunchingPlugin = new LaunchingPlugin();
425         }
426         return fgLaunchingPlugin;
427     }
428     
429     /**
430      * Logs the specified status
431      * @param status
432      */

433     public static void log(IStatus status) {
434         getDefault().getLog().log(status);
435     }
436     
437     /**
438      * Logs the specified message, by creating a new <code>Status</code>
439      * @param message
440      */

441     public static void log(String JavaDoc message) {
442         log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, message, null));
443     }
444         
445     /**
446      * Logs the specified exception by creating a new <code>Status</code>
447      * @param e
448      */

449     public static void log(Throwable JavaDoc e) {
450         log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, e.getMessage(), e));
451     }
452     
453     /**
454      * Clears zip file cache.
455      * Shutdown the launch config helper.
456      *
457      * @see Plugin#stop(BundleContext)
458      */

459     public void stop(BundleContext context) throws Exception JavaDoc {
460         try {
461             DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
462             DebugPlugin.getDefault().removeDebugEventListener(this);
463             ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
464             ArchiveSourceLocation.closeArchives();
465             getPluginPreferences().removePropertyChangeListener(this);
466             JavaRuntime.removeVMInstallChangedListener(this);
467             JavaRuntime.saveVMConfiguration();
468             fgXMLParser = null;
469             ResourcesPlugin.getWorkspace().removeSaveParticipant(this);
470         } finally {
471             super.stop(context);
472         }
473     }
474         
475     /**
476      * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
477      */

478     public void start(BundleContext context) throws Exception JavaDoc {
479         super.start(context);
480         DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.jdt.launching/debug")); //$NON-NLS-1$//$NON-NLS-2$
481
ResourcesPlugin.getWorkspace().addSaveParticipant(this, new ISaveParticipant() {
482             public void doneSaving(ISaveContext context1) {}
483             public void prepareToSave(ISaveContext context1) throws CoreException {}
484             public void rollback(ISaveContext context1) {}
485             public void saving(ISaveContext context1) throws CoreException {
486                 savePluginPreferences();
487             }
488             
489         });
490         // Exclude launch configurations from being copied to the output directory
491
String JavaDoc launchFilter = "*." + ILaunchConfiguration.LAUNCH_CONFIGURATION_FILE_EXTENSION; //$NON-NLS-1$
492
Hashtable JavaDoc optionsMap = JavaCore.getOptions();
493         String JavaDoc filters= (String JavaDoc)optionsMap.get("org.eclipse.jdt.core.builder.resourceCopyExclusionFilter"); //$NON-NLS-1$
494
boolean modified = false;
495         if (filters == null || filters.length() == 0) {
496             filters= launchFilter;
497             modified = true;
498         } else if (filters.indexOf(launchFilter) == -1) {
499             filters= filters + ',' + launchFilter;
500             modified = true;
501         }
502
503         if (modified) {
504             optionsMap.put("org.eclipse.jdt.core.builder.resourceCopyExclusionFilter", filters); //$NON-NLS-1$
505
JavaCore.setOptions(optionsMap);
506         }
507
508         // set default preference values
509
getPluginPreferences().setDefault(JavaRuntime.PREF_CONNECT_TIMEOUT, JavaRuntime.DEF_CONNECT_TIMEOUT);
510         getPluginPreferences().addPropertyChangeListener(this);
511
512         JavaRuntime.addVMInstallChangedListener(this);
513         ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_BUILD);
514         DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
515         DebugPlugin.getDefault().addDebugEventListener(this);
516     }
517     
518     /**
519      * Returns the VM connector with the specified id, or <code>null</code>
520      * if none.
521      *
522      * @param id connector identifier
523      * @return VM connector
524      */

525     public IVMConnector getVMConnector(String JavaDoc id) {
526         if (fVMConnectors == null) {
527             initializeVMConnectors();
528         }
529         return (IVMConnector)fVMConnectors.get(id);
530     }
531     
532     /**
533      * Returns all VM connector extensions.
534      *
535      * @return VM connectors
536      */

537     public IVMConnector[] getVMConnectors() {
538         if (fVMConnectors == null) {
539             initializeVMConnectors();
540         }
541         return (IVMConnector[])fVMConnectors.values().toArray(new IVMConnector[fVMConnectors.size()]);
542     }
543     
544     /**
545      * Loads VM connector extensions
546      */

547     private void initializeVMConnectors() {
548         IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(ID_PLUGIN, ID_EXTENSION_POINT_VM_CONNECTORS);
549         IConfigurationElement[] configs= extensionPoint.getConfigurationElements();
550         MultiStatus status= new MultiStatus(getUniqueIdentifier(), IStatus.OK, "Exception occurred reading vmConnectors extensions.", null); //$NON-NLS-1$
551
fVMConnectors = new HashMap JavaDoc(configs.length);
552         for (int i= 0; i < configs.length; i++) {
553             try {
554                 IVMConnector vmConnector= (IVMConnector)configs[i].createExecutableExtension("class"); //$NON-NLS-1$
555
fVMConnectors.put(vmConnector.getIdentifier(), vmConnector);
556             } catch (CoreException e) {
557                 status.add(e.getStatus());
558             }
559         }
560         if (!status.isOK()) {
561             LaunchingPlugin.log(status);
562         }
563     }
564     
565     /**
566      * Returns a new runtime classpath entry of the specified type.
567      *
568      * @param id extension type id
569      * @return new uninitialized runtime classpath entry
570      * @throws CoreException if unable to create an entry
571      */

572     public IRuntimeClasspathEntry2 newRuntimeClasspathEntry(String JavaDoc id) throws CoreException {
573         if (fClasspathEntryExtensions == null) {
574             initializeRuntimeClasspathExtensions();
575         }
576         IConfigurationElement config = (IConfigurationElement) fClasspathEntryExtensions.get(id);
577         if (config == null) {
578             abort(MessageFormat.format(LaunchingMessages.LaunchingPlugin_32, new String JavaDoc[]{id}), null);
579         }
580         return (IRuntimeClasspathEntry2) config.createExecutableExtension("class"); //$NON-NLS-1$
581
}
582     
583     /**
584      * Loads runtime classpath extensions
585      */

586     private void initializeRuntimeClasspathExtensions() {
587         IExtensionPoint extensionPoint= Platform.getExtensionRegistry().getExtensionPoint(LaunchingPlugin.ID_PLUGIN, ID_EXTENSION_POINT_RUNTIME_CLASSPATH_ENTRIES);
588         IConfigurationElement[] configs= extensionPoint.getConfigurationElements();
589         fClasspathEntryExtensions = new HashMap JavaDoc(configs.length);
590         for (int i= 0; i < configs.length; i++) {
591             fClasspathEntryExtensions.put(configs[i].getAttribute("id"), configs[i]); //$NON-NLS-1$
592
}
593     }
594     
595     /**
596      * Save preferences whenever the connect timeout changes.
597      * Process changes to the list of installed JREs.
598      *
599      * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
600      */

601     public void propertyChange(PropertyChangeEvent event) {
602         String JavaDoc property = event.getProperty();
603         if (property.equals(JavaRuntime.PREF_VM_XML)) {
604             if (!isIgnoreVMDefPropertyChangeEvents()) {
605                 processVMPrefsChanged((String JavaDoc)event.getOldValue(), (String JavaDoc)event.getNewValue());
606             }
607         }
608     }
609
610     /**
611      * Check for differences between the old & new sets of installed JREs.
612      * Differences may include additions, deletions and changes. Take
613      * appropriate action for each type of difference.
614      *
615      * When importing preferences, TWO propertyChange events are fired. The first
616      * has an old value but an empty new value. The second has a new value, but an empty
617      * old value. Normal user changes to the preferences result in a single propertyChange
618      * event, with both old and new values populated. This method handles both types
619      * of notification.
620      */

621     protected void processVMPrefsChanged(String JavaDoc oldValue, String JavaDoc newValue) {
622         
623         // batch changes
624
fBatchingChanges = true;
625         VMChanges vmChanges = null;
626         try {
627
628             String JavaDoc oldPrefString;
629             String JavaDoc newPrefString;
630             
631             // If empty new value, save the old value and wait for 2nd propertyChange notification
632
if (newValue == null || newValue.equals(EMPTY_STRING)) {
633                 fOldVMPrefString = oldValue;
634                 return;
635             }
636             // An empty old value signals the second notification in the import preferences
637
// sequence. Now that we have both old & new prefs, we can parse and compare them.
638
else if (oldValue == null || oldValue.equals(EMPTY_STRING)) {
639                 oldPrefString = fOldVMPrefString;
640                 newPrefString = newValue;
641             }
642             // If both old & new values are present, this is a normal user change
643
else {
644                 oldPrefString = oldValue;
645                 newPrefString = newValue;
646             }
647             
648             vmChanges = new VMChanges();
649             JavaRuntime.addVMInstallChangedListener(vmChanges);
650             
651             // Generate the previous VMs
652
VMDefinitionsContainer oldResults = getVMDefinitions(oldPrefString);
653             
654             // Generate the current
655
VMDefinitionsContainer newResults = getVMDefinitions(newPrefString);
656             
657             // Determine the deleted VMs
658
List JavaDoc deleted = oldResults.getVMList();
659             List JavaDoc current = newResults.getValidVMList();
660             deleted.removeAll(current);
661             
662             // Dispose deleted VMs. The 'disposeVMInstall' method fires notification of the
663
// deletion.
664
Iterator JavaDoc deletedIterator = deleted.iterator();
665             while (deletedIterator.hasNext()) {
666                 VMStandin deletedVMStandin = (VMStandin) deletedIterator.next();
667                 deletedVMStandin.getVMInstallType().disposeVMInstall(deletedVMStandin.getId());
668             }
669             
670             // Fire change notification for added and changed VMs. The 'convertToRealVM'
671
// fires the appropriate notification.
672
Iterator JavaDoc iter = current.iterator();
673             while (iter.hasNext()) {
674                 VMStandin standin = (VMStandin)iter.next();
675                 standin.convertToRealVM();
676             }
677             
678             // set the new default VM install. This will fire a 'defaultVMChanged',
679
// if it in fact changed
680
String JavaDoc newDefaultId = newResults.getDefaultVMInstallCompositeID();
681             if (newDefaultId != null) {
682                 IVMInstall newDefaultVM = JavaRuntime.getVMFromCompositeId(newDefaultId);
683                 if (newDefaultVM != null) {
684                     try {
685                         JavaRuntime.setDefaultVMInstall(newDefaultVM, null, false);
686                     } catch (CoreException ce) {
687                         log(ce);
688                     }
689                 }
690             }
691             
692         } finally {
693             // stop batch changes
694
fBatchingChanges = false;
695             if (vmChanges != null) {
696                 JavaRuntime.removeVMInstallChangedListener(vmChanges);
697                 vmChanges.process();
698             }
699         }
700
701     }
702     
703     /**
704      * Parse the given xml into a VM definitions container, returning an empty
705      * container if an exception occurs.
706      *
707      * @param xml
708      * @return VMDefinitionsContainer
709      */

710     private VMDefinitionsContainer getVMDefinitions(String JavaDoc xml) {
711         if (xml.length() > 0) {
712             try {
713                 ByteArrayInputStream JavaDoc stream = new ByteArrayInputStream JavaDoc(xml.getBytes("UTF8")); //$NON-NLS-1$
714
return VMDefinitionsContainer.parseXMLIntoContainer(stream);
715             } catch (IOException JavaDoc e) {
716                 LaunchingPlugin.log(e);
717             }
718         }
719         return new VMDefinitionsContainer();
720     }
721                         
722     /**
723      * @see IVMInstallChangedListener#defaultVMInstallChanged(IVMInstall, IVMInstall)
724      */

725     public void defaultVMInstallChanged(IVMInstall previous, IVMInstall current) {
726         if (!fBatchingChanges) {
727             VMChanges changes = new VMChanges();
728             changes.defaultVMInstallChanged(previous, current);
729             changes.process();
730         }
731     }
732
733     /* (non-Javadoc)
734      * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmAdded(org.eclipse.jdt.launching.IVMInstall)
735      */

736     public void vmAdded(IVMInstall vm) {
737     }
738
739     /* (non-Javadoc)
740      * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent)
741      */

742     public void vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent event) {
743         if (!fBatchingChanges) {
744             VMChanges changes = new VMChanges();
745             changes.vmChanged(event);
746             changes.process();
747         }
748     }
749
750     /* (non-Javadoc)
751      * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmRemoved(org.eclipse.jdt.launching.IVMInstall)
752      */

753     public void vmRemoved(IVMInstall vm) {
754         if (!fBatchingChanges) {
755             VMChanges changes = new VMChanges();
756             changes.vmRemoved(vm);
757             changes.process();
758         }
759     }
760
761     /**
762      * Clear the archive cache when a project is about to be deleted.
763      * Warn when a build path changes and references an execution environment
764      * that does not have a perfect match.
765      *
766      * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
767      */

768     public void resourceChanged(IResourceChangeEvent event) {
769         ArchiveSourceLocation.closeArchives();
770         if (event.getType() == IResourceChangeEvent.PRE_BUILD) {
771             IResourceDelta delta = event.getDelta();
772             IResourceDelta[] projectDeltas = delta.getAffectedChildren();
773             for (int i = 0, length = projectDeltas.length; i < length; i++) {
774                 IResourceDelta projectDelta = projectDeltas[i];
775                 IResourceDelta classpathDelta = projectDelta.findMember(new Path(".classpath")); //$NON-NLS-1$
776
if (classpathDelta != null || (projectDelta.getFlags() & IResourceDelta.DESCRIPTION) > 0) {
777                     IJavaProject project = (IJavaProject) JavaCore.create(projectDelta.getResource());
778                     if (project != null && project.exists()) {
779                         try {
780                             IClasspathEntry[] rawClasspath = project.getRawClasspath();
781                             for (int j = 0; j < rawClasspath.length; j++) {
782                                 IClasspathEntry entry = rawClasspath[j];
783                                 if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
784                                     IPath path = entry.getPath();
785                                     if (JavaRuntime.JRE_CONTAINER.equals(path.segment(0))) {
786                                         IVMInstall vm = JREContainerInitializer.resolveVM(path);
787                                         validateEnvironment(path, project, vm);
788                                     }
789                                 }
790                             }
791                         } catch (CoreException e) {
792                             LaunchingPlugin.log(e);
793                         }
794                     }
795                 }
796             }
797         }
798     }
799
800     /**
801      * Allows vm property change events to be ignored
802      * @param ignore
803      */

804     public void setIgnoreVMDefPropertyChangeEvents(boolean ignore) {
805         fIgnoreVMDefPropertyChangeEvents = ignore;
806     }
807
808     /**
809      * Returns if vm property changed event should be ignored or not
810      * @return if vm property changed event should be ignored or not
811      */

812     public boolean isIgnoreVMDefPropertyChangeEvents() {
813         return fIgnoreVMDefPropertyChangeEvents;
814     }
815
816     /**
817      * Return the VM definitions contained in this object as a String of XML. The String
818      * is suitable for storing in the workbench preferences.
819      * <p>
820      * The resulting XML is compatible with the static method <code>parseXMLIntoContainer</code>.
821      * </p>
822      * @return String the results of flattening this object into XML
823      * @throws IOException if this method fails. Reasons include:<ul>
824      * <li>serialization of the XML document failed</li>
825      * </ul>
826      */

827     private static String JavaDoc getLibraryInfoAsXML() throws ParserConfigurationException JavaDoc, IOException JavaDoc, TransformerException JavaDoc{
828         
829         Document JavaDoc doc = getDocument();
830         Element config = doc.createElement("libraryInfos"); //$NON-NLS-1$
831
doc.appendChild(config);
832                         
833         // Create a node for each info in the table
834
Iterator JavaDoc locations = fgLibraryInfoMap.keySet().iterator();
835         while (locations.hasNext()) {
836             String JavaDoc home = (String JavaDoc)locations.next();
837             LibraryInfo info = (LibraryInfo) fgLibraryInfoMap.get(home);
838             Element locationElemnet = infoAsElement(doc, info);
839             locationElemnet.setAttribute("home", home); //$NON-NLS-1$
840
config.appendChild(locationElemnet);
841         }
842         
843         // Serialize the Document and return the resulting String
844
return LaunchingPlugin.serializeDocument(doc);
845     }
846     
847     /**
848      * Returns a Document that can be used to build a DOM tree
849      * @return the Document
850      * @throws ParserConfigurationException if an exception occurs creating the document builder
851      */

852     public static Document JavaDoc getDocument() throws ParserConfigurationException JavaDoc {
853         DocumentBuilderFactory JavaDoc dfactory= DocumentBuilderFactory.newInstance();
854         DocumentBuilder JavaDoc docBuilder= dfactory.newDocumentBuilder();
855         Document JavaDoc doc= docBuilder.newDocument();
856         return doc;
857     }
858
859     /**
860      * Creates an XML element for the given info.
861      *
862      * @param doc
863      * @param info
864      * @return Element
865      */

866     private static Element infoAsElement(Document JavaDoc doc, LibraryInfo info) {
867         Element libraryElement = doc.createElement("libraryInfo"); //$NON-NLS-1$
868
libraryElement.setAttribute("version", info.getVersion()); //$NON-NLS-1$
869
appendPathElements(doc, "bootpath", libraryElement, info.getBootpath()); //$NON-NLS-1$
870
appendPathElements(doc, "extensionDirs", libraryElement, info.getExtensionDirs()); //$NON-NLS-1$
871
appendPathElements(doc, "endorsedDirs", libraryElement, info.getEndorsedDirs()); //$NON-NLS-1$
872
return libraryElement;
873     }
874     
875     /**
876      * Appends path elements to the given library element, rooted by an
877      * element of the given type.
878      *
879      * @param doc
880      * @param elementType
881      * @param libraryElement
882      * @param paths
883      */

884     private static void appendPathElements(Document JavaDoc doc, String JavaDoc elementType, Element libraryElement, String JavaDoc[] paths) {
885         if (paths.length > 0) {
886             Element child = doc.createElement(elementType);
887             libraryElement.appendChild(child);
888             for (int i = 0; i < paths.length; i++) {
889                 String JavaDoc path = paths[i];
890                 Element entry = doc.createElement("entry"); //$NON-NLS-1$
891
child.appendChild(entry);
892                 entry.setAttribute("path", path); //$NON-NLS-1$
893
}
894         }
895     }
896     
897     /**
898      * Saves the library info in a local workspace state location
899      */

900     private static void saveLibraryInfo() {
901         OutputStream JavaDoc stream= null;
902         try {
903             String JavaDoc xml = getLibraryInfoAsXML();
904             IPath libPath = getDefault().getStateLocation();
905             libPath = libPath.append("libraryInfos.xml"); //$NON-NLS-1$
906
File JavaDoc file = libPath.toFile();
907             if (!file.exists()) {
908                 file.createNewFile();
909             }
910             stream = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(file));
911             stream.write(xml.getBytes("UTF8")); //$NON-NLS-1$
912
} catch (IOException JavaDoc e) {
913             log(e);
914         } catch (ParserConfigurationException JavaDoc e) {
915             log(e);
916         } catch (TransformerException JavaDoc e) {
917             log(e);
918         } finally {
919             if (stream != null) {
920                 try {
921                     stream.close();
922                 } catch (IOException JavaDoc e1) {
923                 }
924             }
925         }
926     }
927     
928     /**
929      * Restores library information for VMs
930      */

931     private static void restoreLibraryInfo() {
932         fgLibraryInfoMap = new HashMap JavaDoc(10);
933         IPath libPath = getDefault().getStateLocation();
934         libPath = libPath.append("libraryInfos.xml"); //$NON-NLS-1$
935
File JavaDoc file = libPath.toFile();
936         if (file.exists()) {
937             try {
938                 InputStream JavaDoc stream = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(file));
939                 DocumentBuilder JavaDoc parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
940                 parser.setErrorHandler(new DefaultHandler JavaDoc());
941                 Element root = parser.parse(new InputSource JavaDoc(stream)).getDocumentElement();
942                 if(!root.getNodeName().equals("libraryInfos")) { //$NON-NLS-1$
943
return;
944                 }
945                 
946                 NodeList JavaDoc list = root.getChildNodes();
947                 int length = list.getLength();
948                 for (int i = 0; i < length; ++i) {
949                     Node JavaDoc node = list.item(i);
950                     short type = node.getNodeType();
951                     if (type == Node.ELEMENT_NODE) {
952                         Element element = (Element) node;
953                         String JavaDoc nodeName = element.getNodeName();
954                         if (nodeName.equalsIgnoreCase("libraryInfo")) { //$NON-NLS-1$
955
String JavaDoc version = element.getAttribute("version"); //$NON-NLS-1$
956
String JavaDoc location = element.getAttribute("home"); //$NON-NLS-1$
957
String JavaDoc[] bootpath = getPathsFromXML(element, "bootpath"); //$NON-NLS-1$
958
String JavaDoc[] extDirs = getPathsFromXML(element, "extensionDirs"); //$NON-NLS-1$
959
String JavaDoc[] endDirs = getPathsFromXML(element, "endorsedDirs"); //$NON-NLS-1$
960
if (location != null) {
961                                 LibraryInfo info = new LibraryInfo(version, bootpath, extDirs, endDirs);
962                                 fgLibraryInfoMap.put(location, info);
963                             }
964                         }
965                     }
966                 }
967             } catch (IOException JavaDoc e) {
968                 log(e);
969             } catch (ParserConfigurationException JavaDoc e) {
970                 log(e);
971             } catch (SAXException JavaDoc e) {
972                 log(e);
973             }
974         }
975     }
976     
977     /**
978      * Returns paths stored in XML
979      * @param lib
980      * @param pathType
981      * @return paths stored in XML
982      */

983     private static String JavaDoc[] getPathsFromXML(Element lib, String JavaDoc pathType) {
984         List JavaDoc paths = new ArrayList JavaDoc();
985         NodeList JavaDoc list = lib.getChildNodes();
986         int length = list.getLength();
987         for (int i = 0; i < length; ++i) {
988             Node JavaDoc node = list.item(i);
989             short type = node.getNodeType();
990             if (type == Node.ELEMENT_NODE) {
991                 Element element = (Element) node;
992                 String JavaDoc nodeName = element.getNodeName();
993                 if (nodeName.equalsIgnoreCase(pathType)) {
994                     NodeList JavaDoc entries = element.getChildNodes();
995                     int numEntries = entries.getLength();
996                     for (int j = 0; j < numEntries; j++) {
997                         Node JavaDoc n = entries.item(j);
998                         short t = n.getNodeType();
999                         if (t == Node.ELEMENT_NODE) {
1000                            Element entryElement = (Element)n;
1001                            String JavaDoc name = entryElement.getNodeName();
1002                            if (name.equals("entry")) { //$NON-NLS-1$
1003
String JavaDoc path = entryElement.getAttribute("path"); //$NON-NLS-1$
1004
if (path != null && path.length() > 0) {
1005                                    paths.add(path);
1006                                }
1007                            }
1008                        }
1009                    }
1010                }
1011            }
1012        }
1013        return (String JavaDoc[])paths.toArray(new String JavaDoc[paths.size()]);
1014    }
1015    
1016    /**
1017     * When a launch is removed, close all source archives. Prevents file
1018     * sharing violations.
1019     *
1020     * @see ILaunchesListener#launchesRemoved(ILaunch[])
1021     */

1022    public void launchesRemoved(ILaunch[] launches) {
1023        ArchiveSourceLocation.closeArchives();
1024    }
1025    
1026    /**
1027     * @see ILaunchesListener#launchesAdded(ILaunch[])
1028     */

1029    public void launchesAdded(ILaunch[] launches) {
1030    }
1031    
1032    /**
1033     * @see ILaunchesListener#launchesChanged(ILaunch[])
1034     */

1035    public void launchesChanged(ILaunch[] launches) {
1036    }
1037    
1038    /**
1039     * When a debug target or process terminates, close source archives.
1040     * Prevents file sharing violations.
1041     *
1042     * @see IDebugEventSetListener#handleDebugEvents(DebugEvent[])
1043     */

1044    public void handleDebugEvents(DebugEvent[] events) {
1045        for (int i = 0; i < events.length; i++) {
1046            DebugEvent event = events[i];
1047            if (event.getKind() == DebugEvent.TERMINATE) {
1048                Object JavaDoc source = event.getSource();
1049                if (source instanceof IDebugTarget || source instanceof IProcess) {
1050                    ArchiveSourceLocation.closeArchives();
1051                }
1052            }
1053        }
1054    }
1055    
1056    /**
1057     * Serializes a XML document into a string - encoded in UTF8 format,
1058     * with platform line separators.
1059     *
1060     * @param doc document to serialize
1061     * @return the document as a string
1062     */

1063    public static String JavaDoc serializeDocument(Document JavaDoc doc) throws IOException JavaDoc, TransformerException JavaDoc {
1064        ByteArrayOutputStream JavaDoc s= new ByteArrayOutputStream JavaDoc();
1065        
1066        TransformerFactory JavaDoc factory= TransformerFactory.newInstance();
1067        Transformer JavaDoc transformer= factory.newTransformer();
1068        transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
1069
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
1070

1071        DOMSource JavaDoc source= new DOMSource JavaDoc(doc);
1072        StreamResult JavaDoc outputTarget= new StreamResult JavaDoc(s);
1073        transformer.transform(source, outputTarget);
1074        
1075        return s.toString("UTF8"); //$NON-NLS-1$
1076
}
1077
1078    /**
1079     * Returns a shared XML parser.
1080     *
1081     * @return an XML parser
1082     * @throws CoreException if unable to create a parser
1083     * @since 3.0
1084     */

1085    public static DocumentBuilder JavaDoc getParser() throws CoreException {
1086        if (fgXMLParser == null) {
1087            try {
1088                fgXMLParser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
1089                fgXMLParser.setErrorHandler(new DefaultHandler JavaDoc());
1090            } catch (ParserConfigurationException JavaDoc e) {
1091                abort(LaunchingMessages.LaunchingPlugin_33, e);
1092            } catch (FactoryConfigurationError JavaDoc e) {
1093                abort(LaunchingMessages.LaunchingPlugin_34, e);
1094            }
1095        }
1096        return fgXMLParser;
1097    }
1098    
1099    /**
1100     * Throws an exception with the given message and underlying exception.
1101     *
1102     * @param message error message
1103     * @param exception underlying exception or <code>null</code> if none
1104     * @throws CoreException
1105     */

1106    protected static void abort(String JavaDoc message, Throwable JavaDoc exception) throws CoreException {
1107        IStatus status = new Status(IStatus.ERROR, LaunchingPlugin.getUniqueIdentifier(), 0, message, exception);
1108        throw new CoreException(status);
1109    }
1110    
1111    /**
1112     * Validates the environment
1113     * @param containerPath
1114     * @param project
1115     * @param vm
1116     */

1117    private void validateEnvironment(IPath containerPath, final IJavaProject project, IVMInstall vm) {
1118        try {
1119            project.getProject().deleteMarkers(ID_JRE_CONTAINER_MARKER, false, IResource.DEPTH_ZERO);
1120        } catch (CoreException e) {
1121            LaunchingPlugin.log(e);
1122        }
1123        String JavaDoc id = JREContainerInitializer.getExecutionEnvironmentId(containerPath);
1124        if (id != null) {
1125            IExecutionEnvironmentsManager manager = JavaRuntime.getExecutionEnvironmentsManager();
1126            final IExecutionEnvironment environment = manager.getEnvironment(id);
1127            if (environment != null) {
1128                if (vm == null) {
1129                    String JavaDoc message = MessageFormat.format(
1130                            LaunchingMessages.LaunchingPlugin_38,
1131                            new String JavaDoc[]{environment.getId()});
1132                    createJREContainerProblem(project, message, IMarker.SEVERITY_ERROR);
1133                } else if (!environment.isStrictlyCompatible(vm)) {
1134                    // warn that VM does not match EE
1135
// first determine if there is a strictly compatible JRE available
1136
IVMInstall[] compatibleVMs = environment.getCompatibleVMs();
1137                    int exact = 0;
1138                    for (int i = 0; i < compatibleVMs.length; i++) {
1139                        if (environment.isStrictlyCompatible(compatibleVMs[i])) {
1140                            exact++;
1141                        }
1142                    }
1143                    String JavaDoc message = null;
1144                    if (exact == 0) {
1145                        message = MessageFormat.format(
1146                            LaunchingMessages.LaunchingPlugin_35,
1147                            new String JavaDoc[]{environment.getId()});
1148                    } else {
1149                        message = MessageFormat.format(
1150                                LaunchingMessages.LaunchingPlugin_36,
1151                                new String JavaDoc[]{environment.getId()});
1152                    }
1153                    createJREContainerProblem(project, message, IMarker.SEVERITY_WARNING);
1154                }
1155            }
1156        }
1157    }
1158    
1159    /**
1160     * creates a problem marker for a jre container problem
1161     * @param javaProject
1162     * @param message
1163     * @param severity
1164     */

1165    private void createJREContainerProblem(IJavaProject javaProject, String JavaDoc message, int severity) {
1166        try {
1167            IMarker marker = javaProject.getProject().createMarker(ID_JRE_CONTAINER_MARKER);
1168            marker.setAttributes(
1169                new String JavaDoc[] {
1170                        IMarker.MESSAGE,
1171                        IMarker.SEVERITY,
1172                        IMarker.LOCATION},
1173                    new Object JavaDoc[] {
1174                        message,
1175                        new Integer JavaDoc(severity),
1176                        LaunchingMessages.LaunchingPlugin_37
1177                    });
1178        } catch (CoreException e) {
1179            return;
1180        }
1181    }
1182}
1183
1184 
1185
Popular Tags