com.google.dart.tools.core.DartCore.java Source code

Java tutorial

Introduction

Here is the source code for com.google.dart.tools.core.DartCore.java

Source

/*
 * Copyright (c) 2012, the Dart project authors.
 * 
 * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * 
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.dart.tools.core;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.dart.engine.AnalysisEngine;
import com.google.dart.engine.error.ErrorCode;
import com.google.dart.engine.index.Index;
import com.google.dart.engine.index.IndexFactory;
import com.google.dart.engine.index.IndexStore;
import com.google.dart.engine.sdk.DirectoryBasedDartSdk;
import com.google.dart.engine.utilities.instrumentation.Instrumentation;
import com.google.dart.engine.utilities.instrumentation.InstrumentationBuilder;
import com.google.dart.engine.utilities.logging.Logger;
import com.google.dart.server.generated.AnalysisServer;
import com.google.dart.server.internal.remote.DebugPrintStream;
import com.google.dart.server.internal.remote.RemoteAnalysisServerImpl;
import com.google.dart.server.internal.remote.StdioServerSocket;
import com.google.dart.server.utilities.logging.Logging;
import com.google.dart.tools.core.analysis.model.AnalysisServerData;
import com.google.dart.tools.core.analysis.model.ProjectManager;
import com.google.dart.tools.core.analysis.model.PubFolder;
import com.google.dart.tools.core.internal.MessageConsoleImpl;
import com.google.dart.tools.core.internal.OptionManager;
import com.google.dart.tools.core.internal.analysis.model.AnalysisServerDataImpl;
import com.google.dart.tools.core.internal.analysis.model.DartProjectManager;
import com.google.dart.tools.core.internal.analysis.model.ProjectManagerImpl;
import com.google.dart.tools.core.internal.analysis.model.WorkspaceAnalysisServerListener;
import com.google.dart.tools.core.internal.builder.AnalysisMarkerManager;
import com.google.dart.tools.core.internal.model.DartIgnoreManager;
import com.google.dart.tools.core.internal.model.DartProjectNature;
import com.google.dart.tools.core.internal.util.Extensions;
import com.google.dart.tools.core.internal.util.ResourceUtil;
import com.google.dart.tools.core.internal.util.Util;
import com.google.dart.tools.core.jobs.CleanLibrariesJob;
import com.google.dart.tools.core.model.DartIgnoreListener;
import com.google.dart.tools.core.model.DartSdkListener;
import com.google.dart.tools.core.model.DartSdkManager;
import com.google.dart.tools.core.pub.PubCacheManager_NEW;
import com.google.dart.tools.core.utilities.general.StringUtilities;
import com.google.dart.tools.core.utilities.io.FileUtilities;
import com.google.dart.tools.core.utilities.performance.PerformanceManager;
import com.google.dart.tools.core.utilities.yaml.PubYamlUtils;

import org.apache.commons.lang3.StringUtils;
import org.dartlang.analysis.server.protocol.RequestError;
import org.dartlang.analysis.server.protocol.ServerService;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Version;
import org.osgi.service.prefs.BackingStoreException;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.management.ManagementFactory;
import java.net.ServerSocket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;

/**
 * The class <code>DartCore</code> is used to access the elements modeling projects that have a Dart
 * nature.
 * 
 * @coverage dart.tools.core
 */
public class DartCore extends Plugin implements DartSdkListener {

    /**
     * The unique instance of this class.
     */
    private static DartCore PLUG_IN;

    /**
     * The log used by {@link #logError(String)} and other local methods for logging errors, warnings,
     * and information or <code>null</code> to use the default system log.
     */
    private static ILog PLUGIN_LOG;

    /**
     * Flag indicating whether instrumentation logging of errors is enabled
     */
    private static boolean instrumentationLogErrorEnabled = true;

    /**
     * The id of the plug-in that defines the Dart model.
     */
    public static final String PLUGIN_ID = DartCore.class.getPackage().getName();

    /**
     * Name of file containing user-defined properties.
     */
    public static final String EDITOR_PROPERTIES = "editor.properties";

    /**
     * The id of the project nature used for Dart projects.
     */
    public static final String DART_PROJECT_NATURE = PLUGIN_ID + ".dartNature";

    /**
     * The id of the builder used for Dart projects.
     */
    public static final String DART_BUILDER_ID = PLUGIN_ID + ".dartBuilder";

    /**
     * The id of the content type used to represent Dart compilation units.
     */
    public static final String DART_SOURCE_CONTENT_TYPE = PLUGIN_ID + ".dartSourceFile";

    /**
     * Eclipse problem marker type used to display Dart compilation errors.
     */
    public static final String DART_PROBLEM_MARKER_TYPE = PLUGIN_ID + ".problem";

    /**
     * Eclipse problem marker type used to display Dart hints.
     */
    public static final String DART_HINT_MARKER_TYPE = PLUGIN_ID + ".hint";

    /**
     * Eclipse problem marker type used to display todo markers.
     */
    public static final String DART_TASK_MARKER_TYPE = PLUGIN_ID + ".task";

    /**
     * Eclipse problem marker type used to Angular warning markers
     */
    public static final String ANGULAR_WARNING_MARKER_TYPE = PLUGIN_ID + ".angular_warning";

    /**
     * Correction marker attribute.
     */
    public static final String MARKER_ATTR_CORRECTION = "correction";

    /**
     * Extension for single unit compiled into JavaScript.
     */
    public static final String EXTENSION_JS = "js";

    /**
     * Preference for automatically running pub.
     */
    public static final String PUB_AUTO_RUN_PREFERENCE = "pubAutoRun";

    /**
     * Preference for pub global arguments.
     */
    public static final String PUB_GLOBAL_ARGS_PREFERENCE = "pubGlobalArgs";

    /**
     * Preference for enabling hints.
     */
    public static final String ENABLE_HINTS_PREFERENCE = "enableHints";

    /**
     * Preference for enabling lints.
     */
    public static final String ENABLE_LINTS_PREFERENCE = "enableLints";

    /**
     * Preference for enabling dart2js related hints.
     */
    public static final String ENABLE_HINTS_DART2JS_PREFERENCE = "enableHints_dart2js";

    public static final String PROJECT_PREF_PACKAGE_ROOT = "projectPackageRoot";

    /**
     * Project package root for VM launches
     */
    public static final String PROJECT_PREF_VM_PACKAGE_ROOT = "projectVmPackageRoot";

    public static final String PREFS_DART2JS_FLAGS = "dart2jsFlags";

    /**
     * Preference for specifying location of the Dart SDK.
     */
    public static final String PREFS_SDK_LOCATION = "sdkLocation";

    /**
     * Preference for specifying location of Dartium
     */
    public static final String PREFS_DARTIUM_LOCATION = "dartiumLocation";

    /**
     * Preference to control if "not a member" warnings should be reported for inferred types.
     */
    public static final String TYPE_CHECKS_FOR_INFERRED_TYPES = "typeChecksForInferredTypes";

    public static final String PROJECT_PREF_DISABLE_DART_BASED_BUILDER = "disableDartBasedBuilder";

    /**
     * Preference for enabling usage collection
     */
    public static final String PREFS_ENABLE_ANALYTICS = "enableAnalytics";

    public static final String PREFS_SHOW_ANALYTICS_DIALOG = "showAnalyticsDialog";

    // white listed dirs that can be used for pub build
    public static final List<String> pubDirectories = Arrays.asList("assest", "benchmark", "bin", "example", "test",
            "web");

    /**
     * Cached extensions for CSS files.
     */
    private static final String[] CSS_FILE_EXTENSIONS = { "css" };

    /**
     * Cached extensions for HTML files.
     */
    private static final String[] HTML_FILE_EXTENSIONS = { "html", "htm" };

    /**
     * Cached extensions for JS files.
     */
    private static final String[] JS_FILE_EXTENSIONS = { "js" };

    /**
     * Cached extensions for TXT files.
     */
    private static final String[] TXT_FILE_EXTENSIONS = { "txt" };

    /**
     * Cached extensions for files that are generated by the dartc compiler.
     */
    private static final String[] DART_GENERATED_FILE_EXTENSIONS = { "api", "deps", "js", "map" };

    /**
     * Cached extensions for image files.
     */
    public static final String[] IMAGE_FILE_EXTENSIONS = { "bmp", "gif", "jpeg", "jpg", "png", "raw", "thm", "tif",
            "tiff" };

    /**
     * Name of directory for packages installed by pub
     */
    public static final String PACKAGES_DIRECTORY_NAME = "packages";

    /**
     * Name of directory for build artifacts generated by pub
     */
    public static final String BUILD_DIRECTORY_NAME = "build";

    /**
     * Name of "lib" directory in package
     */
    public static final String LIB_DIRECTORY_NAME = "lib";

    /**
     * Path string for packages directory, uses "/" as path separator, equals "/packages/".
     */
    public static final String PACKAGES_DIRECTORY_PATH = "/" + PACKAGES_DIRECTORY_NAME + "/";

    /**
     * Path string for packages directory in a url.
     */
    public static final String PACKAGES_DIRECTORY_URL = "/" + PACKAGES_DIRECTORY_NAME + "/";

    public static final String PACKAGE_SCHEME_SPEC = "package:";

    /**
     * Path string for lib directory in a url.
     */
    public static final String LIB_URL_PATH = "/lib/";

    /**
     * Name of pubspec file
     */
    public static final String PUBSPEC_FILE_NAME = "pubspec.yaml";

    /**
     * Name of special pubspec lock file
     */
    public static final String PUBSPEC_LOCK_FILE_NAME = "pubspec.lock";

    /**
     * The name of the build.dart special file.
     */
    public static final String BUILD_DART_FILE_NAME = "build.dart";

    /**
     * Used by the {@link DartDebugUserAgentManager} to indicate whether the allow remote connection
     * dialog is open.
     */
    public static boolean allowConnectionDialogOpen = false;

    /**
     * The shared message console instance.
     */
    private static final MessageConsole CONSOLE = new MessageConsoleImpl();

    /**
     * The QualifiedName for a resource remapping (a.foo ==> a.bar).
     */
    private static final QualifiedName RESOURCE_REMAP_NAME = new QualifiedName(PLUGIN_ID, "resourceRemap");

    /**
     * The QualifiedName for the package version.
     */
    public static final QualifiedName PUB_PACKAGE_VERSION = new QualifiedName(DartCore.PLUGIN_ID,
            "pub.package.version");

    /**
     * The QualifiedName for library names.
     */
    public static final QualifiedName LIBRARY_NAME = new QualifiedName(DartCore.PLUGIN_ID, "libraryName");

    /**
     * The unique project manager used for analysis of anything in the workspace
     */
    private static ProjectManager projectManager;

    /**
     * Used to synchronize access to {@link #projectManager}.
     */
    private static final Object projectManagerLock = new Object();

    /**
     * The unique {@link AnalysisServer} used for analysis of anything in the workspace.
     */
    private static AnalysisServer analysisServer;

    /**
     * The unique {@link AnalysisServerDataImpl} instance.
     */
    private static AnalysisServerDataImpl analysisServerDataImpl = new AnalysisServerDataImpl();

    /**
     * The unique {@link WorkspaceAnalysisServerListener} instance.
     */
    private static WorkspaceAnalysisServerListener analysisServerListener;

    /**
     * Used to synchronize access to {@link #analysisServer}.
     */
    private static final Object analysisServerLock = new Object();

    /**
     * Add the given listener for dart ignore changes to the Dart Model. Has no effect if an identical
     * listener is already registered.
     * 
     * @param listener the listener to add
     */
    public static void addIgnoreListener(DartIgnoreListener listener) {
        getIgnoreManager().addListener(listener);
    }

    /**
     * Add the given resource to the set of ignored resources.
     * 
     * @param resource the resource to ignore
     * @throws IOException if there was an error accessing the ignore file
     * @throws CoreException if there was an error deleting markers
     */
    public static void addToIgnores(IResource resource) throws IOException, CoreException {
        getIgnoreManager().addToIgnores(resource);
    }

    /**
     * Remove any resource mapping for the given container.
     * 
     * @param resource
     */
    public static void clearResourceRemapping(IContainer container) {
        try {
            container.accept(new IResourceVisitor() {
                @Override
                public boolean visit(IResource resource) throws CoreException {
                    if (resource instanceof IFile) {
                        clearResourceRemapping((IFile) resource);

                        return true;
                    } else if (resource instanceof IContainer) {
                        IContainer childContainer = (IContainer) resource;

                        if (childContainer.getName().startsWith(".")) {
                            return false;
                        } else {
                            return true;
                        }
                    } else {
                        return false;
                    }
                }
            });
        } catch (CoreException e) {
            DartCore.logError(e);
        }
    }

    /**
     * Remove any resource mapping for the given file.
     * 
     * @param resource
     */
    public static void clearResourceRemapping(IFile resource) {
        if (getResourceRemapping(resource) != null) {
            setResourceRemapping(resource, null);
        }
    }

    /**
     * Return true if directory contains a "packages" directory that is installed by pub
     */
    public static boolean containsPackagesDirectory(File file) {
        return new File(file, PACKAGES_DIRECTORY_NAME).isDirectory();
    }

    /**
     * Return <code>true</code> if the directory contains a "pubspec.yaml" file
     */
    public static boolean containsPubspecFile(File directory) {
        return new File(directory, PUBSPEC_FILE_NAME).isFile();
    }

    /**
     * Find and return an unused server socket port.
     */
    public static int findUnusedPort() {
        try {
            ServerSocket ss = new ServerSocket(0);
            int port = ss.getLocalPort();
            ss.close();
            return port;
        } catch (IOException ioe) {
            //$FALL-THROUGH$
        }
        return -1;
    }

    /**
     * Return an array of analysis server arguments.
     * 
     * @return a non-null array of arguments
     */
    public static String[] getAdditionalAnalysisServerArguments() {
        String value = getUserDefinedProperty(ANALYSIS_SERVER_ARG_PROP_KEY);
        if (value == null) {
            return StringUtilities.EMPTY_ARRAY;
        }
        return value.split(",");
    }

    /**
     * Return an list of Dart VM arguments for analysis server.
     * 
     * @return a non-null array of arguments
     */
    public static String[] getAdditionalAnalysisServerVmArguments() {
        String value = getUserDefinedProperty(ANALYSIS_SERVER_VM_ARG_PROP_KEY);
        if (value == null) {
            return StringUtilities.EMPTY_ARRAY;
        }
        return value.split(",");
    }

    /**
     * Answer the unique {@link AnalysisServer} used for analysis of anything in the workspace.
     * 
     * @return the {@link AnalysisServer}
     */
    public static AnalysisServer getAnalysisServer() {
        synchronized (analysisServerLock) {
            if (analysisServer == null) {
                DartSdkManager sdkManager = DartSdkManager.getManager();
                if (!sdkManager.hasSdk()) {
                    DartCore.logError("Add the dart sdk (com.google.dart.sdk) as a JVM argument");
                    return null;
                }

                boolean isRunningFromSource = false;
                String runtimePath = sdkManager.getSdk().getVmExecutable().getAbsolutePath();
                String analysisServerPath = DartCoreDebug.ANALYSIS_SERVER_PATH;
                if (StringUtils.isEmpty(analysisServerPath)) {
                    String svnRoot = System.getProperty("com.google.dart.svnRoot");
                    if (svnRoot == null) {
                        File analysisServerSnapshot = new File(DartSdkManager.getManager().getSdk().getDirectory(),
                                "bin/snapshots/analysis_server.dart.snapshot");
                        analysisServerPath = analysisServerSnapshot.getAbsolutePath();
                        if (!analysisServerSnapshot.exists()) {
                            DartCore.logError("Analysis Server snapshot was not found in "
                                    + analysisServerSnapshot.getAbsolutePath() + ", SDK is corrupt.");
                            return null;
                        }
                    } else {
                        analysisServerPath = svnRoot + "/pkg/analysis_server/bin/server.dart";
                        isRunningFromSource = true;
                    }
                } else {
                    isRunningFromSource = true;
                }

                String packageRoot = System.getProperty("com.google.dart.packageRoot");
                if (packageRoot == null && isRunningFromSource) {
                    DartCore.logError("To run analysis server from source, a package root must be "
                            + "supplied using -Dcom.google.dart.packageRoot.");
                    return null;
                }

                try {
                    // VM arguments
                    List<String> additionalVmArguments = Lists
                            .newArrayList(DartCore.getAdditionalAnalysisServerVmArguments());
                    additionalVmArguments.add("--package-root=" + packageRoot);
                    if (DartCoreDebug.ANALYSIS_SERVER_DEBUG) {
                        int debugPort = findUnusedPort();
                        Logging.getLogger().logInformation("Analysis server debug port " + debugPort);
                        additionalVmArguments.add("--debug:" + debugPort);
                    }
                    if (DartCoreDebug.ANALYSIS_SERVER_PROFILE) {
                        additionalVmArguments.add("--observe");
                        additionalVmArguments.add("--pause-isolates-on-exit");
                        additionalVmArguments.add("--code_comments");
                        additionalVmArguments.add("--collect-code=false");
                    }
                    // Server arguments
                    List<String> additionalArguments = Lists
                            .newArrayList(DartCore.getAdditionalAnalysisServerArguments());
                    // prepare debug stream
                    DebugPrintStream debugStream;
                    {
                        String logPath = DartCoreDebug.ANALYSIS_SERVER_LOG_FILE;
                        if (StringUtils.isBlank(logPath)) {
                            debugStream = null;
                        } else if ("console".equals(logPath)) {
                            debugStream = new DebugPrintStream() {
                                @Override
                                public void println(String s) {
                                    if (s.length() > 1000) {
                                        s = s.substring(0, 1000) + "...";
                                    }
                                    System.out.println(s);
                                }
                            };
                        } else {
                            @SuppressWarnings("resource")
                            final PrintStream fileStream = new PrintStream(logPath);
                            debugStream = new DebugPrintStream() {
                                @Override
                                public void println(String s) {
                                    fileStream.println(s);
                                }
                            };
                        }
                    }
                    // additional options
                    if (DartCoreDebug.ANALYSIS_SERVER_INCREMENTAL_RESOLUTION_API) {
                        additionalArguments.add("--enable-incremental-resolution-api");
                    }
                    if (DartCoreDebug.ANALYSIS_SERVER_NEW_TASK_MODEL) {
                        additionalArguments.add("--enable-new-task-model");
                    }
                    {
                        String log = DartCoreDebug.ANALYSIS_SERVER_INCREMENTAL_RESOLUTION_LOG;
                        if (!StringUtils.isEmpty(log)) {
                            additionalArguments.add("--incremental-resolution-log=" + log);
                        }
                    }
                    if (DartCoreDebug.ANALYSIS_SERVER_INCREMENTAL_RESOLUTION_VALIDATION) {
                        additionalArguments.add("--incremental-resolution-validation");
                    }
                    {
                        String log = DartCoreDebug.ANALYSIS_SERVER_INSTRUMENTATION_LOG_FILE;
                        if (!StringUtils.isEmpty(log)) {
                            log = log.trim();
                            if (log.length() > 0) {
                                additionalArguments.add("--instrumentation-log-file=" + log);
                            }
                        }
                    }
                    if (DartCoreDebug.ANALYSIS_SERVER_PRINT_TO_CONSOLE) {
                        additionalArguments.add("--internal-print-to-console");
                    }
                    additionalArguments.add("--useAnalysisHighlight2");
                    // HTTP port
                    int httpPort = 0;
                    if (DartCoreDebug.ANALYSIS_SERVER_HTTP_PORT != null
                            && !DartCoreDebug.ANALYSIS_SERVER_HTTP_PORT.isEmpty()) {
                        try {
                            httpPort = Integer.parseInt(DartCoreDebug.ANALYSIS_SERVER_HTTP_PORT);
                            additionalArguments.add("--port=" + httpPort);
                            Logging.getLogger().logInformation("Analysis server http port " + httpPort);
                        } catch (NumberFormatException e) {
                            DartCore.logError("Analysis server HTTP port must be an integer.");
                            return null;
                        }
                    }
                    // create server, if "com.google.dart.svnRoot" flag was not set then use snapshot
                    StdioServerSocket socket = new StdioServerSocket(runtimePath, additionalVmArguments,
                            analysisServerPath, additionalArguments, debugStream);
                    if (isPluginsBuild()) {
                        // plugin mode
                        socket.setClientId("org.dartlang.dartplugin");
                    } else {
                        // editor mode
                        socket.setClientId("org.dartlang.darteditor");
                    }
                    socket.setClientVersion(getVersion());
                    // start server
                    analysisServer = new RemoteAnalysisServerImpl(socket);
                    analysisServerDataImpl.setServer(analysisServer);
                    analysisServerListener = new WorkspaceAnalysisServerListener(analysisServerDataImpl,
                            new DartProjectManager(ResourcesPlugin.getWorkspace().getRoot(), analysisServer,
                                    DartIgnoreManager.getInstance()));
                    analysisServer.addAnalysisServerListener(analysisServerListener);
                    analysisServer.start();
                    analysisServer.server_setSubscriptions(ImmutableList.of(ServerService.STATUS));
                    analysisServerDataImpl.updateOptions();
                } catch (Throwable e) {
                    DartCore.logError("Enable to start stdio server", e);
                    return null;
                }
            }
        }
        return analysisServer;
    }

    /**
     * Answer the unique {@link AnalysisServerData} used to provide analysis information in the
     * workspace.
     * 
     * @return the {@link AnalysisServerData} (not {@code null})
     */
    public static AnalysisServerData getAnalysisServerData() {
        getAnalysisServer();
        return analysisServerDataImpl;
    }

    /**
     * Answer the application directory (a directory contains a "packages" directory and a
     * "pubspec.yaml" file) directly or indirectly containing the specified file or the file itself if
     * it is an application directory.
     * 
     * @param libFileOrDir the library file or directory
     * @return the context in which the specified library should be analyzed (not <code>null</code>)
     */
    public static File getApplicationDirectory(File file) {
        while (file != null) {
            if (isApplicationDirectory(file)) {
                return file;
            }
            file = file.getParentFile();
        }
        return null;
    }

    /**
     * Answer the application directory (a directory that contains a "packages" directory and a
     * "pubspec.yaml" file) directly or indirectly containing the specified resource or the resource
     * itself if it is an application directory.
     * 
     * @param resource the file or directory
     * @return the directory with the pubspec for the given file
     */
    public static IContainer getApplicationDirectory(IResource resource) {
        IContainer container;
        if (resource instanceof IFile) {
            container = resource.getParent();
        } else {
            container = (IContainer) resource;
        }
        while (container != null) {
            if (isApplicationDirectory(container)) {
                return container;
            }
            container = container.getParent();
        }
        return null;
    }

    /**
     * Returns the day (yyyy-MM-dd) the product was built.
     */
    public static String getBuildDate() {
        return "@BUILDDATE@";
    }

    /**
     * Returns the SVN revision number as a String.
     */
    public static String getBuildId() {
        return "@REVISION@";
    }

    /**
     * Return a unique token that can be used to determine whether cached data that changes only when
     * the version of the editor changes is still valid.
     * 
     * @return a token used to determine the validity of cached data
     */
    public static String getBuildIdOrDate() {
        String buildIdOrDate = getBuildId();
        if (buildIdOrDate.startsWith("@")) {
            buildIdOrDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        }
        return buildIdOrDate;
    }

    /**
     * Returns the shared message console. Unlike the log ({@link DartCore#getLog()}), the console is
     * intended for communication with the end-user.
     * 
     * @return the message console
     */
    public static MessageConsole getConsole() {
        return CONSOLE;
    }

    /**
     * Return the list of known Dart-like file extensions. Dart-like extensions are defined in the
     * {@link Platform.getContentManager() content type manager} for the
     * {@link #DART_SOURCE_CONTENT_TYPE}. Note that a Dart-like extension does not include the leading
     * dot, and that the "dart" extension is always defined as a Dart-like extension.
     * 
     * @return the list of known Dart-like file extensions
     */
    public static String[] getDartLikeExtensions() {
        IContentType dartContentType = Platform.getContentTypeManager().getContentType(DART_SOURCE_CONTENT_TYPE);
        HashSet<String> extensionSet = new HashSet<String>();
        for (IContentType contentType : Platform.getContentTypeManager().getAllContentTypes()) {
            if (contentType.isKindOf(dartContentType)) {
                for (String extension : contentType.getFileSpecs(IContentType.FILE_EXTENSION_SPEC)) {
                    extensionSet.add(extension);
                }
            }
        }
        extensionSet.remove(Extensions.DART);
        ArrayList<String> extensionList = new ArrayList<String>(extensionSet);
        extensionList.add(0, Extensions.DART);
        return extensionList.toArray(new String[extensionList.size()]);
    }

    /**
     * Returns all existing and open workspace Dart projects.
     */
    public static IProject[] getDartProjects() {
        List<IProject> dartProjects = Lists.newArrayList();
        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
        for (IProject project : projects) {
            if (!project.isAccessible()) {
                continue;
            }
            if (!DartProjectNature.hasDartNature(project)) {
                continue;
            }
            if (PubCacheManager_NEW.isPubCacheProject(project)) {
                continue;
            }
            dartProjects.add(project);
        }
        return dartProjects.toArray(new IProject[dartProjects.size()]);
    }

    /**
     * Return a table of all known configurable options with their default values. These options allow
     * to configure the behavior of the underlying components. The client may safely use the result as
     * a template that they can modify and then pass to {@link #setOptions()}</code>.
     * <p>
     * Helper constants have been defined on DartPreferenceConstants for each of the option IDs
     * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their
     * acceptable values (categorized in Option value). Some options accept open value sets beyond the
     * documented constant values.
     * <p>
     * Note: each release may add new options.
     * 
     * @return a table of all known configurable options with their default values
     */
    public static Hashtable<String, String> getDefaultOptions() {
        return null;
    }

    public static File getEclipseInstallationDirectory() {
        return new File(Platform.getInstallLocation().getURL().getFile());
    }

    /**
     * Return the workspace root default charset encoding.
     * 
     * @return the name of the default charset encoding for the workspace root
     */
    public static String getEncoding() {
        try {
            return ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset();
        } catch (IllegalStateException exception) {
            // happen when there's no workspace (see bug
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=216817)
            // or when it is shutting down (see bug
            // https://bugs.eclipse.org/bugs/show_bug.cgi?id=60687)
            return System.getProperty("file.encoding"); //$NON-NLS-1$
        } catch (CoreException exception) {
            // fails silently and return plugin global encoding if core exception
            // occurs
        }
        return ResourcesPlugin.getEncoding();
    }

    /**
     * Extract {@link ErrorCode} form the given {@link IMarker}.
     * 
     * @return the {@link ErrorCode}, may be {@code null}.
     */
    public static ErrorCode getErrorCode(IMarker marker) {
        return AnalysisMarkerManager.getErrorCode(marker);
    }

    /**
     * Return the DartIgnoreManager
     */
    public static DartIgnoreManager getIgnoreManager() {
        if (DartCoreDebug.ENABLE_ANALYSIS_SERVER) {
            return DartIgnoreManager.getInstance();
        } else {
            return getProjectManager().getIgnoreManager();
        }
    }

    /**
     * Utility method for returning one option value only. Equivalent to
     * <code>DartCore.getOptions().get(optionName)</code> Note that it may answer <code>null</code> if
     * this option does not exist.
     * <p>
     * Helper constants have been defined on DartPreferenceConstants for each of the option IDs
     * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their
     * acceptable values (categorized in Option value). Some options accept open value sets beyond the
     * documented constant values.
     * <p>
     * Note: each release may add new options.
     * 
     * @param optionName the name of the option whose value is to be returned
     * @return the value of a given option
     */
    public static String getOption(String optionName) {
        return OptionManager.getInstance().getOption(optionName);
    }

    /**
     * Return the table of the current options. Initially, all options have their default values, and
     * this method returns a table that includes all known options.
     * <p>
     * Helper constants have been defined on DartPreferenceConstants for each of the option IDs
     * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their
     * acceptable values (categorized in Option value). Some options accept open value sets beyond the
     * documented constant values.
     * <p>
     * Note: each release may add new options.
     * <p>
     * Returns a default set of options even if the platform is not running.
     * </p>
     * 
     * @return table of current settings of all options (key type: <code>String</code>; value type:
     *         <code>String</code>)
     */
    public static HashMap<String, String> getOptions() {
        return OptionManager.getInstance().getOptions();
    }

    /**
     * Return the unique instance of this class.
     * 
     * @return the unique instance of this class
     */
    public static DartCore getPlugin() {
        return PLUG_IN;
    }

    /**
     * Answer the unique project manager used for analysis of anything in the workspace.
     * 
     * @return the manager (not {@code null})
     */
    public static ProjectManager getProjectManager() {
        synchronized (projectManagerLock) {
            if (projectManager == null) {
                // start index
                final Index index;
                {
                    File stateDir = getPlugin().getStateLocation().toFile();
                    File indexDir = new File(stateDir, "index");
                    indexDir.mkdirs();
                    IndexStore indexStore = IndexFactory.newFileIndexStore(indexDir);
                    index = IndexFactory.newIndex(indexStore);
                    Thread thread = new Thread() {
                        @Override
                        public void run() {
                            index.run();
                        }
                    };
                    thread.setName("Index Thread");
                    thread.setDaemon(true);
                    thread.start();
                }
                // create ProjectManagerImpl
                projectManager = new ProjectManagerImpl(ResourcesPlugin.getWorkspace().getRoot(),
                        DartSdkManager.getManager().getSdk(), DartSdkManager.getManager().getSdkContextId(), index,
                        DartIgnoreManager.getInstance());
            }
        }
        return projectManager;
    }

    /**
     * @return the mapping for the given resource, if any
     */
    public static String getResourceRemapping(IFile originalResource) {
        try {
            return originalResource.getPersistentProperty(RESOURCE_REMAP_NAME);
        } catch (CoreException e) {
            return null;
        }
    }

    /**
     * Returns the name of the directory in packages that is linked to the "lib" folder in the project
     * 
     * @param project
     * @return the name of the directory, <code>null</code> if there is no self linked packages folder
     */
    public static String getSelfLinkedPackageName(IResource resource) {
        String packageName = null;

        try {
            IContainer appFolder = getApplicationDirectory(resource);

            if (appFolder != null) {
                IResource pubspec = appFolder.findMember(DartCore.PUBSPEC_FILE_NAME);

                if (pubspec != null) {
                    String contents = FileUtilities.getContents(pubspec.getLocation().toFile(), "UTF-8");

                    if (contents != null) {
                        String name = PubYamlUtils.getPubspecName(contents);

                        if (name != null) {
                            return name;
                        }
                    }
                }
            }
        } catch (Exception e) {

        }

        return packageName;
    }

    /**
     * Returns the path string for the default dart directory - user.home/dart
     * 
     * @return the name of the user.home/dart directory
     */
    public static String getUserDefaultDartFolder() {
        String defaultLocation = System.getProperty("user.home"); //$NON-NLS-1$
        return defaultLocation + File.separator + "dart" + File.separator; //$NON-NLS-1$
    }

    /**
     * Returns the current value of the string-valued user-defined property with the given name.
     * Returns <code>null</code> if there is no user-defined property with the given name.
     * <p>
     * User-defined properties are defined in the <code>editor.properties</code> file located in the
     * eclipse installation directory.
     * 
     * @see DartCore#getEclipseInstallationDirectory()
     * @param name the name of the property
     * @return the string-valued property
     */
    public static String getUserDefinedProperty(String key) {

        Properties properties = new Properties();

        File installDirectory = getEclipseInstallationDirectory();
        File file = new File(installDirectory, EDITOR_PROPERTIES);

        if (file.exists()) {
            try {
                properties.load(new FileReader(file));
            } catch (FileNotFoundException e) {
                logError(e);
            } catch (IOException e) {
                logError(e);
            }
        }

        return properties.getProperty(key);
    }

    /**
     * @return the version text for this plugin (i.e. 1.1.0)
     */
    public static String getVersion() {
        Version version = getPlugin().getBundle().getVersion();

        return version.getMajor() + "." + version.getMinor() + "." + version.getMicro();
    }

    public static boolean is32Bit() {
        return Platform.getOSArch().indexOf("64") == -1;
    }

    /**
     * Return <code>true</code> if the given resource should be analyzed. All resources are to be
     * analyzed unless they have been excluded.
     * 
     * @param resource the resource being tested
     * @return <code>true</code> if the given resource should be analyzed
     */
    public static boolean isAnalyzed(IResource resource) {
        return getIgnoreManager().isAnalyzed(resource);
    }

    /**
     * Return true if directory contains a "packages" directory and a "pubspec.yaml" file
     */
    public static boolean isApplicationDirectory(File directory) {
        return containsPubspecFile(directory);
    }

    /**
     * Return true if directory contains a "packages" directory and a "pubspec.yaml" file
     */
    public static boolean isApplicationDirectory(IContainer container) {
        if (container.getLocation() == null) {
            return false;
        }

        File directory = container.getLocation().toFile();

        return isApplicationDirectory(directory);
    }

    /**
     * Answer {@code true} if the specified resource is a build.dart file and exists either in a
     * project or in a folder containing a pubspec file.
     * 
     * @param file the file
     * @return {@code true} if the file is a build.dart file that will be run by the builder
     */
    public static boolean isBuildDart(IFile file) {
        if (file == null || !file.getName().equals(BUILD_DART_FILE_NAME) || !file.exists()) {
            return false;
        }

        IContainer container = file.getParent();

        // Always run build.dart in a project's root.
        if (container.getType() == IResource.PROJECT) {
            return true;
        }

        return container.getFile(new Path(PUBSPEC_FILE_NAME)).exists();
    }

    /**
     * Return true if directory is one that is generated by pub build
     * 
     * @param folder the folder to be checked
     * @return <code>true</code> if folder name matches and is sibling of pubspec.yaml
     */
    public static boolean isBuildDirectory(IFolder folder) {
        IPath location = folder.getLocation();
        if (location != null && folder.getName().equals(BUILD_DIRECTORY_NAME)) {
            if (folder.getParent().findMember(PUBSPEC_FILE_NAME) != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * Return <code>true</code> if the given file is contained in the packages directory created by
     * pub
     * 
     * @param file the file that is to be checked
     * @return <code>true</code> if the given file is in packages
     */
    public static boolean isContainedInPackages(File file) {
        if (file.getAbsolutePath().contains(PACKAGES_DIRECTORY_NAME)) {
            return true;
        }
        return false;
    }

    /**
     * Return <code>true</code> if the given file is contained in the packages directory created by
     * pub
     * 
     * @param file the file that is to be checked
     * @return <code>true</code> if the given file is in packages
     */
    public static boolean isContainedInPackages(IFile file) {
        return file.getFullPath().toString().contains(DartCore.PACKAGES_DIRECTORY_PATH);
    }

    /**
     * Return <code>true</code> if the given file name's extension is an CSS-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is an CSS-like extension
     */
    public static boolean isCssLikeFileName(String fileName) {
        return isLikeFileName(fileName, CSS_FILE_EXTENSIONS);
    }

    /**
     * Return <code>true</code> if the given file name's extension is a generated Dart like extension.
     * 
     * @return <code>true</code> if the given file name's extension is a generated Dart like extension
     */
    public static boolean isDartGeneratedFile(String fileName) {
        return isLikeFileName(fileName, DART_GENERATED_FILE_EXTENSIONS);
    }

    /**
     * Return <code>true</code> if the name of the given {@link IFile} has a Dart-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the name of the given {@link IFile} has a Dart-like extension
     */
    public static boolean isDartLikeFile(IFile file) {
        String fileName = file.getName();
        return isDartLikeFileName(fileName);
    }

    /**
     * Return <code>true</code> if the given file name's extension is a Dart-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is a Dart-like extension
     */
    public static boolean isDartLikeFileName(String fileName) {
        return StringUtilities.endsWithIgnoreCase(fileName, ".dart");
    }

    /**
     * Return <code>true</code> if file is in the dart sdk lib directory
     * 
     * @param file
     * @return <code>true</code> if file is in dart-sdk/lib
     */
    public static boolean isDartSdkLibraryFile(File file) {
        File sdkLibrary = DartSdkManager.getManager().getSdk().getLibraryDirectory();
        File parentFile = file.getParentFile();
        while (parentFile != null) {
            if (parentFile.equals(sdkLibrary)) {
                return true;
            }
            parentFile = parentFile.getParentFile();
        }
        return false;
    }

    /**
     * Return <code>true</code> if the given file name's extension is an HTML-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is an HTML-like extension
     */
    public static boolean isHtmlLikeFileName(String fileName) {
        return isLikeFileName(fileName, HTML_FILE_EXTENSIONS);
    }

    /**
     * Return <code>true</code> if the given file name's extension is an image-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is an image-like extension
     */
    public static boolean isImageLikeFileName(String fileName) {
        return isLikeFileName(fileName, IMAGE_FILE_EXTENSIONS);
    }

    /**
     * Return true if directory is build directory created by pub
     * 
     * @param folder the folder to be checked
     * @return <code>true</code> if folder/parent name matches and is sibling of pubspec.yaml
     */
    public static boolean isInBuildDirectory(IContainer folder) {
        while (folder.getParent() != null) {
            if (folder.getName().equals(BUILD_DIRECTORY_NAME)
                    && folder.getParent().getFile(new Path(PUBSPEC_FILE_NAME)).exists()) {
                return true;
            }
            folder = folder.getParent();
        }
        return false;
    }

    /**
     * Return true if is in build directory created by pub
     */
    public static boolean isInBuildDirectory(IResource resource) {
        if (resource == null) {
            return false;
        }
        if (!(resource instanceof IContainer)) {
            resource = resource.getParent();
        }
        return !(resource instanceof IProject || resource instanceof IWorkspaceRoot)
                && (isBuildDirectory((IFolder) resource) || isInBuildDirectory((IContainer) resource));

    }

    /**
     * @return {@code true} if the given resource is located in the top-level "packages" folder of its
     *         enclosing package.
     */
    public static boolean isInDuplicatePackageFolder(IResource resource) {
        if (resource == null) {
            return false;
        }
        // prepare "pub" folder
        PubFolder pubFolder = DartCore.getProjectManager().getPubFolder(resource);
        if (pubFolder == null) {
            return false;
        }
        IPath pubPath = pubFolder.getResource().getFullPath();
        // check if resource is in "packages"
        IPath resourcePath = resource.getFullPath();
        String[] segments = resourcePath.segments();
        for (int i = 1; i < segments.length - 1; i++) {
            String segment = segments[i];
            if (segment.equals(PACKAGES_DIRECTORY_NAME)) {
                return !resourcePath.uptoSegment(i).equals(pubPath);
            }
        }
        // not in "packages"
        return false;
    }

    /**
     * @return {@code true} if the given resource is located in the "packages" sub-folder that
     *         corresponds to the enclosing package.
     */
    public static boolean isInSelfLinkedPackageFolder(IResource resource) {
        if (resource == null) {
            return false;
        }
        try {
            // prepare "pub" folder
            PubFolder pubFolder = DartCore.getProjectManager().getPubFolder(resource);
            if (pubFolder == null) {
                return false;
            }
            // the name of the enclosing package
            String packageName = pubFolder.getPubspec().getName();
            // check if resource is in "packages" and references the enclosing package
            String[] segments = resource.getFullPath().segments();
            for (int i = 0; i < segments.length - 1; i++) {
                String segment = segments[i];
                if (segment.equals(PACKAGES_DIRECTORY_NAME) && segments[i + 1].equals(packageName)) {
                    return true;
                }
            }
        } catch (Throwable e) {
            // pubFolder.getPubspec() may fail
            return false;
        }
        // not a self-reference
        return false;
    }

    /**
     * Return <code>true</code> if the given file name's extension is an HTML-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is an HTML-like extension
     */
    public static boolean isJSLikeFileName(String fileName) {
        return isLikeFileName(fileName, JS_FILE_EXTENSIONS);
    }

    public static boolean isLinux() {
        return !isMac() && !isWindows();
    }

    public static boolean isMac() {
        // Look for the "Mac" OS name.
        return System.getProperty("os.name").toLowerCase().startsWith("mac");
    }

    /**
     * Return true if directory is one that is installed by pub
     * 
     * @param file the file to be checked
     * @return <code>true</code> if file name matches and is sibling of pubspec.yaml
     */
    public static boolean isPackagesDirectory(File file) {
        if (file.getName().equals(PACKAGES_DIRECTORY_NAME)) {
            return true;
        }
        return false;
    }

    /**
     * Return true if directory is one that is installed by pub
     * 
     * @param folder the folder to be checked
     * @return <code>true</code> if folder name matches and is sibling of pubspec.yaml
     */
    public static boolean isPackagesDirectory(IFolder folder) {
        IPath location = folder.getLocation();
        return location != null && isPackagesDirectory(location.toFile());
    }

    /**
     * Answer <code>true</code> if the string is a package spec
     */
    public static boolean isPackageSpec(String spec) {
        return spec != null && spec.startsWith(PACKAGE_SCHEME_SPEC);
    }

    /**
     * @return <code>true</code> if given {@link IResource} was installed by pub.
     */
    public static boolean isPackagesResource(IResource resource) {
        if (resource instanceof IFolder) {
            if (isPackagesDirectory((IFolder) resource)) {
                return true;
            }
        }
        if (resource != null && resource.getParent() instanceof IFolder) {
            IFolder parentFolder = (IFolder) resource.getParent();
            return isPackagesResource(parentFolder);
        }
        return false;
    }

    /**
     * Check if this URI denotes a patch file.
     */
    public static boolean isPatchfile(File file) {
        return file != null && file.getName().endsWith("_patch.dart");
    }

    /**
     * @return whether we're running in the context of the eclipse plugins build
     */
    public static boolean isPluginsBuild() {
        return Platform.getBundle("com.google.dart.eclipse.core") != null;
    }

    /**
     * Checks if the given linkedResource points to a file in the container. This is used to check for
     * the self link in the packages directory
     * 
     * @param resource
     * @param linkedResource
     * @return <code>true</code> if the linked resource points to a file/folder in the project
     */
    public static boolean isSelfLinkedResource(IContainer resource, IResource linkedResource) {

        try {
            //     if (linkedResource.getParent().getParent() == resource) {
            String resourcePath = resource.getLocation().toFile().getCanonicalPath();
            String linkPath = linkedResource.getLocation().toFile().getCanonicalPath();
            if (linkPath.startsWith(resourcePath)) {
                return true;
            }
            //     }
        } catch (IOException e) {
            return false;
        }
        return false;
    }

    /**
     * Return <code>true</code> if the given file name's extension is an HTML-like extension.
     * 
     * @param fileName the file name being tested
     * @return <code>true</code> if the given file name's extension is an HTML-like extension
     */
    public static boolean isTxtLikeFileName(String fileName) {
        return isLikeFileName(fileName, TXT_FILE_EXTENSIONS);
    }

    public static boolean isWindows() {
        // Look for the "Windows" OS name.
        return System.getProperty("os.name").toLowerCase().startsWith("win");
    }

    public static boolean isWindowsXp() {
        // Look for the "Windows XP" OS name.
        return System.getProperty("os.name").toLowerCase().equals("windows xp");
    }

    /**
     * Log the given message as an error.
     * 
     * @param message an explanation of why the error occurred or what it means
     */
    public static void logError(String message) {
        logErrorImpl(message, null);
        instrumentationLogErrorImpl(message, null);
    }

    /**
     * Log the given exception as one representing an error.
     * 
     * @param message an explanation of why the error occurred or what it means
     * @param exception the exception being logged
     */
    public static void logError(String message, Throwable exception) {
        logErrorImpl(message, exception);
        instrumentationLogErrorImpl(message, exception);
    }

    /**
     * Log the given exception as one representing an error.
     * 
     * @param exception the exception being logged
     */
    public static void logError(Throwable exception) {
        logErrorImpl(exception.getMessage(), exception);
        instrumentationLogErrorImpl(null, exception);
    }

    /**
     * Log the given informational message.
     * 
     * @param message an explanation of why the error occurred or what it means
     * @param exception the exception being logged
     */
    public static void logInformation(String message) {
        logInformation(message, null);
    }

    /**
     * Log the given exception as one representing an informational message.
     * 
     * @param message an explanation of why the error occurred or what it means
     * @param exception the exception being logged
     */
    public static void logInformation(String message, Throwable exception) {

        if (DartCoreDebug.VERBOSE) {
            ILog pluginLog = getPluginLog();
            if (pluginLog != null) {
                pluginLog.log(new Status(Status.INFO, PLUGIN_ID, "INFO: " + message, exception));
            }
        }

        instrumentationLogInfoImpl(message, exception);
    }

    /**
     * Log the given {@link RequestError}.
     */
    public static void logRequestError(RequestError requestError) {
        StringBuilder buf = new StringBuilder();
        buf.append("RequestError: ");
        buf.append(requestError.getCode());
        buf.append("\n");
        buf.append(requestError.getMessage());
        buf.append("\n");
        buf.append(requestError.getStackTrace());
        buf.append("\n");
        String str = buf.toString();
        DartCore.logError(str);
    }

    /**
     * This method exists as a convenient marker for methods that have not yet been fully implemented.
     * It should be deleted before this product ships.
     */
    public static void notYetImplemented() {
    }

    /**
     * Removes the file extension from the given file name, if it has a Dart-like file extension.
     * Otherwise the file name itself is returned. Note this removes the dot ('.') before the
     * extension as well.
     * 
     * @param fileName the name of a file
     * @return the fileName without the Dart-like extension
     */
    public static String removeDartLikeExtension(String fileName) {
        return Util.getNameWithoutDartLikeExtension(fileName);
    }

    /**
     * Remove the given resource (as a path) from the set of ignored resources.
     * 
     * @param resource the resource path to (un)ignore
     * @throws IOException if there was an error accessing the ignore file
     */
    public static void removeFromIgnores(IPath resource) throws IOException {
        getIgnoreManager().removeFromIgnores(resource);
    }

    /**
     * Remove the given resource from the set of ignored resources.
     * 
     * @param resource the resource to (un)ignore
     * @throws IOException if there was an error accessing the ignore file
     */
    public static void removeFromIgnores(IResource resource) throws IOException {
        getIgnoreManager().removeFromIgnores(resource);
    }

    /**
     * Remove the given listener for dart ignore changes from the Dart Model. Has no effect if an
     * identical listener is not registered.
     * 
     * @param listener the non-<code>null</code> listener to remove
     */
    public static void removeIgnoreListener(DartIgnoreListener listener) {
        getIgnoreManager().removeListener(listener);
    }

    public static void setOptions(HashMap<String, String> newOptions) {

    }

    /**
     * Sets the current table of options. All and only the options explicitly included in the given
     * table are remembered; all previous option settings are forgotten, including ones not explicitly
     * mentioned.
     * <p>
     * Helper constants have been defined on DartPreferenceConstants for each of the option IDs
     * (categorized in Code assist option ID, Compiler option ID and Core option ID) and some of their
     * acceptable values (categorized in Option value). Some options accept open value sets beyond the
     * documented constant values.
     * <p>
     * Note: each release may add new options.
     * 
     * @param newOptions the new options, or <code>null</code> to reset all options to their default
     *          values
     */
    public static void setOptions(Hashtable<String, String> newOptions) {

    }

    /**
     * TESTING ONLY: Set the log used by {@link #logError(String)} and other local methods for logging
     * errors, warnings, and information.
     * 
     * @param log the log or <code>null</code> to use the default system log
     * @return the log prior to calling this method or <code>null</code> for the default system log
     */
    public static ILog setPluginLog(ILog log) {
        ILog oldLog = PLUGIN_LOG;
        PLUGIN_LOG = log;
        return oldLog;
    }

    /**
     * Set a symbolic resource mapping from one resource to another. For some uses of the original
     * resource, like serving web content, the mapped resource should be substituted.
     * 
     * @param originalResource
     * @param newResource
     */
    public static void setResourceRemapping(IFile originalResource, IFile newResource) {
        try {
            String resourcePath = (newResource == null ? null : newResource.getFullPath().toPortableString());
            originalResource.setPersistentProperty(RESOURCE_REMAP_NAME, resourcePath);
        } catch (CoreException e) {
            DartCore.logError(e);
        }
    }

    /**
     * Sets the value of the string-valued user-defined property for the given key.
     * <p>
     * User-defined properties are defined in the <code>editor.properties</code> file located in the
     * eclipse installation directory.
     * 
     * @see DartCore#getEclipseInstallationDirectory()
     * @param key the name of the property
     * @param value the string-valued property
     */
    public static void setUserDefinedProperty(String key, String value) {

        Properties properties = new Properties();

        File installDirectory = getEclipseInstallationDirectory();
        File file = new File(installDirectory, EDITOR_PROPERTIES);

        try {
            if (!file.exists()) {
                file.createNewFile();
            }
            properties.load(new FileReader(file));
            properties.setProperty(key, value);
            properties.store(new FileWriter(file), null);
        } catch (FileNotFoundException e) {
            logError(e);
        } catch (IOException e) {
            logError(e);
        }

    }

    /**
     * Answer the log used by {@link #logError(String)} and other local methods for logging errors,
     * warnings, and information.
     * 
     * @return the {@link ILog} or {@code null} if not accessible (for example during platform
     *         shutdown)
     */
    private static ILog getPluginLog() {
        try {
            return PLUGIN_LOG != null ? PLUGIN_LOG : getPlugin().getLog();
        } catch (Throwable e) {
            return null;
        }
    }

    /**
     * Record an error
     */
    private static void instrumentationLogErrorImpl(String message, Throwable exception) {
        instrumentationLogImpl(message, exception, "LogError");
    }

    /**
     * Internal instrumentation message delivery implementation
     * 
     * @param message optional message to be delivered
     * @param exception optional exception to be delivered
     * @param messageType message type, common values LogError/LogMessage
     */
    private static void instrumentationLogImpl(String message, Throwable exception, String messageType) {
        if (instrumentationLogErrorEnabled) {
            InstrumentationBuilder instrumentation = Instrumentation.builder("DartCore." + messageType);
            try {
                instrumentation.data("Log_Message", message != null ? message : "null");
                instrumentation.data("Log_Exception", exception != null ? exception.toString() : "null");
                if (exception != null) {
                    instrumentation.record(exception);
                }
            } catch (Exception e) {
                instrumentationLogErrorEnabled = false;
                logErrorImpl("Instrumentation failed to log error", exception);
            } finally {
                instrumentation.log();
            }

        }

    }

    /**
     * Record an 'informational exception'
     */
    private static void instrumentationLogInfoImpl(String message, Throwable exception) {

        instrumentationLogImpl(message, exception, "LogInfo");

    }

    /**
     * Return <code>true</code> if the given file name's extension matches one of the passed
     * extensions.
     * 
     * @param fileName the file name being tested
     * @param extensions an array of file extensions to test against
     * @return <code>true</code> if the given file name's extension matches one of the passed
     *         extensions
     */
    private static boolean isLikeFileName(String fileName, String[] extensions) {
        if (fileName == null || fileName.length() == 0) {
            return false;
        }
        for (String extension : extensions) {
            if (StringUtilities.endsWithIgnoreCase(fileName, '.' + extension)) {
                return true;
            }
        }
        return false;
    }

    private static void logErrorImpl(String message, Throwable exception) {
        ILog pluginLog = getPluginLog();
        if (pluginLog != null) {
            pluginLog.log(new Status(Status.ERROR, PLUGIN_ID, message, exception));
        }
    }

    private IEclipsePreferences prefs;

    /**
     * Property key for user-specified analysis server arguments.
     */
    public static final String ANALYSIS_SERVER_ARG_PROP_KEY = "com.dart.tools.server.args";

    /**
     * Property key for user-specified Dart VM arguments for analysis server.
     */
    public static final String ANALYSIS_SERVER_VM_ARG_PROP_KEY = "com.dart.tools.server.vm.args";

    /**
     * Initialize a newly created instance of this class.
     */
    public DartCore() {
        PLUG_IN = this;
    }

    /**
     * Use dart2js if the SDK is present.
     */
    public boolean getCompileWithDart2JS() {
        return DartSdkManager.getManager().hasSdk();
    }

    public String getDart2jsFlags() {
        return getPrefs().get(PREFS_DART2JS_FLAGS, "");
    }

    public String[] getDart2jsFlagsAsArray() {
        return StringUtilities.parseArgumentString(getDart2jsFlags());
    }

    public String getDartiumLocationPref() {
        return getPrefs().get(PREFS_DARTIUM_LOCATION, "");
    }

    public boolean getDisableDartBasedBuilder(IProject project) {
        return getProjectPreferences(project).getBoolean(PROJECT_PREF_DISABLE_DART_BASED_BUILDER, false);
    }

    public boolean getEnableAnalytics() {
        if (DartCoreDebug.ASK_FOR_USER_ANALYTICS) {
            return getPrefs().getBoolean(PREFS_ENABLE_ANALYTICS, false);
        }
        return false;
    }

    /**
     * Given an File, return the appropriate java.io.File representing a package root. This can be
     * null if a package root should not be used.
     * 
     * @param file the File
     * @return the File for the package root, or null if none
     */
    public File getPackageRoot(File file) {
        IResource resource = ResourceUtil.getResource(file);
        if (resource != null) {
            return getPackageRoot(resource.getProject());
        }
        return null;
    }

    /**
     * Given an IProject, return the appropriate java.io.File representing a package root. This can be
     * null if a package root should not be used.
     * 
     * @param project the IProject
     * @return the File for the package root, or null if none
     */
    public File getPackageRoot(IProject project) {
        if (project != null) {
            String setting = getProjectPreferences(project).get(PROJECT_PREF_PACKAGE_ROOT, "");

            if (setting != null && setting.length() > 0) {
                String[] paths = setting.split(File.pathSeparator);
                return new File(paths[0]);
            }
        }

        File[] roots = CmdLineOptions.getOptions().getPackageRoots();

        if (roots.length > 0) {
            return roots[0];
        }

        return null;
    }

    /**
     * Get the core plugin preferences. Use savePrefs() to save the preferences.
     */
    public IEclipsePreferences getPrefs() {
        if (prefs == null) {
            prefs = InstanceScope.INSTANCE.getNode(PLUGIN_ID);
        }

        return prefs;
    }

    public IEclipsePreferences getProjectPreferences(IProject project) {
        ProjectScope projectScope = new ProjectScope(project);

        return projectScope.getNode(PLUGIN_ID);
    }

    public String getSdkLocationPref() {
        return getPrefs().get(PREFS_SDK_LOCATION, "");
    }

    public boolean getShowAnalyticsDailog() {
        return getPrefs().getBoolean(PREFS_SHOW_ANALYTICS_DIALOG, true);
    }

    /**
     * Given an IProject, return string representing a package root to be used for all VM launches.
     * This can be null if a package root should not be used.
     * 
     * @param project the IProject
     * @return the String for the package root, or null if none
     */
    public String getVmPackageRoot(IProject project) {
        if (project != null) {
            String setting = getProjectPreferences(project).get(PROJECT_PREF_VM_PACKAGE_ROOT, "");
            if (!setting.isEmpty()) {
                return setting;
            }
        }
        return null;
    }

    public boolean isAutoRunPubEnabled() {
        return DartCore.getPlugin().getPrefs().getBoolean(PUB_AUTO_RUN_PREFERENCE, true);
    }

    public boolean isHintsDart2JSEnabled() {
        return DartCore.getPlugin().getPrefs().getBoolean(ENABLE_HINTS_DART2JS_PREFERENCE, true);
    }

    public boolean isHintsEnabled() {
        return DartCore.getPlugin().getPrefs().getBoolean(ENABLE_HINTS_PREFERENCE, true);
    }

    public boolean isLintsEnabled() {
        return DartCore.getPlugin().getPrefs().getBoolean(ENABLE_LINTS_PREFERENCE, false);
    }

    /**
     * Save the core plugin preferences
     * 
     * @throws CoreException
     */
    public void savePrefs() throws CoreException {
        try {
            getPrefs().flush();
        } catch (BackingStoreException e) {
            throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, e.toString(), e));
        }
    }

    @Override
    public void sdkUpdated(DirectoryBasedDartSdk sdk) {
        Job job = new CleanLibrariesJob();

        job.schedule();
    }

    public void setDart2JsPreferences(String args) {
        IEclipsePreferences prefs = getPrefs();
        prefs.put(PREFS_DART2JS_FLAGS, args);

        try {
            getPrefs().flush();
        } catch (BackingStoreException exception) {
            logError(exception);
        }
    }

    public void setDisableDartBasedBuilder(IProject project, boolean value) throws CoreException {
        try {
            IEclipsePreferences prefs = getProjectPreferences(project);
            prefs.putBoolean(PROJECT_PREF_DISABLE_DART_BASED_BUILDER, value);
            prefs.flush();
        } catch (BackingStoreException ex) {
            throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, ex.toString(), ex));
        }
    }

    public void setEnableAnalytics(boolean value) {
        if (DartCoreDebug.ASK_FOR_USER_ANALYTICS) {
            IEclipsePreferences prefs = getPrefs();
            prefs.putBoolean(PREFS_ENABLE_ANALYTICS, value);

            try {
                getPrefs().flush();
            } catch (BackingStoreException exception) {
                logError(exception);
            }
        }
    }

    public void setPackageRoot(IProject project, String packageRootPath) throws CoreException {
        try {
            IEclipsePreferences prefs = getProjectPreferences(project);
            prefs.put(PROJECT_PREF_PACKAGE_ROOT, packageRootPath);
            prefs.flush();
        } catch (BackingStoreException ex) {
            throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, ex.toString(), ex));
        }
    }

    public void setShowAnalyticsDialogFalse() {
        IEclipsePreferences prefs = getPrefs();
        prefs.putBoolean(PREFS_SHOW_ANALYTICS_DIALOG, false);

        try {
            getPrefs().flush();
        } catch (BackingStoreException exception) {
            logError(exception);
        }
    }

    public void setVmPackageRoot(IProject project, String packageRootPath) throws CoreException {
        try {
            IEclipsePreferences prefs = getProjectPreferences(project);
            prefs.put(PROJECT_PREF_VM_PACKAGE_ROOT, packageRootPath);
            prefs.flush();
        } catch (BackingStoreException ex) {
            throw new CoreException(new Status(IStatus.ERROR, PLUGIN_ID, ex.toString(), ex));
        }
    }

    @Override
    public void start(BundleContext context) throws Exception {
        super.start(context);

        CmdLineOptions.setOptions(CmdLineOptions.parseCmdLine(Platform.getApplicationArgs()));
        CmdLineOptions.getOptions().printWarnings();

        if (DartCoreDebug.PERF_THREAD_CONTENTION_MONIOR) {
            try {
                java.lang.management.ThreadMXBean th = ManagementFactory.getThreadMXBean();
                th.setThreadContentionMonitoringEnabled(true);
            } catch (UnsupportedOperationException e) {
            }
        }

        AnalysisEngine analysisEngine = AnalysisEngine.getInstance();
        analysisEngine.setLogger(new Logger() {
            @Override
            public void logError(String message) {
                DartCore.logError(message);
            }

            @Override
            public void logError(String message, Throwable exception) {
                DartCore.logError(message, exception);
            }

            @Override
            public void logInformation(String message) {
                DartCore.logInformation(message);
            }

            @Override
            public void logInformation(String message, Throwable exception) {
                DartCore.logInformation(message, exception);
            }
        });
        Logging.setLogger(new com.google.dart.server.utilities.logging.Logger() {
            @Override
            public void logError(String message) {
                DartCore.logError(message);
            }

            @Override
            public void logError(String message, Throwable exception) {
                DartCore.logError(message, exception);
            }

            @Override
            public void logInformation(String message) {
                DartCore.logInformation(message);
            }

            @Override
            public void logInformation(String message, Throwable exception) {
                DartCore.logInformation(message, exception);
            }
        });

        DartSdkManager.getManager().addSdkListener(this);
        if (!DartCoreDebug.ENABLE_ANALYSIS_SERVER) {
            getProjectManager().hookListeners();
        } else {
            getAnalysisServer();
        }
    }

    @Override
    public void stop(BundleContext context) throws Exception {
        DartSdkManager.getManager().removeSdkListener(this);

        try {
            if (!DartCoreDebug.ENABLE_ANALYSIS_SERVER) {
                getProjectManager().stop();
            }

            synchronized (analysisServerLock) {
                if (analysisServer != null) {
                    analysisServer.server_shutdown();
                }
            }

            if (DartCoreDebug.METRICS) {
                StringWriter writer = new StringWriter();
                PerformanceManager.getInstance().printMetrics(new PrintWriter(writer));
                String metricsInfo = writer.toString();
                if (metricsInfo.length() > 0) {
                    getLog().log(new Status(Status.INFO, PLUGIN_ID, metricsInfo, null));
                }
            }
        } finally {
            super.stop(context);
        }
    }
}