001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.launching.environments;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.IOException;
014: import java.util.ArrayList;
015: import java.util.Collection;
016: import java.util.HashMap;
017: import java.util.List;
018: import java.util.Map;
019:
020: import javax.xml.parsers.DocumentBuilder;
021:
022: import org.eclipse.core.runtime.CoreException;
023: import org.eclipse.core.runtime.IConfigurationElement;
024: import org.eclipse.core.runtime.IExtensionPoint;
025: import org.eclipse.core.runtime.IProgressMonitor;
026: import org.eclipse.core.runtime.NullProgressMonitor;
027: import org.eclipse.core.runtime.Platform;
028: import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
029: import org.eclipse.debug.core.DebugPlugin;
030: import org.eclipse.jdt.internal.launching.LaunchingPlugin;
031: import org.eclipse.jdt.launching.IVMInstall;
032: import org.eclipse.jdt.launching.IVMInstallChangedListener;
033: import org.eclipse.jdt.launching.IVMInstallType;
034: import org.eclipse.jdt.launching.JavaRuntime;
035: import org.eclipse.jdt.launching.PropertyChangeEvent;
036: import org.eclipse.jdt.launching.VMStandin;
037: import org.eclipse.jdt.launching.environments.CompatibleEnvironment;
038: import org.eclipse.jdt.launching.environments.IAccessRuleParticipant;
039: import org.eclipse.jdt.launching.environments.IExecutionEnvironment;
040: import org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager;
041: import org.w3c.dom.Document;
042: import org.w3c.dom.Element;
043: import org.w3c.dom.Node;
044: import org.w3c.dom.NodeList;
045: import org.xml.sax.SAXException;
046:
047: import com.ibm.icu.text.MessageFormat;
048:
049: /**
050: * Utility class for execution environments.
051: *
052: * @since 3.2
053: */
054: public class EnvironmentsManager implements
055: IExecutionEnvironmentsManager, IVMInstallChangedListener,
056: IPropertyChangeListener {
057:
058: /**
059: * Extension configuration element name.
060: */
061: private static final String ANALYZER_ELEMENT = "analyzer"; //$NON-NLS-1$
062:
063: /**
064: * Extension configuration element name.
065: */
066: static final String ENVIRONMENT_ELEMENT = "environment"; //$NON-NLS-1$
067:
068: /**
069: * Extension configuration element name.
070: */
071: static final String RULE_PARTICIPANT_ELEMENT = "ruleParticipant"; //$NON-NLS-1$
072:
073: private static EnvironmentsManager fgManager = null;
074:
075: /**
076: * Preference store key for XML storing default environments.
077: */
078: private static final String PREF_DEFAULT_ENVIRONMENTS_XML = "org.eclipse.jdt.launching.PREF_DEFAULT_ENVIRONMENTS_XML"; //$NON-NLS-1$
079:
080: /**
081: * List of environments
082: */
083: private List fEnvironments = null;
084:
085: /**
086: * List of access rule participants
087: */
088: private List fRuleParticipants = null;
089:
090: /**
091: * Map of environments keyed by id
092: */
093: private Map fEnvironmentsMap = null;
094:
095: /**
096: * Map of analyzers keyed by id
097: */
098: private Map fAnalyzers = null;
099:
100: /**
101: * <code>true</code> while updating the default settings pref
102: */
103: private boolean fIsUpdatingDefaults = false;
104:
105: /**
106: * Whether compatibile environnments have been initialized
107: */
108: private boolean fInitializedCompatibilities = false;
109:
110: /**
111: * XML attribute
112: */
113: private static final String VM_ID = "vmId"; //$NON-NLS-1$
114:
115: /**
116: * XML attribute
117: */
118: private static final String ENVIRONMENT_ID = "environmentId"; //$NON-NLS-1$
119:
120: /**
121: * XML element
122: */
123: private static final String DEFAULT_ENVIRONMENT = "defaultEnvironment"; //$NON-NLS-1$
124:
125: /**
126: * XML document
127: */
128: private static final String DEFAULT_ENVIRONMENTS = "defaultEnvironments"; //$NON-NLS-1$
129:
130: /**
131: * Returns the singleton environments manager.
132: *
133: * @return environments manager
134: */
135: public static EnvironmentsManager getDefault() {
136: if (fgManager == null) {
137: fgManager = new EnvironmentsManager();
138: }
139: return fgManager;
140: }
141:
142: /**
143: * Constructs the new manager.
144: */
145: private EnvironmentsManager() {
146: JavaRuntime.addVMInstallChangedListener(this );
147: LaunchingPlugin.getDefault().getPluginPreferences()
148: .addPropertyChangeListener(this );
149: }
150:
151: /* (non-Javadoc)
152: * @see org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager#getExecutionEnvironments()
153: */
154: public synchronized IExecutionEnvironment[] getExecutionEnvironments() {
155: initializeExtensions();
156: return (IExecutionEnvironment[]) fEnvironments
157: .toArray(new IExecutionEnvironment[fEnvironments.size()]);
158: }
159:
160: /**
161: * Returns all access rule participants that are not specific to an execution environment.
162: *
163: * @return all access rule participants that are not specific to an execution environment.
164: * @since 3.3
165: */
166: public synchronized IAccessRuleParticipant[] getAccessRuleParticipants() {
167: initializeExtensions();
168: return (IAccessRuleParticipant[]) fRuleParticipants
169: .toArray(new IAccessRuleParticipant[fRuleParticipants
170: .size()]);
171: }
172:
173: /* (non-Javadoc)
174: * @see org.eclipse.jdt.launching.environments.IExecutionEnvironmentsManager#getEnvironment(java.lang.String)
175: */
176: public synchronized IExecutionEnvironment getEnvironment(String id) {
177: initializeExtensions();
178: return (IExecutionEnvironment) fEnvironmentsMap.get(id);
179: }
180:
181: /**
182: * Returns all registered analyzers
183: *
184: * @return
185: */
186: public synchronized Analyzer[] getAnalyzers() {
187: initializeExtensions();
188: Collection collection = fAnalyzers.values();
189: return (Analyzer[]) collection.toArray(new Analyzer[collection
190: .size()]);
191: }
192:
193: private synchronized void initializeExtensions() {
194: if (fEnvironments == null) {
195: IExtensionPoint extensionPoint = Platform
196: .getExtensionRegistry()
197: .getExtensionPoint(
198: LaunchingPlugin.ID_PLUGIN,
199: JavaRuntime.EXTENSION_POINT_EXECUTION_ENVIRONMENTS);
200: IConfigurationElement[] configs = extensionPoint
201: .getConfigurationElements();
202: fEnvironments = new ArrayList();
203: fRuleParticipants = new ArrayList();
204: fEnvironmentsMap = new HashMap(configs.length);
205: fAnalyzers = new HashMap(configs.length);
206: for (int i = 0; i < configs.length; i++) {
207: IConfigurationElement element = configs[i];
208: String name = element.getName();
209: if (name.equals(ENVIRONMENT_ELEMENT)) {
210: String id = element.getAttribute("id"); //$NON-NLS-1$
211: if (id == null) {
212: LaunchingPlugin
213: .log(MessageFormat
214: .format(
215: "Execution environment must specify \"id\" attribute. Contributed by {0}.", new String[] { element.getContributor().getName() })); //$NON-NLS-1$
216: } else {
217: IExecutionEnvironment env = new ExecutionEnvironment(
218: element);
219: fEnvironments.add(env);
220: fEnvironmentsMap.put(id, env);
221: }
222: } else if (name.equals(ANALYZER_ELEMENT)) {
223: String id = element.getAttribute("id"); //$NON-NLS-1$
224: if (id == null) {
225: LaunchingPlugin
226: .log(MessageFormat
227: .format(
228: "Execution environment analyzer must specify \"id\" attribute. Contributed by {0}", new String[] { element.getContributor().getName() })); //$NON-NLS-1$
229: } else {
230: fAnalyzers.put(id, new Analyzer(element));
231: }
232: } else if (name.equals(RULE_PARTICIPANT_ELEMENT)) {
233: String id = element.getAttribute("id"); //$NON-NLS-1$
234: if (id == null) {
235: LaunchingPlugin
236: .log(MessageFormat
237: .format(
238: "Execution environment rule participant must specify \"id\" attribute. Contributed by {0}", new String[] { element.getContributor().getName() })); //$NON-NLS-1$
239: } else {
240: fRuleParticipants
241: .add(new AccessRuleParticipant(element));
242: }
243: }
244: }
245: }
246: }
247:
248: /**
249: * Initializes compatibility settings.
250: */
251: void initializeCompatibilities() {
252: IVMInstallType[] installTypes = JavaRuntime.getVMInstallTypes();
253: synchronized (this ) {
254: if (!fInitializedCompatibilities) {
255: fInitializedCompatibilities = true;
256: for (int i = 0; i < installTypes.length; i++) {
257: IVMInstallType type = installTypes[i];
258: IVMInstall[] installs = type.getVMInstalls();
259: for (int j = 0; j < installs.length; j++) {
260: IVMInstall install = installs[j];
261: // TODO: progress reporting?
262: analyze(install, new NullProgressMonitor());
263: }
264: }
265: initializeDefaultVMs();
266: }
267: }
268: }
269:
270: /**
271: * Reads persisted default VMs from pref store
272: */
273: private synchronized void initializeDefaultVMs() {
274: String xml = LaunchingPlugin.getDefault()
275: .getPluginPreferences().getString(
276: PREF_DEFAULT_ENVIRONMENTS_XML);
277: try {
278: if (xml.length() > 0) {
279: DocumentBuilder parser = LaunchingPlugin.getParser();
280:
281: Document document = parser
282: .parse(new ByteArrayInputStream(xml.getBytes()));
283: Element envs = document.getDocumentElement();
284: NodeList list = envs.getChildNodes();
285: int length = list.getLength();
286: for (int i = 0; i < length; ++i) {
287: Node node = list.item(i);
288: short type = node.getNodeType();
289: if (type == Node.ELEMENT_NODE) {
290: Element element = (Element) node;
291: if (element.getNodeName().equals(
292: DEFAULT_ENVIRONMENT)) {
293: String envId = element
294: .getAttribute(ENVIRONMENT_ID);
295: String vmId = element.getAttribute(VM_ID);
296: ExecutionEnvironment environment = (ExecutionEnvironment) getEnvironment(envId);
297: if (environment != null) {
298: IVMInstall vm = JavaRuntime
299: .getVMFromCompositeId(vmId);
300: if (vm != null) {
301: environment.initDefaultVM(vm);
302: }
303: }
304: }
305: }
306: }
307: }
308: } catch (CoreException e) {
309: LaunchingPlugin.log(e);
310: } catch (SAXException e) {
311: LaunchingPlugin.log(e);
312: } catch (IOException e) {
313: LaunchingPlugin.log(e);
314: }
315: }
316:
317: /**
318: * Returns an XML description of default VMs per environment. Returns
319: * an empty string when there are none.
320: */
321: private String getDefatulVMsAsXML() {
322: int count = 0;
323: try {
324: Document doc = DebugPlugin.newDocument();
325: Element envs = doc.createElement(DEFAULT_ENVIRONMENTS);
326: doc.appendChild(envs);
327: IExecutionEnvironment[] environments = getExecutionEnvironments();
328: for (int i = 0; i < environments.length; i++) {
329: IExecutionEnvironment env = environments[i];
330: IVMInstall vm = env.getDefaultVM();
331: if (vm != null) {
332: count++;
333: Element element = doc
334: .createElement(DEFAULT_ENVIRONMENT);
335: element.setAttribute(ENVIRONMENT_ID, env.getId());
336: element.setAttribute(VM_ID, JavaRuntime
337: .getCompositeIdFromVM(vm));
338: envs.appendChild(element);
339: }
340: }
341: if (count > 0) {
342: return DebugPlugin.serializeDocument(doc);
343: }
344: } catch (CoreException e) {
345: LaunchingPlugin.log(e);
346: }
347: return ""; //$NON-NLS-1$
348: }
349:
350: /**
351: * Analyzes and compatible execution environments for the given vm install.
352: *
353: * @param vm
354: * @param monitor
355: */
356: private void analyze(IVMInstall vm, IProgressMonitor monitor) {
357: Analyzer[] analyzers = getAnalyzers();
358: for (int i = 0; i < analyzers.length; i++) {
359: Analyzer analyzer = analyzers[i];
360: try {
361: CompatibleEnvironment[] environments = analyzer
362: .analyze(vm, monitor);
363: for (int j = 0; j < environments.length; j++) {
364: CompatibleEnvironment compatibleEnvironment = environments[j];
365: ExecutionEnvironment environment = (ExecutionEnvironment) compatibleEnvironment
366: .getCompatibleEnvironment();
367: environment.add(vm, compatibleEnvironment
368: .isStrictlyCompatbile());
369: }
370: } catch (CoreException e) {
371: LaunchingPlugin.log(e);
372: }
373: }
374: }
375:
376: /* (non-Javadoc)
377: * @see org.eclipse.jdt.launching.IVMInstallChangedListener#defaultVMInstallChanged(org.eclipse.jdt.launching.IVMInstall, org.eclipse.jdt.launching.IVMInstall)
378: */
379: public void defaultVMInstallChanged(IVMInstall previous,
380: IVMInstall current) {
381: // nothing
382: }
383:
384: /* (non-Javadoc)
385: * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmChanged(org.eclipse.jdt.launching.PropertyChangeEvent)
386: */
387: public synchronized void vmChanged(PropertyChangeEvent event) {
388: IVMInstall vm = (IVMInstall) event.getSource();
389: if (vm instanceof VMStandin) {
390: return;
391: }
392: vmRemoved(vm);
393: vmAdded(vm);
394: }
395:
396: /* (non-Javadoc)
397: * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmAdded(org.eclipse.jdt.launching.IVMInstall)
398: */
399: public synchronized void vmAdded(IVMInstall vm) {
400: // TODO: progress reporting?
401: if (vm instanceof VMStandin) {
402: return;
403: }
404: analyze(vm, new NullProgressMonitor());
405: }
406:
407: /* (non-Javadoc)
408: * @see org.eclipse.jdt.launching.IVMInstallChangedListener#vmRemoved(org.eclipse.jdt.launching.IVMInstall)
409: */
410: public synchronized void vmRemoved(IVMInstall vm) {
411: if (vm instanceof VMStandin) {
412: return;
413: }
414: IExecutionEnvironment[] environments = getExecutionEnvironments();
415: for (int i = 0; i < environments.length; i++) {
416: ExecutionEnvironment environment = (ExecutionEnvironment) environments[i];
417: environment.remove(vm);
418: }
419: }
420:
421: synchronized void updateDefaultVMs() {
422: try {
423: fIsUpdatingDefaults = true;
424: LaunchingPlugin.getDefault().getPluginPreferences()
425: .setValue(PREF_DEFAULT_ENVIRONMENTS_XML,
426: getDefatulVMsAsXML());
427: } finally {
428: fIsUpdatingDefaults = false;
429: }
430: }
431:
432: /* (non-Javadoc)
433: * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)
434: */
435: public synchronized void propertyChange(
436: org.eclipse.core.runtime.Preferences.PropertyChangeEvent event) {
437: // don't respond to myself
438: if (fIsUpdatingDefaults) {
439: return;
440: }
441: if (event.getProperty().equals(PREF_DEFAULT_ENVIRONMENTS_XML)) {
442: initializeDefaultVMs();
443: }
444: }
445:
446: }
|