/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.editor.js; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.TextAttribute; import org.osgi.framework.Bundle; import com.aptana.ide.core.FileUtils; import com.aptana.ide.core.IdeLog; import com.aptana.ide.core.StringUtils; import com.aptana.ide.core.ui.CoreUIUtils; import com.aptana.ide.editor.js.environment.LexemeBasedEnvironmentLoader; import com.aptana.ide.editor.js.parsing.JSMimeType; import com.aptana.ide.editor.js.parsing.JSParseState; import com.aptana.ide.editor.js.preferences.IPreferenceConstants; import com.aptana.ide.editor.js.runtime.Environment; import com.aptana.ide.editor.js.runtime.FunctionBase; import com.aptana.ide.editor.js.runtime.IObject; import com.aptana.ide.editor.js.runtime.JSFunction; import com.aptana.ide.editor.js.runtime.JSObjectConstructor; import com.aptana.ide.editor.js.runtime.ObjectBase; import com.aptana.ide.editor.js.runtime.Property; import com.aptana.ide.editor.js.runtime.Reference; import com.aptana.ide.editor.scriptdoc.parsing.FunctionDocumentation; import com.aptana.ide.editor.scriptdoc.parsing.ScriptDocMimeType; import com.aptana.ide.editor.scriptdoc.parsing.reader.NativeObjectsReader; import com.aptana.ide.editor.scriptdoc.parsing.reader.NativeObjectsReader2; import com.aptana.ide.editors.UnifiedEditorsPlugin; import com.aptana.ide.editors.managers.EnvironmentManager; import com.aptana.ide.editors.managers.FileContextManager; import com.aptana.ide.editors.unified.FileService; import com.aptana.ide.editors.unified.IFileLanguageService; import com.aptana.ide.editors.unified.ILanguageEnvironment; import com.aptana.ide.editors.unified.LanguageRegistry; import com.aptana.ide.lexer.Range; import com.aptana.ide.metadata.IDocumentation; import com.aptana.ide.parsing.IParser; import com.aptana.ide.parsing.IRuntimeEnvironment; /** * Initializes the JavaScript environment * * @author Robin Debreuil */ public class JSLanguageEnvironment implements ILanguageEnvironment { /* * Fields */ private static ILanguageEnvironment instance; private Environment environment; private ObjectBase global; private boolean isEnvironmentLoaded = false; /** * SCRIPTDOC_ID */ public static final String SCRIPTDOC_ID = "scriptdoc"; //$NON-NLS-1$ /** * TAG_BINARY_FILE */ public static final String TAG_BINARY_FILE = "binary-file"; //$NON-NLS-1$ /** * TAG_JS_FILE */ public static final String TAG_JS_FILE = "js-file"; //$NON-NLS-1$ /** * TAG_XML_FILE */ public static final String TAG_XML_FILE = "xml-file"; //$NON-NLS-1$ /** * ATTR_FILE_PATH */ public static final String ATTR_FILE_PATH = "path"; //$NON-NLS-1$ /** * ATTR_USER_AGENT */ public static final String ATTR_USER_AGENT = "user-agent"; //$NON-NLS-1$ /** * ATTR_ICON */ public static final String ATTR_ICON = "icon"; //$NON-NLS-1$ /** * ATTR_LOAD */ public static final String ATTR_LOAD = "load"; //$NON-NLS-1$ /** * JS_CORE */ public static final String JS_CORE = "JS Core"; //$NON-NLS-1$ /** * DOM_5 */ public static final String DOM_5 = "DOM 5"; //$NON-NLS-1$ /** * DOM_3 */ public static final String DOM_3 = "DOM 3"; //$NON-NLS-1$ /** * DOM_1_2 */ public static final String DOM_1_2 = "DOM 1 & 2"; //$NON-NLS-1$ /** * DOM_0 */ public static final String DOM_0 = "DOM 0"; //$NON-NLS-1$ /** * SLEEP_DELAY */ public static int SLEEP_DELAY = 2000; /** * True if we wish to include default js objects in the environment (turn off for debugging). */ public static boolean includeCore = false; /** * True if we wish to include default DOM0 objects in the environment (turn off for debugging). */ public static boolean includeHtml0 = false; /** * True if we wish to include default DOM1&2 objects in the environment (turn off for debugging). */ public static boolean includeHtml12 = false; /** * True if we wish to include default DOM3 objects in the environment (turn off for debugging). */ public static boolean includeHtml3 = false; /** * True if we wish to include default DOM5 objects in the environment (turn off for debugging). */ public static boolean includeHtml5 = false; private IObject undef = ObjectBase.UNDEFINED; /* * Constructors */ /** * JSLanguageEnvironment */ JSLanguageEnvironment() { isEnvironmentLoaded = false; initEnvironment(); EnvironmentManager.addEnvironmentMapping(JSMimeType.MimeType, environment); EnvironmentManager.addEnvironmentMapping(ScriptDocMimeType.MimeType, environment); } /** * Rebuild the JavaScript environment */ public static void rebuildEnvironment() { if (instance != null) { ((JSLanguageEnvironment) instance).buildEnvironment(); EnvironmentManager.addEnvironmentMapping(JSMimeType.MimeType, getInstance().getRuntimeEnvironment()); EnvironmentManager.addEnvironmentMapping(ScriptDocMimeType.MimeType, getInstance().getRuntimeEnvironment()); } } /** * Resets the JavaScript environment with profiles considered as well */ public static void resetEnvironment() { if (instance != null) { rebuildEnvironment(); JSLanguageEnvironment.getInstance().cleanEnvironment(); UnifiedEditorsPlugin.getDefault().getProfileManager().addLanguageSupport(JSMimeType.MimeType, JSLanguageEnvironment.getInstance(), null); UnifiedEditorsPlugin.getDefault().getProfileManager().onUpdaterThreadUpdate(); } } /* * Methods */ /** * @see com.aptana.ide.editors.unified.ILanguageEnvironment#getRuntimeEnvironment() */ public IRuntimeEnvironment getRuntimeEnvironment() { return environment; } /** * Gets specifically the JSEnvironment, rather than needing a cast on getEnvironment * * @return JS Environment */ public Environment getJSEnvironment() { return environment; } private void buildEnvironment() { isEnvironmentLoaded = false; global = environment.initBuiltInObjects(); loadEnvironment(); } private void initEnvironment() { // create javascript environment environment = new Environment(); global = environment.initBuiltInObjects(); Thread t = new Thread(new Runnable() { public void run() { try { Thread.sleep(SLEEP_DELAY); loadEnvironment(); } catch (Exception e1) { IdeLog.logInfo(JSPlugin.getDefault(), "initEnvironment aborted", e1); //$NON-NLS-1$ } } }, "Aptana: JS Language Environment Loader"); //$NON-NLS-1$ t.setPriority(Thread.MIN_PRIORITY); t.setDaemon(true); t.start(); } /** * getInstance * * @return JSLanguageEnvironment */ public static ILanguageEnvironment getInstance() { if (instance == null) { instance = new JSLanguageEnvironment(); } return instance; } // /** // * getDocumentationManager // * // * @return DocumentationManager // */ // public DocumentationManager getDocumentationManager() // { // return documentationManager; // } /** * @see com.aptana.ide.editors.unified.ILanguageEnvironment#cleanEnvironment() */ public void cleanEnvironment() { synchronized (this) { String[] keys = FileContextManager.getKeySet(); for (int i = 0; i < keys.length; i++) { String path = keys[i]; FileService fileService = FileContextManager.get(path); if (fileService != null) { // [RD] this must also delete the languages held inside it IFileLanguageService jsfs = fileService.getLanguageService(JSMimeType.MimeType); if (jsfs != null) { jsfs.reset(false); } JSFileLanguageService languageService = JSFileLanguageService.getJSFileLanguageService(fileService); if (languageService != null) { languageService.reset(false); } } else { // This appears to happen on shutdown. May be an error IdeLog.logError(JSPlugin.getDefault(), StringUtils.format( Messages.JSLanguageEnvironment_FileServiceNull, path)); } // clears the doc @id mappings synchronized (environment) { // clears out the properties added via orphaned @id props (docs with no mapped object) Map idProps = EnvironmentManager.getDocumentationRefMap(); Iterator props = idProps.values().iterator(); while (props.hasNext()) { Object o = props.next(); Reference reference = (Reference) o; String propertyName = reference.getPropertyName(); IObject parentObject = reference.getObjectBase(); parentObject.deletePropertyName(propertyName); } idProps.clear(); EnvironmentManager.getDocumentationIdMap().clear(); } } } } /** * @see com.aptana.ide.editors.unified.ILanguageEnvironment#loadEnvironment() */ public void loadEnvironment() { if (isEnvironmentLoaded) { return; } isEnvironmentLoaded = true; Map<String, TextAttribute> htmlIdents = JSColorizer.htmlIdents; Map<String, TextAttribute> jsCoreIdents = JSColorizer.jsCoreIdents; ObjectBase gb = global; Environment env = environment; // load documentation // create native objects documentation reader NativeObjectsReader reader = new NativeObjectsReader(env); // load core objects and documentation into our JavaScript environment try { int fileIndex = FileContextManager.BUILT_IN_FILE_INDEX; int offset = Range.Empty.getStartingOffset(); String[] envs = getLoadedEnvironments(); includeHtml5 = false; includeHtml3 = false; includeHtml12 = false; includeHtml0 = false; for (int i = 0; i < envs.length; i++) { if (DOM_5.equals(envs[i])) { includeHtml5 = true; } if (DOM_3.equals(envs[i])) { includeHtml3 = true; } if (DOM_1_2.equals(envs[i])) { includeHtml12 = true; } else if (DOM_0.equals(envs[i])) { includeHtml0 = true; } } // Always include core since removing affects other js libraries from loading includeCore = true; gb.putPropertyValue("this", gb, fileIndex, Property.DONT_DELETE | Property.DONT_ENUM); //$NON-NLS-1$ if (includeCore) { // get core JavaScript documentation // InputStream jsIn = // reader.getClass().getResourceAsStream("/com/aptana/ide/editor/js/resources/js_core.xml"); InputStream jsIn = this.getClass().getResourceAsStream("/com/aptana/ide/editor/js/parsing/js_core.bin"); //$NON-NLS-1$ // load core JS documentation // try{reader.loadXML(jsIn, false);}catch (Exception e){} reader.setUserAgent(JS_CORE); //$NON-NLS-1$ reader.load(jsIn, false); jsCoreIdents.putAll(reader.getNames()); // GenJSStubsFromXml.generate("C:/jsStubs.js", jsIn); // close the input stream jsIn.close(); // add a prototype property to global JSObjectConstructor gObj = (JSObjectConstructor) gb.getPropertyValue("Object", fileIndex, offset); //$NON-NLS-1$ IObject newobj = gObj.construct(env, FunctionBase.EmptyArgs, fileIndex, Range.Empty); gb.putPropertyValue("prototype", newobj, fileIndex, Property.DONT_DELETE | Property.DONT_ENUM); //$NON-NLS-1$ gb.setPrototype(gb.getPropertyValue("prototype", fileIndex, offset)); //$NON-NLS-1$ } if (includeHtml0) { // add html base // window is the gb object gb.putPropertyValue("window", gb, fileIndex, Property.DONT_DELETE | Property.DONT_ENUM); //$NON-NLS-1$ // we must make sure the "Window" class puts its members on global gb.putPropertyValue("Window", gb, fileIndex, Property.DONT_DELETE | Property.DONT_ENUM //$NON-NLS-1$ | Property.INTERNAL | Property.NOT_VISIBLE); // IObject winProt = gb.getPropertyValue("Window", fileIndex, offset).getPropertyValue("prototype", // fileIndex, offset); // gb.setPrototype(winProt); // get core HTML documentation // InputStream dom0 = // reader.getClass().getResourceAsStream("/com/aptana/ide/editor/js/resources/dom_0.xml"); InputStream dom0 = this.getClass().getResourceAsStream("/com/aptana/ide/editor/js/parsing/dom_0.bin"); //$NON-NLS-1$ // load core JS documentation // try{reader.loadXML(dom0, true);}catch (Exception e){} reader.setUserAgent("DOM 0"); //$NON-NLS-1$ reader.load(dom0, true); // add names for code assist htmlIdents.putAll(reader.getNames()); // close the input stream dom0.close(); htmlIdents.put("window", null); //$NON-NLS-1$ } if (includeHtml12) { // get core HTML documentation // InputStream dom2 = // reader.getClass().getResourceAsStream("/com/aptana/ide/editor/js/resources/dom_2.xml"); InputStream dom2 = this.getClass().getResourceAsStream("/com/aptana/ide/editor/js/parsing/dom_2.bin"); //$NON-NLS-1$ // load core JS documentation // try{reader.loadXML(dom2, true);}catch (Exception e){} reader.setUserAgent(DOM_1_2); //$NON-NLS-1$ reader.load(dom2, true); htmlIdents.putAll(reader.getNames()); // close the input stream dom2.close(); IObject hdoc = gb.getPropertyValue("HTMLDocument", fileIndex, offset); //$NON-NLS-1$ if (hdoc != undef) { JSFunction htmldocFn = (JSFunction) hdoc; IObject doc = htmldocFn.construct(env, FunctionBase.EmptyArgs, fileIndex, Range.Empty); // win.attributedPut("Document", doc, Property.DONT_DELETE | Property.DONT_ENUM); gb.putPropertyValue("document", doc, fileIndex, Property.DONT_DELETE | Property.DONT_ENUM); //$NON-NLS-1$ // Not sure why these were here, probably to manually hook up the prototype before the docs were // set // (docs used to be double defined) - keep in to watch for issues on 'document', but seems to // work/ // IObject docClassProto = gb.getPropertyValue("Document", fileIndex, // offset).getPropertyValue("prototype", fileIndex, offset); // doc.setPrototype(docClassProto); // set docs manually ((FunctionDocumentation) htmldocFn.getDocumentation()).setIsInstance(true); doc.setDocumentation(htmldocFn.getDocumentation()); } htmlIdents.put("document", null); //$NON-NLS-1$ } if (includeHtml3) { // get core DOM 3 documentation InputStream dom3 = this.getClass().getResourceAsStream("/com/aptana/ide/editor/js/parsing/dom_3.bin"); //$NON-NLS-1$ // load core JS documentation reader.setUserAgent(DOM_3); //$NON-NLS-1$ reader.load(dom3, true); htmlIdents.putAll(reader.getNames()); // close the input stream dom3.close(); } if (includeHtml5) { // get core DOM 5 documentation InputStream dom5 = this.getClass().getResourceAsStream("/com/aptana/ide/editor/js/parsing/dom_5.bin"); //$NON-NLS-1$ // load core JS documentation reader.setUserAgent(DOM_5); //$NON-NLS-1$ reader.load(dom5, true); htmlIdents.putAll(reader.getNames()); // close the input stream dom5.close(); } try { loadContributedFiles(); } catch (Exception e) { IdeLog.logInfo(JSPlugin.getDefault(), Messages.JSLanguageEnvironment_ErrorLoadingEnvironment, e); } } catch (IOException e) { IdeLog.logInfo(JSPlugin.getDefault(), Messages.JSLanguageEnvironment_ErrorLoadingEnvironment, e); } } /** * Enables a particular environment * * @param environmentName */ public static void enableEnvironment(String environmentName) { IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); String[] envsToLoad = getEnabledEnvironments(); String[] envsToDisable = getDisabledEnvironments(); Set<String> envs = new HashSet<String>(); envs.addAll(Arrays.asList(envsToLoad)); Set<String> disabledEnvs = new HashSet<String>(); disabledEnvs.addAll(Arrays.asList(envsToDisable)); if (!envs.contains(environmentName)) { envs.add(environmentName); } if (disabledEnvs.contains(environmentName)) { disabledEnvs.remove(environmentName); } store.setValue(IPreferenceConstants.LOADED_ENVIRONMENTS, StringUtils.join(",", envs.toArray(new String[0]))); //$NON-NLS-1$ store.setValue(IPreferenceConstants.DISABLED_ENVIRONMENTS, StringUtils.join(",", disabledEnvs //$NON-NLS-1$ .toArray(new String[0]))); } /** * Disables a particular environment * * @param environmentName */ public static void disableEnvironment(String environmentName) { IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); String[] envsToLoad = getEnabledEnvironments(); String[] envsToDisable = getDisabledEnvironments(); Set<String> envs = new HashSet<String>(); envs.addAll(Arrays.asList(envsToLoad)); Set<String> disabledEnvs = new HashSet<String>(); disabledEnvs.addAll(Arrays.asList(envsToDisable)); if (envs.contains(environmentName)) { envs.remove(environmentName); } if (!disabledEnvs.contains(environmentName)) { disabledEnvs.add(environmentName); } store.setValue(IPreferenceConstants.LOADED_ENVIRONMENTS, StringUtils.join(",", envs.toArray(new String[0]))); //$NON-NLS-1$ store.setValue(IPreferenceConstants.DISABLED_ENVIRONMENTS, StringUtils.join(",", disabledEnvs //$NON-NLS-1$ .toArray(new String[0]))); } /** * Returns the list of environments to load * * @return - loaded environments ids */ public static String[] getLoadedEnvironments() { // loaded envs are all envs specified in preference store + items marked // as load by default that are not marked as disabled. String[] loaded = getEnabledEnvironments(); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Enabled_environments, StringUtils.join(",", //$NON-NLS-1$ loaded))); Set<String> envs = new HashSet<String>(); envs.addAll(Arrays.asList(loaded)); String[] defaults = getDefaultLoadedEnvironments(); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Default_loaded_environments, StringUtils.join( ",", defaults))); //$NON-NLS-1$ envs.addAll(Arrays.asList(defaults)); String[] disabled = getDisabledEnvironments(); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Disabled_environments, StringUtils.join(",", //$NON-NLS-1$ disabled))); envs.removeAll(Arrays.asList(disabled)); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Resulting_set, StringUtils.join(",", envs //$NON-NLS-1$ .toArray(new String[0])))); return envs.toArray(new String[0]); } /** * gets the list of enabled environments * * @return - enabled environment ids */ public static String[] getEnabledEnvironments() { String envsToLoad = JSPlugin.getDefault().getPreferenceStore().getString( IPreferenceConstants.LOADED_ENVIRONMENTS); if (envsToLoad != null) { return envsToLoad.split(","); //$NON-NLS-1$ } else { return new String[0]; } } /** * gets the list of enabled environments * * @return - disabled environment ids */ public static String[] getDisabledEnvironments() { String envsToDisable = JSPlugin.getDefault().getPreferenceStore().getString( IPreferenceConstants.DISABLED_ENVIRONMENTS); if (envsToDisable != null) { return envsToDisable.split(","); //$NON-NLS-1$ } else { return new String[0]; } } /** * Sets the list of currently enabled environments * * @param environments */ public static void setEnabledEnvironments(String[] environments) { String env = StringUtils.join(",", environments); //$NON-NLS-1$ IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); store.setValue(IPreferenceConstants.LOADED_ENVIRONMENTS, env); } /** * Sets the list of currently disabled environments * * @param environments */ public static void setDisabledEnvironments(String[] environments) { String env = StringUtils.join(",", environments); //$NON-NLS-1$ IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); store.setValue(IPreferenceConstants.DISABLED_ENVIRONMENTS, env); } /** * Adds a user environment that is an absolute path to a file on disk * * @param toAdd */ public static void addUserEnvironment(String toAdd) { IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); String value = store.getString(IPreferenceConstants.ADDED_ENVIRONMENTS); value += "," + toAdd; //$NON-NLS-1$ store.setValue(IPreferenceConstants.ADDED_ENVIRONMENTS, value); } /** * Removes a user environment for the given absolute path * * @param toRemove */ public static void removeUserEnvironment(String toRemove) { String[] envs = getUserAddedJSEnvironments(); List<String> newEnvs = new ArrayList<String>(); for (int i = 0; i < envs.length; i++) { if (!envs[i].equals(toRemove) && !newEnvs.contains(envs[i])) { newEnvs.add(envs[i]); } } String toSet = StringUtils.join(",", newEnvs.toArray(new String[0])); //$NON-NLS-1$ IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); store.setValue(IPreferenceConstants.ADDED_ENVIRONMENTS, toSet); } /** * Gets the list of absolute paths to global reference files on disk * * @return - array of string absolute paths */ public static String[] getUserAddedJSEnvironments() { IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); String jsEnv = store.getString(IPreferenceConstants.ADDED_ENVIRONMENTS); return jsEnv.split(","); //$NON-NLS-1$ } /** * Returns the list of environments to load * * @return - default environments ids */ public static String[] getDefaultLoadedEnvironments() { // If preference is default, then automatically add in any items marked as // "load" from extension point. Otherwise, just use preset list. String defaultEnvsToLoad = JSPlugin.getDefault().getPreferenceStore().getDefaultString( IPreferenceConstants.LOADED_ENVIRONMENTS); List<String> list = new ArrayList<String>(); String[] envs = defaultEnvsToLoad.split(","); //$NON-NLS-1$ list.addAll(Arrays.asList(envs)); envs = getLoadedEnvironmentsFromExtension(TAG_BINARY_FILE); list.addAll(Arrays.asList(envs)); envs = getLoadedEnvironmentsFromExtension(TAG_XML_FILE); list.addAll(Arrays.asList(envs)); envs = getLoadedEnvironmentsFromExtension(TAG_JS_FILE); list.addAll(Arrays.asList(envs)); return list.toArray(new String[0]); } private void addContributedXML(NativeObjectsReader2 reader, URL key, String userAgent) { if (userAgent != null) { reader.setUserAgent(userAgent); } try { reader.loadXML(key.openStream()); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Loaded_environment, key.toExternalForm())); } catch (Exception e) { IdeLog.logError(JSPlugin.getDefault(), Messages.JSLanguageEnvironment_ErrorLoadingEnvironment, e); } } private void addContributedBinary(NativeObjectsReader2 reader, URL key, String userAgent) { if (userAgent != null) { reader.setUserAgent(userAgent); } try { reader.load(key.openStream()); IdeLog.logInfo(JSPlugin.getDefault(), StringUtils.format(Messages.JSLanguageEnvironment_INF_Loaded_environment, key.toExternalForm())); } catch (Exception e) { IdeLog.logError(JSPlugin.getDefault(), Messages.JSLanguageEnvironment_ErrorLoadingEnvironment, e); } } private void addContributedJS(URL key, String userAgent) { if (!DOM_5.equals(userAgent) && !DOM_3.equals(userAgent) && !DOM_1_2.equals(userAgent) && !DOM_0.equals(userAgent)) { try { key = FileLocator.toFileURL(key); } catch (IOException e) { } // Load js file String path = CoreUIUtils.getPathFromURI(key.getFile()); String source; try { source = FileUtils.readContent(new File(path)); IParser parser = LanguageRegistry.getParser(JSMimeType.MimeType); JSParseState parseState = (JSParseState) parser.createParseState(null); parseState.setEditState(source, source, 0, 0); parseState.setFileIndex(FileContextManager.CURRENT_FILE_INDEX); parser.parse(parseState); LexemeBasedEnvironmentLoader loader = new LexemeBasedEnvironmentLoader(this.environment); loader.reloadEnvironment(parseState); IDocumentation[] docs = parseState.getDocumentationStore().getDocumentationObjects(); if (docs != null) { for (int i = 0; i < docs.length; i++) { docs[i].setUserAgent(userAgent); } } IdeLog.logInfo(JSPlugin.getDefault(), StringUtils .format(Messages.JSLanguageEnvironment_INF_Loaded_environment, key.toExternalForm())); } catch (Exception e) { IdeLog.logError(JSPlugin.getDefault(), StringUtils.format( Messages.JSLanguageEnvironment_ERR_Loading_contributed_javascript_file, key.toExternalForm()), e); } } } /** * loadContributedFiles Loads the files contributed via an extension point */ private void loadContributedFiles() { Map<URL, String> xmlFiles = new Hashtable<URL, String>(); addFromExtension(xmlFiles, TAG_XML_FILE); NativeObjectsReader2 reader = new NativeObjectsReader2(environment); Set<URL> keys = xmlFiles.keySet(); for (Iterator<URL> iterator = keys.iterator(); iterator.hasNext();) { URL key = iterator.next(); String userAgent = xmlFiles.get(key); addContributedXML(reader, key, userAgent); } Map<URL, String> binaryFiles = new Hashtable<URL, String>(); addFromExtension(binaryFiles, TAG_BINARY_FILE); keys = binaryFiles.keySet(); for (Iterator<URL> iterator = keys.iterator(); iterator.hasNext();) { URL key = iterator.next(); String userAgent = binaryFiles.get(key); addContributedBinary(reader, key, userAgent); } Map<URL, String> jsFiles = new Hashtable<URL, String>(); addFromExtension(jsFiles, TAG_JS_FILE); keys = jsFiles.keySet(); for (Iterator<URL> iterator = keys.iterator(); iterator.hasNext();) { URL key = iterator.next(); String userAgent = jsFiles.get(key); addContributedJS(key, userAgent); } Map<URL, String> userXMLFiles = new Hashtable<URL, String>(); addUserContributedFiles(userXMLFiles, IPreferenceConstants.ADDED_ENVIRONMENTS); keys = userXMLFiles.keySet(); for (Iterator<URL> iterator = keys.iterator(); iterator.hasNext();) { URL key = iterator.next(); String userAgent = userXMLFiles.get(key); String keyValue = key.toExternalForm(); if (keyValue.endsWith(".js") || keyValue.endsWith(".sdoc")) //$NON-NLS-1$ //$NON-NLS-2$ { addContributedJS(key, userAgent); } else if (keyValue.endsWith(".bin")) //$NON-NLS-1$ { addContributedBinary(reader, key, userAgent); } else if (keyValue.endsWith(".xml")) //$NON-NLS-1$ { addContributedXML(reader, key, userAgent); } } } private static void addUserContributedFiles(Map<URL, String> ids, String prefKey) { IPreferenceStore store = JSPlugin.getDefault().getPreferenceStore(); String values = store.getString(prefKey); String[] entries = values.split(","); //$NON-NLS-1$ String[] envs = getLoadedEnvironments(); for (String entry : entries) { try { File file = new File(entry); if (file.exists()) { boolean load = false; for (int k = 0; k < envs.length; k++) { if (file.getName().equals(envs[k])) { load = true; break; } } if (load) { ids.put(file.toURL(), file.getName()); } } } catch (Exception e1) { } } } /** * @return Returns the isEnvironmentLoaded flag. */ public boolean isEnvironmentLoaded() { return isEnvironmentLoaded; } /** * addFromExtension * * @param ids * @param elementName */ private static void addFromExtension(Map<URL, String> ids, String elementName) { IExtensionRegistry registry = Platform.getExtensionRegistry(); String[] envs = getLoadedEnvironments(); if (registry != null) { IExtensionPoint extensionPoint = registry.getExtensionPoint(JSPlugin.ID, SCRIPTDOC_ID); if (extensionPoint != null) { IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] elements = extension.getConfigurationElements(); for (int j = 0; j < elements.length; j++) { IConfigurationElement element = elements[j]; // InstanceCreator inst = null; if (element.getName().equals(elementName)) { String resourceName = element.getAttribute(ATTR_FILE_PATH); String userAgent = element.getAttribute(ATTR_USER_AGENT); if (userAgent != null) { boolean load = false; for (int k = 0; k < envs.length; k++) { if (userAgent.equals(envs[k])) { load = true; break; } } if (load) { IExtension ext = element.getDeclaringExtension(); String pluginId = ext.getNamespaceIdentifier(); Bundle bundle = Platform.getBundle(pluginId); URL resource = bundle.getResource(resourceName); if (resource != null) { ids.put(resource, userAgent); } else { IdeLog.logError(JSPlugin.getDefault(), StringUtils.format( Messages.JSLanguageEnvironment_ERR_Unable_load_javascript_env_resource, resourceName)); } } } // // inst = new InstanceCreator(element, resourceName) // { // public Object createInstance() // { // IExtension ext = element.getDeclaringExtension(); // String pluginId = ext.getNamespaceIdentifier(); // Bundle bundle = Platform.getBundle(pluginId); // URL resource = bundle.getResource(this.attributeName); // return resource; // } // }; // if (inst != null) // { // Object url = inst.createInstance(); // ids.put(url, userAgent); // } } } } } } } /** * addFromExtension * * @param ids * @param elementName */ private static String[] getLoadedEnvironmentsFromExtension(String elementName) { List<String> ids = new ArrayList<String>(); IExtensionRegistry registry = Platform.getExtensionRegistry(); if (registry != null) { IExtensionPoint extensionPoint = registry.getExtensionPoint(JSPlugin.ID, SCRIPTDOC_ID); if (extensionPoint != null) { IExtension[] extensions = extensionPoint.getExtensions(); for (int i = 0; i < extensions.length; i++) { IExtension extension = extensions[i]; IConfigurationElement[] elements = extension.getConfigurationElements(); for (int j = 0; j < elements.length; j++) { IConfigurationElement element = elements[j]; // InstanceCreator inst = null; if (element.getName().equals(elementName)) { String userAgent = element.getAttribute(ATTR_USER_AGENT); String loadByDefault = element.getAttribute(ATTR_LOAD); if (userAgent != null && Boolean.parseBoolean(loadByDefault)) { ids.add(userAgent); } } } } } } return ids.toArray(new String[0]); } }