/******************************************************************************* * Copyright © 2000, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.core.model; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Preferences; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.edt.ide.core.EDTCoreIDEPlugin; import org.eclipse.edt.ide.core.EGLNature; import org.eclipse.edt.ide.core.internal.model.Assert; import org.eclipse.edt.ide.core.internal.model.BatchOperation; import org.eclipse.edt.ide.core.internal.model.BufferManager; import org.eclipse.edt.ide.core.internal.model.EGLModel; import org.eclipse.edt.ide.core.internal.model.EGLModelManager; import org.eclipse.edt.ide.core.internal.model.EGLPathEntry; import org.eclipse.edt.ide.core.internal.model.EGLProject; import org.eclipse.edt.ide.core.internal.model.Region; import org.eclipse.edt.ide.core.internal.model.SetEGLPathOperation; import org.eclipse.edt.ide.core.internal.model.Util; /** * The plug-in runtime class for the EGL model plug-in containing the core * (UI-free) support for EGL projects. * <p> * Like all plug-in runtime classes (subclasses of <code>Plugin</code>), this * class is automatically instantiated by the platform when the plug-in gets * activated. Clients must not attempt to instantiate plug-in runtime classes * directly. * </p> * <p> * The single instance of this class can be accessed from any plug-in declaring * the EGL model plug-in as a prerequisite via * <code>EGLCore.getEGLCore()</code>. The EGL model plug-in will be activated * automatically if not already active. * </p> */ @SuppressWarnings("deprecation") public final class EGLCore { /** * The plug-in identifier of the EGL core support * (value <code>"com.ibm.etools.egl.internal.model.core"</code>). */ //TODO EDT Redo? public static final String PLUGIN_ID = EDTCoreIDEPlugin.PLUGIN_ID; //$NON-NLS-1$ /** * The identifier for the EGL builder * (value <code>"com.ibm.etools.egl.internal.model.core.eglbuilder"</code>). */ public static final String BUILDER_ID = PLUGIN_ID + ".eglbuilder"; //$NON-NLS-1$ /** * The identifier for the EGL model * (value <code>"com.ibm.etools.egl.internal.model.core.eglmodel"</code>). */ public static final String MODEL_ID = PLUGIN_ID + ".eglmodel"; //$NON-NLS-1$ /** * The identifier for the EGL nature * (value <code>"org.eclipse.edt.ide.core.eglnature"</code>). * The presence of this nature on a project indicates that it is * EGL-capable. * * @see org.eclipse.core.resources.IProject#hasNature(egl.lang.String) */ public static final String NATURE_ID = EGLNature.EGL_NATURE_ID; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions */ public static final String CORE_EGL_BUILD_ORDER = PLUGIN_ID + ".computeEGLBuildOrder"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.0 */ public static final String CORE_EGL_BUILD_RESOURCE_COPY_FILTER = PLUGIN_ID + ".builder.resourceCopyExclusionFilter"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.1 */ public static final String CORE_EGL_BUILD_DUPLICATE_RESOURCE = PLUGIN_ID + ".builder.duplicateResourceTask"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.1 */ public static final String CORE_EGL_BUILD_CLEAN_OUTPUT_FOLDER = PLUGIN_ID + ".builder.cleanOutputFolder"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.1 */ public static final String CORE_INCOMPLETE_CLASSPATH = PLUGIN_ID + ".incompleteEGLPath"; //$NON-NLS-1$ // /** // * Possible configurable option ID. // * @see #getDefaultOptions // * @since 2.1 // */ // public static final String CORE_CIRCULAR_CLASSPATH = PLUGIN_ID + ".circularEGLPath"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.0 */ public static final String CORE_EGL_BUILD_INVALID_CLASSPATH = PLUGIN_ID + ".builder.invalidEGLPath"; //$NON-NLS-1$ /** * Possible configurable option ID. * @see #getDefaultOptions * @since 2.0 */ public static final String CORE_ENCODING = PLUGIN_ID + ".encoding"; //$NON-NLS-1$ // /** // * Possible configurable option ID. // * @see #getDefaultOptions // * @since 2.1 // */ // public static final String CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS = PLUGIN_ID + ".eglpath.exclusionPatterns"; //$NON-NLS-1$ // /** // * Possible configurable option ID. // * @see #getDefaultOptions // * @since 2.1 // */ // public static final String CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS = PLUGIN_ID + ".eglpath.multipleOutputLocations"; //$NON-NLS-1$ /** * Default task tag * @since 2.1 */ public static final String DEFAULT_TASK_TAG = "TODO"; //$NON-NLS-1$ /** * Default task priority * @since 2.1 */ public static final String DEFAULT_TASK_PRIORITY = "NORMAL"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String ABORT = "abort"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions */ public static final String ERROR = "error"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions */ public static final String WARNING = "warning"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions */ public static final String IGNORE = "ignore"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions */ public static final String COMPUTE = "compute"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String INSERT = "insert"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String DO_NOT_INSERT = "do not insert"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String PRESERVE_ONE = "preserve one"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String CLEAR_ALL = "clear all"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String NORMAL = "normal"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String COMPACT = "compact"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String TAB = "tab"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String SPACE = "space"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String ENABLED = "enabled"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.0 */ public static final String DISABLED = "disabled"; //$NON-NLS-1$ /** * Possible configurable option value. * @see #getDefaultOptions * @since 2.1 */ public static final String CLEAN = "clean"; //$NON-NLS-1$ /** * Name of the processor extension point. */ public static final String PT_PROCESSOR = "processor"; //$NON-NLS-1$ /** * Name of the processor extension point attribute that holds the class name. */ public static final String CLASS = "class"; //$NON-NLS-1$ /** * Name of default EGL Source Folder. */ // This value is now stored in a preference instead of hardcorded. Use // EDTCoreIDEPlugin.getPlugin().getPreferenceStore().getString( EDTCorePreferenceConstants.EGL_SOURCE_FOLDER ). // public static final String DEFAULT_EGL_SOURCE = "eglsource"; //$NON-NLS-1$ /** * Name of default EGL Source Folder. */ public static final String DEFAULT_JAVA_SOURCE = "javasource"; //$NON-NLS-1$ /** * Name of default EGL JavaScript Folder. */ public static final String DEFAULT_JAVASCRIPT_SOURCE = "javascript"; //$NON-NLS-1$ /** * Name of default COBOL Source Folder. */ public static final String DEFAULT_COBOL_SOURCE = "cobolsource"; //$NON-NLS-1$ /** * Name of default folder containing IR files. */ // This value is now stored in a preference instead of hardcorded. Use // EDTCoreIDEPlugin.getPlugin().getPreferenceStore().getString( EDTCorePreferenceConstants.EGL_OUTPUT_FOLDER ). // public static final String DEFAULT_EGL_BIN = "eglbin"; //$NON-NLS-1$ public static IWorkspace getWorkspace() { return ResourcesPlugin.getWorkspace(); } /** * Adds the given listener for changes to EGL elements. * Has no effect if an identical listener is already registered. * * This listener will only be notified during the POST_CHANGE resource change notification * and any reconcile operation (POST_RECONCILE). * For finer control of the notification, use <code>addElementChangedListener(IElementChangedListener,int)</code>, * which allows to specify a different eventMask. * * @see ElementChangedEvent * @param listener the listener */ public static void addElementChangedListener(IElementChangedListener listener) { addElementChangedListener(listener, ElementChangedEvent.POST_CHANGE | ElementChangedEvent.POST_RECONCILE); } /** * Adds the given listener for changes to EGL elements. * Has no effect if an identical listener is already registered. * After completion of this method, the given listener will be registered for exactly * the specified events. If they were previously registered for other events, they * will be deregistered. * <p> * Once registered, a listener starts receiving notification of changes to * egl elements in the model. The listener continues to receive * notifications until it is replaced or removed. * </p> * <p> * Listeners can listen for several types of event as defined in <code>ElementChangeEvent</code>. * Clients are free to register for any number of event types however if they register * for more than one, it is their responsibility to ensure they correctly handle the * case where the same egl element change shows up in multiple notifications. * Clients are guaranteed to receive only the events for which they are registered. * </p> * * @param listener the listener * @param eventMask the bit-wise OR of all event types of interest to the listener * @see IElementChangedListener * @see ElementChangedEvent * @see #removeElementChangedListener(IElementChangedListener) * @since 2.0 */ public static void addElementChangedListener(IElementChangedListener listener, int eventMask) { EGLModelManager.getEGLModelManager().addElementChangedListener(listener, eventMask); } /** * Configures the given marker attribute map for the given EGL element. * Used for markers, which denote a EGL element rather than a resource. * * @param attributes the mutable marker attribute map (key type: <code>String</code>, * value type: <code>String</code>) * @param element the EGL element for which the marker needs to be configured */ public static void addEGLElementMarkerAttributes(Map attributes, IEGLElement element) { if (element instanceof IMember) element = ((IMember) element).getEGLFile(); if (attributes != null && element != null) attributes.put(EDTCoreIDEPlugin.ATT_HANDLE_ID, element.getHandleIdentifier()); } /** * Returns the EGL model element corresponding to the given handle identifier * generated by <code>IEGLElement.getHandleIdentifier()</code>, or * <code>null</code> if unable to create the associated element. */ public static IEGLElement create(String handleIdentifier) { if (handleIdentifier == null) { return null; } try { return EGLModelManager.getEGLModelManager().getHandleFromMemento(handleIdentifier); } catch (EGLModelException e) { return null; } } /** * Returns the EGL element corresponding to the given file, or * <code>null</code> if unable to associate the given file * with a EGL element. * * <p>The file must be one of:<ul> * <li>a <code>.egl</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li> * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li> * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li> * </ul> * <p> * Creating a EGL element has the side effect of creating and opening all of the * element's parents if they are not yet open. * * @param the given file * @return the EGL element corresponding to the given file, or * <code>null</code> if unable to associate the given file * with a EGL element */ public static IEGLElement create(IFile file) { return EGLModelManager.create(file, null); } /** * Returns the package fragment or package fragment root corresponding to the given folder, or * <code>null</code> if unable to associate the given folder with a EGL element. * <p> * Note that a package fragment root is returned rather than a default package. * <p> * Creating a EGL element has the side effect of creating and opening all of the * element's parents if they are not yet open. * * @param the given folder * @return the package fragment or package fragment root corresponding to the given folder, or * <code>null</code> if unable to associate the given folder with a EGL element */ public static IEGLElement create(IFolder folder) { return EGLModelManager.create(folder, null); } /** * Returns the EGL project corresponding to the given project. * <p> * Creating a EGL Project has the side effect of creating and opening all of the * project's parents if they are not yet open. * <p> * Note that no check is done at this time on the existence or the egl nature of this project. * * @param project the given project * @return the EGL project corresponding to the given project, null if the given project is null */ public static IEGLProject create(IProject project) { if (project == null) { return null; } EGLModel eglModel = EGLModelManager.getEGLModelManager().getEGLModel(); return eglModel.getEGLProject(project); } /** * Returns the EGL element corresponding to the given resource, or * <code>null</code> if unable to associate the given resource * with a EGL element. * <p> * The resource must be one of:<ul> * <li>a project - the element returned is the corresponding <code>IEGLProject</code></li> * <li>a <code>.egl</code> file - the element returned is the corresponding <code>IEGLFile</code></li> * <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code> * or <code>IPackageFragment</code></li> * <li>the workspace root resource - the element returned is the <code>IEGLModel</code></li> * </ul> * <p> * Creating a EGL element has the side effect of creating and opening all of the * element's parents if they are not yet open. * * @param resource the given resource * @return the EGL element corresponding to the given resource, or * <code>null</code> if unable to associate the given resource * with a EGL element */ public static IEGLElement create(IResource resource) { return EGLModelManager.create(resource, null); } /** * Returns the EGL model. * * @param root the given root * @return the EGL model, or <code>null</code> if the root is null */ public static IEGLModel create(IWorkspaceRoot root) { if (root == null) { return null; } return EGLModelManager.getEGLModelManager().getEGLModel(); } /** * Creates and returns a compilation unit element for * the given <code>.egl</code> file. Returns <code>null</code> if unable * to recognize the compilation unit. * * @param file the given <code>.egl</code> file * @return a compilation unit element for the given <code>.egl</code> file, or <code>null</code> if unable * to recognize the compilation unit */ public static IEGLFile createEGLFileFrom(IFile file) { return EGLModelManager.createEGLFileFrom(file, null); } /** * Returns a table of all known configurable options with their default values. * These options allow to configure the behaviour of the underlying components. * The client may safely use the result as a template that they can modify and * then pass to <code>setOptions</code>. * * Helper constants have been defined on JavaCore for each of the option ID and * their possible constant values. * * Note: more options might be added in further releases. * <pre> * RECOGNIZED OPTIONS: * COMPILER / Generating Local Variable Debug Attribute * When generated, this attribute will enable local variable names * to be displayed in debugger, only in place where variables are * definitely assigned (.class file is then bigger) * - option id: "org.eclipse.jdt.core.compiler.debug.localVariable" * - possible values: { "generate", "do not generate" } * - default: "generate" * * COMPILER / Generating Line Number Debug Attribute * When generated, this attribute will enable source code highlighting in debugger * (.class file is then bigger). * - option id: "org.eclipse.jdt.core.compiler.debug.lineNumber" * - possible values: { "generate", "do not generate" } * - default: "generate" * * COMPILER / Generating Source Debug Attribute * When generated, this attribute will enable the debugger to present the * corresponding source code. * - option id: "org.eclipse.jdt.core.compiler.debug.sourceFile" * - possible values: { "generate", "do not generate" } * - default: "generate" * * COMPILER / Preserving Unused Local Variables * Unless requested to preserve unused local variables (that is, never read), the * compiler will optimize them out, potentially altering debugging * - option id: "org.eclipse.jdt.core.compiler.codegen.unusedLocal" * - possible values: { "preserve", "optimize out" } * - default: "preserve" * * COMPILER / Defining Target Java Platform * For binary compatibility reason, .class files can be tagged to with certain VM versions and later. * Note that "1.4" target require to toggle compliance mode to "1.4" too. * - option id: "org.eclipse.jdt.core.compiler.codegen.targetPlatform" * - possible values: { "1.1", "1.2", "1.3", "1.4" } * - default: "1.1" * * COMPILER / Reporting Unreachable Code * Unreachable code can optionally be reported as an error, warning or simply * ignored. The bytecode generation will always optimized it out. * - option id: "org.eclipse.jdt.core.compiler.problem.unreachableCode" * - possible values: { "error", "warning", "ignore" } * - default: "error" * * COMPILER / Reporting Invalid Import * An import statement that cannot be resolved might optionally be reported * as an error, as a warning or ignored. * - option id: "org.eclipse.jdt.core.compiler.problem.invalidImport" * - possible values: { "error", "warning", "ignore" } * - default: "error" * * COMPILER / Reporting Attempt to Override Package-Default Method * A package default method is not visible in a different package, and thus * cannot be overridden. When enabling this option, the compiler will signal * such scenarii either as an error or a warning. * - option id: "org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Method With Constructor Name * Naming a method with a constructor name is generally considered poor * style programming. When enabling this option, the compiler will signal such * scenarii either as an error or a warning. * - option id: "org.eclipse.jdt.core.compiler.problem.methodWithConstructorName" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Deprecation * When enabled, the compiler will signal use of deprecated API either as an * error or a warning. * - option id: "org.eclipse.jdt.core.compiler.problem.deprecation" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Deprecation Inside Deprecated Code * When enabled, the compiler will signal use of deprecated API inside deprecated code. * The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.deprecation". * - option id: "org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode" * - possible values: { "enabled", "disabled" } * - default: "disabled" * * COMPILER / Reporting Hidden Catch Block * Locally to a try statement, some catch blocks may hide others . For example, * try { throw new java.io.CharConversionException(); * } catch (java.io.CharConversionException e) { * } catch (java.io.IOException e) {}. * When enabling this option, the compiler will issue an error or a warning for hidden * catch blocks corresponding to checked exceptions * - option id: "org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Unused Local * When enabled, the compiler will issue an error or a warning for unused local * variables (that is, variables never read from) * - option id: "org.eclipse.jdt.core.compiler.problem.unusedLocal" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Unused Parameter * When enabled, the compiler will issue an error or a warning for unused method * parameters (that is, parameters never read from) * - option id: "org.eclipse.jdt.core.compiler.problem.unusedParameter" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Unused Parameter if Implementing Abstract Method * When enabled, the compiler will signal unused parameters in abstract method implementations. * The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.unusedParameter". * - option id: "org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract" * - possible values: { "enabled", "disabled" } * - default: "disabled" * * COMPILER / Reporting Unused Parameter if Overriding Concrete Method * When enabled, the compiler will signal unused parameters in methods overriding concrete ones. * The severity of the problem is controlled with option "org.eclipse.jdt.core.compiler.problem.unusedParameter". * - option id: "org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete" * - possible values: { "enabled", "disabled" } * - default: "disabled" * * COMPILER / Reporting Unused Import * When enabled, the compiler will issue an error or a warning for unused import * reference * - option id: "org.eclipse.jdt.core.compiler.problem.unusedImport" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Unused Private Members * When enabled, the compiler will issue an error or a warning whenever a private * method or field is declared but never used within the same unit. * - option id: "org.eclipse.jdt.core.compiler.problem.unusedPrivateMember" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Synthetic Access Emulation * When enabled, the compiler will issue an error or a warning whenever it emulates * access to a non-accessible member of an enclosing type. Such access can have * performance implications. * - option id: "org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Non-Externalized String Literal * When enabled, the compiler will issue an error or a warning for non externalized * String literal (that is, not tagged with //$NON-NLS-<n>$). * - option id: "org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Usage of 'assert' Identifier * When enabled, the compiler will issue an error or a warning whenever 'assert' is * used as an identifier (reserved keyword in 1.4) * - option id: "org.eclipse.jdt.core.compiler.problem.assertIdentifier" * - possible values: { "error", "warning", "ignore" } * - default: "ignore" * * COMPILER / Reporting Non-Static Reference to a Static Member * When enabled, the compiler will issue an error or a warning whenever a static field * or method is accessed with an expression receiver. A reference to a static member should * be qualified with a type name. * - option id: "org.eclipse.jdt.core.compiler.problem.staticAccessReceiver" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Assignment with no Effect * When enabled, the compiler will issue an error or a warning whenever an assignment * has no effect (e.g 'x = x'). * - option id: "org.eclipse.jdt.core.compiler.problem.noEffectAssignment" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Interface Method not Compatible with non-Inherited Methods * When enabled, the compiler will issue an error or a warning whenever an interface * defines a method incompatible with a non-inherited Object method. Until this conflict * is resolved, such an interface cannot be implemented, For example, * interface I { * int clone(); * } * - option id: "org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Reporting Usage of char[] Expressions in String Concatenations * When enabled, the compiler will issue an error or a warning whenever a char[] expression * is used in String concatenations (for example, "hello" + new char[]{'w','o','r','l','d'}). * - option id: "org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion" * - possible values: { "error", "warning", "ignore" } * - default: "warning" * * COMPILER / Setting Source Compatibility Mode * Specify whether source is 1.3 or 1.4 compatible. From 1.4 on, 'assert' is a keyword * reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM * level should be set to "1.4" and the compliance mode should be "1.4". * - option id: "org.eclipse.jdt.core.compiler.source" * - possible values: { "1.3", "1.4" } * - default: "1.3" * * COMPILER / Setting Compliance Level * Select the compliance level for the compiler. In "1.3" mode, source and target settings * should not go beyond "1.3" level. * - option id: "org.eclipse.jdt.core.compiler.compliance" * - possible values: { "1.3", "1.4" } * - default: "1.3" * * COMPILER / Maximum number of problems reported per compilation unit * Specify the maximum number of problems reported on each compilation unit. * - option id: "org.eclipse.jdt.core.compiler.maxProblemPerUnit" * - possible values: "<n>" where <n> is zero or a positive integer (if zero then all problems are reported). * - default: "100" * * COMPILER / Define the Automatic Task Tags * When the tag list is not empty, the compiler will issue a task marker whenever it encounters * one of the corresponding tag inside any comment in Java source code. * Generated task messages will include the tag, and range until the next line separator or comment ending. * Note that tasks messages are trimmed. * - option id: "org.eclipse.jdt.core.compiler.taskTags" * - possible values: { "<tag>[,<tag>]*" } where <tag> is a String without any wild-card or leading/trailing spaces * - default: "" * * COMPILER / Define the Automatic Task Priorities * In parallel with the Automatic Task Tags, this list defines the priorities (high, normal or low) * of the task markers issued by the compiler. * If the default is specified, the priority of each task marker is "NORMAL". * - option id: "org.eclipse.jdt.core.compiler.taskPriorities" * - possible values: { "<priority>[,<priority>]*" } where <priority> is one of "HIGH", "NORMAL" or "LOW" * - default: "" * * BUILDER / Specifying Filters for Resource Copying Control * Allow to specify some filters to control the resource copy process. * - option id: "org.eclipse.jdt.core.builder.resourceCopyExclusionFilter" * - possible values: { "<name>[,<name>]* } where <name> is a file name pattern (* and ? wild-cards allowed) * or the name of a folder which ends with '/' * - default: "" * * BUILDER / Abort if Invalid Classpath * Allow to toggle the builder to abort if the classpath is invalid * - option id: "org.eclipse.jdt.core.builder.invalidClasspath" * - possible values: { "abort", "ignore" } * - default: "abort" * * BUILDER / Cleaning Output Folder(s) * Indicate whether the JavaBuilder is allowed to clean the output folders * when performing full build operations. * - option id: "org.eclipse.jdt.core.builder.cleanOutputFolder" * - possible values: { "clean", "ignore" } * - default: "clean" * * BUILDER / Reporting Duplicate Resources * Indicate the severity of the problem reported when more than one occurrence * of a resource is to be copied into the output location. * - option id: "org.eclipse.jdt.core.builder.duplicateResourceTask" * - possible values: { "error", "warning" } * - default: "warning" * * JAVACORE / Computing Project Build Order * Indicate whether JavaCore should enforce the project build order to be based on * the classpath prerequisite chain. When requesting to compute, this takes over * the platform default order (based on project references). * - option id: "org.eclipse.jdt.core.computeJavaBuildOrder" * - possible values: { "compute", "ignore" } * - default: "ignore" * * JAVACORE / Specify Default Source Encoding Format * Get the encoding format for compiled sources. This setting is read-only, it is equivalent * to 'ResourcesPlugin.getEncoding()'. * - option id: "org.eclipse.jdt.core.encoding" * - possible values: { any of the supported encoding name}. * - default: <platform default> * * JAVACORE / Reporting Incomplete Classpath * Indicate the severity of the problem reported when an entry on the classpath does not exist, * is not legite or is not visible (for example, a referenced project is closed). * - option id: "org.eclipse.jdt.core.incompleteClasspath" * - possible values: { "error", "warning"} * - default: "error" * * JAVACORE / Reporting Classpath Cycle * Indicate the severity of the problem reported when a project is involved in a cycle. * - option id: "org.eclipse.jdt.core.circularClasspath" * - possible values: { "error", "warning" } * - default: "error" * * JAVACORE / Enabling Usage of Classpath Exclusion Patterns * When disabled, no entry on a project classpath can be associated with * an exclusion pattern. * - option id: "org.eclipse.jdt.core.classpath.exclusionPatterns" * - possible values: { "enabled", "disabled" } * - default: "enabled" * * JAVACORE / Enabling Usage of Classpath Multiple Output Locations * When disabled, no entry on a project classpath can be associated with * a specific output location, preventing thus usage of multiple output locations. * - option id: "org.eclipse.jdt.core.classpath.multipleOutputLocations" * - possible values: { "enabled", "disabled" } * - default: "enabled" * * FORMATTER / Inserting New Line Before Opening Brace * When Insert, a new line is inserted before an opening brace, otherwise nothing * is inserted * - option id: "org.eclipse.jdt.core.formatter.newline.openingBrace" * - possible values: { "insert", "do not insert" } * - default: "do not insert" * * FORMATTER / Inserting New Line Inside Control Statement * When Insert, a new line is inserted between } and following else, catch, finally * - option id: "org.eclipse.jdt.core.formatter.newline.controlStatement" * - possible values: { "insert", "do not insert" } * - default: "do not insert" * * FORMATTER / Clearing Blank Lines * When Clear all, all blank lines are removed. When Preserve one, only one is kept * and all others removed. * - option id: "org.eclipse.jdt.core.formatter.newline.clearAll" * - possible values: { "clear all", "preserve one" } * - default: "preserve one" * * FORMATTER / Inserting New Line Between Else/If * When Insert, a blank line is inserted between an else and an if when they are * contiguous. When choosing to not insert, else-if will be kept on the same * line when possible. * - option id: "org.eclipse.jdt.core.formatter.newline.elseIf" * - possible values: { "insert", "do not insert" } * - default: "do not insert" * * FORMATTER / Inserting New Line In Empty Block * When insert, a line break is inserted between contiguous { and }, if } is not followed * by a keyword. * - option id: "org.eclipse.jdt.core.formatter.newline.emptyBlock" * - possible values: { "insert", "do not insert" } * - default: "insert" * * FORMATTER / Splitting Lines Exceeding Length * Enable splitting of long lines (exceeding the configurable length). Length of 0 will * disable line splitting * - option id: "org.eclipse.jdt.core.formatter.lineSplit" * - possible values: "<n>", where n is zero or a positive integer * - default: "80" * * FORMATTER / Compacting Assignment * Assignments can be formatted asymmetrically, for example 'int x= 2;', when Normal, a space * is inserted before the assignment operator * - option id: "org.eclipse.jdt.core.formatter.style.assignment" * - possible values: { "compact", "normal" } * - default: "normal" * * FORMATTER / Defining Indentation Character * Either choose to indent with tab characters or spaces * - option id: "org.eclipse.jdt.core.formatter.tabulation.char" * - possible values: { "tab", "space" } * - default: "tab" * * FORMATTER / Defining Space Indentation Length * When using spaces, set the amount of space characters to use for each * indentation mark. * - option id: "org.eclipse.jdt.core.formatter.tabulation.size" * - possible values: "<n>", where n is a positive integer * - default: "4" * * FORMATTER / Inserting space in cast expression * When Insert, a space is added between the type and the expression in a cast expression. * - option id: "org.eclipse.jdt.core.formatter.space.castexpression" * - possible values: { "insert", "do not insert" } * - default: "insert" * * CODEASSIST / Activate Visibility Sensitive Completion * When active, completion doesn't show that you can not see * (for example, you can not see private methods of a super class). * - option id: "org.eclipse.jdt.core.codeComplete.visibilityCheck" * - possible values: { "enabled", "disabled" } * - default: "disabled" * * CODEASSIST / Automatic Qualification of Implicit Members * When active, completion automatically qualifies completion on implicit * field references and message expressions. * - option id: "org.eclipse.jdt.core.codeComplete.forceImplicitQualification" * - possible values: { "enabled", "disabled" } * - default: "disabled" * * CODEASSIST / Define the Prefixes for Field Name * When the prefixes is non empty, completion for field name will begin with * one of the proposed prefixes. * - option id: "org.eclipse.jdt.core.codeComplete.fieldPrefixes" * - possible values: { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Prefixes for Static Field Name * When the prefixes is non empty, completion for static field name will begin with * one of the proposed prefixes. * - option id: "org.eclipse.jdt.core.codeComplete.staticFieldPrefixes" * - possible values: { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Prefixes for Local Variable Name * When the prefixes is non empty, completion for local variable name will begin with * one of the proposed prefixes. * - option id: "org.eclipse.jdt.core.codeComplete.localPrefixes" * - possible values: { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Prefixes for Argument Name * When the prefixes is non empty, completion for argument name will begin with * one of the proposed prefixes. * - option id: "org.eclipse.jdt.core.codeComplete.argumentPrefixes" * - possible values: { "<prefix>[,<prefix>]*" } where <prefix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Suffixes for Field Name * When the suffixes is non empty, completion for field name will end with * one of the proposed suffixes. * - option id: "org.eclipse.jdt.core.codeComplete.fieldSuffixes" * - possible values: { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Suffixes for Static Field Name * When the suffixes is non empty, completion for static field name will end with * one of the proposed suffixes. * - option id: "org.eclipse.jdt.core.codeComplete.staticFieldSuffixes" * - possible values: { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Suffixes for Local Variable Name * When the suffixes is non empty, completion for local variable name will end with * one of the proposed suffixes. * - option id: "org.eclipse.jdt.core.codeComplete.localSuffixes" * - possible values: { "<suffix>[,<suffix>]*" } where <suffix> is a String without any wild-card * - default: "" * * CODEASSIST / Define the Suffixes for Argument Name * When the suffixes is non empty, completion for argument name will end with * one of the proposed suffixes. * - option id: "org.eclipse.jdt.core.codeComplete.argumentSuffixes" * - possible values: { "<suffix>[,<suffix>]*" } where <prefix> is a String without any wild-card * - default: "" * </pre> * * @return a mutable table containing the default settings of all known options * (key type: <code>String</code>; value type: <code>String</code>) * @see #setOptions */ public static Hashtable getDefaultOptions() { Hashtable defaultOptions = new Hashtable(10); // see #initializeDefaultPluginPreferences() for changing default settings Preferences preferences = getPlugin().getPluginPreferences(); HashSet optionNames = EGLModelManager.OptionNames; // get preferences set to their default String[] defaultPropertyNames = preferences.defaultPropertyNames(); for (int i = 0; i < defaultPropertyNames.length; i++) { String propertyName = defaultPropertyNames[i]; if (optionNames.contains(propertyName)) { defaultOptions.put(propertyName, preferences.getDefaultString(propertyName)); } } // get preferences not set to their default String[] propertyNames = preferences.propertyNames(); for (int i = 0; i < propertyNames.length; i++) { String propertyName = propertyNames[i]; if (optionNames.contains(propertyName)) { defaultOptions.put(propertyName, preferences.getDefaultString(propertyName)); } } // get encoding through resource plugin defaultOptions.put(CORE_ENCODING, ResourcesPlugin.getEncoding()); return defaultOptions; } /** * Answers the project specific value for a given EGLPath container. * In case this container path could not be resolved, then will answer <code>null</code>. * Both the container path and the project context are supposed to be non-null. * <p> * The containerPath is a formed by a first ID segment followed with extra segments, which can be * used as additional hints for resolution. If no container was ever recorded for this container path * onto this project (using <code>setEGLPathContainer</code>, then a * <code>EGLPathContainerInitializer</code> will be activated if any was registered for this container * ID onto the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". * <p> * There is no assumption that the returned container must answer the exact same containerPath * when requested <code>IEGLPathContainer#getPath</code>. * Indeed, the containerPath is just an indication for resolving it to an actual container object. * <p> * EGLPath container values are persisted locally to the workspace, but * are not preserved from a session to another. It is thus highly recommended to register a * <code>EGLPathContainerInitializer</code> for each referenced container * (through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer"). * <p> * @param containerPath the name of the container, which needs to be resolved * @param project a specific project in which the container is being resolved * @return the corresponding EGLPath container or <code>null</code> if unable to find one. * * @exception EGLModelException if an exception occurred while resolving the container, or if the resolved container * contains illegal entries (contains CPE_CONTAINER entries or null entries). * * @see EGLPathContainerInitializer * @see IEGLPathContainer * @see #setEGLPathContainer(IPath, IEGLProject[], IEGLPathContainer[], IProgressMonitor) * @since 2.0 */ public static IEGLPathContainer getEGLPathContainer(final IPath containerPath, final IEGLProject project) throws EGLModelException { IEGLPathContainer container = EGLModelManager.containerGet(project, containerPath); if (container == EGLModelManager.ContainerInitializationInProgress) return null; // break cycle if (container == null) { final EGLPathContainerInitializer initializer = EGLCore.getEGLPathContainerInitializer(containerPath.segment(0)); if (initializer != null) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer INIT - triggering initialization of: [" + project.getElementName() + "] " + containerPath + " using initializer: " + initializer); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ new Exception("FAKE exception for dumping current CPContainer ([" + project.getElementName() + "] " + containerPath + ")INIT invocation stack trace").printStackTrace(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ } EGLModelManager.containerPut(project, containerPath, EGLModelManager.ContainerInitializationInProgress); // avoid initialization cycles boolean ok = false; try { // wrap initializer call with Safe runnable in case initializer would be causing some grief Platform.run(new ISafeRunnable() { public void handleException(Throwable exception) { Util.log(exception, "Exception occurred in EGLPath container initializer: " + initializer); //$NON-NLS-1$ } public void run() throws Exception { initializer.initialize(containerPath, project); } }); // retrieve value (if initialization was successful) container = EGLModelManager.containerGet(project, containerPath); if (container == EGLModelManager.ContainerInitializationInProgress) return null; // break cycle ok = true; } finally { if (!ok) EGLModelManager.containerPut(project, containerPath, null); // flush cache } if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.print("CPContainer INIT - after resolution: [" + project.getElementName() + "] " + containerPath + " --> "); //$NON-NLS-2$//$NON-NLS-1$//$NON-NLS-3$ if (container != null) { System.out.print("container: " + container.getDescription() + " {"); //$NON-NLS-2$//$NON-NLS-1$ IEGLPathEntry[] entries = container.getEGLPathEntries(); if (entries != null) { for (int i = 0; i < entries.length; i++) { if (i > 0) System.out.println(", "); //$NON-NLS-1$ System.out.println(entries[i]); } } System.out.println("}"); //$NON-NLS-1$ } else { System.out.println("{unbound}"); //$NON-NLS-1$ } } } else { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer INIT - no initializer found for: " + project.getElementName() + "] " + containerPath); //$NON-NLS-1$ //$NON-NLS-2$ } } } return container; } /** * Helper method finding the EGLPath container initializer registered for a given EGLPath container ID * or <code>null</code> if none was found while iterating over the contributions to extension point to * the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". * <p> * A containerID is the first segment of any container path, used to identify the registered container initializer. * <p> * @param String - a containerID identifying a registered initializer * @return EGLPathContainerInitializer - the registered EGLPath container initializer or <code>null</code> if * none was found. * @since 2.1 */ public static EGLPathContainerInitializer getEGLPathContainerInitializer(String containerID) { IConfigurationElement[] configElements = Platform.getExtensionRegistry().getConfigurationElementsFor(PLUGIN_ID + "." + EGLModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID); //$NON-NLS-1$ if (configElements != null) { for (int j = 0; j < configElements.length; j++) { String initializerID = configElements[j].getAttribute("id"); //$NON-NLS-1$ if (initializerID != null && initializerID.equals(containerID)) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer INIT - found initializer: " + containerID + " --> " + configElements[j].getAttribute("class")); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ } try { Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$ if (execExt instanceof EGLPathContainerInitializer) { return (EGLPathContainerInitializer) execExt; } } catch (CoreException e) { } } } } return null; } /** * Returns the path held in the given EGLPath variable. * Returns <node>null</code> if unable to bind. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * Note that EGLPath variables can be contributed registered initializers for, * using the extension point "com.ibm.etools.egl.internal.model.core.EGLPathVariableInitializer". * If an initializer is registered for a variable, its persisted value will be ignored: * its initializer will thus get the opportunity to rebind the variable differently on * each session. * * @param variableName the name of the EGLPath variable * @return the path, or <code>null</code> if none * @see #setEGLPathVariable */ public static IPath getEGLPathVariable(final String variableName) { IPath variablePath = EGLModelManager.variableGet(variableName); if (variablePath == EGLModelManager.VariableInitializationInProgress) return null; // break cycle if (variablePath != null) { return variablePath; } // even if persisted value exists, initializer is given priority, only if no initializer is found the persisted value is reused final EGLPathVariableInitializer initializer = EGLCore.getEGLPathVariableInitializer(variableName); if (initializer != null) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable INIT - triggering initialization of: " + variableName + " using initializer: " + initializer); //$NON-NLS-1$ //$NON-NLS-2$ new Exception("FAKE exception for dumping current CPVariable (" + variableName + ")INIT invocation stack trace").printStackTrace(); //$NON-NLS-1$//$NON-NLS-2$ } EGLModelManager.variablePut(variableName, EGLModelManager.VariableInitializationInProgress); // avoid initialization cycles boolean ok = false; try { // wrap initializer call with Safe runnable in case initializer would be causing some grief Platform.run(new ISafeRunnable() { public void handleException(Throwable exception) { Util.log(exception, "Exception occurred in EGLPath variable initializer: " + initializer + " while initializing variable: " + variableName); //$NON-NLS-1$ //$NON-NLS-2$ } public void run() throws Exception { initializer.initialize(variableName); } }); variablePath = (IPath) EGLModelManager.variableGet(variableName); // initializer should have performed side-effect if (variablePath == EGLModelManager.VariableInitializationInProgress) return null; // break cycle (initializer did not init or reentering call) if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable INIT - after initialization: " + variableName + " --> " + variablePath); //$NON-NLS-2$//$NON-NLS-1$ } ok = true; } finally { if (!ok) EGLModelManager.variablePut(variableName, null); // flush cache } } else { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable INIT - no initializer found for: " + variableName); //$NON-NLS-1$ } } return variablePath; } /** * Helper method finding the EGLPath variable initializer registered for a given EGLPath variable name * or <code>null</code> if none was found while iterating over the contributions to extension point to * the extension point "com.ibm.etools.egl.internal.model.core.EGLPathVariableInitializer". * <p> * @param the given variable * @return EGLPathVariableInitializer - the registered EGLPath variable initializer or <code>null</code> if * none was found. * @since 2.1 */ public static EGLPathVariableInitializer getEGLPathVariableInitializer(String variable) { Plugin jdtCorePlugin = EGLCore.getPlugin(); if (jdtCorePlugin == null) return null; IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(EGLModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID); if (extension != null) { IExtension[] extensions = extension.getExtensions(); for (int i = 0; i < extensions.length; i++) { IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); for (int j = 0; j < configElements.length; j++) { try { String varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$ if (variable.equals(varAttribute)) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable INIT - found initializer: " + variable + " --> " + configElements[j].getAttribute("class")); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ } Object execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$ if (execExt instanceof EGLPathVariableInitializer) { return (EGLPathVariableInitializer) execExt; } } } catch (CoreException e) { } } } } return null; } /** * Returns the names of all known EGLPath variables. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * * @return the list of EGLPath variable names * @see #setEGLPathVariable */ public static String[] getEGLPathVariableNames() { return EGLModelManager.variableNames(); } /** * Helper method for returning one option value only. Equivalent to <code>(String)JavaCore.getOptions().get(optionName)</code> * Note that it may answer <code>null</code> if this option does not exist. * <p> * For a complete description of the configurable options, see <code>getDefaultOptions</code>. * </p> * * @param optionName the name of an option * @return the String value of a given option * @see #getDefaultOptions * @since 2.0 */ public static String getOption(String optionName) { if (CORE_ENCODING.equals(optionName)) { return ResourcesPlugin.getEncoding(); } if (EGLModelManager.OptionNames.contains(optionName)) { Preferences preferences = getPlugin().getPluginPreferences(); return preferences.getString(optionName).trim(); } return null; } /** * Returns 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> * For a complete description of the configurable options, see <code>getDefaultOptions</code>. * </p> * * @return table of current settings of all options * (key type: <code>String</code>; value type: <code>String</code>) * @see #getDefaultOptions */ public static Hashtable getOptions() { Hashtable options = new Hashtable(10); // see #initializeDefaultPluginPreferences() for changing default settings Plugin plugin = getPlugin(); if (plugin != null) { Preferences preferences = getPlugin().getPluginPreferences(); HashSet optionNames = EGLModelManager.OptionNames; // get preferences set to their default String[] defaultPropertyNames = preferences.defaultPropertyNames(); for (int i = 0; i < defaultPropertyNames.length; i++) { String propertyName = defaultPropertyNames[i]; if (optionNames.contains(propertyName)) { options.put(propertyName, preferences.getDefaultString(propertyName)); } } // get preferences not set to their default String[] propertyNames = preferences.propertyNames(); for (int i = 0; i < propertyNames.length; i++) { String propertyName = propertyNames[i]; if (optionNames.contains(propertyName)) { options.put(propertyName, preferences.getString(propertyName).trim()); } } // get encoding through resource plugin options.put(CORE_ENCODING, ResourcesPlugin.getEncoding()); } return options; } /** * Returns the single instance of the EGL core plug-in runtime class. * * @return the single instance of the EGL core plug-in runtime class */ public static Plugin getPlugin() { return EDTCoreIDEPlugin.getPlugin(); } /** * This is a helper method, which returns the resolved EGLPath entry denoted * by a given entry (if it is a variable entry). It is obtained by resolving the variable * reference in the first segment. Returns <node>null</code> if unable to resolve using * the following algorithm: * <ul> * <li> if variable segment cannot be resolved, returns <code>null</code></li> * <li> finds a project, JAR or binary folder in the workspace at the resolved path location</li> * <li> if none finds an external JAR file or folder outside the workspace at the resolved path location </li> * <li> if none returns <code>null</code></li> * </ul> * <p> * Variable source attachment path and root path are also resolved and recorded in the resulting EGLPath entry. * <p> * NOTE: This helper method does not handle EGLPath containers, for which should rather be used * <code>EGLCore#getEGLPathContainer(IPath, IEGLProject)</code>. * <p> * * @param entry the given variable entry * @return the resolved library or project EGLPath entry, or <code>null</code> * if the given variable entry could not be resolved to a valid EGLPath entry */ public static IEGLPathEntry getResolvedEGLPathEntry(IEGLPathEntry entry) { return entry; // TODO Do not handle variable yet /* if (entry.getEntryKind() != IEGLPathEntry.CPE_VARIABLE) return entry; else return null; IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); IPath resolvedPath = EGLCore.getResolvedVariablePath(entry.getPath()); if (resolvedPath == null) return null; Object target = EGLModel.getTarget(workspaceRoot, resolvedPath, false); if (target == null) return null; // inside the workspace if (target instanceof IResource) { IResource resolvedResource = (IResource) target; if (resolvedResource != null) { switch (resolvedResource.getType()) { case IResource.PROJECT : // internal project return EGLCore.newProjectEntry(resolvedPath, entry.isExported()); case IResource.FILE : if (Util.isArchiveFileName(resolvedResource.getName())) { // internal binary archive return EGLCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath()), getResolvedVariablePath(entry.getSourceAttachmentRootPath()), entry.isExported()); } break; case IResource.FOLDER : // internal binary folder return EGLCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath()), getResolvedVariablePath(entry.getSourceAttachmentRootPath()), entry.isExported()); } } } // outside the workspace if (target instanceof File) { File externalFile = (File) target; if (externalFile.isFile()) { String fileName = externalFile.getName().toLowerCase(); if (fileName.endsWith(".jar" //$NON-NLS-1$ ) || fileName.endsWith(".zip" //$NON-NLS-1$ )) { // external binary archive return EGLCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath()), getResolvedVariablePath(entry.getSourceAttachmentRootPath()), entry.isExported()); } } else { // external binary folder if (resolvedPath.isAbsolute()){ return EGLCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath()), getResolvedVariablePath(entry.getSourceAttachmentRootPath()), entry.isExported()); } } } return null; */ } /** * Resolve a variable path (helper method). * * @param variablePath the given variable path * @return the resolved variable path or <code>null</code> if none */ public static IPath getResolvedVariablePath(IPath variablePath) { if (variablePath == null) return null; int count = variablePath.segmentCount(); if (count == 0) return null; // lookup variable String variableName = variablePath.segment(0); IPath resolvedPath = EGLCore.getEGLPathVariable(variableName); if (resolvedPath == null) return null; // append path suffix if (count > 1) { resolvedPath = resolvedPath.append(variablePath.removeFirstSegments(1)); } return resolvedPath; } /** * Answers the shared working copies currently registered for this buffer factory. * Working copies can be shared by several clients using the same buffer factory,see * <code>IWorkingCopy.getSharedWorkingCopy</code>. * * @param factory the given buffer factory * @return the list of shared working copies for a given buffer factory * @see IWorkingCopy * @since 2.0 */ public static IWorkingCopy[] getSharedWorkingCopies(IBufferFactory factory) { // if factory is null, default factory must be used if (factory == null) factory = BufferManager.getDefaultBufferManager().getDefaultBufferFactory(); Map sharedWorkingCopies = EGLModelManager.getEGLModelManager().sharedWorkingCopies; Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(factory); if (perFactoryWorkingCopies == null) return EGLModelManager.NoWorkingCopy; Collection copies = perFactoryWorkingCopies.values(); IWorkingCopy[] result = new IWorkingCopy[copies.size()]; copies.toArray(result); return result; } /** * Returns whether the given marker references the given EGL element. * Used for markers, which denote a EGL element rather than a resource. * * @param element the element * @param marker the marker * @return <code>true</code> if the marker references the element, false otherwise * @exception CoreException if the <code>IMarker.getAttribute</code> on the marker fails */ public static boolean isReferencedBy(IEGLElement element, IMarker marker) throws CoreException { // only match units or classfiles if (element instanceof IMember) { IMember member = (IMember) element; element = member.getEGLFile(); } if (element == null) return false; if (marker == null) return false; String markerHandleId = (String) marker.getAttribute(EDTCoreIDEPlugin.ATT_HANDLE_ID); if (markerHandleId == null) return false; IEGLElement markerElement = EGLCore.create(markerHandleId); while (true) { if (element.equals(markerElement)) return true; // external elements may still be equal with different handleIDs. break; } return false; } /** * Returns whether the given marker delta references the given EGL element. * Used for markers deltas, which denote a EGL element rather than a resource. * * @param element the element * @param markerDelta the marker delta * @return <code>true</code> if the marker delta references the element * @exception CoreException if the <code>IMarkerDelta.getAttribute</code> on the marker delta fails */ public static boolean isReferencedBy(IEGLElement element, IMarkerDelta markerDelta) throws CoreException { // only match units or classfiles if (element instanceof IMember) { IMember member = (IMember) element; element = member.getEGLFile(); } if (element == null) return false; if (markerDelta == null) return false; String markerDeltarHandleId = (String) markerDelta.getAttribute(EDTCoreIDEPlugin.ATT_HANDLE_ID); if (markerDeltarHandleId == null) return false; IEGLElement markerElement = EGLCore.create(markerDeltarHandleId); while (true) { if (element.equals(markerElement)) return true; // external elements may still be equal with different handleIDs. break; } return false; } /** * Creates and returns a new EGLPath entry of kind <code>CPE_CONTAINER</code> * for the given path. The path of the container will be used during resolution so as to map this * container entry to a set of other EGLPath entries the container is acting for. * <p> * A container entry allows to express indirect references to a set of libraries, projects and variable entries, * which can be interpreted differently for each EGL project where it is used. * A EGLPath container entry can be resolved using <code>EGLCore.getResolvedEGLPathContainer</code>, * and updated with <code>EGLCore.EGLPathContainerChanged</code> * <p> * A container is exclusively resolved by a <code>EGLPathContainerInitializer</code> registered onto the * extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". * <p> * A container path must be formed of at least one segment, where: <ul> * <li> the first segment is a unique ID identifying the target container, there must be a container initializer registered * onto this ID through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". </li> * <li> the remaining segments will be passed onto the initializer, and can be used as additional * hints during the initialization phase. </li> * </ul> * <p> * Example of an EGLPathContainerInitializer for a EGLPath container denoting a default JDK container: * * containerEntry = EGLCore.newContainerEntry(new Path("MyProvidedJDK/default")); * * <extension * point="com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer"> * <containerInitializer * id="MyProvidedJDK" * class="com.example.MyInitializer"/> * <p> * Note that this operation does not attempt to validate EGLPath containers * or access the resources at the given paths. * <p> * The resulting entry is not exported to dependent projects. This method is equivalent to * <code>newContainerEntry(-,false)</code>. * <p> * @param containerPath the path identifying the container, it must be formed of two * segments * @return a new container EGLPath entry * * @see EGLCore#getEGLPathContainer(IPath, IEGLProject) * @see EGLCore#newContainerEntry(IPath, boolean) * @since 2.0 */ public static IEGLPathEntry newContainerEntry(IPath containerPath) { return newContainerEntry(containerPath, false); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_CONTAINER</code> * for the given path. The path of the container will be used during resolution so as to map this * container entry to a set of other EGLPath entries the container is acting for. * <p> * A container entry allows to express indirect references to a set of libraries, projects and variable entries, * which can be interpreted differently for each EGL project where it is used. * A EGLPath container entry can be resolved using <code>EGLCore.getResolvedEGLPathContainer</code>, * and updated with <code>EGLCore.EGLPathContainerChanged</code> * <p> * A container is exclusively resolved by a <code>EGLPathContainerInitializer</code> registered onto the * extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". * <p> * A container path must be formed of at least one segment, where: <ul> * <li> the first segment is a unique ID identifying the target container, there must be a container initializer registered * onto this ID through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". </li> * <li> the remaining segments will be passed onto the initializer, and can be used as additional * hints during the initialization phase. </li> * </ul> * <p> * Example of an EGLPathContainerInitializer for a EGLPath container denoting a default JDK container: * * containerEntry = EGLCore.newContainerEntry(new Path("MyProvidedJDK/default")); * * <extension * point="com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer"> * <containerInitializer * id="MyProvidedJDK" * class="com.example.MyInitializer"/> * <p> * Note that this operation does not attempt to validate EGLPath containers * or access the resources at the given paths. * <p> * @param containerPath the path identifying the container, it must be formed of at least * one segment (ID+hints) * @param isExported a boolean indicating whether this entry is contributed to dependent * projects in addition to the output location * @return a new container EGLPath entry * * @see EGLCore#getEGLPathContainer(IPath, IEGLProject) * @see EGLCore#setEGLPathContainer(IPath, IEGLProject[], IEGLPathContainer[], IProgressMonitor) * @see EGLCore#newContainerEntry(IPath, boolean) * @since 2.0 */ public static IEGLPathEntry newContainerEntry(IPath containerPath, boolean isExported) { if (containerPath == null || containerPath.segmentCount() < 1) { Assert.isTrue(false, "Illegal EGLPath container path: \'" + containerPath.makeRelative().toString() + "\', must have at least one segment (containerID+hints)"); //$NON-NLS-1$//$NON-NLS-2$ } return new EGLPathEntry( IPackageFragmentRoot.K_SOURCE, IEGLPathEntry.CPE_CONTAINER, containerPath, EGLPathEntry.EXCLUDE_NONE); } /** * Creates and returns a new non-exported EGLPath entry of kind <code>CPE_LIBRARY</code> for the * JAR or folder identified by the given absolute path. This specifies that all package fragments * within the root will have children of type <code>IClassFile</code>. * <p> * A library entry is used to denote a prerequisite JAR or root folder containing binaries. * The target JAR or folder can either be defined internally to the workspace (absolute path relative * to the workspace root) or externally to the workspace (absolute path in the file system). * <p> * e.g. Here are some examples of binary path usage<ul> * <li><code> "c:/jdk1.2.2/jre/lib/rt.jar" </code> - reference to an external JAR</li> * <li><code> "/Project/someLib.jar" </code> - reference to an internal JAR </li> * <li><code> "c:/classes/" </code> - reference to an external binary folder</li> * </ul> * Note that this operation does not attempt to validate or access the * resources at the given paths. * <p> * The resulting entry is not exported to dependent projects. This method is equivalent to * <code>newLibraryEntry(-,-,-,false)</code>. * <p> * * @param path the absolute path of the binary archive * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder, * or <code>null</code> if none * @param sourceAttachmentRootPath the location of the root within the source archive or folder * or <code>null</code> if this location should be automatically detected. * @return a new library EGLPath entry * * @see #newLibraryEntry(IPath, IPath, IPath, boolean) */ public static IEGLPathEntry newLibraryEntry(IPath path, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath) { return newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, false); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_LIBRARY</code> for the JAR or folder * identified by the given absolute path. This specifies that all package fragments within the root * will have children of type <code>IClassFile</code>. * <p> * A library entry is used to denote a prerequisite JAR or root folder containing binaries. * The target JAR or folder can either be defined internally to the workspace (absolute path relative * to the workspace root) or externally to the workspace (absolute path in the file system). * <p> * e.g. Here are some examples of binary path usage<ul> * <li><code> "c:/jdk1.2.2/jre/lib/rt.jar" </code> - reference to an external JAR</li> * <li><code> "/Project/someLib.jar" </code> - reference to an internal JAR </li> * <li><code> "c:/classes/" </code> - reference to an external binary folder</li> * </ul> * Note that this operation does not attempt to validate or access the * resources at the given paths. * <p> * * @param path the absolute path of the binary archive * @param sourceAttachmentPath the absolute path of the corresponding source archive or folder, * or <code>null</code> if none * @param sourceAttachmentRootPath the location of the root within the source archive or folder * or <code>null</code> if this location should be automatically detected. * @param isExported indicates whether this entry is contributed to dependent * projects in addition to the output location * @return a new library EGLPath entry * @since 2.0 */ public static IEGLPathEntry newLibraryEntry( IPath path, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath, boolean isExported) { if (!path.isAbsolute()) Assert.isTrue(false, "Path for IEGLPathEntry must be absolute"); //$NON-NLS-1$ return new EGLPathEntry( IPackageFragmentRoot.K_BINARY, IEGLPathEntry.CPE_LIBRARY, EGLProject.canonicalizedPath(path), EGLPathEntry.EXCLUDE_NONE, sourceAttachmentPath, sourceAttachmentRootPath, null, // specific output folder isExported); } /** * Creates and returns a new non-exported EGLPath entry of kind <code>CPE_PROJECT</code> * for the project identified by the given absolute path. * <p> * A project entry is used to denote a prerequisite project on a EGLPath. * The referenced project will be contributed as a whole, either as sources (in the EGL Model, it * contributes all its package fragment roots) or as binaries (when building, it contributes its * whole output location). * <p> * A project reference allows to indirect through another project, independently from its internal layout. * <p> * The prerequisite project is referred to using an absolute path relative to the workspace root. * <p> * The resulting entry is not exported to dependent projects. This method is equivalent to * <code>newProjectEntry(_,false)</code>. * <p> * * @param path the absolute path of the binary archive * @return a new project EGLPath entry * * @see EGLCore#newProjectEntry(IPath, boolean) */ public static IEGLPathEntry newProjectEntry(IPath path) { return newProjectEntry(path, false); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_PROJECT</code> * for the project identified by the given absolute path. * <p> * A project entry is used to denote a prerequisite project on a EGLPath. * The referenced project will be contributed as a whole, either as sources (in the EGL Model, it * contributes all its package fragment roots) or as binaries (when building, it contributes its * whole output location). * <p> * A project reference allows to indirect through another project, independently from its internal layout. * <p> * The prerequisite project is referred to using an absolute path relative to the workspace root. * <p> * * @param path the absolute path of the prerequisite project * @param isExported indicates whether this entry is contributed to dependent * projects in addition to the output location * @return a new project EGLPath entry * @since 2.0 */ public static IEGLPathEntry newProjectEntry(IPath path, boolean isExported) { if (!path.isAbsolute()) Assert.isTrue(false, "Path for IEGLPathEntry must be absolute"); //$NON-NLS-1$ return new EGLPathEntry( IPackageFragmentRoot.K_SOURCE, IEGLPathEntry.CPE_PROJECT, path, EGLPathEntry.EXCLUDE_NONE, null, // source attachment null, // source attachment root null, // specific output folder isExported); } /** * Returns a new empty region. * * @return a new empty region */ public static IRegion newRegion() { return new Region(); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_SOURCE</code> * for the project's source folder identified by the given absolute * workspace-relative path. This specifies that all package fragments * within the root will have children of type <code>ICompilationUnit</code>. * <p> * The source folder is referred to using an absolute path relative to the * workspace root, e.g. <code>/Project/src</code>. A project's source * folders are located with that project. That is, a source EGLPath * entry specifying the path <code>/P1/src</code> is only usable for * project <code>P1</code>. * </p> * <p> * The source EGLPath entry created by this method includes all source * files below the given workspace-relative path. To selectively exclude * some of these source files, use the factory method * <code>EGLCore.newSourceEntry(IPath,IPath[])</code> instead. * </p> * <p> * Note that all sources/binaries inside a project are contributed as a whole through * a project entry (see <code>EGLCore.newProjectEntry</code>). Particular * source entries cannot be selectively exported. * </p> * * @param path the absolute workspace-relative path of a source folder * @return a new source EGLPath entry with not exclusion patterns * * @see #newSourceEntry(org.eclipse.core.runtime.IPath,org.eclipse.core.runtime.IPath[]) */ public static IEGLPathEntry newSourceEntry(IPath path) { return newSourceEntry(path, EGLPathEntry.EXCLUDE_NONE, null /*output location*/ ); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_SOURCE</code> * for the project's source folder identified by the given absolute * workspace-relative path but excluding all source files with paths * matching any of the given patterns. This specifies that all package * fragments within the root will have children of type * <code>ICompilationUnit</code>. * <p> * The source folder is referred to using an absolute path relative to the * workspace root, e.g. <code>/Project/src</code>. A project's source * folders are located with that project. That is, a source EGLPath * entry specifying the path <code>/P1/src</code> is only usable for * project <code>P1</code>. * </p> * <p> * The source EGLPath entry created by this method includes all source * files below the given workspace-relative path except for those matched * by one (or more) of the given exclusion patterns. Each exclusion pattern * is represented by a relative path, which is interpreted as relative to * the source folder. For example, if the source folder path is * <code>/Project/src</code> and the exclusion pattern is * <code>com/xyz/tests/**</code>, then source files * like <code>/Project/src/com/xyz/Foo.egl</code> * and <code>/Project/src/com/xyz/utils/Bar.egl</code> would be included, * whereas <code>/Project/src/com/xyz/tests/T1.egl</code> * and <code>/Project/src/com/xyz/tests/quick/T2.egl</code> would be * excluded. Exclusion patterns can contain can contain '**', '*' or '?' * wildcards; see <code>IEGLPathEntry.getExclusionPatterns</code> * for the full description of the syntax and semantics of exclusion * patterns. * </p> * If the empty list of exclusion patterns is specified, the source folder * will automatically include all resources located inside the source * folder. In that case, the result is entirely equivalent to using the * factory method <code>EGLCore.newSourceEntry(IPath)</code>. * </p> * <p> * Note that all sources/binaries inside a project are contributed as a whole through * a project entry (see <code>EGLCore.newProjectEntry</code>). Particular * source entries cannot be selectively exported. * </p> * * @param path the absolute workspace-relative path of a source folder * @param exclusionPatterns the possibly empty list of exclusion patterns * represented as relative paths * @return a new source EGLPath entry with the given exclusion patterns * @see #newSourceEntry(org.eclipse.core.runtime.IPath) * @see IEGLPathEntry#getExclusionPatterns * * @since 2.1 */ public static IEGLPathEntry newSourceEntry(IPath path, IPath[] exclusionPatterns) { return newSourceEntry(path, exclusionPatterns, null /*output location*/ ); } /** * Creates and returns a new EGLPath entry of kind <code>CPE_SOURCE</code> * for the project's source folder identified by the given absolute * workspace-relative path but excluding all source files with paths * matching any of the given patterns, and associated with a specific output location * (that is, ".class" files are not going to the project default output location). * All package fragments within the root will have children of type * <code>ICompilationUnit</code>. * <p> * The source folder is referred to using an absolute path relative to the * workspace root, e.g. <code>/Project/src</code>. A project's source * folders are located with that project. That is, a source EGLPath * entry specifying the path <code>/P1/src</code> is only usable for * project <code>P1</code>. * </p> * <p> * The source EGLPath entry created by this method includes all source * files below the given workspace-relative path except for those matched * by one (or more) of the given exclusion patterns. Each exclusion pattern * is represented by a relative path, which is interpreted as relative to * the source folder. For example, if the source folder path is * <code>/Project/src</code> and the exclusion pattern is * <code>com/xyz/tests/**</code>, then source files * like <code>/Project/src/com/xyz/Foo.egl</code> * and <code>/Project/src/com/xyz/utils/Bar.egl</code> would be included, * whereas <code>/Project/src/com/xyz/tests/T1.egl</code> * and <code>/Project/src/com/xyz/tests/quick/T2.egl</code> would be * excluded. Exclusion patterns can contain can contain '**', '*' or '?' * wildcards; see <code>IEGLPathEntry.getExclusionPatterns</code> * for the full description of the syntax and semantics of exclusion * patterns. * </p> * If the empty list of exclusion patterns is specified, the source folder * will automatically include all resources located inside the source * folder. In that case, the result is entirely equivalent to using the * factory method <code>EGLCore.newSourceEntry(IPath)</code>. * </p> * <p> * Additionally, a source entry can be associated with a specific output location. * By doing so, the EGL builder will ensure that the generated ".class" files will * be issued inside this output location, as opposed to be generated into the * project default output location (when output location is <code>null</code>). * Note that multiple source entries may target the same output location. * The output location is referred to using an absolute path relative to the * workspace root, e.g. <code>"/Project/bin"</code>, it must be located inside * the same project as the source folder. * </p> * <p> * Also note that all sources/binaries inside a project are contributed as a whole through * a project entry (see <code>EGLCore.newProjectEntry</code>). Particular * source entries cannot be selectively exported. * </p> * * @param path the absolute workspace-relative path of a source folder * @param exclusionPatterns the possibly empty list of exclusion patterns * represented as relative paths * @param outputLocation the specific output location for this source entry (<code>null</code> if using project default ouput location) * @return a new source EGLPath entry with the given exclusion patterns * @see #newSourceEntry(org.eclipse.core.runtime.IPath) * @see IEGLPathEntry#getExclusionPatterns * @see IEGLPathEntry#getOutputLocation() * * @since 2.1 */ public static IEGLPathEntry newSourceEntry(IPath path, IPath[] exclusionPatterns, IPath specificOutputLocation) { if (!path.isAbsolute()) Assert.isTrue(false, "Path for IEGLPathEntry must be absolute"); //$NON-NLS-1$ if (exclusionPatterns == null) Assert.isTrue(false, "Exclusion pattern set cannot be null"); //$NON-NLS-1$ return new EGLPathEntry( IPackageFragmentRoot.K_SOURCE, IEGLPathEntry.CPE_SOURCE, path, exclusionPatterns, null, // source attachment null, // source attachment root specificOutputLocation, // custom output location false); } /** * Creates and returns a new non-exported EGLPath entry of kind <code>CPE_VARIABLE</code> * for the given path. The first segment of the path is the name of a EGLPath variable. * The trailing segments of the path will be appended to resolved variable path. * <p> * A variable entry allows to express indirect references on a EGLPath to other projects or libraries, * depending on what the EGLPath variable is referring. * <p> * It is possible to register an automatic initializer (<code>EGLPathVariableInitializer</code>), * which will be invoked through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathVariableInitializer". * After resolution, a EGLPath variable entry may either correspond to a project or a library entry. </li> * <p> * e.g. Here are some examples of variable path usage<ul> * <li> "JDTCORE" where variable <code>JDTCORE</code> is * bound to "c:/jars/jdtcore.jar". The resolved EGLPath entry is denoting the library "c:\jars\jdtcore.jar"</li> * <li> "JDTCORE" where variable <code>JDTCORE</code> is * bound to "/Project_JDTCORE". The resolved EGLPath entry is denoting the project "/Project_JDTCORE"</li> * <li> "PLUGINS/com.example/example.jar" where variable <code>PLUGINS</code> * is bound to "c:/eclipse/plugins". The resolved EGLPath entry is denoting the library "c:/eclipse/plugins/com.example/example.jar"</li> * </ul> * Note that this operation does not attempt to validate EGLPath variables * or access the resources at the given paths. * <p> * The resulting entry is not exported to dependent projects. This method is equivalent to * <code>newVariableEntry(-,-,-,false)</code>. * <p> * * @param variablePath the path of the binary archive; first segment is the * name of a EGLPath variable * @param variableSourceAttachmentPath the path of the corresponding source archive, * or <code>null</code> if none; if present, the first segment is the * name of a EGLPath variable (not necessarily the same variable * as the one that begins <code>variablePath</code>) * @param sourceAttachmentRootPath the location of the root within the source archive * or <code>null</code> if <code>archivePath</code> is also <code>null</code> * @return a new library EGLPath entry * * @see EGLCore#newVariableEntry(IPath, IPath, IPath, boolean) */ public static IEGLPathEntry newVariableEntry(IPath variablePath, IPath variableSourceAttachmentPath, IPath sourceAttachmentRootPath) { return newVariableEntry(variablePath, variableSourceAttachmentPath, sourceAttachmentRootPath, false); } /** * Creates and returns a new non-exported EGLPath entry of kind <code>CPE_VARIABLE</code> * for the given path. The first segment of the path is the name of a EGLPath variable. * The trailing segments of the path will be appended to resolved variable path. * <p> * A variable entry allows to express indirect references on a EGLPath to other projects or libraries, * depending on what the EGLPath variable is referring. * <p> * It is possible to register an automatic initializer (<code>EGLPathVariableInitializer</code>), * which will be invoked through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathVariableInitializer". * After resolution, a EGLPath variable entry may either correspond to a project or a library entry. </li> * <p> * e.g. Here are some examples of variable path usage<ul> * <li> "JDTCORE" where variable <code>JDTCORE</code> is * bound to "c:/jars/jdtcore.jar". The resolved EGLPath entry is denoting the library "c:\jars\jdtcore.jar"</li> * <li> "JDTCORE" where variable <code>JDTCORE</code> is * bound to "/Project_JDTCORE". The resolved EGLPath entry is denoting the project "/Project_JDTCORE"</li> * <li> "PLUGINS/com.example/example.jar" where variable <code>PLUGINS</code> * is bound to "c:/eclipse/plugins". The resolved EGLPath entry is denoting the library "c:/eclipse/plugins/com.example/example.jar"</li> * </ul> * Note that this operation does not attempt to validate EGLPath variables * or access the resources at the given paths. * <p> * * @param variablePath the path of the binary archive; first segment is the * name of a EGLPath variable * @param variableSourceAttachmentPath the path of the corresponding source archive, * or <code>null</code> if none; if present, the first segment is the * name of a EGLPath variable (not necessarily the same variable * as the one that begins <code>variablePath</code>) * @param sourceAttachmentRootPath the location of the root within the source archive * or <code>null</code> if <code>archivePath</code> is also <code>null</code> * @param isExported indicates whether this entry is contributed to dependent * projects in addition to the output location * @return a new variable EGLPath entry * @since 2.0 */ public static IEGLPathEntry newVariableEntry( IPath variablePath, IPath variableSourceAttachmentPath, IPath variableSourceAttachmentRootPath, boolean isExported) { if (variablePath == null || variablePath.segmentCount() < 1) { Assert.isTrue(false, "Illegal EGLPath variable path: \'" + variablePath.makeRelative().toString() + "\', must have at least one segment"); //$NON-NLS-1$//$NON-NLS-2$ } return new EGLPathEntry( IPackageFragmentRoot.K_SOURCE, IEGLPathEntry.CPE_VARIABLE, variablePath, EGLPathEntry.EXCLUDE_NONE, variableSourceAttachmentPath, // source attachment variableSourceAttachmentRootPath, // source attachment root null, // specific output folder isExported); } /** * Removed the given EGLPath variable. Does nothing if no value was * set for this EGLPath variable. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * * @param variableName the name of the EGLPath variable * @see #setEGLPathVariable * * @deprecated - use version with extra IProgressMonitor */ public static void removeEGLPathVariable(String variableName) { removeEGLPathVariable(variableName, null); } /** * Removed the given EGLPath variable. Does nothing if no value was * set for this EGLPath variable. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * * @param variableName the name of the EGLPath variable * @param monitor the progress monitor to report progress * @see #setEGLPathVariable */ public static void removeEGLPathVariable(String variableName, IProgressMonitor monitor) { try { updateVariableValues(new String[] { variableName }, new IPath[] { null }, monitor); } catch (EGLModelException e) { } } /** * Removes the given element changed listener. * Has no affect if an identical listener is not registered. * * @param listener the listener */ public static void removeElementChangedListener(IElementChangedListener listener) { EGLModelManager.getEGLModelManager().removeElementChangedListener(listener); } /** * Runs the given action as an atomic EGL model operation. * <p> * After running a method that modifies EGL elements, * registered listeners receive after-the-fact notification of * what just transpired, in the form of a element changed event. * This method allows clients to call a number of * methods that modify egl elements and only have element * changed event notifications reported at the end of the entire * batch. * </p> * <p> * If this method is called outside the dynamic scope of another such * call, this method runs the action and then reports a single * element changed event describing the net effect of all changes * done to egl elements by the action. * </p> * <p> * If this method is called in the dynamic scope of another such * call, this method simply runs the action. * </p> * * @param action the action to perform * @param monitor a progress monitor, or <code>null</code> if progress * reporting and cancellation are not desired * @exception CoreException if the operation failed. * @since 2.1 */ public static void run(IWorkspaceRunnable action, IProgressMonitor monitor) throws CoreException { run(action, ResourcesPlugin.getWorkspace().getRoot(), monitor); } public static void run(IWorkspaceRunnable action, ISchedulingRule rule, IProgressMonitor monitor) throws CoreException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace.isTreeLocked()) { new BatchOperation(action).run(monitor); } else { // use IWorkspace.run(...) to ensure that a build will be done in autobuild mode workspace.run(new BatchOperation(action), rule, IWorkspace.AVOID_UPDATE, monitor); } } /** * Bind a container reference path to some actual containers (<code>IEGLPathContainer</code>). * This API must be invoked whenever changes in container need to be reflected onto the EGLModel. * Containers can have distinct values in different projects, therefore this API considers a * set of projects with their respective containers. * <p> * <code>containerPath</code> is the path under which these values can be referenced through * container EGLPath entries (<code>IEGLPathEntry#CPE_CONTAINER</code>). A container path * is formed by a first ID segment followed with extra segments, which can be used as additional hints * for the resolution. The container ID is used to identify a <code>EGLPathContainerInitializer</code> * registered on the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer". * <p> * There is no assumption that each individual container value passed in argument * (<code>respectiveContainers</code>) must answer the exact same path when requested * <code>IEGLPathContainer#getPath</code>. * Indeed, the containerPath is just an indication for resolving it to an actual container object. It can be * delegated to a <code>EGLPathContainerInitializer</code>, which can be activated through the extension * point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer"). * <p> * In reaction to changing container values, the EGLModel will be updated to reflect the new * state of the updated container. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath container values are persisted locally to the workspace, but * are not preserved from a session to another. It is thus highly recommended to register a * <code>EGLPathContainerInitializer</code> for each referenced container * (through the extension point "com.ibm.etools.egl.internal.model.core.EGLPathContainerInitializer"). * <p> * Note: setting a container to <code>null</code> will cause it to be lazily resolved again whenever * its value is required. In particular, this will cause a registered initializer to be invoked * again. * <p> * @param containerPath - the name of the container reference, which is being updated * @param affectedProjects - the set of projects for which this container is being bound * @param respectiveContainers - the set of respective containers for the affected projects * @param monitor a monitor to report progress * * @see EGLPathContainerInitializer * @see #getEGLPathContainer(IPath, IEGLProject) * @see IEGLPathContainer * @since 2.0 */ public static void setEGLPathContainer( final IPath containerPath, IEGLProject[] affectedProjects, IEGLPathContainer[] respectiveContainers, IProgressMonitor monitor) throws EGLModelException { if (affectedProjects.length != respectiveContainers.length) Assert.isTrue(false, "Projects and containers collections should have the same size"); //$NON-NLS-1$ if (monitor != null && monitor.isCanceled()) return; if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer SET - setting container: [" + containerPath + "] for projects: {" //$NON-NLS-1$ //$NON-NLS-2$ + (Util.toString(affectedProjects, new Util.Displayable() { public String displayString(Object o) { return ((IEGLProject) o).getElementName(); } })) + "} with values: " //$NON-NLS-1$ + (Util.toString(respectiveContainers, new Util.Displayable() { public String displayString(Object o) { return ((IEGLPathContainer) o).getDescription(); } }))); } final int projectLength = affectedProjects.length; final IEGLProject[] modifiedProjects; System.arraycopy(affectedProjects, 0, modifiedProjects = new IEGLProject[projectLength], 0, projectLength); final IEGLPathEntry[][] oldResolvedPaths = new IEGLPathEntry[projectLength][]; // filter out unmodified project containers int remaining = 0; for (int i = 0; i < projectLength; i++) { if (monitor != null && monitor.isCanceled()) return; IEGLProject affectedProject = affectedProjects[i]; IEGLPathContainer newContainer = respectiveContainers[i]; if (newContainer == null) newContainer = EGLModelManager.ContainerInitializationInProgress; // 30920 - prevent infinite loop boolean found = false; if (EGLProject.hasEGLNature(affectedProject.getProject())) { IEGLPathEntry[] rawEGLPath = affectedProject.getRawEGLPath(); for (int j = 0, cpLength = rawEGLPath.length; j < cpLength; j++) { IEGLPathEntry entry = rawEGLPath[j]; if (entry.getEntryKind() == IEGLPathEntry.CPE_CONTAINER && entry.getPath().equals(containerPath)) { found = true; break; } } } if (!found) { modifiedProjects[i] = null; // filter out this project - does not reference the container path, or isnt't yet EGL project EGLModelManager.containerPut(affectedProject, containerPath, newContainer); continue; } IEGLPathContainer oldContainer = EGLModelManager.containerGet(affectedProject, containerPath); if (oldContainer == EGLModelManager.ContainerInitializationInProgress) { Map previousContainerValues = (Map) EGLModelManager.PreviousSessionContainers.get(affectedProject); if (previousContainerValues != null) { IEGLPathContainer previousContainer = (IEGLPathContainer) previousContainerValues.get(containerPath); if (previousContainer != null) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer INIT - reentering access to project container: [" + affectedProject.getElementName() + "] " + containerPath + " during its initialization, will see previous value: " + previousContainer.getDescription()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } EGLModelManager.containerPut(affectedProject, containerPath, previousContainer); } oldContainer = null; //33695 - cannot filter out restored container, must update affected project to reset cached CP } else { oldContainer = null; } } if (oldContainer != null && oldContainer.equals(respectiveContainers[i])) { // TODO: could improve to only compare entries modifiedProjects[i] = null; // filter out this project - container did not change continue; } remaining++; oldResolvedPaths[i] = affectedProject.getResolvedEGLPath(true); EGLModelManager.containerPut(affectedProject, containerPath, newContainer); } if (remaining == 0) return; // trigger model refresh try { EGLCore.run(new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { for (int i = 0; i < projectLength; i++) { if (monitor != null && monitor.isCanceled()) return; EGLProject affectedProject = (EGLProject) modifiedProjects[i]; if (affectedProject == null) continue; // was filtered out if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer SET - updating affected project: [" + affectedProject.getElementName() + "] due to setting container: " + containerPath); //$NON-NLS-1$ //$NON-NLS-2$ } // force a refresh of the affected project (will compute deltas) affectedProject .setRawEGLPath( affectedProject.getRawEGLPath(), SetEGLPathOperation.ReuseOutputLocation, monitor, !ResourcesPlugin.getWorkspace().isTreeLocked(), // can save resources oldResolvedPaths[i], false, // updating - no validation false); // updating - no need to save } } }, monitor); } catch (CoreException e) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPContainer SET - FAILED DUE TO EXCEPTION: " + containerPath); //$NON-NLS-1$ e.printStackTrace(); } if (e instanceof EGLModelException) { throw (EGLModelException) e; } else { throw new EGLModelException(e); } } finally { for (int i = 0; i < projectLength; i++) { if (respectiveContainers[i] == null) { EGLModelManager.containerPut(affectedProjects[i], containerPath, null); // reset init in progress marker } } } } /** * Sets the value of the given EGLPath variable. * The path must have at least one segment. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * * @param variableName the name of the EGLPath variable * @param path the path * @see #getEGLPathVariable * * @deprecated - use API with IProgressMonitor */ public static void setEGLPathVariable(String variableName, IPath path) throws EGLModelException { setEGLPathVariable(variableName, path, null); } /** * Sets the value of the given EGLPath variable. * The path must not be null. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * Updating a variable with the same value has no effect. * * @param variableName the name of the EGLPath variable * @param path the path * @param monitor a monitor to report progress * @see #getEGLPathVariable */ public static void setEGLPathVariable(String variableName, IPath path, IProgressMonitor monitor) throws EGLModelException { if (path == null) Assert.isTrue(false, "Variable path cannot be null"); //$NON-NLS-1$ setEGLPathVariables(new String[] { variableName }, new IPath[] { path }, monitor); } /** * Sets the values of all the given EGLPath variables at once. * Null paths can be used to request corresponding variable removal. * <p> * This functionality cannot be used while the resource tree is locked. * <p> * EGLPath variable values are persisted locally to the workspace, and * are preserved from session to session. * <p> * Updating a variable with the same value has no effect. * * @param variableNames an array of names for the updated EGLPath variables * @param paths an array of path updates for the modified EGLPath variables (null * meaning that the corresponding value will be removed * @param monitor a monitor to report progress * @see #getEGLPathVariable * @since 2.0 */ public static void setEGLPathVariables(String[] variableNames, IPath[] paths, IProgressMonitor monitor) throws EGLModelException { if (variableNames.length != paths.length) Assert.isTrue(false, "Variable names and paths collections should have the same size"); //$NON-NLS-1$ //TODO: should check that null cannot be used as variable paths updateVariableValues(variableNames, paths, monitor); } /** * 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> * For a complete description of the configurable options, see <code>getDefaultOptions</code>. * </p> * * @param newOptions the new options (key type: <code>String</code>; value type: <code>String</code>), * or <code>null</code> to reset all options to their default values * @see EGLCore#getDefaultOptions */ public static void setOptions(Hashtable newOptions) { // see #initializeDefaultPluginPreferences() for changing default settings Preferences preferences = getPlugin().getPluginPreferences(); if (newOptions == null) { newOptions = EGLCore.getDefaultOptions(); } Enumeration keys = newOptions.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (!EGLModelManager.OptionNames.contains(key)) continue; // unrecognized option if (key.equals(CORE_ENCODING)) continue; // skipped, contributed by resource prefs String value = (String) newOptions.get(key); preferences.setValue(key, value); } // persist options getPlugin().savePluginPreferences(); } /** * Internal updating of a variable values (null path meaning removal), allowing to change multiple variable values at once. */ private static void updateVariableValues(String[] variableNames, IPath[] variablePaths, IProgressMonitor monitor) throws EGLModelException { if (monitor != null && monitor.isCanceled()) return; if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable SET - setting variables: {" + Util.toString(variableNames) //$NON-NLS-1$ +"} with values: " + Util.toString(variablePaths)); //$NON-NLS-1$ } int varLength = variableNames.length; // gather EGLPath information for updating final HashMap affectedProjects = new HashMap(5); EGLModelManager manager = EGLModelManager.getEGLModelManager(); IEGLModel model = manager.getEGLModel(); // filter out unmodified variables int discardCount = 0; for (int i = 0; i < varLength; i++) { String variableName = variableNames[i]; IPath oldPath = (IPath) EGLModelManager.variableGet(variableName); // if reentering will provide previous session value if (oldPath == EGLModelManager.VariableInitializationInProgress) { IPath previousPath = (IPath) EGLModelManager.PreviousSessionVariables.get(variableName); if (previousPath != null) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable INIT - reentering access to variable: " + variableName + " during its initialization, will see previous value: " + previousPath); //$NON-NLS-1$ //$NON-NLS-2$ } EGLModelManager.variablePut(variableName, previousPath); // replace value so reentering calls are seeing old value } oldPath = null; //33695 - cannot filter out restored variable, must update affected project to reset cached CP } if (oldPath != null && oldPath.equals(variablePaths[i])) { variableNames[i] = null; discardCount++; } } if (discardCount > 0) { if (discardCount == varLength) return; int changedLength = varLength - discardCount; String[] changedVariableNames = new String[changedLength]; IPath[] changedVariablePaths = new IPath[changedLength]; for (int i = 0, index = 0; i < varLength; i++) { if (variableNames[i] != null) { changedVariableNames[index] = variableNames[i]; changedVariablePaths[index] = variablePaths[i]; index++; } } variableNames = changedVariableNames; variablePaths = changedVariablePaths; varLength = changedLength; } if (monitor != null && monitor.isCanceled()) return; if (model != null) { IEGLProject[] projects = model.getEGLProjects(); nextProject : for (int i = 0, projectLength = projects.length; i < projectLength; i++) { IEGLProject project = projects[i]; // check to see if any of the modified variables is present on the EGLPath IEGLPathEntry[] EGLPath = project.getRawEGLPath(); for (int j = 0, cpLength = EGLPath.length; j < cpLength; j++) { IEGLPathEntry entry = EGLPath[j]; for (int k = 0; k < varLength; k++) { String variableName = variableNames[k]; if (entry.getEntryKind() == IEGLPathEntry.CPE_VARIABLE) { if (variableName.equals(entry.getPath().segment(0))) { affectedProjects.put(project, project.getResolvedEGLPath(true)); continue nextProject; } IPath sourcePath, sourceRootPath; if (((sourcePath = entry.getSourceAttachmentPath()) != null && variableName.equals(sourcePath.segment(0))) || ((sourceRootPath = entry.getSourceAttachmentRootPath()) != null && variableName.equals(sourceRootPath.segment(0)))) { affectedProjects.put(project, project.getResolvedEGLPath(true)); continue nextProject; } } } } } } // update variables for (int i = 0; i < varLength; i++) { EGLModelManager.variablePut(variableNames[i], variablePaths[i]); } final String[] dbgVariableNames = variableNames; // update affected project EGLPaths if (!affectedProjects.isEmpty()) { try { EGLCore.run(new IWorkspaceRunnable() { public void run(IProgressMonitor monitor) throws CoreException { // propagate EGLPath change Iterator projectsToUpdate = affectedProjects.keySet().iterator(); while (projectsToUpdate.hasNext()) { if (monitor != null && monitor.isCanceled()) return; EGLProject project = (EGLProject) projectsToUpdate.next(); if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable SET - updating affected project: [" + project.getElementName() + "] due to setting variables: " + Util.toString(dbgVariableNames)); //$NON-NLS-1$ //$NON-NLS-2$ } project.setRawEGLPath(project.getRawEGLPath(), SetEGLPathOperation.ReuseOutputLocation, null, // don't call beginTask on the monitor (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=3717) !ResourcesPlugin.getWorkspace().isTreeLocked(), // can change resources (IEGLPathEntry[]) affectedProjects.get(project), false, // updating - no validation false); // updating - no need to save } } }, monitor); } catch (CoreException e) { if (EGLModelManager.CP_RESOLVE_VERBOSE) { System.out.println("CPVariable SET - FAILED DUE TO EXCEPTION: " + Util.toString(dbgVariableNames)); //$NON-NLS-1$ e.printStackTrace(); } if (e instanceof EGLModelException) { throw (EGLModelException) e; } else { throw new EGLModelException(e); } } } } }