Copyright (c) 2000, 2018 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache before its contents (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422) Stephan Herrmann - Contributions for Bug 346010 - [model] strange initialization dependency in OptionTests Bug 440477 - [null] Infrastructure for feeding external annotations into compilation Terry Parker - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 Thirumala Reddy Mutchukota - Contribution to bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=411423 Terry Parker - [performance] Low hit rates in JavaModel caches - https://bugs.eclipse.org/421165 Terry Parker - Enable the Java model caches to recover from IO errors - https://bugs.eclipse.org/455042 Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions Karsten Thoms - Bug 532505 - Reduce memory footprint of ClasspathAccessRule
/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache * before its contents * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422) * Stephan Herrmann - Contributions for * Bug 346010 - [model] strange initialization dependency in OptionTests * Bug 440477 - [null] Infrastructure for feeding external annotations into compilation * Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 * Thirumala Reddy Mutchukota <thirumala@google.com> - Contribution to bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=411423 * Terry Parker <tparker@google.com> - [performance] Low hit rates in JavaModel caches - https://bugs.eclipse.org/421165 * Terry Parker <tparker@google.com> - Enable the Java model caches to recover from IO errors - https://bugs.eclipse.org/455042 * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions * Karsten Thoms - Bug 532505 - Reduce memory footprint of ClasspathAccessRule *******************************************************************************/
package org.eclipse.jdt.internal.core; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.StringReader; import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.WeakHashMap; import java.util.zip.ZipException; import java.util.zip.ZipFile; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.ISaveContext; import org.eclipse.core.resources.ISaveParticipant; import org.eclipse.core.resources.ISavedState; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.WorkspaceJob; 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.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.PerformanceStats; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.content.IContentTypeManager; import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent; import org.eclipse.core.runtime.content.IContentTypeManager.IContentTypeChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.core.runtime.preferences.IPreferencesService; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jdt.core.ClasspathContainerInitializer; import org.eclipse.jdt.core.IAccessRule; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.IClasspathAttribute; import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModel; import org.eclipse.jdt.core.IJavaModelStatus; import org.eclipse.jdt.core.IJavaModelStatusConstants; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IParent; import org.eclipse.jdt.core.IProblemRequestor; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaConventions; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.WorkingCopyOwner; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.compiler.CompilationParticipant; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.jdt.internal.codeassist.CompletionEngine; import org.eclipse.jdt.internal.codeassist.SelectionEngine; import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager; import org.eclipse.jdt.internal.compiler.Compiler; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; import org.eclipse.jdt.internal.compiler.util.JRTUtil; import org.eclipse.jdt.internal.compiler.util.ObjectVector; import org.eclipse.jdt.internal.core.DeltaProcessor.RootInfo; import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache; import org.eclipse.jdt.internal.core.builder.JavaBuilder; import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier; import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore; import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy; import org.eclipse.jdt.internal.core.nd.IReader; import org.eclipse.jdt.internal.core.nd.Nd; import org.eclipse.jdt.internal.core.nd.db.Database; import org.eclipse.jdt.internal.core.nd.indexer.Indexer; import org.eclipse.jdt.internal.core.nd.java.JavaIndex; import org.eclipse.jdt.internal.core.nd.java.NdResourceFile; import org.eclipse.jdt.internal.core.search.AbstractSearchScope; import org.eclipse.jdt.internal.core.search.BasicSearchEngine; import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor; import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope; import org.eclipse.jdt.internal.core.search.indexing.IndexManager; import org.eclipse.jdt.internal.core.search.processing.IJob; import org.eclipse.jdt.internal.core.search.processing.JobManager; import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject; import org.eclipse.jdt.internal.core.util.LRUCache; import org.eclipse.jdt.internal.core.util.Messages; import org.eclipse.jdt.internal.core.util.Util; import org.eclipse.jdt.internal.core.util.WeakHashSet; import org.eclipse.jdt.internal.core.util.WeakHashSetOfCharArray; import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter; import org.eclipse.osgi.service.debug.DebugOptions; import org.eclipse.osgi.service.debug.DebugOptionsListener; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.prefs.BackingStoreException; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException;
The JavaModelManager manages instances of IJavaModel. IElementChangedListeners register with the JavaModelManager, and receive ElementChangedEvents for all IJavaModels.

The single instance of JavaModelManager is available from the static method JavaModelManager.getJavaModelManager().

/** * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>. * <code>IElementChangedListener</code>s register with the <code>JavaModelManager</code>, * and receive <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s. * <p> * The single instance of <code>JavaModelManager</code> is available from * the static method <code>JavaModelManager.getJavaModelManager()</code>. */
public class JavaModelManager implements ISaveParticipant, IContentTypeChangeListener { private static ServiceRegistration<DebugOptionsListener> DEBUG_REGISTRATION; private static final String NON_CHAINING_JARS_CACHE = "nonChainingJarsCache"; //$NON-NLS-1$ private static final String EXTERNAL_FILES_CACHE = "externalFilesCache"; //$NON-NLS-1$ private static final String ASSUMED_EXTERNAL_FILES_CACHE = "assumedExternalFilesCache"; //$NON-NLS-1$ public static enum ArchiveValidity { BAD_FORMAT, UNABLE_TO_READ, FILE_NOT_FOUND, VALID; public boolean isValid() { return this == VALID; } }
Define a zip cache object.
/** * Define a zip cache object. */
static class ZipCache { private Map<Object, ZipFile> map; Object owner; ZipCache(Object owner) { this.map = new HashMap<>(); this.owner = owner; } public void flush() { Thread currentThread = Thread.currentThread(); Iterator<ZipFile> iterator = this.map.values().iterator(); while (iterator.hasNext()) { ZipFile zipFile = iterator.next(); try { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + currentThread + ") [ZipCache[" + this.owner //$NON-NLS-1$//$NON-NLS-2$ + "].flush()] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$ } zipFile.close(); } catch (IOException e) { // problem occured closing zip file: cannot do much more JavaCore.getPlugin().getLog().log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "Error closing " + zipFile.getName(), e)); //$NON-NLS-1$ } } } public ZipFile getCache(IPath path) { return this.map.get(path); } public void setCache(IPath path, ZipFile zipFile) { ZipFile old = this.map.put(path, zipFile); if(old != null) { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { Thread currentThread = Thread.currentThread(); System.out.println("(" + currentThread + ") [ZipCache[" + this.owner //$NON-NLS-1$//$NON-NLS-2$ + "].setCache()] leaked ZipFile on " + old.getName() + " for path: " + path); //$NON-NLS-1$ //$NON-NLS-2$ } } } }
Unique handle onto the JavaModel
/** * Unique handle onto the JavaModel */
final JavaModel javaModel = new JavaModel();
Classpath variables pool
/** * Classpath variables pool */
public HashMap<String, IPath> variables = new HashMap<>(5); public HashSet<String> variablesWithInitializer = new HashSet<>(5); public HashMap<String, String> deprecatedVariables = new HashMap<>(5); public HashSet<String> readOnlyVariables = new HashSet<>(5); public HashMap<String, IPath> previousSessionVariables = new HashMap<>(5); private ThreadLocal<Set<String>> variableInitializationInProgress = new ThreadLocal<>();
Classpath containers pool
/** * Classpath containers pool */
public HashMap<IJavaProject, Map<IPath, IClasspathContainer>> containers = new HashMap<>(5); public HashMap<IJavaProject, Map<IPath, IClasspathContainer>> previousSessionContainers = new HashMap<>(5); private ThreadLocal<Map<IJavaProject, Set<IPath>>> containerInitializationInProgress = new ThreadLocal<>(); ThreadLocal<Map<IJavaProject, Map<IPath, IClasspathContainer>>> containersBeingInitialized = new ThreadLocal<>(); public static final int NO_BATCH_INITIALIZATION = 0; public static final int NEED_BATCH_INITIALIZATION = 1; public static final int BATCH_INITIALIZATION_IN_PROGRESS = 2; public static final int BATCH_INITIALIZATION_FINISHED = 3; public int batchContainerInitializations = NO_BATCH_INITIALIZATION; public Object batchContainerInitializationsLock = new Object(); public BatchInitializationMonitor batchContainerInitializationsProgress = new BatchInitializationMonitor(); public Hashtable<String, ClasspathContainerInitializer> containerInitializersCache = new Hashtable<>(5); /* * A HashSet that contains the IJavaProject whose classpath is being resolved. */ private ThreadLocal<Set<IJavaProject>> classpathsBeingResolved = new ThreadLocal<>(); /* * The unique workspace scope */ public JavaWorkspaceScope workspaceScope; /* * Pools of symbols used in the Java model. * Used as a replacement for String#intern() that could prevent garbage collection of strings on some VMs. */ private WeakHashSet stringSymbols = new WeakHashSet(5); private WeakHashSetOfCharArray charArraySymbols = new WeakHashSetOfCharArray(5); /* * Extension used to construct Java 6 annotation processor managers */ private IConfigurationElement annotationProcessorManagerFactory = null; /* * Map from a package fragment root's path to a source attachment property (source path + ATTACHMENT_PROPERTY_DELIMITER + source root path) */ public Map<IPath, String> rootPathToAttachments = new Hashtable<>(); public final static String CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$ public final static String CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$ public final static String CP_USERLIBRARY_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".userLibrary."; //$NON-NLS-1$ public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$ public final static IPath CP_ENTRY_IGNORE_PATH = new Path(CP_ENTRY_IGNORE); public final static String TRUE = "true"; //$NON-NLS-1$ private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 2;
Name of the extension point for contributing classpath variable initializers
/** * Name of the extension point for contributing classpath variable initializers */
public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID = "classpathVariableInitializer" ; //$NON-NLS-1$
Name of the extension point for contributing classpath container initializers
/** * Name of the extension point for contributing classpath container initializers */
public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID = "classpathContainerInitializer" ; //$NON-NLS-1$
Name of the extension point for contributing a source code formatter
/** * Name of the extension point for contributing a source code formatter */
public static final String FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$NON-NLS-1$
Name of the extension point for contributing a compilation participant
/** * Name of the extension point for contributing a compilation participant */
public static final String COMPILATION_PARTICIPANT_EXTPOINT_ID = "compilationParticipant" ; //$NON-NLS-1$
Name of the extension point for contributing the Java 6 annotation processor manager
/** * Name of the extension point for contributing the Java 6 annotation processor manager */
public static final String ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID = "annotationProcessorManager" ; //$NON-NLS-1$
Name of the JVM parameter to specify whether or not referenced JAR should be resolved for container libraries.
/** * Name of the JVM parameter to specify whether or not referenced JAR should be resolved for container libraries. */
private static final String RESOLVE_REFERENCED_LIBRARIES_FOR_CONTAINERS = "resolveReferencedLibrariesForContainers"; //$NON-NLS-1$
Name of the JVM parameter to specify how many compilation units must be handled at once by the builder. The default value is represented by AbstractImageBuilder#MAX_AT_ONCE.
/** * Name of the JVM parameter to specify how many compilation units must be handled at once by the builder. * The default value is represented by <code>AbstractImageBuilder#MAX_AT_ONCE</code>. */
public static final String MAX_COMPILED_UNITS_AT_ONCE = "maxCompiledUnitsAtOnce"; //$NON-NLS-1$
Special value used for recognizing ongoing initialization and breaking initialization cycles
/** * Special value used for recognizing ongoing initialization and breaking initialization cycles */
public final static IPath VARIABLE_INITIALIZATION_IN_PROGRESS = new Path("Variable Initialization In Progress"); //$NON-NLS-1$ public final static IClasspathContainer CONTAINER_INITIALIZATION_IN_PROGRESS = new IClasspathContainer() { @Override public IClasspathEntry[] getClasspathEntries() { return null; } @Override public String getDescription() { return "Container Initialization In Progress"; } //$NON-NLS-1$ @Override public int getKind() { return 0; } @Override public IPath getPath() { return null; } @Override public String toString() { return getDescription(); } }; private static final String DEBUG = JavaCore.PLUGIN_ID + "/debug"; //$NON-NLS-1$ private static final String BUFFER_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/buffermanager" ; //$NON-NLS-1$ private static final String INDEX_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$ private static final String INDEX_MANAGER_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager/advanced" ; //$NON-NLS-1$ private static final String COMPILER_DEBUG = JavaCore.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$ private static final String JAVAMODEL_CLASSPATH = JavaCore.PLUGIN_ID + "/debug/javamodel/classpath" ; //$NON-NLS-1$ private static final String JAVAMODEL_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$ private static final String JAVAMODEL_INVALID_ARCHIVES = JavaCore.PLUGIN_ID + "/debug/javamodel/invalid_archives" ; //$NON-NLS-1$ private static final String JAVAMODELCACHE_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/cache" ; //$NON-NLS-1$ private static final String JAVAMODELCACHE_INSERTIONS_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/insertions" ; //$NON-NLS-1$ private static final String CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$ private static final String CP_RESOLVE_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/advanced" ; //$NON-NLS-1$ private static final String CP_RESOLVE_FAILURE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/failure" ; //$NON-NLS-1$ private static final String ZIP_ACCESS_DEBUG = JavaCore.PLUGIN_ID + "/debug/zipaccess" ; //$NON-NLS-1$ private static final String DELTA_DEBUG =JavaCore.PLUGIN_ID + "/debug/javadelta" ; //$NON-NLS-1$ private static final String DELTA_DEBUG_VERBOSE =JavaCore.PLUGIN_ID + "/debug/javadelta/verbose" ; //$NON-NLS-1$ private static final String DOM_AST_DEBUG = JavaCore.PLUGIN_ID + "/debug/dom/ast" ; //$NON-NLS-1$ private static final String DOM_AST_DEBUG_THROW = JavaCore.PLUGIN_ID + "/debug/dom/ast/throw" ; //$NON-NLS-1$ private static final String DOM_REWRITE_DEBUG = JavaCore.PLUGIN_ID + "/debug/dom/rewrite" ; //$NON-NLS-1$ private static final String HIERARCHY_DEBUG = JavaCore.PLUGIN_ID + "/debug/hierarchy" ; //$NON-NLS-1$ private static final String POST_ACTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/postaction" ; //$NON-NLS-1$ private static final String BUILDER_DEBUG = JavaCore.PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$ private static final String BUILDER_STATS_DEBUG = JavaCore.PLUGIN_ID + "/debug/builder/stats" ; //$NON-NLS-1$ private static final String COMPLETION_DEBUG = JavaCore.PLUGIN_ID + "/debug/completion" ; //$NON-NLS-1$ private static final String RESOLUTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/resolution" ; //$NON-NLS-1$ private static final String SELECTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$ private static final String SEARCH_DEBUG = JavaCore.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$ private static final String SOURCE_MAPPER_DEBUG_VERBOSE = JavaCore.PLUGIN_ID + "/debug/sourcemapper" ; //$NON-NLS-1$ private static final String FORMATTER_DEBUG = JavaCore.PLUGIN_ID + "/debug/formatter" ; //$NON-NLS-1$ private static final String INDEX_DEBUG_LARGE_CHUNKS = JavaCore.PLUGIN_ID + "/debug/index/freespacetest" ; //$NON-NLS-1$ private static final String INDEX_DEBUG_PAGE_CACHE = JavaCore.PLUGIN_ID + "/debug/index/pagecache" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/indexer" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_INSERTIONS = JavaCore.PLUGIN_ID + "/debug/index/insertions" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_SCHEDULING = JavaCore.PLUGIN_ID + "/debug/index/scheduling" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_SELFTEST = JavaCore.PLUGIN_ID + "/debug/index/selftest" ; //$NON-NLS-1$ private static final String INDEX_LOCKS_DEBUG = JavaCore.PLUGIN_ID + "/debug/index/locks" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_SPACE = JavaCore.PLUGIN_ID + "/debug/index/space" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_TIMING = JavaCore.PLUGIN_ID + "/debug/index/timing" ; //$NON-NLS-1$ private static final String INDEX_INDEXER_LOG_SIZE_MEGS = JavaCore.PLUGIN_ID + "/debug/index/logsizemegs"; //$NON-NLS-1$ public static final String COMPLETION_PERF = JavaCore.PLUGIN_ID + "/perf/completion" ; //$NON-NLS-1$ public static final String SELECTION_PERF = JavaCore.PLUGIN_ID + "/perf/selection" ; //$NON-NLS-1$ public static final String DELTA_LISTENER_PERF = JavaCore.PLUGIN_ID + "/perf/javadeltalistener" ; //$NON-NLS-1$ public static final String VARIABLE_INITIALIZER_PERF = JavaCore.PLUGIN_ID + "/perf/variableinitializer" ; //$NON-NLS-1$ public static final String CONTAINER_INITIALIZER_PERF = JavaCore.PLUGIN_ID + "/perf/containerinitializer" ; //$NON-NLS-1$ public static final String RECONCILE_PERF = JavaCore.PLUGIN_ID + "/perf/reconcile" ; //$NON-NLS-1$ public static boolean PERF_VARIABLE_INITIALIZER = false; public static boolean PERF_CONTAINER_INITIALIZER = false; // Non-static, which will give it a chance to retain the default when and if JavaModelManager is restarted. boolean resolveReferencedLibrariesForContainers = false; public final static ICompilationUnit[] NO_WORKING_COPY = new ICompilationUnit[0]; // Options private final static int UNKNOWN_OPTION = 0; private final static int DEPRECATED_OPTION = 1; private final static int VALID_OPTION = 2; HashSet<String> optionNames = new HashSet<>(20); Map<String, String[]> deprecatedOptions = new HashMap<>(); Hashtable<String, String> optionsCache; // Preferences public final IEclipsePreferences[] preferencesLookup = new IEclipsePreferences[2]; static final int PREF_INSTANCE = 0; static final int PREF_DEFAULT = 1; static final Object[][] NO_PARTICIPANTS = new Object[0][]; public static class CompilationParticipants { static final int MAX_SOURCE_LEVEL = JavaCore.getAllVersions().size() - 1; // All except VERSION_CLDC_1_1 /* * The registered compilation participants (a table from int (source level) to Object[]) * The Object array contains first IConfigurationElements when not resolved yet, then * it contains CompilationParticipants. */ private Object[][] registeredParticipants = null; private HashSet<String> managedMarkerTypes; public CompilationParticipant[] getCompilationParticipants(IJavaProject project) { final Object[][] participantsPerSource = getRegisteredParticipants(); if (participantsPerSource == NO_PARTICIPANTS) return null; String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true/*inherit options*/); final int sourceLevelIndex = indexForSourceLevel(sourceLevel); final Object[] participants = participantsPerSource[sourceLevelIndex]; int length = participants.length; CompilationParticipant[] result = new CompilationParticipant[length]; int index = 0; for (int i = 0; i < length; i++) { if (participants[i] instanceof IConfigurationElement) { final IConfigurationElement configElement = (IConfigurationElement) participants[i]; final int participantIndex = i; SafeRunner.run(new ISafeRunnable() { @Override public void handleException(Throwable exception) { Util.log(exception, "Exception occurred while creating compilation participant"); //$NON-NLS-1$ } @Override public void run() throws Exception { Object executableExtension = configElement.createExecutableExtension("class"); //$NON-NLS-1$ for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++) participantsPerSource[j][participantIndex] = executableExtension; } }); } CompilationParticipant participant; if ((participants[i] instanceof CompilationParticipant) && (participant = (CompilationParticipant) participants[i]).isActive(project)) result[index++] = participant; } if (index == 0) return null; if (index < length) System.arraycopy(result, 0, result = new CompilationParticipant[index], 0, index); return result; } public HashSet<String> managedMarkerTypes() { if (this.managedMarkerTypes == null) { // force extension points to be read getRegisteredParticipants(); } return this.managedMarkerTypes; } private synchronized Object[][] getRegisteredParticipants() { if (this.registeredParticipants != null) { return this.registeredParticipants; } this.managedMarkerTypes = new HashSet<>(); IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, COMPILATION_PARTICIPANT_EXTPOINT_ID); if (extension == null) return this.registeredParticipants = NO_PARTICIPANTS; final ArrayList<IConfigurationElement> modifyingEnv = new ArrayList<>(); final ArrayList<IConfigurationElement> creatingProblems = new ArrayList<>(); final ArrayList<IConfigurationElement> others = new ArrayList<>(); IExtension[] extensions = extension.getExtensions(); // for all extensions of this point... for(int i = 0; i < extensions.length; i++) { IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); // for all config elements named "compilationParticipant" for(int j = 0; j < configElements.length; j++) { final IConfigurationElement configElement = configElements[j]; String elementName =configElement.getName(); if (!("compilationParticipant".equals(elementName))) { //$NON-NLS-1$ continue; } // add config element in the group it belongs to if (TRUE.equals(configElement.getAttribute("modifiesEnvironment"))) //$NON-NLS-1$ modifyingEnv.add(configElement); else if (TRUE.equals(configElement.getAttribute("createsProblems"))) //$NON-NLS-1$ creatingProblems.add(configElement); else others.add(configElement); // add managed marker types IConfigurationElement[] managedMarkers = configElement.getChildren("managedMarker"); //$NON-NLS-1$ for (int k = 0, length = managedMarkers.length; k < length; k++) { IConfigurationElement element = managedMarkers[k]; String markerType = element.getAttribute("markerType"); //$NON-NLS-1$ if (markerType != null) this.managedMarkerTypes.add(markerType); } } } int size = modifyingEnv.size() + creatingProblems.size() + others.size(); if (size == 0) return this.registeredParticipants = NO_PARTICIPANTS; // sort config elements in each group IConfigurationElement[] configElements = new IConfigurationElement[size]; int index = 0; index = sortParticipants(modifyingEnv, configElements, index); index = sortParticipants(creatingProblems, configElements, index); index = sortParticipants(others, configElements, index); // create result table Object[][] result = new Object[MAX_SOURCE_LEVEL][]; int length = configElements.length; for (int i = 0; i < MAX_SOURCE_LEVEL; i++) { result[i] = new Object[length]; } for (int i = 0; i < length; i++) { String sourceLevel = configElements[i].getAttribute("requiredSourceLevel"); //$NON-NLS-1$ int sourceLevelIndex = indexForSourceLevel(sourceLevel); for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++) { result[j][i] = configElements[i]; } } return this.registeredParticipants = result; } /* * 1.1 -> 0 * 1.2 -> 1 * ... * 1.6 -> 5 * 1.7 -> 6 * 1.8 -> 7 * 9 -> 8 * null -> 0 */ private int indexForSourceLevel(String sourceLevel) { if (sourceLevel == null) return 0; int majVersion = (int) (CompilerOptions.versionToJdkLevel(sourceLevel) >>> 16); if (majVersion > ClassFileConstants.MAJOR_VERSION_1_2) { return (majVersion - ClassFileConstants.MAJOR_VERSION_1_1); } // all other cases including ClassFileConstants.MAJOR_VERSION_1_1 return 0; } private int sortParticipants(ArrayList<IConfigurationElement> group, IConfigurationElement[] configElements, int index) { int size = group.size(); if (size == 0) return index; Object[] elements = group.toArray(); Util.sort(elements, new Util.Comparer() { @Override public int compare(Object a, Object b) { if (a == b) return 0; String id = ((IConfigurationElement) a).getAttribute("id"); //$NON-NLS-1$ if (id == null) return -1; IConfigurationElement[] requiredElements = ((IConfigurationElement) b).getChildren("requires"); //$NON-NLS-1$ for (int i = 0, length = requiredElements.length; i < length; i++) { IConfigurationElement required = requiredElements[i]; if (id.equals(required.getAttribute("id"))) //$NON-NLS-1$ return 1; } return -1; } }); for (int i = 0; i < size; i++) configElements[index+i] = (IConfigurationElement) elements[i]; return index + size; } } public final CompilationParticipants compilationParticipants = new CompilationParticipants(); /* whether an AbortCompilationUnit should be thrown when the source of a compilation unit cannot be retrieved */ public ThreadLocal<Boolean> abortOnMissingSource = new ThreadLocal<>(); private ExternalFoldersManager externalFoldersManager = ExternalFoldersManager.getExternalFoldersManager();
Returns whether the given full path (for a package) conflicts with the output location of the given project.
/** * Returns whether the given full path (for a package) conflicts with the output location * of the given project. */
public static boolean conflictsWithOutputLocation(IPath folderPath, JavaProject project) { try { IPath outputLocation = project.getOutputLocation(); if (outputLocation == null) { // in doubt, there is a conflict return true; } if (outputLocation.isPrefixOf(folderPath)) { // only allow nesting in project's output if there is a corresponding source folder // or if the project's output is not used (in other words, if all source folders have their custom output) IClasspathEntry[] classpath = project.getResolvedClasspath(); boolean isOutputUsed = false; for (int i = 0, length = classpath.length; i < length; i++) { IClasspathEntry entry = classpath[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (entry.getPath().equals(outputLocation)) { return false; } if (entry.getOutputLocation() == null) { isOutputUsed = true; } } } return isOutputUsed; } return false; } catch (JavaModelException e) { // in doubt, there is a conflict return true; } } public synchronized IClasspathContainer containerGet(IJavaProject project, IPath containerPath) { // check initialization in progress first if (containerIsInitializationInProgress(project, containerPath)) { return CONTAINER_INITIALIZATION_IN_PROGRESS; } Map<IPath, IClasspathContainer> projectContainers = this.containers.get(project); if (projectContainers == null){ return null; } IClasspathContainer container = projectContainers.get(containerPath); return container; } synchronized boolean containerIsSet(IJavaProject project, IPath containerPath) { Map<IPath, IClasspathContainer> projectContainers = this.containers.get(project); if (projectContainers == null){ return false; } IClasspathContainer container = projectContainers.get(containerPath); return container != null; } public synchronized IClasspathContainer containerGetDefaultToPreviousSession(IJavaProject project, IPath containerPath) { Map<IPath, IClasspathContainer> projectContainers = this.containers.get(project); if (projectContainers == null) return getPreviousSessionContainer(containerPath, project); IClasspathContainer container = projectContainers.get(containerPath); if (container == null) return getPreviousSessionContainer(containerPath, project); return container; } private boolean containerIsInitializationInProgress(IJavaProject project, IPath containerPath) { Map<IJavaProject, Set<IPath>> initializations = this.containerInitializationInProgress.get(); if (initializations == null) return false; Set<IPath> projectInitializations = initializations.get(project); if (projectInitializations == null) return false; return projectInitializations.contains(containerPath); } private void containerAddInitializationInProgress(IJavaProject project, IPath containerPath) { Map<IJavaProject, Set<IPath>> initializations = this.containerInitializationInProgress.get(); if (initializations == null) this.containerInitializationInProgress.set(initializations = new HashMap<>()); Set<IPath> projectInitializations = initializations.get(project); if (projectInitializations == null) initializations.put(project, projectInitializations = new HashSet<>()); projectInitializations.add(containerPath); } public void containerBeingInitializedPut(IJavaProject project, IPath containerPath, IClasspathContainer container) { Map<IJavaProject, Map<IPath, IClasspathContainer>> perProjectContainers = this.containersBeingInitialized.get(); if (perProjectContainers == null) this.containersBeingInitialized.set(perProjectContainers = new HashMap<>()); Map<IPath, IClasspathContainer> perPathContainers = perProjectContainers.get(project); if (perPathContainers == null) perProjectContainers.put(project, perPathContainers = new HashMap<>()); perPathContainers.put(containerPath, container); } public IClasspathContainer containerBeingInitializedGet(IJavaProject project, IPath containerPath) { Map<IJavaProject, Map<IPath, IClasspathContainer>> perProjectContainers = this.containersBeingInitialized.get(); if (perProjectContainers == null) return null; Map<IPath, IClasspathContainer> perPathContainers = perProjectContainers.get(project); if (perPathContainers == null) return null; return perPathContainers.get(containerPath); } public IClasspathContainer containerBeingInitializedRemove(IJavaProject project, IPath containerPath) { Map<IJavaProject, Map<IPath, IClasspathContainer>> perProjectContainers = this.containersBeingInitialized.get(); if (perProjectContainers == null) return null; Map<IPath, IClasspathContainer> perPathContainers = perProjectContainers.get(project); if (perPathContainers == null) return null; IClasspathContainer container = perPathContainers.remove(containerPath); if (perPathContainers.size() == 0) perProjectContainers.remove(project); if (perProjectContainers.size() == 0) this.containersBeingInitialized.set(null); return container; } public synchronized void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){ // set/unset the initialization in progress if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) { containerAddInitializationInProgress(project, containerPath); // do not write out intermediate initialization value return; } else { containerRemoveInitializationInProgress(project, containerPath); Map<IPath, IClasspathContainer> projectContainers = this.containers.get(project); if (projectContainers == null){ projectContainers = new HashMap<>(1); this.containers.put(project, projectContainers); } if (container == null) { projectContainers.remove(containerPath); } else { projectContainers.put(containerPath, container); } // discard obsoleted information about previous session Map<IPath, IClasspathContainer> previousContainers = this.previousSessionContainers.get(project); if (previousContainers != null){ previousContainers.remove(containerPath); } } // container values are persisted in preferences during save operations, see #saving(ISaveContext) } /* * The given project is being removed. Remove all containers for this project from the cache. */ public synchronized void containerRemove(IJavaProject project) { Map<IJavaProject, Set<IPath>> initializations = this.containerInitializationInProgress.get(); if (initializations != null) { initializations.remove(project); } this.containers.remove(project); } public boolean containerPutIfInitializingWithSameEntries(IPath containerPath, IJavaProject[] projects, IClasspathContainer[] respectiveContainers) { int projectLength = projects.length; if (projectLength != 1) return false; final IClasspathContainer container = respectiveContainers[0]; IJavaProject project = projects[0]; // optimize only if initializing, otherwise we are in a regular setContainer(...) call if (!containerIsInitializationInProgress(project, containerPath)) return false; IClasspathContainer previousContainer = containerGetDefaultToPreviousSession(project, containerPath); if (container == null) { if (previousContainer == null) { containerPut(project, containerPath, null); return true; } return false; } final IClasspathEntry[] newEntries = container.getClasspathEntries(); if (previousContainer == null) if (newEntries.length == 0) { containerPut(project, containerPath, container); return true; } else { if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, null/*no old entries*/); return false; } final IClasspathEntry[] oldEntries = previousContainer.getClasspathEntries(); if (oldEntries.length != newEntries.length) { if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries); return false; } for (int i = 0, length = newEntries.length; i < length; i++) { if (newEntries[i] == null) { if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_missbehaving_container(project, containerPath, newEntries); return false; } if (!newEntries[i].equals(oldEntries[i])) { if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries); return false; } } containerPut(project, containerPath, container); return true; } private void verbose_missbehaving_container( IPath containerPath, IJavaProject[] projects, IClasspathContainer[] respectiveContainers, final IClasspathContainer container, final IClasspathEntry[] newEntries, final IClasspathEntry[] oldEntries) { Util.verbose( "CPContainer SET - missbehaving container\n" + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " projects: {" +//$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( projects, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ @Override public String displayString(Object o) { return ((IJavaProject) o).getElementName(); } }) + "}\n values on previous session: {\n" +//$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( respectiveContainers, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ @Override public String displayString(Object o) { StringBuffer buffer = new StringBuffer(" "); //$NON-NLS-1$ if (o == null) { buffer.append("<null>"); //$NON-NLS-1$ return buffer.toString(); } buffer.append(container.getDescription()); buffer.append(" {\n"); //$NON-NLS-1$ if (oldEntries == null) { buffer.append(" "); //$NON-NLS-1$ buffer.append("<null>\n"); //$NON-NLS-1$ } else { for (int j = 0; j < oldEntries.length; j++){ buffer.append(" "); //$NON-NLS-1$ buffer.append(oldEntries[j]); buffer.append('\n'); } } buffer.append(" }"); //$NON-NLS-1$ return buffer.toString(); } }) + "}\n new values: {\n" +//$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( respectiveContainers, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ @Override public String displayString(Object o) { StringBuffer buffer = new StringBuffer(" "); //$NON-NLS-1$ if (o == null) { buffer.append("<null>"); //$NON-NLS-1$ return buffer.toString(); } buffer.append(container.getDescription()); buffer.append(" {\n"); //$NON-NLS-1$ for (int j = 0; j < newEntries.length; j++){ buffer.append(" "); //$NON-NLS-1$ buffer.append(newEntries[j]); buffer.append('\n'); } buffer.append(" }"); //$NON-NLS-1$ return buffer.toString(); } }) + "\n }"); //$NON-NLS-1$ } void verbose_missbehaving_container(IJavaProject project, IPath containerPath, IClasspathEntry[] classpathEntries) { Util.verbose( "CPContainer GET - missbehaving container (returning null classpath entry)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " classpath entries: {\n" + //$NON-NLS-1$ org.eclipse.jdt.internal.compiler.util.Util.toString( classpathEntries, new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){ @Override public String displayString(Object o) { StringBuffer buffer = new StringBuffer(" "); //$NON-NLS-1$ if (o == null) { buffer.append("<null>"); //$NON-NLS-1$ return buffer.toString(); } buffer.append(o); return buffer.toString(); } }) + "\n }" //$NON-NLS-1$ ); } void verbose_missbehaving_container_null_entries(IJavaProject project, IPath containerPath) { Util.verbose( "CPContainer GET - missbehaving container (returning null as classpath entries)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " classpath entries: <null>" //$NON-NLS-1$ ); } void containerRemoveInitializationInProgress(IJavaProject project, IPath containerPath) { Map<IJavaProject, Set<IPath>> initializations = this.containerInitializationInProgress.get(); if (initializations == null) return; Set<IPath> projectInitializations = initializations.get(project); if (projectInitializations == null) return; projectInitializations.remove(containerPath); if (projectInitializations.size() == 0) initializations.remove(project); if (initializations.size() == 0) this.containerInitializationInProgress.set(null); } private synchronized void containersReset(String[] containerIDs) { for (int i = 0; i < containerIDs.length; i++) { String containerID = containerIDs[i]; Iterator<Map<IPath, IClasspathContainer>> projectIterator = this.containers.values().iterator(); while (projectIterator.hasNext()){ Map<IPath, IClasspathContainer> projectContainers = projectIterator.next(); if (projectContainers != null){ Iterator<IPath> containerIterator = projectContainers.keySet().iterator(); while (containerIterator.hasNext()){ IPath containerPath = containerIterator.next(); if (containerID.equals(containerPath.segment(0))) { // registered container projectContainers.put(containerPath, null); // reset container value, but leave entry in Map } } } } } }
Returns the Java element corresponding to the given resource, or null if unable to associate the given resource with a Java element.

The resource must be one of:

  • a project - the element returned is the corresponding IJavaProject
  • a .java file - the element returned is the corresponding ICompilationUnit
  • a .class file - the element returned is the corresponding IClassFile
  • a ZIP archive (e.g. a .jar, a .zip file, etc.) - the element returned is the corresponding IPackageFragmentRoot
  • a folder - the element returned is the corresponding IPackageFragmentRoot or IPackageFragment
  • the workspace root resource - the element returned is the IJavaModel

Creating a Java element has the side effect of creating and opening all of the element's parents if they are not yet open.

/** * Returns the Java element corresponding to the given resource, or * <code>null</code> if unable to associate the given resource * with a Java element. * <p> * The resource must be one of:<ul> * <li>a project - the element returned is the corresponding <code>IJavaProject</code></li> * <li>a <code>.java</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 ZIP archive (e.g. a <code>.jar</code>, a <code>.zip</code> file, etc.) - the element returned is the corresponding <code>IPackageFragmentRoot</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>IJavaModel</code></li> * </ul> * <p> * Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */
public static IJavaElement create(IResource resource, IJavaProject project) { if (resource == null) { return null; } int type = resource.getType(); switch (type) { case IResource.PROJECT : return JavaCore.create((IProject) resource); case IResource.FILE : return create((IFile) resource, project); case IResource.FOLDER : return create((IFolder) resource, project); case IResource.ROOT : return JavaCore.create((IWorkspaceRoot) resource); default : return null; } }
Returns the Java element corresponding to the given file, its project being the given project. Returns null if unable to associate the given file with a Java element.

The file must be one of:

  • a .java file - the element returned is the corresponding ICompilationUnit
  • a .class file - the element returned is the corresponding IClassFile
  • a ZIP archive (e.g. a .jar, a .zip file, etc.) - the element returned is the corresponding IPackageFragmentRoot

Creating a Java element has the side effect of creating and opening all of the element's parents if they are not yet open.

/** * Returns the Java element corresponding to the given file, its project being the given * project. * Returns <code>null</code> if unable to associate the given file * with a Java element. * * <p>The file must be one of:<ul> * <li>a <code>.java</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 ZIP archive (e.g. a <code>.jar</code>, a <code>.zip</code> file, etc.) - the element returned is the corresponding <code>IPackageFragmentRoot</code></li> * </ul> * <p> * Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */
public static IJavaElement create(IFile file, IJavaProject project) { if (file == null) { return null; } if (project == null) { project = JavaCore.create(file.getProject()); } if (file.getFileExtension() != null) { String name = file.getName(); if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name)) return createCompilationUnitFrom(file, project); if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) return createClassFileFrom(file, project); return createJarPackageFragmentRootFrom(file, project); } return null; }
Returns the package fragment or package fragment root corresponding to the given folder, its parent or great parent being the given project. or null if unable to associate the given folder with a Java element.

Note that a package fragment root is returned rather than a default package.

Creating a Java element has the side effect of creating and opening all of the element's parents if they are not yet open.

/** * Returns the package fragment or package fragment root corresponding to the given folder, * its parent or great parent being the given project. * or <code>null</code> if unable to associate the given folder with a Java element. * <p> * Note that a package fragment root is returned rather than a default package. * <p> * Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */
public static IJavaElement create(IFolder folder, IJavaProject project) { if (folder == null) { return null; } IJavaElement element; if (project == null) { project = JavaCore.create(folder.getProject()); element = determineIfOnClasspath(folder, project); if (element == null) { // walk all projects and find one that have the given folder on its classpath IJavaProject[] projects; try { projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects(); } catch (JavaModelException e) { return null; } for (int i = 0, length = projects.length; i < length; i++) { project = projects[i]; element = determineIfOnClasspath(folder, project); if (element != null) break; } } } else { element = determineIfOnClasspath(folder, project); } return element; }
Creates and returns a class file element for the given .class file, its project being the given project. Returns null if unable to recognize the class file.
/** * Creates and returns a class file element for the given <code>.class</code> file, * its project being the given project. Returns <code>null</code> if unable * to recognize the class file. */
public static IClassFile createClassFileFrom(IFile file, IJavaProject project ) { if (file == null) { return null; } if (project == null) { project = JavaCore.create(file.getProject()); } IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project); if (pkg == null) { // fix for 1FVS7WE // not on classpath - make the root its folder, and a default package PackageFragmentRoot root = (PackageFragmentRoot) project.getPackageFragmentRoot(file.getParent()); pkg = root.getPackageFragment(CharOperation.NO_STRINGS); } String fileName = file.getName(); if (TypeConstants.MODULE_INFO_CLASS_NAME_STRING.equals(fileName)) return pkg.getModularClassFile(); return pkg.getClassFile(file.getName()); }
Creates and returns a compilation unit element for the given .java file, its project being the given project. Returns null if unable to recognize the compilation unit.
/** * Creates and returns a compilation unit element for the given <code>.java</code> * file, its project being the given project. Returns <code>null</code> if unable * to recognize the compilation unit. */
public static ICompilationUnit createCompilationUnitFrom(IFile file, IJavaProject project) { if (file == null) return null; if (project == null) { project = JavaCore.create(file.getProject()); } IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project); if (pkg == null) { // not on classpath - make the root its folder, and a default package PackageFragmentRoot root = (PackageFragmentRoot) project.getPackageFragmentRoot(file.getParent()); pkg = root.getPackageFragment(CharOperation.NO_STRINGS); if (VERBOSE){ System.out.println("WARNING : creating unit element outside classpath ("+ Thread.currentThread()+"): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$ } } return pkg.getCompilationUnit(file.getName()); }
Creates and returns a handle for the given JAR file, its project being the given project. The Java model associated with the JAR's project may be created as a side effect. Returns null if unable to create a JAR package fragment root. (for example, if the JAR file represents a non-Java resource)
/** * Creates and returns a handle for the given JAR file, its project being the given project. * The Java model associated with the JAR's project may be * created as a side effect. * Returns <code>null</code> if unable to create a JAR package fragment root. * (for example, if the JAR file represents a non-Java resource) */
public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile file, IJavaProject project) { if (file == null) { return null; } if (project == null) { project = JavaCore.create(file.getProject()); } // Create a jar package fragment root only if on the classpath IPath resourcePath = file.getFullPath(); try { IClasspathEntry entry = ((JavaProject)project).getClasspathEntryFor(resourcePath); if (entry != null) { return project.getPackageFragmentRoot(file); } } catch (JavaModelException e) { // project doesn't exist: return null } return null; }
Returns the package fragment root represented by the resource, or the package fragment the given resource is located in, or null if the given resource is not on the classpath of the given project.
/** * Returns the package fragment root represented by the resource, or * the package fragment the given resource is located in, or <code>null</code> * if the given resource is not on the classpath of the given project. */
public static IJavaElement determineIfOnClasspath(IResource resource, IJavaProject project) { IPath resourcePath = resource.getFullPath(); boolean isExternal = ExternalFoldersManager.isInternalPathForExternalFolder(resourcePath); if (isExternal) resourcePath = resource.getLocation(); try { JavaProjectElementInfo projectInfo = (JavaProjectElementInfo) getJavaModelManager().getInfo(project); ProjectCache projectCache = projectInfo == null ? null : projectInfo.projectCache; HashtableOfArrayToObject allPkgFragmentsCache = projectCache == null ? null : projectCache.allPkgFragmentsCache; boolean isJavaLike = org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourcePath.lastSegment()); IClasspathEntry[] entries = isJavaLike ? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path) : ((JavaProject)project).getResolvedClasspath(); int length = entries.length; if (length > 0) { String sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true); String complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true); for (int i = 0; i < length; i++) { IClasspathEntry entry = entries[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue; IPath rootPath = entry.getPath(); if (rootPath.equals(resourcePath)) { if (isJavaLike) return null; return project.getPackageFragmentRoot(resource); } else if (rootPath.isPrefixOf(resourcePath)) { // allow creation of package fragment if it contains a .java file that is included if (!Util.isExcluded(resource, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars())) { // given we have a resource child of the root, it cannot be a JAR pkg root PackageFragmentRoot root = isExternal ? new ExternalPackageFragmentRoot(rootPath, (JavaProject) project) : (PackageFragmentRoot) ((JavaProject) project).getFolderPackageFragmentRoot(rootPath); if (root == null) return null; IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount()); if (resource.getType() == IResource.FILE) { // if the resource is a file, then remove the last segment which // is the file name in the package pkgPath = pkgPath.removeLastSegments(1); } String[] pkgName = pkgPath.segments(); // if package name is in the cache, then it has already been validated // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=133141) if (allPkgFragmentsCache != null && allPkgFragmentsCache.containsKey(pkgName)) return root.getPackageFragment(pkgName); if (pkgName.length != 0 && JavaConventions.validatePackageName(Util.packageName(pkgPath, sourceLevel, complianceLevel), sourceLevel, complianceLevel).getSeverity() == IStatus.ERROR) { return null; } return root.getPackageFragment(pkgName); } } } } } catch (JavaModelException npe) { return null; } return null; }
The singleton manager
/** * The singleton manager */
private static JavaModelManager MANAGER= new JavaModelManager();
Infos cache.
/** * Infos cache. */
private JavaModelCache cache; /* * Temporary cache of newly opened elements */ private ThreadLocal<HashMap<IJavaElement, Object>> temporaryCache = new ThreadLocal<>();
Set of elements which are out of sync with their buffers.
/** * Set of elements which are out of sync with their buffers. */
protected HashSet<Openable> elementsOutOfSynchWithBuffers = new HashSet<>(11);
Holds the state used for delta processing.
/** * Holds the state used for delta processing. */
public DeltaProcessingState deltaState = new DeltaProcessingState(); public IndexManager indexManager = null;
Table from IProject to PerProjectInfo. NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos
/** * Table from IProject to PerProjectInfo. * NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos */
protected Map<IProject, PerProjectInfo> perProjectInfos = new HashMap<>(5);
Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo. NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos
/** * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo. * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos */
protected HashMap<WorkingCopyOwner, Map<CompilationUnit, PerWorkingCopyInfo>> perWorkingCopyInfos = new HashMap<>(5);
A weak set of the known search scopes.
/** * A weak set of the known search scopes. */
protected WeakHashMap<AbstractSearchScope, ?> searchScopes = new WeakHashMap<>(); public static class PerProjectInfo { private static final int JAVADOC_CACHE_INITIAL_SIZE = 10; static final IJavaModelStatus NEED_RESOLUTION = new JavaModelStatus(); public IProject project; public Object savedState; public boolean triedRead; public IClasspathEntry[] rawClasspath; public IClasspathEntry[] referencedEntries; public IJavaModelStatus rawClasspathStatus; public int rawTimeStamp = 0; public boolean writtingRawClasspath = false; public IClasspathEntry[] resolvedClasspath; public IJavaModelStatus unresolvedEntryStatus; public Map<IPath, IClasspathEntry> rootPathToRawEntries; // reverse map from a package fragment root's path to the raw entry public Map<IPath, IClasspathEntry> rootPathToResolvedEntries; // map from a package fragment root's path to the resolved entry public IPath outputLocation; public Map<IPath, ObjectVector> jrtRoots; // A map between a JRT file system (as a string) and the package fragment roots found in it. public IEclipsePreferences preferences; public Hashtable<String, String> options; public Hashtable<String, Map<String, IType>> secondaryTypes;
The temporary structure used while indexing, previously known as INDEXED_SECONDARY_TYPES entry
/** * The temporary structure used while indexing, previously known as INDEXED_SECONDARY_TYPES entry */
volatile Map<IFile, Map<String, Map<String, IType>>> indexingSecondaryCache; // NB: PackageFragment#getAttachedJavadoc uses this map differently // and stores String data, not JavadocContents as values public LRUCache<IJavaElement, Object> javadocCache; public PerProjectInfo(IProject project) { this.triedRead = false; this.savedState = null; this.project = project; this.javadocCache = new LRUCache<>(JAVADOC_CACHE_INITIAL_SIZE); } public synchronized IClasspathEntry[] getResolvedClasspath() { if (this.unresolvedEntryStatus == NEED_RESOLUTION) return null; return this.resolvedClasspath; } public void forgetExternalTimestampsAndIndexes() { IClasspathEntry[] classpath = this.resolvedClasspath; if (classpath == null) return; JavaModelManager manager = JavaModelManager.getJavaModelManager(); IndexManager indexManager = manager.indexManager; Hashtable<IPath, Long> externalTimeStamps = manager.deltaState.getExternalLibTimeStamps(); Map<IPath, List<RootInfo>> rootInfos = JavaModelManager.getDeltaState().otherRoots; for (int i = 0, length = classpath.length; i < length; i++) { IClasspathEntry entry = classpath[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath path = entry.getPath(); if (rootInfos.get(path) == null) { externalTimeStamps.remove(path); indexManager.removeIndex(path); // force reindexing on next reference (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=250083 ) } } } } public void rememberExternalLibTimestamps() { IClasspathEntry[] classpath = this.resolvedClasspath; if (classpath == null) return; Map<IPath, Long> externalTimeStamps = JavaModelManager.getJavaModelManager().deltaState.getExternalLibTimeStamps(); for (int i = 0, length = classpath.length; i < length; i++) { IClasspathEntry entry = classpath[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath path = entry.getPath(); if (externalTimeStamps.get(path) == null) { Object target = JavaModel.getExternalTarget(path, true); if (target instanceof File) { long timestamp = DeltaProcessor.getTimeStamp((java.io.File)target); externalTimeStamps.put(path, Long.valueOf(timestamp)); } } } } } public synchronized ClasspathChange resetResolvedClasspath() { // clear non-chaining jars cache and invalid jars cache JavaModelManager.getJavaModelManager().resetClasspathListCache(); // null out resolved information return setResolvedClasspath(null, null, null, null, this.rawTimeStamp, true/*add classpath change*/); } private ClasspathChange setClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map<IPath, IClasspathEntry> newRootPathToRawEntries, Map<IPath, IClasspathEntry> newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, boolean addClasspathChange) { if (DEBUG_CLASSPATH) { System.out.println("Setting resolved classpath for " + this.project.getFullPath()); //$NON-NLS-1$ if (newResolvedClasspath == null) { System.out.println("New classpath = null"); //$NON-NLS-1$ } else { for (IClasspathEntry next : newResolvedClasspath) { System.out.println(" " + next); //$NON-NLS-1$ } } } ClasspathChange classpathChange = addClasspathChange ? addClasspathChange() : null; if (referencedEntries != null) this.referencedEntries = referencedEntries; if (this.referencedEntries == null) this.referencedEntries = ClasspathEntry.NO_ENTRIES; this.rawClasspath = newRawClasspath; this.outputLocation = newOutputLocation; this.rawClasspathStatus = newRawClasspathStatus; this.resolvedClasspath = newResolvedClasspath; this.rootPathToRawEntries = newRootPathToRawEntries; this.rootPathToResolvedEntries = newRootPathToResolvedEntries; this.unresolvedEntryStatus = newUnresolvedEntryStatus; this.javadocCache = new LRUCache<>(JAVADOC_CACHE_INITIAL_SIZE); return classpathChange; } protected ClasspathChange addClasspathChange() { // remember old info JavaModelManager manager = JavaModelManager.getJavaModelManager(); ClasspathChange classpathChange = manager.deltaState.addClasspathChange(this.project, this.rawClasspath, this.outputLocation, this.resolvedClasspath); return classpathChange; } public ClasspathChange setRawClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus) { return setRawClasspath(newRawClasspath, null, newOutputLocation, newRawClasspathStatus); } public synchronized ClasspathChange setRawClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus) { this.rawTimeStamp++; return setClasspath(newRawClasspath, referencedEntries, newOutputLocation, newRawClasspathStatus, null/*resolved classpath*/, null/*root to raw map*/, null/*root to resolved map*/, null/*unresolved status*/, true/*add classpath change*/); } public ClasspathChange setResolvedClasspath(IClasspathEntry[] newResolvedClasspath, Map<IPath, IClasspathEntry> newRootPathToRawEntries, Map<IPath, IClasspathEntry> newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, int timeStamp, boolean addClasspathChange) { return setResolvedClasspath(newResolvedClasspath, null, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, timeStamp, addClasspathChange); } public synchronized ClasspathChange setResolvedClasspath(IClasspathEntry[] newResolvedClasspath, IClasspathEntry[] referencedEntries, Map<IPath, IClasspathEntry> newRootPathToRawEntries, Map<IPath, IClasspathEntry> newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus, int timeStamp, boolean addClasspathChange) { if (this.rawTimeStamp != timeStamp) return null; return setClasspath(this.rawClasspath, referencedEntries, this.outputLocation, this.rawClasspathStatus, newResolvedClasspath, newRootPathToRawEntries, newRootPathToResolvedEntries, newUnresolvedEntryStatus, addClasspathChange); } public synchronized void setJrtPackageRoots(IPath jrtPath, ObjectVector roots) { if (this.jrtRoots == null) this.jrtRoots = new HashMap<>(); this.jrtRoots.put(jrtPath, roots); }
Reads the classpath and caches the entries. Returns a two-dimensional array, where the number of elements in the row is fixed to 2. The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored by the client earlier. See IJavaProject.getReferencedClasspathEntries() for more details.
/** * Reads the classpath and caches the entries. Returns a two-dimensional array, where the number of elements in the row is fixed to 2. * The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored * by the client earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details. * */
public synchronized IClasspathEntry[][] readAndCacheClasspath(JavaProject javaProject) { // read file entries and update status IClasspathEntry[][] classpath; IJavaModelStatus status; try { classpath = javaProject.readFileEntriesWithException(null/*not interested in unknown elements*/); status = JavaModelStatus.VERIFIED_OK; } catch (CoreException e) { classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES}; status = new JavaModelStatus( IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName())); } catch (IOException e) { classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES}; if (Messages.file_badFormat.equals(e.getMessage())) status = new JavaModelStatus( IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, Messages.bind(Messages.classpath_xmlFormatError, javaProject.getElementName(), Messages.file_badFormat)); else status = new JavaModelStatus( IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName())); } catch (ClasspathEntry.AssertionFailedException e) { classpath = new IClasspathEntry[][]{JavaProject.INVALID_CLASSPATH, ClasspathEntry.NO_ENTRIES}; status = new JavaModelStatus( IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT, Messages.bind(Messages.classpath_illegalEntryInClasspathFile, new String[] {javaProject.getElementName(), e.getMessage()})); } // extract out the output location int rawClasspathLength = classpath[0].length; IPath output = null; if (rawClasspathLength > 0) { IClasspathEntry entry = classpath[0][rawClasspathLength - 1]; if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) { output = entry.getPath(); IClasspathEntry[] copy = new IClasspathEntry[rawClasspathLength - 1]; System.arraycopy(classpath[0], 0, copy, 0, copy.length); classpath[0] = copy; } } // store new raw classpath, new output and new status, and null out resolved info setRawClasspath(classpath[0], classpath[1], output, status); return classpath; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("Info for "); //$NON-NLS-1$ buffer.append(this.project.getFullPath()); buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$ if (this.rawClasspath == null) { buffer.append(" <null>\n"); //$NON-NLS-1$ } else { for (int i = 0, length = this.rawClasspath.length; i < length; i++) { buffer.append(" "); //$NON-NLS-1$ buffer.append(this.rawClasspath[i]); buffer.append('\n'); } } buffer.append("Resolved classpath:\n"); //$NON-NLS-1$ IClasspathEntry[] resolvedCP = this.resolvedClasspath; if (resolvedCP == null) { buffer.append(" <null>\n"); //$NON-NLS-1$ } else { for (int i = 0, length = resolvedCP.length; i < length; i++) { buffer.append(" "); //$NON-NLS-1$ buffer.append(resolvedCP[i]); buffer.append('\n'); } } buffer.append("Resolved classpath status: "); //$NON-NLS-1$ if (this.unresolvedEntryStatus == NEED_RESOLUTION) buffer.append("NEED RESOLUTION"); //$NON-NLS-1$ else buffer.append(this.unresolvedEntryStatus == null ? "<null>\n" : this.unresolvedEntryStatus.toString()); //$NON-NLS-1$ buffer.append("Output location:\n "); //$NON-NLS-1$ if (this.outputLocation == null) { buffer.append("<null>"); //$NON-NLS-1$ } else { buffer.append(this.outputLocation); } return buffer.toString(); } public boolean writeAndCacheClasspath( JavaProject javaProject, final IClasspathEntry[] newRawClasspath, IClasspathEntry[] newReferencedEntries, final IPath newOutputLocation) throws JavaModelException { try { this.writtingRawClasspath = true; if (newReferencedEntries == null) newReferencedEntries = this.referencedEntries; // write .classpath if (!javaProject.writeFileEntries(newRawClasspath, newReferencedEntries, newOutputLocation)) { return false; } // store new raw classpath, new output and new status, and null out resolved info setRawClasspath(newRawClasspath, newReferencedEntries, newOutputLocation, JavaModelStatus.VERIFIED_OK); } finally { this.writtingRawClasspath = false; } return true; } public boolean writeAndCacheClasspath(JavaProject javaProject, final IClasspathEntry[] newRawClasspath, final IPath newOutputLocation) throws JavaModelException { return writeAndCacheClasspath(javaProject, newRawClasspath, null, newOutputLocation); } } public static class PerWorkingCopyInfo implements IProblemRequestor { int useCount = 0; IProblemRequestor problemRequestor; CompilationUnit workingCopy; public PerWorkingCopyInfo(CompilationUnit workingCopy, IProblemRequestor problemRequestor) { this.workingCopy = workingCopy; this.problemRequestor = problemRequestor; } @Override public void acceptProblem(IProblem problem) { IProblemRequestor requestor = getProblemRequestor(); if (requestor == null) return; requestor.acceptProblem(problem); } @Override public void beginReporting() { IProblemRequestor requestor = getProblemRequestor(); if (requestor == null) return; requestor.beginReporting(); } @Override public void endReporting() { IProblemRequestor requestor = getProblemRequestor(); if (requestor == null) return; requestor.endReporting(); } public IProblemRequestor getProblemRequestor() { if (this.problemRequestor == null && this.workingCopy.owner != null) { return this.workingCopy.owner.getProblemRequestor(this.workingCopy); } return this.problemRequestor; } public ICompilationUnit getWorkingCopy() { return this.workingCopy; } @Override public boolean isActive() { IProblemRequestor requestor = getProblemRequestor(); return requestor != null && requestor.isActive(); } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("Info for "); //$NON-NLS-1$ buffer.append(((JavaElement)this.workingCopy).toStringWithAncestors()); buffer.append("\nUse count = "); //$NON-NLS-1$ buffer.append(this.useCount); buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$ buffer.append(this.problemRequestor); if (this.problemRequestor == null) { IProblemRequestor requestor = getProblemRequestor(); buffer.append("\nOwner problem requestor:\n "); //$NON-NLS-1$ buffer.append(requestor); } return buffer.toString(); } } public static boolean VERBOSE = false; public static boolean DEBUG_CLASSPATH = false; public static boolean DEBUG_INVALID_ARCHIVES = false; public static boolean CP_RESOLVE_VERBOSE = false; public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false; public static boolean CP_RESOLVE_VERBOSE_FAILURE = false; public static boolean ZIP_ACCESS_VERBOSE = false; public static boolean JRT_ACCESS_VERBOSE = false;
A cache of opened zip files per thread. (for a given thread, the object value is a HashMap from IPath to java.io.ZipFile)
/** * A cache of opened zip files per thread. * (for a given thread, the object value is a HashMap from IPath to java.io.ZipFile) */
private ThreadLocal<ZipCache> zipFiles = new ThreadLocal<>(); private UserLibraryManager userLibraryManager; private ModuleSourcePathManager modulePathManager; /* * A set of IPaths for jars that are known to not contain a chaining (through MANIFEST.MF) to another library */ private Set<IPath> nonChainingJars; // The amount of time from when an invalid archive is first sensed until that state is considered stale. private static long INVALID_ARCHIVE_TTL_MILLISECONDS = 2 * 60 * 1000; private static class InvalidArchiveInfo {
Time at which this entry will be removed from the invalid archive list.
/** * Time at which this entry will be removed from the invalid archive list. */
final long evictionTimestamp;
Reason the entry was added to the invalid archive list.
/** * Reason the entry was added to the invalid archive list. */
final ArchiveValidity reason; InvalidArchiveInfo(long evictionTimestamp, ArchiveValidity reason) { this.evictionTimestamp = evictionTimestamp; this.reason = reason; } } /* * A map of IPaths for jars that are known to be invalid (such as not being in a valid/known format), to an eviction timestamp. * Synchronize on invalidArchivesMutex before accessing. */ private final Map<IPath, InvalidArchiveInfo> invalidArchives = new HashMap<>(); private final Object invalidArchivesMutex = new Object(); /* * A set of IPaths for files that are known to be external to the workspace. * Need not be referenced by the classpath. */ private Set<IPath> externalFiles; /* * A set of IPaths for files that do not exist on the file system but are assumed to be * external archives (rather than external folders). */ private Set<IPath> assumedExternalFiles;
Update the classpath variable cache
/** * Update the classpath variable cache */
public static class EclipsePreferencesListener implements IEclipsePreferences.IPreferenceChangeListener {
See Also:
  • preferenceChange.preferenceChange(PreferenceChangeEvent)
/** * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent) */
@Override public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) { String propertyName = event.getKey(); if (propertyName.startsWith(JavaCore.PLUGIN_ID)) { if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) { String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length()); JavaModelManager manager = getJavaModelManager(); if (manager.variablesWithInitializer.contains(varName)) { // revert preference value as we will not apply it to JavaCore classpath variable String oldValue = (String) event.getOldValue(); if (oldValue == null) { // unexpected old value => remove variable from set manager.variablesWithInitializer.remove(varName); } else { manager.getInstancePreferences().put(varName, oldValue); } } else { String newValue = (String)event.getNewValue(); IPath newPath; if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) { newPath = new Path(newValue); } else { newPath = null; } try { SetVariablesOperation operation = new SetVariablesOperation(new String[] {varName}, new IPath[] {newPath}, false/*don't update preferences*/); operation.runOperation(null/*no progress available*/); } catch (JavaModelException e) { Util.log(e, "Could not set classpath variable " + varName + " to " + newPath); //$NON-NLS-1$ //$NON-NLS-2$ } } } else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) { recreatePersistedContainer(propertyName, (String)event.getNewValue(), false); } else if (propertyName.equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) || propertyName.equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER) || propertyName.equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE) || propertyName.equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER) || propertyName.equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH) || propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS) || propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) || propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL) || propertyName.equals(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY) || propertyName.equals(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM) || propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE)) { JavaModelManager manager = JavaModelManager.getJavaModelManager(); IJavaModel model = manager.getJavaModel(); IJavaProject[] jProjects; try { jProjects = model.getJavaProjects(); IProject[] projects = new IProject[jProjects.length]; for (int i = 0, pl = jProjects.length; i < pl; i++) { JavaProject javaProject = (JavaProject) jProjects[i]; projects[i] = javaProject.getProject(); manager.deltaState.addClasspathValidation(javaProject); } manager.touchProjects(projects, null); } catch (JavaModelException e) { // skip } } else if (propertyName.startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) { String libName = propertyName.substring(CP_USERLIBRARY_PREFERENCES_PREFIX.length()); UserLibraryManager manager = JavaModelManager.getUserLibraryManager(); manager.updateUserLibrary(libName, (String)event.getNewValue()); } } // Reset all project caches (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=233568 ) try { IJavaProject[] projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects(); for (int i = 0, length = projects.length; i < length; i++) { ((JavaProject) projects[i]).resetCaches(); } } catch (JavaModelException e) { // cannot retrieve Java projects } } }
Listener on eclipse preferences changes.
/** * Listener on eclipse preferences changes. */
EclipsePreferencesListener instancePreferencesListener = new EclipsePreferencesListener();
Listener on eclipse preferences default/instance node changes.
/** * Listener on eclipse preferences default/instance node changes. */
IEclipsePreferences.INodeChangeListener instanceNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == JavaModelManager.this.preferencesLookup[PREF_INSTANCE]) { JavaModelManager.this.preferencesLookup[PREF_INSTANCE] = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); JavaModelManager.this.preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener()); } } }; IEclipsePreferences.INodeChangeListener defaultNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == JavaModelManager.this.preferencesLookup[PREF_DEFAULT]) { JavaModelManager.this.preferencesLookup[PREF_DEFAULT] = DefaultScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); } } };
Listener on properties changes.
/** * Listener on properties changes. */
IEclipsePreferences.IPreferenceChangeListener propertyListener; IEclipsePreferences.IPreferenceChangeListener resourcesPropertyListener;
Constructs a new JavaModelManager
/** * Constructs a new JavaModelManager */
private JavaModelManager() { // singleton: prevent others from creating a new instance /* * It is required to initialize all fields that depends on a headless environment * only if the platform is running. Otherwise this breaks the ability to use * ASTParser in a non-headless environment. */ if (Platform.isRunning()) { this.indexManager = new IndexManager(); this.nonChainingJars = loadClasspathListCache(NON_CHAINING_JARS_CACHE); this.externalFiles = loadClasspathListCache(EXTERNAL_FILES_CACHE); this.assumedExternalFiles = loadClasspathListCache(ASSUMED_EXTERNAL_FILES_CACHE); String includeContainerReferencedLib = System.getProperty(RESOLVE_REFERENCED_LIBRARIES_FOR_CONTAINERS); this.resolveReferencedLibrariesForContainers = TRUE.equalsIgnoreCase(includeContainerReferencedLib); } }
Deprecated:
/** * @deprecated */
private void addDeprecatedOptions(Hashtable<String, String> options) { options.put(JavaCore.COMPILER_PB_INVALID_IMPORT, JavaCore.ERROR); options.put(JavaCore.COMPILER_PB_UNREACHABLE_CODE, JavaCore.ERROR); } public void addNonChainingJar(IPath path) { if (this.nonChainingJars != null) this.nonChainingJars.add(path); } public void addInvalidArchive(IPath path, ArchiveValidity reason) { if (DEBUG_INVALID_ARCHIVES) { System.out.println("Invalid JAR cache: adding " + path + ", reason: " + reason); //$NON-NLS-1$//$NON-NLS-2$ } synchronized (this.invalidArchivesMutex) { this.invalidArchives.put(path, new InvalidArchiveInfo(System.currentTimeMillis() + INVALID_ARCHIVE_TTL_MILLISECONDS, reason)); } }
Adds a path to the external files cache. It is the responsibility of callers to determine the file's existence, as determined by File.isFile().
/** * Adds a path to the external files cache. It is the responsibility of callers to * determine the file's existence, as determined by {@link File#isFile()}. */
public void addExternalFile(IPath path) { // unlikely to be null if (this.externalFiles == null) { this.externalFiles = Collections.synchronizedSet(new HashSet<IPath>()); } if(this.externalFiles != null) { this.externalFiles.add(path); } }
Starts caching ZipFiles. Ignores if there are already clients.
/** * Starts caching ZipFiles. * Ignores if there are already clients. */
public void cacheZipFiles(Object owner) { ZipCache zipCache = this.zipFiles.get(); if (zipCache != null) { return; } // the owner will be responsible for flushing the cache this.zipFiles.set(new ZipCache(owner)); } public void closeZipFile(ZipFile zipFile) { if (zipFile == null) return; if (this.zipFiles.get() != null) { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] NOT closed ZipFile (cache exist!) on " +zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } return; // zip file will be closed by call to flushZipFiles } try { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } zipFile.close(); } catch (IOException e) { // problem occured closing zip file: cannot do much more JavaCore.getPlugin().getLog().log(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, "Error closing " + zipFile.getName(), e)); //$NON-NLS-1$ } } public static void registerDebugOptionsListener(BundleContext context) { // register debug options listener Hashtable<String, String> properties = new Hashtable<>(2); properties.put(DebugOptions.LISTENER_SYMBOLICNAME, JavaCore.PLUGIN_ID); DEBUG_REGISTRATION = context.registerService(DebugOptionsListener.class, new DebugOptionsListener() { @Override public void optionsChanged(DebugOptions options) { boolean debug = options.getBooleanOption(DEBUG, false); BufferManager.VERBOSE = debug && options.getBooleanOption(BUFFER_MANAGER_DEBUG, false); JavaBuilder.DEBUG = debug && options.getBooleanOption(BUILDER_DEBUG, false); Compiler.DEBUG = debug && options.getBooleanOption(COMPILER_DEBUG, false); JavaBuilder.SHOW_STATS = debug && options.getBooleanOption(BUILDER_STATS_DEBUG, false); CompletionEngine.DEBUG = debug && options.getBooleanOption(COMPLETION_DEBUG, false); JavaModelManager.CP_RESOLVE_VERBOSE = debug && options.getBooleanOption(CP_RESOLVE_DEBUG, false); JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED = debug && options.getBooleanOption(CP_RESOLVE_ADVANCED_DEBUG, false); JavaModelManager.CP_RESOLVE_VERBOSE_FAILURE = debug && options.getBooleanOption(CP_RESOLVE_FAILURE_DEBUG, false); DeltaProcessor.DEBUG = debug && options.getBooleanOption(DELTA_DEBUG, false); DeltaProcessor.VERBOSE = debug && options.getBooleanOption(DELTA_DEBUG_VERBOSE, false); SourceRangeVerifier.DEBUG = debug && options.getBooleanOption(DOM_AST_DEBUG, false); SourceRangeVerifier.DEBUG_THROW = debug && options.getBooleanOption(DOM_AST_DEBUG_THROW, false); SourceRangeVerifier.DEBUG |= SourceRangeVerifier.DEBUG_THROW; RewriteEventStore.DEBUG = debug && options.getBooleanOption(DOM_REWRITE_DEBUG, false); TypeHierarchy.DEBUG = debug && options.getBooleanOption(HIERARCHY_DEBUG, false); JobManager.VERBOSE = debug && options.getBooleanOption(INDEX_MANAGER_DEBUG, false); IndexManager.DEBUG = debug && options.getBooleanOption(INDEX_MANAGER_ADVANCED_DEBUG, false); JavaModelManager.DEBUG_CLASSPATH = debug && options.getBooleanOption(JAVAMODEL_CLASSPATH, false); JavaModelManager.DEBUG_INVALID_ARCHIVES = debug && options.getBooleanOption(JAVAMODEL_INVALID_ARCHIVES, false); JavaModelManager.VERBOSE = debug && options.getBooleanOption(JAVAMODEL_DEBUG, false); JavaModelCache.VERBOSE = debug && options.getBooleanOption(JAVAMODELCACHE_DEBUG, false); JavaModelCache.DEBUG_CACHE_INSERTIONS = debug && options.getBooleanOption(JAVAMODELCACHE_INSERTIONS_DEBUG, false); JavaModelOperation.POST_ACTION_VERBOSE = debug && options.getBooleanOption(POST_ACTION_DEBUG, false); NameLookup.VERBOSE = debug && options.getBooleanOption(RESOLUTION_DEBUG, false); BasicSearchEngine.VERBOSE = debug && options.getBooleanOption(SEARCH_DEBUG, false); SelectionEngine.DEBUG = debug && options.getBooleanOption(SELECTION_DEBUG, false); JavaModelManager.ZIP_ACCESS_VERBOSE = debug && options.getBooleanOption(ZIP_ACCESS_DEBUG, false); SourceMapper.VERBOSE = debug && options.getBooleanOption(SOURCE_MAPPER_DEBUG_VERBOSE, false); DefaultCodeFormatter.DEBUG = debug && options.getBooleanOption(FORMATTER_DEBUG, false); Database.DEBUG_FREE_SPACE = debug && options.getBooleanOption(INDEX_DEBUG_LARGE_CHUNKS, false); Database.DEBUG_PAGE_CACHE = debug && options.getBooleanOption(INDEX_DEBUG_PAGE_CACHE, false); Indexer.DEBUG = debug && options.getBooleanOption(INDEX_INDEXER_DEBUG, false); Indexer.DEBUG_INSERTIONS = debug && options.getBooleanOption(INDEX_INDEXER_INSERTIONS, false); Indexer.DEBUG_ALLOCATIONS = debug && options.getBooleanOption(INDEX_INDEXER_SPACE, false); Indexer.DEBUG_TIMING = debug && options.getBooleanOption(INDEX_INDEXER_TIMING, false); Indexer.DEBUG_SCHEDULING = debug && options.getBooleanOption(INDEX_INDEXER_SCHEDULING, false); Indexer.DEBUG_SELFTEST = debug && options.getBooleanOption(INDEX_INDEXER_SELFTEST, false); Indexer.DEBUG_LOG_SIZE_MB = debug ? options.getIntegerOption(INDEX_INDEXER_LOG_SIZE_MEGS, 0) : 0; Nd.sDEBUG_LOCKS = debug && options.getBooleanOption(INDEX_LOCKS_DEBUG, false); // configure performance options if(PerformanceStats.ENABLED) { CompletionEngine.PERF = PerformanceStats.isEnabled(COMPLETION_PERF); SelectionEngine.PERF = PerformanceStats.isEnabled(SELECTION_PERF); DeltaProcessor.PERF = PerformanceStats.isEnabled(DELTA_LISTENER_PERF); JavaModelManager.PERF_VARIABLE_INITIALIZER = PerformanceStats.isEnabled(VARIABLE_INITIALIZER_PERF); JavaModelManager.PERF_CONTAINER_INITIALIZER = PerformanceStats.isEnabled(CONTAINER_INITIALIZER_PERF); ReconcileWorkingCopyOperation.PERF = PerformanceStats.isEnabled(RECONCILE_PERF); } } }, properties); } public static void unregisterDebugOptionsListener() { // unregister debug options listener DEBUG_REGISTRATION.unregister(); DEBUG_REGISTRATION = null; } /* * Return a new Java 6 annotation processor manager. The manager will need to * be configured before it can be used. Returns null if a manager cannot be * created, i.e. if the current VM does not support Java 6 annotation processing. */ public AbstractAnnotationProcessorManager createAnnotationProcessorManager() { synchronized(this) { if (this.annotationProcessorManagerFactory == null) { IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID); if (extension == null) return null; IExtension[] extensions = extension.getExtensions(); for(int i = 0; i < extensions.length; i++) { if (i > 0) { Util.log(null, "An annotation processor manager is already registered: ignoring " + extensions[i].getUniqueIdentifier()); //$NON-NLS-1$ break; } IConfigurationElement[] configElements = extensions[i].getConfigurationElements(); for(int j = 0; j < configElements.length; j++) { final IConfigurationElement configElement = configElements[j]; if ("annotationProcessorManager".equals(configElement.getName())) { //$NON-NLS-1$ this.annotationProcessorManagerFactory = configElement; break; } } } } } if (this.annotationProcessorManagerFactory == null) { return null; } final AbstractAnnotationProcessorManager[] apm = new AbstractAnnotationProcessorManager[1]; apm[0] = null; final IConfigurationElement factory = this.annotationProcessorManagerFactory; SafeRunner.run(new ISafeRunnable() { @Override public void handleException(Throwable exception) { Util.log(exception, "Exception occurred while loading annotation processor manager"); //$NON-NLS-1$ } @Override public void run() throws Exception { Object executableExtension = factory.createExecutableExtension("class"); //$NON-NLS-1$ if (executableExtension instanceof AbstractAnnotationProcessorManager) { apm[0] = (AbstractAnnotationProcessorManager) executableExtension; } } }); return apm[0]; } /* * Discards the per working copy info for the given working copy (making it a compilation unit) * if its use count was 1. Otherwise, just decrement the use count. * If the working copy is primary, computes the delta between its state and the original compilation unit * and register it. * Close the working copy, its buffer and remove it from the shared working copy table. * Ignore if no per-working copy info existed. * NOTE: it must NOT be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667. * Returns the new use count (or -1 if it didn't exist). */ public int discardPerWorkingCopyInfo(CompilationUnit workingCopy) throws JavaModelException { // create the delta builder (this remembers the current content of the working copy) // outside the perWorkingCopyInfos lock (see bug 50667) JavaElementDeltaBuilder deltaBuilder = null; if (workingCopy.isPrimary() && workingCopy.hasUnsavedChanges()) { deltaBuilder = new JavaElementDeltaBuilder(workingCopy); } PerWorkingCopyInfo info = null; synchronized(this.perWorkingCopyInfos) { WorkingCopyOwner owner = workingCopy.owner; Map<CompilationUnit, PerWorkingCopyInfo> workingCopyToInfos = this.perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null) return -1; info = workingCopyToInfos.get(workingCopy); if (info == null) return -1; if (--info.useCount == 0) { // remove per working copy info workingCopyToInfos.remove(workingCopy); if (workingCopyToInfos.isEmpty()) { this.perWorkingCopyInfos.remove(owner); } } } if (info.useCount == 0) { // info cannot be null here (check was done above) // remove infos + close buffer (since no longer working copy) // outside the perWorkingCopyInfos lock (see bug 50667) removeInfoAndChildren(workingCopy); workingCopy.closeBuffer(); // compute the delta if needed and register it if there are changes if (deltaBuilder != null) { deltaBuilder.buildDeltas(); if (deltaBuilder.delta != null) { getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta); } } } return info.useCount; }
See Also:
  • ISaveParticipant
/** * @see ISaveParticipant */
@Override public void doneSaving(ISaveContext context){ // nothing to do for jdt.core }
Flushes ZipFiles cache if there are no more clients.
/** * Flushes ZipFiles cache if there are no more clients. */
public void flushZipFiles(Object owner) { ZipCache zipCache = this.zipFiles.get(); if (zipCache == null) { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.flushZipFiles(String)] NOT found cache for " + owner); //$NON-NLS-1$ //$NON-NLS-2$ } return; } // the owner will be responsible for flushing the cache // we want to check object identity to make sure this is the owner that created the cache if (zipCache.owner == owner) { this.zipFiles.set(null); zipCache.flush(); } else { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() //$NON-NLS-1$ + ") [JavaModelManager.flushZipFiles(String)] NOT closed cache, wrong owner, expected: " //$NON-NLS-1$ + zipCache.owner + ", got: " + owner); //$NON-NLS-1$ } } } /* * Returns true if forcing batch initialization was successful. * Returns false if batch initialization is already running. */ public synchronized boolean forceBatchInitializations(boolean initAfterLoad) { switch (this.batchContainerInitializations) { case NO_BATCH_INITIALIZATION: this.batchContainerInitializations = NEED_BATCH_INITIALIZATION; return true; case BATCH_INITIALIZATION_FINISHED: if (initAfterLoad) return false; // no need to initialize again this.batchContainerInitializations = NEED_BATCH_INITIALIZATION; return true; } return false; } private synchronized boolean batchContainerInitializations() { switch (this.batchContainerInitializations) { case NEED_BATCH_INITIALIZATION: this.batchContainerInitializations = BATCH_INITIALIZATION_IN_PROGRESS; return true; case BATCH_INITIALIZATION_IN_PROGRESS: return true; } return false; } private synchronized void batchInitializationFinished() { this.batchContainerInitializations = BATCH_INITIALIZATION_FINISHED; } public IClasspathContainer getClasspathContainer(final IPath containerPath, final IJavaProject project) throws JavaModelException { IClasspathContainer container = containerGet(project, containerPath); if (container == null) { if (batchContainerInitializations()) { // avoid deep recursion while initializing container on workspace restart // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=60437) try { container = initializeAllContainers(project, containerPath); } finally { batchInitializationFinished(); } } else { container = initializeContainer(project, containerPath); containerBeingInitializedRemove(project, containerPath); SetContainerOperation operation = new SetContainerOperation(containerPath, new IJavaProject[] {project}, new IClasspathContainer[] {container}); operation.runOperation(null); } } return container; } public IClasspathEntry[] getReferencedClasspathEntries(IClasspathEntry libraryEntry, IJavaProject project) { IClasspathEntry[] referencedEntries = ((ClasspathEntry)libraryEntry).resolvedChainedLibraries(); if (project == null) return referencedEntries; PerProjectInfo perProjectInfo = getPerProjectInfo(project.getProject(), false); if(perProjectInfo == null) return referencedEntries; LinkedHashSet<IPath> pathToReferencedEntries = new LinkedHashSet<>(referencedEntries.length); for (int index = 0; index < referencedEntries.length; index++) { if (pathToReferencedEntries.contains(referencedEntries[index].getPath())) continue; IClasspathEntry persistedEntry = null; if ((persistedEntry = perProjectInfo.rootPathToResolvedEntries.get(referencedEntries[index].getPath())) != null) { // TODO: reconsider this - may want to copy the values instead of reference assignment? referencedEntries[index] = persistedEntry; } pathToReferencedEntries.add(referencedEntries[index].getPath()); } return referencedEntries; } public DeltaProcessor getDeltaProcessor() { return this.deltaState.getDeltaProcessor(); } public static DeltaProcessingState getDeltaState() { return MANAGER.deltaState; }
Returns the set of elements which are out of synch with their buffers.
/** * Returns the set of elements which are out of synch with their buffers. */
protected HashSet<Openable> getElementsOutOfSynchWithBuffers() { return this.elementsOutOfSynchWithBuffers; } public static ExternalFoldersManager getExternalManager() { return MANAGER.externalFoldersManager; } public static IndexManager getIndexManager() { return MANAGER.indexManager; }
Returns the info for the element.
/** * Returns the info for the element. */
public synchronized Object getInfo(IJavaElement element) { HashMap<IJavaElement, Object> tempCache = this.temporaryCache.get(); if (tempCache != null) { Object result = tempCache.get(element); if (result != null) { return result; } } return this.cache.getInfo(element); }
Returns the existing element in the cache that is equal to the given element.
/** * Returns the existing element in the cache that is equal to the given element. */
public synchronized IJavaElement getExistingElement(IJavaElement element) { return this.cache.getExistingElement(element); } public HashSet<IJavaProject> getExternalWorkingCopyProjects() { synchronized (this.perWorkingCopyInfos) { HashSet<IJavaProject> result = null; Iterator<Map<CompilationUnit, PerWorkingCopyInfo>> values = this.perWorkingCopyInfos.values().iterator(); while (values.hasNext()) { Map<CompilationUnit, PerWorkingCopyInfo> ownerCopies = values.next(); Iterator<CompilationUnit> workingCopies = ownerCopies.keySet().iterator(); while (workingCopies.hasNext()) { ICompilationUnit workingCopy = workingCopies.next(); IJavaProject project = workingCopy.getJavaProject(); if (project.getElementName().equals(ExternalJavaProject.EXTERNAL_PROJECT_NAME)) { if (result == null) result = new HashSet<>(); result.add(project); } } } return result; } }
Get workspace eclipse preference for JavaCore plug-in.
/** * Get workspace eclipse preference for JavaCore plug-in. */
public IEclipsePreferences getInstancePreferences() { return this.preferencesLookup[PREF_INSTANCE]; } // If modified, also modify the method getDefaultOptionsNoInitialization() public Hashtable<String, String> getDefaultOptions(){ Hashtable<String, String> defaultOptions = new Hashtable<>(10); // see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings // If modified, also modify the method getDefaultOptionsNoInitialization() IEclipsePreferences defaultPreferences = getDefaultPreferences(); // initialize preferences to their default Iterator<String> iterator = this.optionNames.iterator(); while (iterator.hasNext()) { String propertyName = iterator.next(); String value = defaultPreferences.get(propertyName, null); if (value != null) defaultOptions.put(propertyName, value); } // get encoding through resource plugin defaultOptions.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding()); // backward compatibility addDeprecatedOptions(defaultOptions); return defaultOptions; }
Get default eclipse preference for JavaCore plugin.
/** * Get default eclipse preference for JavaCore plugin. */
public IEclipsePreferences getDefaultPreferences() { return this.preferencesLookup[PREF_DEFAULT]; }
Returns the handle to the active Java Model.
/** * Returns the handle to the active Java Model. */
public final JavaModel getJavaModel() { return this.javaModel; }
Returns the singleton JavaModelManager
/** * Returns the singleton JavaModelManager */
public final static JavaModelManager getJavaModelManager() { return MANAGER; }
Returns the last built state for the given project, or null if there is none. Deserializes the state if necessary. For use by image builder and evaluation support only
/** * Returns the last built state for the given project, or null if there is none. * Deserializes the state if necessary. * * For use by image builder and evaluation support only */
public Object getLastBuiltState(IProject project, IProgressMonitor monitor) { if (!JavaProject.hasJavaNature(project)) { if (JavaBuilder.DEBUG) System.out.println(project + " is not a Java project"); //$NON-NLS-1$ return null; // should never be requested on non-Java projects } PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/); if (!info.triedRead) { info.triedRead = true; try { if (monitor != null) monitor.subTask(Messages.bind(Messages.build_readStateProgress, project.getName())); info.savedState = readState(project); } catch (CoreException e) { Util.log(e, "Exception while reading last build state for: " + project); //$NON-NLS-1$ } } return info.savedState; } public String getOption(String optionName) { if (JavaCore.CORE_ENCODING.equals(optionName)){ return JavaCore.getEncoding(); } // backward compatibility if (isDeprecatedOption(optionName)) { return JavaCore.ERROR; } int optionLevel = getOptionLevel(optionName); if (optionLevel != UNKNOWN_OPTION){ IPreferencesService service = Platform.getPreferencesService(); String value = service.get(optionName, null, this.preferencesLookup); if (value == null && optionLevel == DEPRECATED_OPTION) { // May be a deprecated option, retrieve the new value in compatible options String[] compatibleOptions = this.deprecatedOptions.get(optionName); value = service.get(compatibleOptions[0], null, this.preferencesLookup); } return value==null ? null : value.trim(); } return null; }
Returns the value of the given option for the given Eclipse preferences. If no value was already set, then inherits from the global options if specified.
Params:
  • optionName – The name of the option
  • inheritJavaCoreOptions – Tells whether the value can be inherited from global JavaCore options
  • projectPreferences – The eclipse preferences from which to get the value
Returns:The value of the option. May be null
/** * Returns the value of the given option for the given Eclipse preferences. * If no value was already set, then inherits from the global options if specified. * * @param optionName The name of the option * @param inheritJavaCoreOptions Tells whether the value can be inherited from global JavaCore options * @param projectPreferences The eclipse preferences from which to get the value * @return The value of the option. May be <code>null</code> */
public String getOption(String optionName, boolean inheritJavaCoreOptions, IEclipsePreferences projectPreferences) { // Return the option value depending on its level switch (getOptionLevel(optionName)) { case VALID_OPTION: // Valid option, return the preference value String javaCoreDefault = inheritJavaCoreOptions ? JavaCore.getOption(optionName) : null; if (projectPreferences == null) return javaCoreDefault; String value = projectPreferences.get(optionName, javaCoreDefault); return value == null ? null : value.trim(); case DEPRECATED_OPTION: // Return the deprecated option value if it was already set String oldValue = projectPreferences.get(optionName, null); if (oldValue != null) { return oldValue.trim(); } // Get the new compatible value String[] compatibleOptions = this.deprecatedOptions.get(optionName); String newDefault = inheritJavaCoreOptions ? JavaCore.getOption(compatibleOptions[0]) : null; String newValue = projectPreferences.get(compatibleOptions[0], newDefault); return newValue == null ? null : newValue.trim(); } return null; }
Returns whether an option name is known or not.
Params:
  • optionName – The name of the option
Returns:true when the option name is either valid or deprecated, false otherwise.
/** * Returns whether an option name is known or not. * * @param optionName The name of the option * @return <code>true</code> when the option name is either * {@link #VALID_OPTION valid} or {@link #DEPRECATED_OPTION deprecated}, * <code>false</code> otherwise. */
public boolean knowsOption(String optionName) { boolean knownOption = this.optionNames.contains(optionName); if (!knownOption) { knownOption = this.deprecatedOptions.get(optionName) != null; } return knownOption; }
Returns the level of the given option.
Params:
  • optionName – The name of the option
Returns:The level of the option as an int which may have the following values:
/** * Returns the level of the given option. * * @param optionName The name of the option * @return The level of the option as an int which may have the following * values: * <ul> * <li>{@link #UNKNOWN_OPTION}: the given option is unknown</li> * <li>{@link #DEPRECATED_OPTION}: the given option is deprecated</li> * <li>{@link #VALID_OPTION}: the given option is valid</li> * </ul> */
public int getOptionLevel(String optionName) { if (this.optionNames.contains(optionName)) { return VALID_OPTION; } if (this.deprecatedOptions.get(optionName) != null) { return DEPRECATED_OPTION; } return UNKNOWN_OPTION; } public Hashtable<String, String> getOptions() { // return cached options if already computed Hashtable<String, String> cachedOptions; // use a local variable to avoid race condition (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=256329 ) if ((cachedOptions = this.optionsCache) != null) { return new Hashtable<>(cachedOptions); } if (!Platform.isRunning()) { this.optionsCache = getDefaultOptionsNoInitialization(); return new Hashtable<>(this.optionsCache); } // init Hashtable<String, String> options = new Hashtable<>(10); IPreferencesService service = Platform.getPreferencesService(); // set options using preferences service lookup Iterator<String> iterator = this.optionNames.iterator(); while (iterator.hasNext()) { String propertyName = iterator.next(); String propertyValue = service.get(propertyName, null, this.preferencesLookup); if (propertyValue != null) { options.put(propertyName, propertyValue); } } // set deprecated options using preferences service lookup Iterator<Entry<String, String[]>> deprecatedEntries = this.deprecatedOptions.entrySet().iterator(); while (deprecatedEntries.hasNext()) { Entry<String, String[]> entry = deprecatedEntries.next(); String propertyName = entry.getKey(); String propertyValue = service.get(propertyName, null, this.preferencesLookup); if (propertyValue != null) { options.put(propertyName, propertyValue); String[] compatibleOptions = entry.getValue(); for (int co=0, length=compatibleOptions.length; co < length; co++) { String compatibleOption = compatibleOptions[co]; if (!options.containsKey(compatibleOption)) options.put(compatibleOption, propertyValue); } } } // get encoding through resource plugin options.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding()); // backward compatibility addDeprecatedOptions(options); Util.fixTaskTags(options); // store built map in cache this.optionsCache = new Hashtable<>(options); // return built map return options; } // Do not modify without modifying getDefaultOptions() private Hashtable<String, String> getDefaultOptionsNoInitialization() { Map<String, String> defaultOptionsMap = new CompilerOptions().getMap(); // compiler defaults // Override some compiler defaults defaultOptionsMap.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaCore.GENERATE); defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaCore.PRESERVE); defaultOptionsMap.put(JavaCore.COMPILER_TASK_TAGS, JavaCore.DEFAULT_TASK_TAGS); defaultOptionsMap.put(JavaCore.COMPILER_TASK_PRIORITIES, JavaCore.DEFAULT_TASK_PRIORITIES); defaultOptionsMap.put(JavaCore.COMPILER_TASK_CASE_SENSITIVE, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR); // Builder settings defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, JavaCore.ABORT); defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, JavaCore.WARNING); defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, JavaCore.CLEAN); // JavaCore settings defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_MAIN_ONLY_PROJECT_HAS_TEST_ONLY_DEPENDENCY, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); // Formatter settings defaultOptionsMap.putAll(DefaultCodeFormatterConstants.getEclipseDefaultSettings()); // CodeAssist settings defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK, JavaCore.DISABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_DEPRECATION_CHECK, JavaCore.DISABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION, JavaCore.DISABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FINAL_FIELD_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FINAL_FIELD_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$ defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_SUBSTRING_MATCH, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED); // Time out for parameter names defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$ return new Hashtable<>(defaultOptionsMap); } /* * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist. */ public PerProjectInfo getPerProjectInfo(IProject project, boolean create) { synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock PerProjectInfo info= this.perProjectInfos.get(project); if (info == null && create) { info= new PerProjectInfo(project); this.perProjectInfos.put(project, info); } return info; } } /* * Returns the per-project info for the given project. * If the info doesn't exist, check for the project existence and create the info. * @throws JavaModelException if the project doesn't exist. */ public PerProjectInfo getPerProjectInfoCheckExistence(IProject project) throws JavaModelException { JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /* don't create info */); if (info == null) { if (!JavaProject.hasJavaNature(project)) { throw ((JavaProject)JavaCore.create(project)).newNotPresentException(); } info = getPerProjectInfo(project, true /* create info */); } return info; } /* * Returns the per-working copy info for the given working copy at the given path. * If it doesn't exist and if create, add a new per-working copy info with the given problem requestor. * If recordUsage, increment the per-working copy info's use count. * Returns null if it doesn't exist and not create. */ public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy,boolean create, boolean recordUsage, IProblemRequestor problemRequestor) { synchronized(this.perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock WorkingCopyOwner owner = workingCopy.owner; Map<CompilationUnit, PerWorkingCopyInfo> workingCopyToInfos = this.perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null && create) { workingCopyToInfos = new HashMap<>(); this.perWorkingCopyInfos.put(owner, workingCopyToInfos); } PerWorkingCopyInfo info = workingCopyToInfos == null ? null : workingCopyToInfos.get(workingCopy); if (info == null && create) { info= new PerWorkingCopyInfo(workingCopy, problemRequestor); workingCopyToInfos.put(workingCopy, info); } if (info != null && recordUsage) info.useCount++; return info; } }
Returns a persisted container from previous session if any. Note that it is not the original container from previous session (i.e. it did not get serialized) but rather a summary of its entries recreated for CP initialization purpose. As such it should not be stored into container caches.
/** * Returns a persisted container from previous session if any. Note that it is not the original container from previous * session (i.e. it did not get serialized) but rather a summary of its entries recreated for CP initialization purpose. * As such it should not be stored into container caches. */
public IClasspathContainer getPreviousSessionContainer(IPath containerPath, IJavaProject project) { Map<IPath, IClasspathContainer> previousContainerValues = this.previousSessionContainers.get(project); if (previousContainerValues != null){ IClasspathContainer previousContainer = previousContainerValues.get(containerPath); if (previousContainer != null) { if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED) verbose_reentering_project_container_access(containerPath, project, previousContainer); return previousContainer; } } return null; // break cycle if none found } private void verbose_reentering_project_container_access( IPath containerPath, IJavaProject project, IClasspathContainer previousContainer) { StringBuffer buffer = new StringBuffer(); buffer.append("CPContainer INIT - reentering access to project container during its initialization, will see previous value\n"); //$NON-NLS-1$ buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$ buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$ buffer.append(" previous value: "); //$NON-NLS-1$ buffer.append(previousContainer.getDescription()); buffer.append(" {\n"); //$NON-NLS-1$ IClasspathEntry[] entries = previousContainer.getClasspathEntries(); if (entries != null){ for (int j = 0; j < entries.length; j++){ buffer.append(" "); //$NON-NLS-1$ buffer.append(entries[j]); buffer.append('\n'); } } buffer.append(" }"); //$NON-NLS-1$ Util.verbose(buffer.toString()); new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ }
Returns a persisted container from previous session if any
/** * Returns a persisted container from previous session if any */
public IPath getPreviousSessionVariable(String variableName) { IPath previousPath = this.previousSessionVariables.get(variableName); if (previousPath != null){ if (CP_RESOLVE_VERBOSE_ADVANCED) verbose_reentering_variable_access(variableName, previousPath); return previousPath; } return null; // break cycle } private void verbose_reentering_variable_access(String variableName, IPath previousPath) { Util.verbose( "CPVariable INIT - reentering access to variable during its initialization, will see previous value\n" + //$NON-NLS-1$ " variable: "+ variableName + '\n' + //$NON-NLS-1$ " previous value: " + previousPath); //$NON-NLS-1$ new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ }
Returns the temporary cache for newly opened elements for the current thread. Creates it if not already created.
/** * Returns the temporary cache for newly opened elements for the current thread. * Creates it if not already created. */
public HashMap<IJavaElement, Object> getTemporaryCache() { HashMap<IJavaElement, Object> result = this.temporaryCache.get(); if (result == null) { result = new HashMap<>(); this.temporaryCache.set(result); } return result; } private File getVariableAndContainersFile() { return JavaCore.getPlugin().getStateLocation().append("variablesAndContainers.dat").toFile(); //$NON-NLS-1$ }
Returns the name of the variables for which an CP variable initializer is registered through an extension point
/** * Returns the name of the variables for which an CP variable initializer is registered through an extension point */
public static String[] getRegisteredVariableNames(){ Plugin jdtCorePlugin = JavaCore.getPlugin(); if (jdtCorePlugin == null) return null; ArrayList<String> variableList = new ArrayList<>(5); IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.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++){ String varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$ if (varAttribute != null) variableList.add(varAttribute); } } } String[] variableNames = new String[variableList.size()]; variableList.toArray(variableNames); return variableNames; }
Returns the name of the container IDs for which an CP container initializer is registered through an extension point
/** * Returns the name of the container IDs for which an CP container initializer is registered through an extension point */
public static String[] getRegisteredContainerIDs(){ Plugin jdtCorePlugin = JavaCore.getPlugin(); if (jdtCorePlugin == null) return null; ArrayList<String> containerIDList = new ArrayList<>(5); IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.CPCONTAINER_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++){ String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$ if (idAttribute != null) containerIDList.add(idAttribute); } } } String[] containerIDs = new String[containerIDList.size()]; containerIDList.toArray(containerIDs); return containerIDs; } public IClasspathEntry resolveVariableEntry(IClasspathEntry entry, boolean usePreviousSession) { if (entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE) return entry; IPath resolvedPath = getResolvedVariablePath(entry.getPath(), usePreviousSession); if (resolvedPath == null) return null; // By passing a null reference path, we keep it relative to workspace root. resolvedPath = ClasspathEntry.resolveDotDot(null, resolvedPath); Object target = JavaModel.getTarget(resolvedPath, false); if (target == null) return null; // inside the workspace if (target instanceof IResource) { IResource resolvedResource = (IResource) target; switch (resolvedResource.getType()) { case IResource.PROJECT : // internal project return JavaCore.newProjectEntry( resolvedPath, entry.getAccessRules(), entry.combineAccessRules(), entry.getExtraAttributes(), entry.isExported()); case IResource.FILE : // internal binary archive return JavaCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath(), usePreviousSession), getResolvedVariablePath(entry.getSourceAttachmentRootPath(), usePreviousSession), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); case IResource.FOLDER : // internal binary folder return JavaCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath(), usePreviousSession), getResolvedVariablePath(entry.getSourceAttachmentRootPath(), usePreviousSession), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); } } if (target instanceof File) { File externalFile = JavaModel.getFile(target); if (externalFile != null) { // external binary archive return JavaCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath(), usePreviousSession), getResolvedVariablePath(entry.getSourceAttachmentRootPath(), usePreviousSession), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); } else { // non-existing file if (resolvedPath.isAbsolute()){ return JavaCore.newLibraryEntry( resolvedPath, getResolvedVariablePath(entry.getSourceAttachmentPath(), usePreviousSession), getResolvedVariablePath(entry.getSourceAttachmentRootPath(), usePreviousSession), entry.getAccessRules(), entry.getExtraAttributes(), entry.isExported()); } } } return null; } public IPath getResolvedVariablePath(IPath variablePath, boolean usePreviousSession) { if (variablePath == null) return null; int count = variablePath.segmentCount(); if (count == 0) return null; // lookup variable String variableName = variablePath.segment(0); IPath resolvedPath = usePreviousSession ? getPreviousSessionVariable(variableName) : JavaCore.getClasspathVariable(variableName); if (resolvedPath == null) return null; // append path suffix if (count > 1) { resolvedPath = resolvedPath.append(variablePath.removeFirstSegments(1)); } return resolvedPath; }
Returns the File to use for saving and restoring the last built state for the given project.
/** * Returns the File to use for saving and restoring the last built state for the given project. */
private File getSerializationFile(IProject project) { if (!project.exists()) return null; IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID); return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$ } public static UserLibraryManager getUserLibraryManager() { if (MANAGER.userLibraryManager == null) { UserLibraryManager libraryManager = new UserLibraryManager(); synchronized(MANAGER) { if (MANAGER.userLibraryManager == null) { // ensure another library manager was not set while creating the instance above MANAGER.userLibraryManager = libraryManager; } } } return MANAGER.userLibraryManager; } public static ModuleSourcePathManager getModulePathManager() { if (MANAGER.modulePathManager == null) { ModuleSourcePathManager modulePathManager = new ModuleSourcePathManager(); synchronized(MANAGER) { if (MANAGER.modulePathManager == null) { // ensure another library manager was not set while creating the instance above MANAGER.modulePathManager = modulePathManager; } } } return MANAGER.modulePathManager; } /* * Returns all the working copies which have the given owner. * Adds the working copies of the primary owner if specified. * Returns null if it has none. */ public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner, boolean addPrimary) { synchronized(this.perWorkingCopyInfos) { ICompilationUnit[] primaryWCs = addPrimary && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false) : null; Map<CompilationUnit, PerWorkingCopyInfo> workingCopyToInfos = this.perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null) return primaryWCs; int primaryLength = primaryWCs == null ? 0 : primaryWCs.length; int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null ICompilationUnit[] result = new ICompilationUnit[primaryLength + size]; int index = 0; if (primaryWCs != null) { for (int i = 0; i < primaryLength; i++) { ICompilationUnit primaryWorkingCopy = primaryWCs[i]; ICompilationUnit workingCopy = new CompilationUnit((PackageFragment) primaryWorkingCopy.getParent(), primaryWorkingCopy.getElementName(), owner); if (!workingCopyToInfos.containsKey(workingCopy)) result[index++] = primaryWorkingCopy; } if (index != primaryLength) System.arraycopy(result, 0, result = new ICompilationUnit[index+size], 0, index); } Iterator<PerWorkingCopyInfo> iterator = workingCopyToInfos.values().iterator(); while(iterator.hasNext()) { result[index++] = iterator.next().getWorkingCopy(); } return result; } } public JavaWorkspaceScope getWorkspaceScope() { if (this.workspaceScope == null) { this.workspaceScope = new JavaWorkspaceScope(); } return this.workspaceScope; } public static boolean isJrt(IPath path) { return path.toString().endsWith(JRTUtil.JRT_FS_JAR); } public static boolean isJrt(String path) { return isJrt(new Path(path)); } public void verifyArchiveContent(IPath path) throws CoreException { // TODO: we haven't finalized what path the JRT is represented by. Don't attempt to validate it. if (isJrt(path)) { return; } throwExceptionIfArchiveInvalid(path); // Check if we can determine the archive's validity by examining the index if (JavaIndex.isEnabled()) { JavaIndex index = JavaIndex.getIndex(); String location = JavaModelManager.getLocalFile(path).getAbsolutePath(); try (IReader reader = index.getNd().acquireReadLock()) { NdResourceFile resourceFile = index.getResourceFile(location.toCharArray()); if (index.isUpToDate(resourceFile)) { // We have this file in the index and the index is up-to-date, so we can determine the file's // validity without touching the filesystem. if (resourceFile.isCorruptedZipFile()) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, new ZipException())); } return; } } } ZipFile file = getZipFile(path); closeZipFile(file); }
Returns the open ZipFile at the given path. If the ZipFile does not yet exist, it is created, opened, and added to the cache of open ZipFiles. The path must be a file system path if representing an external zip/jar, or it must be an absolute workspace relative path if representing a zip/jar inside the workspace.
Throws:
/** * Returns the open ZipFile at the given path. If the ZipFile * does not yet exist, it is created, opened, and added to the cache * of open ZipFiles. * * The path must be a file system path if representing an external * zip/jar, or it must be an absolute workspace relative path if * representing a zip/jar inside the workspace. * * @exception CoreException If unable to create/open the ZipFile. The * cause will be a {@link ZipException} if the file was corrupt, a * {@link FileNotFoundException} if the file does not exist, or a * {@link IOException} if we were unable to read the file. */
public ZipFile getZipFile(IPath path) throws CoreException { return getZipFile(path, true); }
For use in the JDT unit tests only. Used for testing error handling. Causes an IOException to be thrown in getZipFile whenever it attempts to read a zip file.
@noreferenceThis field is not intended to be referenced by clients.
/** * For use in the JDT unit tests only. Used for testing error handling. Causes an * {@link IOException} to be thrown in {@link #getZipFile} whenever it attempts to * read a zip file. * * @noreference This field is not intended to be referenced by clients. */
public static boolean throwIoExceptionsInGetZipFile = false; public ZipFile getZipFile(IPath path, boolean checkInvalidArchiveCache) throws CoreException { if (checkInvalidArchiveCache) { throwExceptionIfArchiveInvalid(path); } ZipCache zipCache; ZipFile zipFile; if ((zipCache = this.zipFiles.get()) != null && (zipFile = zipCache.getCache(path)) != null) { return zipFile; } File localFile = getLocalFile(path); try { if (ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile ); //$NON-NLS-1$ //$NON-NLS-2$ } if (throwIoExceptionsInGetZipFile) { throw new IOException(); } zipFile = new ZipFile(localFile); if (zipCache != null) { zipCache.setCache(path, zipFile); } return zipFile; } catch (IOException e) { ArchiveValidity reason; if (e instanceof ZipException) { reason = ArchiveValidity.BAD_FORMAT; } else if (e instanceof FileNotFoundException) { reason = ArchiveValidity.FILE_NOT_FOUND; } else { reason = ArchiveValidity.UNABLE_TO_READ; } addInvalidArchive(path, reason); throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, e)); } } public static File getLocalFile(IPath path) throws CoreException { File localFile = null; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IResource file = root.findMember(path); if (file != null) { // internal resource URI location; if (file.getType() != IResource.FILE || (location = file.getLocationURI()) == null) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null)); } localFile = Util.toLocalFile(location, null/*no progress availaible*/); if (localFile == null) throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null)); } else { // external resource -> it is ok to use toFile() localFile= path.toFile(); } return localFile; } private void throwExceptionIfArchiveInvalid(IPath path) throws CoreException { ArchiveValidity validity = getArchiveValidity(path); IOException reason; switch (validity) { case BAD_FORMAT: reason = new ZipException("Bad format in archive: " + path); break; //$NON-NLS-1$ case FILE_NOT_FOUND: reason = new FileNotFoundException("Archive not found for path: " + path); break; //$NON-NLS-1$ case UNABLE_TO_READ: reason = new IOException("Unable to read archive: " + path); break; //$NON-NLS-1$ default: reason = null; } if (reason != null) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, reason)); } } /* * Returns whether there is a temporary cache for the current thread. */ public boolean hasTemporaryCache() { return this.temporaryCache.get() != null; } /* * Initialize all container at the same time as the given container. * Return the container for the given path and project. */ private IClasspathContainer initializeAllContainers(IJavaProject javaProjectToInit, IPath containerToInit) throws JavaModelException { if (CP_RESOLVE_VERBOSE_ADVANCED) verbose_batching_containers_initialization(javaProjectToInit, containerToInit); // collect all container paths final HashMap<IJavaProject, Set<IPath>> allContainerPaths = new HashMap<>(); IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (int i = 0, length = projects.length; i < length; i++) { IProject project = projects[i]; if (!JavaProject.hasJavaNature(project)) continue; IJavaProject javaProject = new JavaProject(project, getJavaModel()); Set<IPath> paths = allContainerPaths.get(javaProject); IClasspathEntry[] rawClasspath = javaProject.getRawClasspath(); for (int j = 0, length2 = rawClasspath.length; j < length2; j++) { IClasspathEntry entry = rawClasspath[j]; IPath path = entry.getPath(); if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER && containerGet(javaProject, path) == null) { if (paths == null) { paths = new HashSet<>(); allContainerPaths.put(javaProject, paths); } paths.add(path); } } /* TODO (frederic) put back when JDT/UI dummy project will be thrown away... * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97524 * if (javaProject.equals(javaProjectToInit)) { if (paths == null) { paths = new HashSet(); allContainerPaths.put(javaProject, paths); } paths.add(containerToInit); } */ } // TODO (frederic) remove following block when JDT/UI dummy project will be thrown away... if (javaProjectToInit != null) { Set<IPath> containerPaths = allContainerPaths.get(javaProjectToInit); if (containerPaths == null) { containerPaths = new HashSet<>(); allContainerPaths.put(javaProjectToInit, containerPaths); } containerPaths.add(containerToInit); } // end block // initialize all containers boolean ok = false; try { // if possible run inside an IWokspaceRunnable with AVOID_UPATE to avoid unwanted builds // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=118507) IWorkspaceRunnable runnable = new IWorkspaceRunnable() { @Override public void run(IProgressMonitor monitor) throws CoreException { try { // Collect all containers Set<Entry<IJavaProject, Set<IPath>>> entrySet = allContainerPaths.entrySet(); int length = entrySet.size(); if (monitor != null) monitor.beginTask("", length); //$NON-NLS-1$ Set<Entry<IJavaProject, Set<IPath>>> entries = new HashSet<>(entrySet); // clone as the following will have a side effect for (Entry<IJavaProject, Set<IPath>> entry : entries) { IJavaProject javaProject = entry.getKey(); Set<IPath> pathSet = entry.getValue(); if (pathSet == null) continue; int length2 = pathSet.size(); IPath[] paths = new IPath[length2]; pathSet.toArray(paths); // clone as the following will have a side effect for (int j = 0; j < length2; j++) { IPath path = paths[j]; synchronized(JavaModelManager.this.batchContainerInitializationsLock) { if (containerIsSet(javaProject, path)) { // another thread has concurrently initialized the container. continue; } } initializeContainer(javaProject, path); IClasspathContainer container = containerBeingInitializedGet(javaProject, path); if (container != null) { synchronized(JavaModelManager.this.batchContainerInitializationsLock) { if (containerIsSet(javaProject, path)) { // another thread has concurrently initialized the container. containerBeingInitializedRemove(javaProject, path); containerRemoveInitializationInProgress(javaProject, path); } else { containerPut(javaProject, path, container); } } } } if (monitor != null) monitor.worked(1); } // Set all containers Map<IJavaProject, Map<IPath, IClasspathContainer>> perProjectContainers = JavaModelManager.this.containersBeingInitialized.get(); // Note that during the operation below new containers could be added to the map, // so we should loop until containersBeingInitialized will be empty while (perProjectContainers != null && !perProjectContainers.isEmpty()) { initKnownContainers(perProjectContainers, monitor); } JavaModelManager.this.containersBeingInitialized.set(null); } finally { if (monitor != null) monitor.done(); } } private void initKnownContainers(Map<IJavaProject, Map<IPath, IClasspathContainer>> perProjectContainers, IProgressMonitor monitor) throws JavaModelException { Iterator<Entry<IJavaProject, Map<IPath, IClasspathContainer>>> entriesIterator = perProjectContainers.entrySet().iterator(); List<SetContainerOperation> operations = new ArrayList<>(); while (entriesIterator.hasNext()) { Entry<IJavaProject, Map<IPath, IClasspathContainer>> entry = entriesIterator.next(); IJavaProject project = entry.getKey(); Map<IPath, IClasspathContainer> perPathContainers = entry.getValue(); Iterator<Entry<IPath, IClasspathContainer>> containersIterator = perPathContainers.entrySet().iterator(); while (containersIterator.hasNext()) { Entry<IPath, IClasspathContainer> containerEntry = containersIterator.next(); IPath containerPath = containerEntry.getKey(); IClasspathContainer container = containerEntry.getValue(); SetContainerOperation operation = new SetContainerOperation(containerPath, new IJavaProject[] {project}, new IClasspathContainer[] {container}); operations.add(operation); } } // operation.runOperation() below could put something into the map again // so we clear the map to make sure we only see new content there perProjectContainers.clear(); for (SetContainerOperation operation : operations) { operation.runOperation(monitor); } } }; IProgressMonitor monitor = this.batchContainerInitializationsProgress; IWorkspace workspace = ResourcesPlugin.getWorkspace(); if (workspace.isTreeLocked()) runnable.run(monitor); else workspace.run( runnable, null/*don't take any lock*/, IWorkspace.AVOID_UPDATE, monitor); ok = true; } catch (CoreException e) { // ignore Util.log(e, "Exception while initializing all containers"); //$NON-NLS-1$ } finally { if (!ok) { // if we're being traversed by an exception, ensure that that containers are // no longer marked as initialization in progress // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=66437) this.containerInitializationInProgress.set(null); } } return containerGet(javaProjectToInit, containerToInit); } private void verbose_batching_containers_initialization(IJavaProject javaProjectToInit, IPath containerToInit) { Util.verbose( "CPContainer INIT - batching containers initialization\n" + //$NON-NLS-1$ " project to init: " + (javaProjectToInit == null ? "null" : javaProjectToInit.getElementName()) + '\n' + //$NON-NLS-1$ //$NON-NLS-2$ " container path to init: " + containerToInit); //$NON-NLS-1$ } IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException { IProgressMonitor monitor = this.batchContainerInitializationsProgress; if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException(); IClasspathContainer container = null; final ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer(containerPath.segment(0)); if (initializer != null){ if (CP_RESOLVE_VERBOSE) verbose_triggering_container_initialization(project, containerPath, initializer); if (CP_RESOLVE_VERBOSE_ADVANCED) verbose_triggering_container_initialization_invocation_trace(); PerformanceStats stats = null; if(JavaModelManager.PERF_CONTAINER_INITIALIZER) { stats = PerformanceStats.getStats(JavaModelManager.CONTAINER_INITIALIZER_PERF, this); stats.startRun(containerPath + " of " + project.getPath()); //$NON-NLS-1$ } containerPut(project, containerPath, CONTAINER_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles boolean ok = false; try { if (monitor != null) monitor.subTask(Messages.bind(Messages.javamodel_configuring, initializer.getDescription(containerPath, project))); // let OperationCanceledException go through // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59363) initializer.initialize(containerPath, project); if (monitor != null) monitor.subTask(""); //$NON-NLS-1$ // retrieve value (if initialization was successful) container = containerBeingInitializedGet(project, containerPath); if (container == null && containerGet(project, containerPath) == CONTAINER_INITIALIZATION_IN_PROGRESS) { // initializer failed to do its job: redirect to the failure container container = initializer.getFailureContainer(containerPath, project); if (container == null) { if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_container_null_failure_container(project, containerPath, initializer); return null; // break cycle } if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_container_using_failure_container(project, containerPath, initializer); containerPut(project, containerPath, container); } ok = true; } catch (CoreException e) { if (e instanceof JavaModelException) { throw (JavaModelException) e; } else { throw new JavaModelException(e); } } catch (RuntimeException | Error e) { if (JavaModelManager.CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) e.printStackTrace(); throw e; } finally { if(JavaModelManager.PERF_CONTAINER_INITIALIZER) { stats.endRun(); } if (!ok) { // just remove initialization in progress and keep previous session container so as to avoid a full build // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92588 containerRemoveInitializationInProgress(project, containerPath); if (CP_RESOLVE_VERBOSE || CP_RESOLVE_VERBOSE_FAILURE) verbose_container_initialization_failed(project, containerPath, container, initializer); } } if (CP_RESOLVE_VERBOSE_ADVANCED) verbose_container_value_after_initialization(project, containerPath, container); } else { // create a dummy initializer and get the default failure container container = (new ClasspathContainerInitializer() { @Override public void initialize(IPath path, IJavaProject javaProject) throws CoreException { // not used } }).getFailureContainer(containerPath, project); if (CP_RESOLVE_VERBOSE_ADVANCED || CP_RESOLVE_VERBOSE_FAILURE) verbose_no_container_initializer_found(project, containerPath); } return container; } private void verbose_no_container_initializer_found(IJavaProject project, IPath containerPath) { Util.verbose( "CPContainer INIT - no initializer found\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath); //$NON-NLS-1$ } private void verbose_container_value_after_initialization(IJavaProject project, IPath containerPath, IClasspathContainer container) { StringBuffer buffer = new StringBuffer(); buffer.append("CPContainer INIT - after resolution\n"); //$NON-NLS-1$ buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$ buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$ if (container != null){ buffer.append(" container: "+container.getDescription()+" {\n"); //$NON-NLS-2$//$NON-NLS-1$ IClasspathEntry[] entries = container.getClasspathEntries(); if (entries != null){ for (int i = 0; i < entries.length; i++) { buffer.append(" " + entries[i] + '\n'); //$NON-NLS-1$ } } buffer.append(" }");//$NON-NLS-1$ } else { buffer.append(" container: {unbound}");//$NON-NLS-1$ } Util.verbose(buffer.toString()); } private void verbose_container_initialization_failed(IJavaProject project, IPath containerPath, IClasspathContainer container, ClasspathContainerInitializer initializer) { if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) { Util.verbose( "CPContainer INIT - FAILED (initializer did not initialize container)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " initializer: " + initializer); //$NON-NLS-1$ } else { Util.verbose( "CPContainer INIT - FAILED (see exception above)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " initializer: " + initializer); //$NON-NLS-1$ } } private void verbose_container_null_failure_container(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) { Util.verbose( "CPContainer INIT - FAILED (and failure container is null)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " initializer: " + initializer); //$NON-NLS-1$ } private void verbose_container_using_failure_container(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) { Util.verbose( "CPContainer INIT - FAILED (using failure container)\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " initializer: " + initializer); //$NON-NLS-1$ } private void verbose_triggering_container_initialization(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) { Util.verbose( "CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$ " project: " + project.getElementName() + '\n' + //$NON-NLS-1$ " container path: " + containerPath + '\n' + //$NON-NLS-1$ " initializer: " + initializer); //$NON-NLS-1$ } private void verbose_triggering_container_initialization_invocation_trace() { Util.verbose( "CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$ " invocation trace:"); //$NON-NLS-1$ new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$ }
Initialize preferences lookups for JavaCore plug-in.
/** * Initialize preferences lookups for JavaCore plug-in. */
public void initializePreferences() { // Create lookups this.preferencesLookup[PREF_INSTANCE] = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); this.preferencesLookup[PREF_DEFAULT] = DefaultScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); // Listen to instance preferences node removal from parent in order to refresh stored one this.instanceNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == JavaModelManager.this.preferencesLookup[PREF_INSTANCE]) { JavaModelManager.this.preferencesLookup[PREF_INSTANCE] = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); JavaModelManager.this.preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener()); } } }; ((IEclipsePreferences) this.preferencesLookup[PREF_INSTANCE].parent()).addNodeChangeListener(this.instanceNodeListener); this.preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(this.instancePreferencesListener = new EclipsePreferencesListener()); // Listen to default preferences node removal from parent in order to refresh stored one this.defaultNodeListener = new IEclipsePreferences.INodeChangeListener() { @Override public void added(IEclipsePreferences.NodeChangeEvent event) { // do nothing } @Override public void removed(IEclipsePreferences.NodeChangeEvent event) { if (event.getChild() == JavaModelManager.this.preferencesLookup[PREF_DEFAULT]) { JavaModelManager.this.preferencesLookup[PREF_DEFAULT] = DefaultScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); } } }; ((IEclipsePreferences) this.preferencesLookup[PREF_DEFAULT].parent()).addNodeChangeListener(this.defaultNodeListener); } public synchronized char[] intern(char[] array) { return this.charArraySymbols.add(array); } public synchronized String intern(String s) { return (String) this.stringSymbols.add(s); // Note1: String#intern() cannot be used as on some VMs this prevents the string from being garbage collected // Note 2: Instead of using a WeakHashset, one could use a WeakHashMap with the following implementation // This would costs more per entry (one Entry object and one WeakReference more)) /* WeakReference reference = (WeakReference) this.symbols.get(s); String existing; if (reference != null && (existing = (String) reference.get()) != null) return existing; this.symbols.put(s, new WeakReference(s)); return s; */ } void touchProjects(final IProject[] projectsToTouch, IProgressMonitor progressMonitor) throws JavaModelException { WorkspaceJob touchJob = new WorkspaceJob(Messages.synchronizing_projects_job) { @Override public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { SubMonitor subMonitor = SubMonitor.convert(monitor, projectsToTouch.length); for (IProject iProject : projectsToTouch) { if (JavaBuilder.DEBUG) { System.out.println("Touching project " + iProject.getName()); //$NON-NLS-1$ } if (iProject.isAccessible()) { iProject.touch(subMonitor.split(1)); } } return Status.OK_STATUS; } @Override public boolean belongsTo(Object family) { return ResourcesPlugin.FAMILY_MANUAL_REFRESH == family; } }; touchJob.schedule(); } private Set<IJavaProject> getClasspathBeingResolved() { Set<IJavaProject> result = this.classpathsBeingResolved.get(); if (result == null) { result = new HashSet<>(); this.classpathsBeingResolved.set(result); } return result; } public boolean isClasspathBeingResolved(IJavaProject project) { return getClasspathBeingResolved().contains(project); }
Deprecated:
/** * @deprecated */
private boolean isDeprecatedOption(String optionName) { return JavaCore.COMPILER_PB_INVALID_IMPORT.equals(optionName) || JavaCore.COMPILER_PB_UNREACHABLE_CODE.equals(optionName); } public boolean isNonChainingJar(IPath path) { return this.nonChainingJars != null && this.nonChainingJars.contains(path); } public ArchiveValidity getArchiveValidity(IPath path) { InvalidArchiveInfo invalidArchiveInfo; synchronized (this.invalidArchivesMutex) { invalidArchiveInfo = this.invalidArchives.get(path); } if (invalidArchiveInfo == null) return ArchiveValidity.VALID; long now = System.currentTimeMillis(); // If the TTL for this cache entry has expired, directly check whether the archive is still invalid. // If it transitioned to being valid, remove it from the cache and force an update to project caches. if (now > invalidArchiveInfo.evictionTimestamp) { try { getZipFile(path, false); removeFromInvalidArchiveCache(path); } catch (CoreException e) { // Archive is still invalid, fall through to reporting it is invalid. } // Retry the test from the start, now that we have an up-to-date result return getArchiveValidity(path); } return invalidArchiveInfo.reason; } public void removeFromInvalidArchiveCache(IPath path) { synchronized(this.invalidArchivesMutex) { if (this.invalidArchives.remove(path) != null) { if (DEBUG_INVALID_ARCHIVES) { System.out.println("Invalid JAR cache: removed " + path); //$NON-NLS-1$ } try { // Bug 455042: Force an update of the JavaProjectElementInfo project caches. for (IJavaProject project : getJavaModel().getJavaProjects()) { if (project.findPackageFragmentRoot(path) != null) { ((JavaProject) project).resetCaches(); } } } catch (JavaModelException e) { Util.log(e, "Unable to retrieve the Java model."); //$NON-NLS-1$ } } } }
Returns the cached value for whether the file referred to by path exists and is a file, as determined by the return value of File.isFile().
/** * Returns the cached value for whether the file referred to by <code>path</code> exists * and is a file, as determined by the return value of {@link File#isFile()}. */
public boolean isExternalFile(IPath path) { return this.externalFiles != null && this.externalFiles.contains(path); }
Removes the cached state of a single entry in the externalFiles cache.
/** * Removes the cached state of a single entry in the externalFiles cache. */
public void clearExternalFileState(IPath path) { if (this.externalFiles != null) { this.externalFiles.remove(path); } }
Resets the entire externalFiles cache.
/** * Resets the entire externalFiles cache. */
public void resetExternalFilesCache() { if (this.externalFiles != null) { this.externalFiles.clear(); } }
Returns whether the provided IPath appears to be an external file, which is true if the path does not represent an internal resource, does not exist on the file system, and does have a file extension (this is the definition provided by ExternalFoldersManager.isExternalFolderPath).
/** * Returns whether the provided {@link IPath} appears to be an external file, * which is true if the path does not represent an internal resource, does not * exist on the file system, and does have a file extension (this is the definition * provided by {@link ExternalFoldersManager#isExternalFolderPath}). */
public boolean isAssumedExternalFile(IPath path) { if (this.assumedExternalFiles == null) { return false; } return this.assumedExternalFiles.contains(path); }
Adds the provided IPath to the list of assumed external files.
/** * Adds the provided {@link IPath} to the list of assumed external files. */
public void addAssumedExternalFile(IPath path) { this.assumedExternalFiles.add(path); } public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) { if (classpathIsResolved) { getClasspathBeingResolved().add(project); } else { getClasspathBeingResolved().remove(project); } } private Set<IPath> loadClasspathListCache(String cacheName) { Set<IPath> pathCache = new HashSet<>(); File cacheFile = getClasspathListFile(cacheName); DataInputStream in = null; try { in = new DataInputStream(new BufferedInputStream(new FileInputStream(cacheFile))); int size = in.readInt(); while (size-- > 0) { String path = in.readUTF(); pathCache.add(Path.fromPortableString(path)); } } catch (IOException e) { if (cacheFile.exists()) Util.log(e, "Unable to read JavaModelManager " + cacheName + " file"); //$NON-NLS-1$ //$NON-NLS-2$ } finally { if (in != null) { try { in.close(); } catch (IOException e) { // nothing we can do: ignore } } } return Collections.synchronizedSet(pathCache); } private File getClasspathListFile(String fileName) { return JavaCore.getPlugin().getStateLocation().append(fileName).toFile(); } private Set<IPath> getNonChainingJarsCache() throws CoreException { // Even if there is one entry in the cache, just return it. It may not be // the complete cache, but avoid going through all the projects to populate the cache. if (this.nonChainingJars != null && this.nonChainingJars.size() > 0) { return this.nonChainingJars; } Set<IPath> result = new HashSet<>(); IJavaProject[] projects = getJavaModel().getJavaProjects(); for (int i = 0, length = projects.length; i < length; i++) { IJavaProject javaProject = projects[i]; IClasspathEntry[] classpath = ((JavaProject) javaProject).getResolvedClasspath(); for (int j = 0, length2 = classpath.length; j < length2; j++) { IClasspathEntry entry = classpath[j]; IPath path; if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY && !result.contains(path = entry.getPath()) && ClasspathEntry.resolvedChainedLibraries(path).length == 0) { result.add(path); } } } this.nonChainingJars = Collections.synchronizedSet(result); return this.nonChainingJars; } private Set<IPath> getClasspathListCache(String cacheName) throws CoreException { if (cacheName == NON_CHAINING_JARS_CACHE) return getNonChainingJarsCache(); else if (cacheName == EXTERNAL_FILES_CACHE) return this.externalFiles; else if (cacheName == ASSUMED_EXTERNAL_FILES_CACHE) return this.assumedExternalFiles; else return null; } public void loadVariablesAndContainers() throws CoreException { // backward compatibility, consider persistent property QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "variables"); //$NON-NLS-1$ String xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName); try { if (xmlString != null){ StringReader reader = new StringReader(xmlString); Element cpElement; try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); cpElement = parser.parse(new InputSource(reader)).getDocumentElement(); } catch(SAXException | ParserConfigurationException e){ return; } finally { reader.close(); } if (cpElement == null) return; if (!cpElement.getNodeName().equalsIgnoreCase("variables")) { //$NON-NLS-1$ return; } NodeList list= cpElement.getChildNodes(); int length= list.getLength(); for (int i= 0; i < length; ++i) { Node node= list.item(i); short type= node.getNodeType(); if (type == Node.ELEMENT_NODE) { Element element= (Element) node; if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$ variablePut( element.getAttribute("name"), //$NON-NLS-1$ new Path(element.getAttribute("path"))); //$NON-NLS-1$ } } } } } catch(IOException e){ // problem loading xml file: nothing we can do } finally { if (xmlString != null){ ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, null); // flush old one } } // backward compatibility, load variables and containers from preferences into cache loadVariablesAndContainers(getDefaultPreferences()); loadVariablesAndContainers(getInstancePreferences()); // load variables and containers from saved file into cache File file = getVariableAndContainersFile(); DataInputStream in = null; try { in = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); switch (in.readInt()) { case 2 : new VariablesAndContainersLoadHelper(in).load(); break; case 1 : // backward compatibility, load old format // variables int size = in.readInt(); while (size-- > 0) { String varName = in.readUTF(); String pathString = in.readUTF(); if (CP_ENTRY_IGNORE.equals(pathString)) continue; IPath varPath = Path.fromPortableString(pathString); this.variables.put(varName, varPath); this.previousSessionVariables.put(varName, varPath); } // containers IJavaModel model = getJavaModel(); int projectSize = in.readInt(); while (projectSize-- > 0) { String projectName = in.readUTF(); IJavaProject project = model.getJavaProject(projectName); int containerSize = in.readInt(); while (containerSize-- > 0) { IPath containerPath = Path.fromPortableString(in.readUTF()); int length = in.readInt(); byte[] containerString = new byte[length]; in.readFully(containerString); recreatePersistedContainer(project, containerPath, new String(containerString), true/*add to container values*/); } } break; } } catch (IOException e) { if (file.exists()) Util.log(e, "Unable to read variable and containers file"); //$NON-NLS-1$ } catch (RuntimeException e) { if (file.exists()) Util.log(e, "Unable to read variable and containers file (file is corrupt)"); //$NON-NLS-1$ } finally { if (in != null) { try { in.close(); } catch (IOException e) { // nothing we can do: ignore } } } // override persisted values for variables which have a registered initializer String[] registeredVariables = getRegisteredVariableNames(); for (int i = 0; i < registeredVariables.length; i++) { String varName = registeredVariables[i]; this.variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names. } // override persisted values for containers which have a registered initializer containersReset(getRegisteredContainerIDs()); } private void loadVariablesAndContainers(IEclipsePreferences preferences) { try { // only get variable from preferences not set to their default String[] propertyNames = preferences.keys(); int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length(); for (int i = 0; i < propertyNames.length; i++){ String propertyName = propertyNames[i]; if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){ String varName = propertyName.substring(variablePrefixLength); String propertyValue = preferences.get(propertyName, null); if (propertyValue != null) { String pathString = propertyValue.trim(); if (CP_ENTRY_IGNORE.equals(pathString)) { // cleanup old preferences preferences.remove(propertyName); continue; } // add variable to table IPath varPath = new Path(pathString); this.variables.put(varName, varPath); this.previousSessionVariables.put(varName, varPath); } } else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){ String propertyValue = preferences.get(propertyName, null); if (propertyValue != null) { // cleanup old preferences preferences.remove(propertyName); // recreate container recreatePersistedContainer(propertyName, propertyValue, true/*add to container values*/); } } } } catch (BackingStoreException e1) { // TODO (frederic) see if it's necessary to report this failure... } } private static final class PersistedClasspathContainer implements IClasspathContainer { private final IPath containerPath; private final IClasspathEntry[] entries; private final IJavaProject project; PersistedClasspathContainer(IJavaProject project, IPath containerPath, IClasspathEntry[] entries) { super(); this.containerPath = containerPath; this.entries = entries; this.project = project; } @Override public IClasspathEntry[] getClasspathEntries() { return this.entries; } @Override public String getDescription() { return "Persisted container [" + this.containerPath //$NON-NLS-1$ + " for project [" + this.project.getElementName() //$NON-NLS-1$ + "]]"; //$NON-NLS-1$ } @Override public int getKind() { return 0; } @Override public IPath getPath() { return this.containerPath; } @Override public String toString() { return getDescription(); } } private final class VariablesAndContainersLoadHelper { private static final int ARRAY_INCREMENT = 200; private IClasspathEntry[] allClasspathEntries; private int allClasspathEntryCount; private final Map<String, IPath> allPaths; private String[] allStrings; private int allStringsCount; private final DataInputStream in; VariablesAndContainersLoadHelper(DataInputStream in) { super(); this.allClasspathEntries = null; this.allClasspathEntryCount = 0; this.allPaths = new HashMap<>(); this.allStrings = null; this.allStringsCount = 0; this.in = in; } void load() throws IOException { loadProjects(getJavaModel()); loadVariables(); } private IAccessRule loadAccessRule() throws IOException { int problemId = loadInt(); IPath pattern = loadPath(); return getAccessRuleForProblemId(pattern.toString().toCharArray(), problemId); } private IAccessRule[] loadAccessRules() throws IOException { int count = loadInt(); if (count == 0) return ClasspathEntry.NO_ACCESS_RULES; IAccessRule[] rules = new IAccessRule[count]; for (int i = 0; i < count; ++i) rules[i] = loadAccessRule(); return rules; } private IClasspathAttribute loadAttribute() throws IOException { String name = loadString(); String value = loadString(); return new ClasspathAttribute(name, value); } private IClasspathAttribute[] loadAttributes() throws IOException { int count = loadInt(); if (count == 0) return ClasspathEntry.NO_EXTRA_ATTRIBUTES; IClasspathAttribute[] attributes = new IClasspathAttribute[count]; for (int i = 0; i < count; ++i) attributes[i] = loadAttribute(); return attributes; } private boolean loadBoolean() throws IOException { return this.in.readBoolean(); } private IClasspathEntry[] loadClasspathEntries() throws IOException { int count = loadInt(); IClasspathEntry[] entries = new IClasspathEntry[count]; for (int i = 0; i < count; ++i) entries[i] = loadClasspathEntry(); return entries; } private IClasspathEntry loadClasspathEntry() throws IOException { int id = loadInt(); if (id < 0 || id > this.allClasspathEntryCount) throw new IOException("Unexpected classpathentry id"); //$NON-NLS-1$ if (id < this.allClasspathEntryCount) return this.allClasspathEntries[id]; int contentKind = loadInt(); int entryKind = loadInt(); IPath path = loadPath(); IPath[] inclusionPatterns = loadPaths(); IPath[] exclusionPatterns = loadPaths(); IPath sourceAttachmentPath = loadPath(); IPath sourceAttachmentRootPath = loadPath(); IPath specificOutputLocation = loadPath(); boolean isExported = loadBoolean(); IAccessRule[] accessRules = loadAccessRules(); boolean combineAccessRules = loadBoolean(); IClasspathAttribute[] extraAttributes = loadAttributes(); IClasspathEntry entry = new ClasspathEntry(contentKind, entryKind, path, inclusionPatterns, exclusionPatterns, sourceAttachmentPath, sourceAttachmentRootPath, specificOutputLocation, isExported, accessRules, combineAccessRules, extraAttributes); IClasspathEntry[] array = this.allClasspathEntries; if (array == null || id == array.length) { array = new IClasspathEntry[id + ARRAY_INCREMENT]; if (id != 0) System.arraycopy(this.allClasspathEntries, 0, array, 0, id); this.allClasspathEntries = array; } array[id] = entry; this.allClasspathEntryCount = id + 1; return entry; } private void loadContainers(IJavaProject project) throws IOException { boolean projectIsAccessible = project.getProject().isAccessible(); int count = loadInt(); for (int i = 0; i < count; ++i) { IPath path = loadPath(); IClasspathEntry[] entries = loadClasspathEntries(); if (!projectIsAccessible) // avoid leaking deleted project's persisted container, // but still read the container as it is is part of the file format continue; IClasspathContainer container = new PersistedClasspathContainer(project, path, entries); containerPut(project, path, container); Map<IPath, IClasspathContainer> oldContainers = JavaModelManager.this.previousSessionContainers.get(project); if (oldContainers == null) { oldContainers = new HashMap<>(); JavaModelManager.this.previousSessionContainers.put(project, oldContainers); } oldContainers.put(path, container); } } private int loadInt() throws IOException { return this.in.readInt(); } private IPath loadPath() throws IOException { if (loadBoolean()) return null; String portableString = loadString(); IPath path = this.allPaths.get(portableString); if (path == null) { path = Path.fromPortableString(portableString); this.allPaths.put(portableString, path); } return path; } private IPath[] loadPaths() throws IOException { int count = loadInt(); IPath[] pathArray = new IPath[count]; for (int i = 0; i < count; ++i) pathArray[i] = loadPath(); return pathArray; } private void loadProjects(IJavaModel model) throws IOException { int count = loadInt(); for (int i = 0; i < count; ++i) { String projectName = loadString(); loadContainers(model.getJavaProject(projectName)); } } private String loadString() throws IOException { int id = loadInt(); if (id < 0 || id > this.allStringsCount) throw new IOException("Unexpected string id"); //$NON-NLS-1$ if (id < this.allStringsCount) return this.allStrings[id]; String string = this.in.readUTF(); String[] array = this.allStrings; if (array == null || id == array.length) { array = new String[id + ARRAY_INCREMENT]; if (id != 0) System.arraycopy(this.allStrings, 0, array, 0, id); this.allStrings = array; } array[id] = string; this.allStringsCount = id + 1; return string; } private void loadVariables() throws IOException { int size = loadInt(); Map<String, IPath> loadedVars = new HashMap<>(size); for (int i = 0; i < size; ++i) { String varName = loadString(); IPath varPath = loadPath(); if (varPath != null) loadedVars.put(varName, varPath); } JavaModelManager.this.previousSessionVariables.putAll(loadedVars); JavaModelManager.this.variables.putAll(loadedVars); } }
Returns the info for this element without disturbing the cache ordering.
/** * Returns the info for this element without * disturbing the cache ordering. */
protected synchronized Object peekAtInfo(IJavaElement element) { HashMap<IJavaElement, Object> tempCache = this.temporaryCache.get(); if (tempCache != null) { Object result = tempCache.get(element); if (result != null) { return result; } } return this.cache.peekAtInfo(element); }
See Also:
  • ISaveParticipant
/** * @see ISaveParticipant */
@Override public void prepareToSave(ISaveContext context) /*throws CoreException*/ { // nothing to do } /* * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos) * in the Java model cache in an atomic way if the info is not already present in the cache. * If the info is already present in the cache, it depends upon the forceAdd parameter. * If forceAdd is false it just returns the existing info and if true, this element and it's children are closed and then * this particular info is added to the cache. */ protected synchronized Object putInfos(IJavaElement openedElement, Object newInfo, boolean forceAdd, Map<IJavaElement, Object> newElements) { // remove existing children as the are replaced with the new children contained in newElements Object existingInfo = this.cache.peekAtInfo(openedElement); if (existingInfo != null && !forceAdd) { // If forceAdd is false, then it could mean that the particular element // wasn't in cache at that point of time, but would have got added through // another thread. In that case, removing the children could remove it's own // children. So, we should not remove the children but return the already existing // info. // https://bugs.eclipse.org/bugs/show_bug.cgi?id=372687 return existingInfo; } if (openedElement instanceof IParent) { closeChildren(existingInfo); } // Need to put any JarPackageFragmentRoot in first. // This is due to the way the LRU cache flushes entries. // When a JarPackageFragment is flushed from the LRU cache, the entire // jar is flushed by removing the JarPackageFragmentRoot and all of its // children (see ElementCache.close()). If we flush the JarPackageFragment // when its JarPackageFragmentRoot is not in the cache and the root is about to be // added (during the 'while' loop), we will end up in an inconsistent state. // Subsequent resolution against package in the jar would fail as a result. // https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422 // (theodora) for(Iterator<Entry<IJavaElement, Object>> it = newElements.entrySet().iterator(); it.hasNext(); ) { Entry<IJavaElement, Object> entry = it.next(); IJavaElement element = entry.getKey(); if (element instanceof JarPackageFragmentRoot) { JavaElementInfo info = (JavaElementInfo) entry.getValue(); it.remove(); this.cache.putInfo(element, info); } } Iterator<Entry<IJavaElement, Object>> iterator = newElements.entrySet().iterator(); while (iterator.hasNext()) { Entry<IJavaElement, Object> entry = iterator.next(); this.cache.putInfo(entry.getKey(), entry.getValue()); } return newInfo; } private void closeChildren(Object info) { if (info instanceof JavaElementInfo) { IJavaElement[] children = ((JavaElementInfo)info).getChildren(); for (int i = 0, size = children.length; i < size; ++i) { JavaElement child = (JavaElement) children[i]; try { child.close(); } catch (JavaModelException e) { // ignore } } } }
Remember the info for the jar binary type
Params:
/** * Remember the info for the jar binary type * @param info instanceof IBinaryType or {@link JavaModelCache#NON_EXISTING_JAR_TYPE_INFO} */
protected synchronized void putJarTypeInfo(IJavaElement type, Object info) { this.cache.jarTypeCache.put(type, info); }
Reads the build state for the relevant project.
/** * Reads the build state for the relevant project. */
protected Object readState(IProject project) throws CoreException { File file = getSerializationFile(project); if (file != null && file.exists()) { try { DataInputStream in= new DataInputStream(new BufferedInputStream(new FileInputStream(file))); try { String pluginID= in.readUTF(); if (!pluginID.equals(JavaCore.PLUGIN_ID)) throw new IOException(Messages.build_wrongFileFormat); String kind= in.readUTF(); if (!kind.equals("STATE")) //$NON-NLS-1$ throw new IOException(Messages.build_wrongFileFormat); if (in.readBoolean()) return JavaBuilder.readState(project, in); if (JavaBuilder.DEBUG) System.out.println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$ } finally { in.close(); } } catch (Exception e) { e.printStackTrace(); throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error reading last build state for project "+ project.getName(), e)); //$NON-NLS-1$ } } else if (JavaBuilder.DEBUG) { if (file == null) System.out.println("Project does not exist: " + project); //$NON-NLS-1$ else System.out.println("Build state file " + file.getPath() + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$ } return null; } public static void recreatePersistedContainer(String propertyName, String containerString, boolean addToContainerValues) { int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length(); int index = propertyName.indexOf('|', containerPrefixLength); if (containerString != null) containerString = containerString.trim(); if (index > 0) { String projectName = propertyName.substring(containerPrefixLength, index).trim(); IJavaProject project = getJavaModelManager().getJavaModel().getJavaProject(projectName); IPath containerPath = new Path(propertyName.substring(index+1).trim()); recreatePersistedContainer(project, containerPath, containerString, addToContainerValues); } } private static void recreatePersistedContainer(final IJavaProject project, final IPath containerPath, String containerString, boolean addToContainerValues) { if (!project.getProject().isAccessible()) return; // avoid leaking deleted project's persisted container if (containerString == null) { getJavaModelManager().containerPut(project, containerPath, null); } else { IClasspathEntry[] entries; try { entries = ((JavaProject) project).decodeClasspath(containerString, null/*not interested in unknown elements*/)[0]; } catch (IOException e) { Util.log(e, "Could not recreate persisted container: \n" + containerString); //$NON-NLS-1$ entries = JavaProject.INVALID_CLASSPATH; } if (entries != JavaProject.INVALID_CLASSPATH) { final IClasspathEntry[] containerEntries = entries; IClasspathContainer container = new IClasspathContainer() { @Override public IClasspathEntry[] getClasspathEntries() { return containerEntries; } @Override public String getDescription() { return "Persisted container ["+containerPath+" for project ["+ project.getElementName()+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ } @Override public int getKind() { return 0; } @Override public IPath getPath() { return containerPath; } @Override public String toString() { return getDescription(); } }; if (addToContainerValues) { getJavaModelManager().containerPut(project, containerPath, container); } Map<IPath, IClasspathContainer> projectContainers = getJavaModelManager().previousSessionContainers.get(project); if (projectContainers == null){ projectContainers = new HashMap<>(1); getJavaModelManager().previousSessionContainers.put(project, projectContainers); } projectContainers.put(containerPath, container); } } }
Remembers the given scope in a weak set (so no need to remove it: it will be removed by the garbage collector)
/** * Remembers the given scope in a weak set * (so no need to remove it: it will be removed by the garbage collector) */
public void rememberScope(AbstractSearchScope scope) { // NB: The value has to be null so as to not create a strong reference on the scope this.searchScopes.put(scope, null); } /* * Removes all cached info for the given element (including all children) * from the cache. * Returns the info for the given element, or null if it was closed. */ public synchronized Object removeInfoAndChildren(JavaElement element) throws JavaModelException { Object info = this.cache.peekAtInfo(element); if (info != null) { boolean wasVerbose = false; try { if (JavaModelCache.VERBOSE) { String elementType = JavaModelCache.getElementType(element); System.out.println(Thread.currentThread() + " CLOSING "+ elementType + " " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$ wasVerbose = true; JavaModelCache.VERBOSE = false; } element.closing(info); if (element instanceof IParent) { closeChildren(info); } this.cache.removeInfo(element); if (wasVerbose) { System.out.println(this.cache.toStringFillingRation("-> ")); //$NON-NLS-1$ } } finally { JavaModelCache.VERBOSE = wasVerbose; } return info; } return null; } void removeFromJarTypeCache(BinaryType type) { this.cache.removeFromJarTypeCache(type); } public void removePerProjectInfo(JavaProject javaProject, boolean removeExtJarInfo) { synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock IProject project = javaProject.getProject(); PerProjectInfo info= this.perProjectInfos.get(project); if (info != null) { this.perProjectInfos.remove(project); if (removeExtJarInfo) { info.forgetExternalTimestampsAndIndexes(); } } } resetClasspathListCache(); } /* * Reset project options stored in info cache. */ public void resetProjectOptions(JavaProject javaProject) { synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock IProject project = javaProject.getProject(); PerProjectInfo info= this.perProjectInfos.get(project); if (info != null) { info.options = null; } } } /* * Reset project preferences stored in info cache. */ public void resetProjectPreferences(JavaProject javaProject) { synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock IProject project = javaProject.getProject(); PerProjectInfo info= this.perProjectInfos.get(project); if (info != null) { info.preferences = null; } } } public static final void doNotUse() { // used by tests to simulate a startup MANAGER.deltaState.doNotUse(); MANAGER = new JavaModelManager(); } /* * Resets the cache that holds on binary type in jar files */ protected synchronized void resetJarTypeCache() { this.cache.resetJarTypeCache(); } public void resetClasspathListCache() { if (this.nonChainingJars != null) this.nonChainingJars.clear(); if (DEBUG_INVALID_ARCHIVES) { synchronized(this.invalidArchivesMutex) { if (!this.invalidArchives.isEmpty()) { System.out.println("Invalid JAR cache: clearing cache"); //$NON-NLS-1$ } } } synchronized(this.invalidArchivesMutex) { this.invalidArchives.clear(); } if (this.externalFiles != null) this.externalFiles.clear(); if (this.assumedExternalFiles != null) this.assumedExternalFiles.clear(); } /* * Resets the temporary cache for newly created elements to null. */ public void resetTemporaryCache() { this.temporaryCache.set(null); }
See Also:
  • ISaveParticipant
/** * @see ISaveParticipant */
@Override public void rollback(ISaveContext context){ // nothing to do } private void saveState(PerProjectInfo info, ISaveContext context) throws CoreException { // passed this point, save actions are non trivial if (context.getKind() == ISaveContext.SNAPSHOT) return; // save built state if (info.triedRead) saveBuiltState(info); }
Saves the built state for the project.
/** * Saves the built state for the project. */
private void saveBuiltState(PerProjectInfo info) throws CoreException { if (JavaBuilder.DEBUG) System.out.println(Messages.bind(Messages.build_saveStateProgress, info.project.getName())); File file = getSerializationFile(info.project); if (file == null) return; long t = System.currentTimeMillis(); try { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); try { out.writeUTF(JavaCore.PLUGIN_ID); out.writeUTF("STATE"); //$NON-NLS-1$ if (info.savedState == null) { out.writeBoolean(false); } else { out.writeBoolean(true); JavaBuilder.writeState(info.savedState, out); } } finally { out.close(); } } catch (RuntimeException | IOException e) { try { file.delete(); } catch(SecurityException se) { // could not delete file: cannot do much more } throw new CoreException( new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, Messages.bind(Messages.build_cannotSaveState, info.project.getName()), e)); } if (JavaBuilder.DEBUG) { t = System.currentTimeMillis() - t; System.out.println(Messages.bind(Messages.build_saveStateComplete, String.valueOf(t))); } } private void saveClasspathListCache(String cacheName) throws CoreException { File file = getClasspathListFile(cacheName); DataOutputStream out = null; try { out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); Set<IPath> pathCache = getClasspathListCache(cacheName); synchronized (pathCache) { out.writeInt(pathCache.size()); Iterator<IPath> entries = pathCache.iterator(); while (entries.hasNext()) { IPath path = entries.next(); out.writeUTF(path.toPortableString()); } } } catch (IOException e) { IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving non-chaining jar cache", e); //$NON-NLS-1$ throw new CoreException(status); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // nothing we can do: ignore } } } } private void saveVariablesAndContainers(ISaveContext context) throws CoreException { File file = getVariableAndContainersFile(); DataOutputStream out = null; try { out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION); new VariablesAndContainersSaveHelper(out).save(context); } catch (IOException e) { IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving variables and containers", e); //$NON-NLS-1$ throw new CoreException(status); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // nothing we can do: ignore } } } } private final class VariablesAndContainersSaveHelper { private final HashtableOfObjectToInt classpathEntryIds; // IClasspathEntry -> int private final DataOutputStream out; private final HashtableOfObjectToInt stringIds; // Strings -> int VariablesAndContainersSaveHelper(DataOutputStream out) { super(); this.classpathEntryIds = new HashtableOfObjectToInt(); this.out = out; this.stringIds = new HashtableOfObjectToInt(); } void save(ISaveContext context) throws IOException, JavaModelException { saveProjects(getJavaModel().getJavaProjects()); // remove variables that should not be saved HashMap<String, IPath> varsToSave = null; Iterator<Entry<String, IPath>> iterator = JavaModelManager.this.variables.entrySet().iterator(); IEclipsePreferences defaultPreferences = getDefaultPreferences(); while (iterator.hasNext()) { Entry<String, IPath> entry = iterator.next(); String varName = entry.getKey(); if (defaultPreferences.get(CP_VARIABLE_PREFERENCES_PREFIX + varName, null) != null // don't save classpath variables from the default preferences as there is no delta if they are removed || CP_ENTRY_IGNORE_PATH.equals(entry.getValue())) { if (varsToSave == null) varsToSave = new HashMap<>(JavaModelManager.this.variables); varsToSave.remove(varName); } } saveVariables(varsToSave != null ? varsToSave : JavaModelManager.this.variables); } private void saveAccessRule(ClasspathAccessRule rule) throws IOException { saveInt(rule.problemId); savePath(rule.getPattern()); } private void saveAccessRules(IAccessRule[] rules) throws IOException { int count = rules == null ? 0 : rules.length; saveInt(count); for (int i = 0; i < count; ++i) saveAccessRule((ClasspathAccessRule) rules[i]); } private void saveAttribute(IClasspathAttribute attribute) throws IOException { saveString(attribute.getName()); saveString(attribute.getValue()); } private void saveAttributes(IClasspathAttribute[] attributes) throws IOException { int count = attributes == null ? 0 : attributes.length; saveInt(count); for (int i = 0; i < count; ++i) saveAttribute(attributes[i]); } private void saveClasspathEntries(IClasspathEntry[] entries) throws IOException { int count = entries == null ? 0 : entries.length; saveInt(count); for (int i = 0; i < count; ++i) saveClasspathEntry(entries[i]); } private void saveClasspathEntry(IClasspathEntry entry) throws IOException { if (saveNewId(entry, this.classpathEntryIds)) { saveInt(entry.getContentKind()); saveInt(entry.getEntryKind()); savePath(entry.getPath()); savePaths(entry.getInclusionPatterns()); savePaths(entry.getExclusionPatterns()); savePath(entry.getSourceAttachmentPath()); savePath(entry.getSourceAttachmentRootPath()); savePath(entry.getOutputLocation()); this.out.writeBoolean(entry.isExported()); saveAccessRules(entry.getAccessRules()); this.out.writeBoolean(entry.combineAccessRules()); saveAttributes(entry.getExtraAttributes()); } } private void saveContainers(IJavaProject project, Map<IPath, IClasspathContainer> containerMap) throws IOException { saveInt(containerMap.size()); for (Iterator<Entry<IPath, IClasspathContainer>> i = containerMap.entrySet().iterator(); i.hasNext();) { Entry<IPath, IClasspathContainer> entry = i.next(); IPath path = entry.getKey(); IClasspathContainer container = entry.getValue(); IClasspathEntry[] cpEntries = null; if (container == null) { // container has not been initialized yet, use previous // session value // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969) container = getPreviousSessionContainer(path, project); } if (container != null) cpEntries = container.getClasspathEntries(); savePath(path); saveClasspathEntries(cpEntries); } } private void saveInt(int value) throws IOException { this.out.writeInt(value); } private boolean saveNewId(Object key, HashtableOfObjectToInt map) throws IOException { int id = map.get(key); if (id == -1) { int newId = map.size(); map.put(key, newId); saveInt(newId); return true; } else { saveInt(id); return false; } } private void savePath(IPath path) throws IOException { if (path == null) { this.out.writeBoolean(true); } else { this.out.writeBoolean(false); saveString(path.toPortableString()); } } private void savePaths(IPath[] paths) throws IOException { int count = paths == null ? 0 : paths.length; saveInt(count); for (int i = 0; i < count; ++i) savePath(paths[i]); } private void saveProjects(IJavaProject[] projects) throws IOException, JavaModelException { int count = projects.length; saveInt(count); for (int i = 0; i < count; ++i) { IJavaProject project = projects[i]; saveString(project.getElementName()); Map<IPath, IClasspathContainer> containerMap = JavaModelManager.this.containers.get(project); if (containerMap == null) { containerMap = Collections.EMPTY_MAP; } else { // clone while iterating // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638) containerMap = new HashMap<>(containerMap); } saveContainers(project, containerMap); } } private void saveString(String string) throws IOException { if (saveNewId(string, this.stringIds)) this.out.writeUTF(string); } private void saveVariables(Map<String, IPath> map) throws IOException { saveInt(map.size()); for (Iterator<Entry<String, IPath>> i = map.entrySet().iterator(); i.hasNext();) { Entry<String, IPath> entry = i.next(); String varName = entry.getKey(); IPath varPath = entry.getValue(); saveString(varName); savePath(varPath); } } } private void traceVariableAndContainers(String action, long start) { Long delta = Long.valueOf(System.currentTimeMillis() - start); Long length = Long.valueOf(getVariableAndContainersFile().length()); String pattern = "{0} {1} bytes in variablesAndContainers.dat in {2}ms"; //$NON-NLS-1$ String message = MessageFormat.format(pattern, new Object[]{action, length, delta}); System.out.println(message); }
See Also:
  • ISaveParticipant
/** * @see ISaveParticipant */
@Override public void saving(ISaveContext context) throws CoreException { long start = -1; if (VERBOSE) start = System.currentTimeMillis(); // save variable and container values on snapshot/full save saveVariablesAndContainers(context); if (VERBOSE) traceVariableAndContainers("Saved", start); //$NON-NLS-1$ switch(context.getKind()) { case ISaveContext.FULL_SAVE : { // save non-chaining jar, invalid jar and external file caches on full save saveClasspathListCache(NON_CHAINING_JARS_CACHE); saveClasspathListCache(EXTERNAL_FILES_CACHE); saveClasspathListCache(ASSUMED_EXTERNAL_FILES_CACHE); // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658) context.needDelta(); // clean up indexes on workspace full save // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347) IndexManager manager = this.indexManager; if (manager != null // don't force initialization of workspace scope as we could be shutting down // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93941) && this.workspaceScope != null) { manager.cleanUpIndexes(); } } //$FALL-THROUGH$ case ISaveContext.SNAPSHOT : { // clean up external folders on full save or snapshot this.externalFoldersManager.cleanUp(null); } } IProject savedProject = context.getProject(); if (savedProject != null) { if (!JavaProject.hasJavaNature(savedProject)) return; // ignore PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */); saveState(info, context); return; } ArrayList<IStatus> vStats= null; // lazy initialized ArrayList<PerProjectInfo> values = null; synchronized(this.perProjectInfos) { values = new ArrayList<>(this.perProjectInfos.values()); } Iterator<PerProjectInfo> iterator = values.iterator(); while (iterator.hasNext()) { try { PerProjectInfo info = iterator.next(); saveState(info, context); } catch (CoreException e) { if (vStats == null) vStats= new ArrayList<>(); vStats.add(e.getStatus()); } } if (vStats != null) { IStatus[] stats= new IStatus[vStats.size()]; vStats.toArray(stats); throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Messages.build_cannotSaveStates, null)); } // save external libs timestamps this.deltaState.saveExternalLibTimeStamps(); }
Add a secondary type in temporary indexing cache for a project got from given path. Current secondary types cache is not modified as we want to wait that indexing was finished before taking new secondary types into account.
See Also:
  • secondaryTypes(IJavaProject, boolean, IProgressMonitor)
/** * Add a secondary type in temporary indexing cache for a project got from given path. * * Current secondary types cache is not modified as we want to wait that indexing * was finished before taking new secondary types into account. * * @see #secondaryTypes(IJavaProject, boolean, IProgressMonitor) */
public void secondaryTypeAdding(String path, char[] typeName, char[] packageName) { if (VERBOSE) { StringBuffer buffer = new StringBuffer("JavaModelManager.addSecondaryType("); //$NON-NLS-1$ buffer.append(path); buffer.append(','); buffer.append('['); buffer.append(new String(packageName)); buffer.append('.'); buffer.append(new String(typeName)); buffer.append(']'); buffer.append(')'); Util.verbose(buffer.toString()); } IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot(); IResource resource = wRoot.findMember(path); if (resource instanceof IFile) { if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path)) { IProject project = resource.getProject(); try { PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project); // Get or create map to cache secondary types while indexing (can be not synchronized as indexing insure a non-concurrent usage) Map<IFile, Map<String, Map<String, IType>>> indexedSecondaryTypes; if (projectInfo.secondaryTypes == null) { projectInfo.secondaryTypes = new Hashtable<>(3); indexedSecondaryTypes = new HashMap<>(3); projectInfo.indexingSecondaryCache = indexedSecondaryTypes; } else { indexedSecondaryTypes = projectInfo.indexingSecondaryCache; if (indexedSecondaryTypes == null) { indexedSecondaryTypes = new HashMap<>(3); projectInfo.indexingSecondaryCache = indexedSecondaryTypes; } } // Store the secondary type in temporary cache (these are just handles => no problem to create it now...) Map<String, Map<String, IType>> allTypes = indexedSecondaryTypes.get(resource); if (allTypes == null) { allTypes = new HashMap<>(3); indexedSecondaryTypes.put((IFile) resource, allTypes); } ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom((IFile)resource, null); if (unit != null) { String typeString = new String(typeName); IType type = unit.getType(typeString); // String packageString = new String(packageName); // use package fragment name instead of parameter as it may be invalid... // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=186781 String packageString = type.getPackageFragment().getElementName(); Map<String, IType> packageTypes = allTypes.get(packageString); if (packageTypes == null) { packageTypes = new HashMap<>(3); allTypes.put(packageString, packageTypes); } packageTypes.put(typeString, type); } if (VERBOSE) { Util.verbose(" - indexing cache:"); //$NON-NLS-1$ Iterator<Entry<IFile, Map<String, Map<String, IType>>>> entries = indexedSecondaryTypes.entrySet().iterator(); while (entries.hasNext()) { Entry<IFile, Map<String, Map<String, IType>>> entry = entries.next(); IFile file = entry.getKey(); Util.verbose(" + "+file.getFullPath()+':'+ entry.getValue()); //$NON-NLS-1$ } } } catch (JavaModelException jme) { // do nothing } } } }
Get all secondary types for a project and store result in per project info cache.

This cache is an Hashtable<String, HashMap<String, IType>>:

  • key: package name
  • value:
    • key: type name
    • value: java model handle for the secondary type
Hashtable was used to protect callers from possible concurrent access.

Note, if indexing is not finished and caller does not wait for the end of indexing, returned map is the current secondary types cache content which may be invalid...
Params:
  • project – Project we want get secondary types from
Returns:HashMap Table of secondary type names->path for given project
/** * Get all secondary types for a project and store result in per project info cache. * <p> * This cache is an <code>Hashtable&lt;String, HashMap&lt;String, IType&gt;&gt;</code>: * <ul> * <li>key: package name * <li>value: * <ul> * <li>key: type name * <li>value: java model handle for the secondary type * </ul> * </ul> * Hashtable was used to protect callers from possible concurrent access. * </p> * Note, if indexing is not finished and caller does * not wait for the end of indexing, returned map is the current secondary * types cache content which may be invalid... * * @param project Project we want get secondary types from * @return HashMap Table of secondary type names->path for given project */
public Map<String, Map<String, IType>> secondaryTypes(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor) throws JavaModelException { if (VERBOSE) { StringBuffer buffer = new StringBuffer("JavaModelManager.secondaryTypes("); //$NON-NLS-1$ buffer.append(project.getElementName()); buffer.append(','); buffer.append(waitForIndexes); buffer.append(')'); Util.verbose(buffer.toString()); } // Return cache if not empty and there's no new secondary types created during indexing final PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project.getProject()); Map<IFile, Map<String, Map<String, IType>>> indexingSecondaryCache = projectInfo.secondaryTypes == null ? null : projectInfo.indexingSecondaryCache; if (projectInfo.secondaryTypes != null && indexingSecondaryCache == null) { return projectInfo.secondaryTypes; } // Perform search request only if secondary types cache is not initialized yet (this will happen only once!) if (projectInfo.secondaryTypes == null) { return secondaryTypesSearching(project, waitForIndexes, monitor, projectInfo); } // New secondary types have been created while indexing secondary types cache // => need to know whether the indexing is finished or not boolean indexing = this.indexManager.awaitingJobsCount() > 0; if (indexing) { if (!waitForIndexes) { // Indexing is running but caller cannot wait => return current cache return projectInfo.secondaryTypes; } // Wait for the end of indexing or a cancel try { this.indexManager.performConcurrentJob(new IJob() { @Override public boolean belongsTo(String jobFamily) { return true; } @Override public void cancel() { // job is cancelled through progress } @Override public void ensureReadyToRun() { // always ready } @Override public boolean execute(IProgressMonitor progress) { return progress == null || !progress.isCanceled(); } @Override public String getJobFamily() { return ""; //$NON-NLS-1$ } }, IJob.WaitUntilReady, monitor); } catch (OperationCanceledException oce) { return projectInfo.secondaryTypes; } } // Indexing is finished => merge caches and return result return secondaryTypesMerging(projectInfo); } /* * Return secondary types cache merged with new secondary types created while indexing * Note that merge result is directly stored in given parameter map. */ private Map<String, Map<String, IType>> secondaryTypesMerging(PerProjectInfo projectInfo) { Map<String, Map<String, IType>> secondaryTypes = projectInfo.secondaryTypes; if (VERBOSE) { Util.verbose("JavaModelManager.getSecondaryTypesMerged()"); //$NON-NLS-1$ Util.verbose(" - current cache to merge:"); //$NON-NLS-1$ Iterator<Entry<String, Map<String, IType>>> entries = secondaryTypes.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, IType>> entry = entries.next(); String packName = entry.getKey(); Util.verbose(" + "+packName+':'+ entry.getValue() ); //$NON-NLS-1$ } } // Return current cache if there's no indexing cache (double check, this should not happen) Map<IFile, Map<String, Map<String, IType>>> indexedSecondaryTypes = projectInfo.indexingSecondaryCache; projectInfo.indexingSecondaryCache = null; if (indexedSecondaryTypes == null) { return secondaryTypes; } // Merge indexing cache in secondary types one Iterator<Entry<IFile, Map<String, Map<String, IType>>>> entries = indexedSecondaryTypes.entrySet().iterator(); while (entries.hasNext()) { Entry<IFile, Map<String, Map<String, IType>>> entry = entries.next(); IFile file = entry.getKey(); // Remove all secondary types of indexed file from cache secondaryTypesRemoving(secondaryTypes, file); // Add all indexing file secondary types in given secondary types cache Map<String, Map<String, IType>> fileSecondaryTypes = entry.getValue(); Iterator<Entry<String, Map<String, IType>>> entries2 = fileSecondaryTypes.entrySet().iterator(); while (entries2.hasNext()) { Entry<String, Map<String, IType>> entry2 = entries2.next(); String packageName = entry2.getKey(); Map<String, IType> cachedTypes = secondaryTypes.get(packageName); if (cachedTypes == null) { secondaryTypes.put(packageName, entry2.getValue()); } else { Map<String, IType> types = entry2.getValue(); Iterator<Entry<String, IType>> entries3 = types.entrySet().iterator(); while (entries3.hasNext()) { Entry<String, IType> entry3 = entries3.next(); String typeName = entry3.getKey(); cachedTypes.put(typeName, entry3.getValue()); } } } } if (VERBOSE) { Util.verbose(" - secondary types cache merged:"); //$NON-NLS-1$ Iterator<Entry<String, Map<String, IType>>> entries2 = secondaryTypes.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, IType>> entry = entries2.next(); String packName = entry.getKey(); Util.verbose(" + "+packName+':'+ entry.getValue()); //$NON-NLS-1$ } } return secondaryTypes; } /* * Perform search request to get all secondary types of a given project. * If not waiting for indexes and indexing is running, will return types found in current built indexes... */ private static Map<String, Map<String, IType>> secondaryTypesSearching(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor, final PerProjectInfo projectInfo) throws JavaModelException { if (VERBOSE || BasicSearchEngine.VERBOSE) { StringBuffer buffer = new StringBuffer("JavaModelManager.secondaryTypesSearch("); //$NON-NLS-1$ buffer.append(project.getElementName()); buffer.append(','); buffer.append(waitForIndexes); buffer.append(')'); Util.verbose(buffer.toString()); } final Hashtable<String, Map<String, String>> secondaryTypesSearch = new Hashtable<>(3); IRestrictedAccessTypeRequestor nameRequestor = new IRestrictedAccessTypeRequestor() { @Override public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path, AccessRestriction access) { String key = packageName==null ? "" : new String(packageName); //$NON-NLS-1$ Map<String, String> types = secondaryTypesSearch.get(key); if (types == null) types = new HashMap<>(3); types.put(new String(simpleTypeName), path); secondaryTypesSearch.put(key, types); } }; // Build scope using prereq projects but only source folders IPackageFragmentRoot[] allRoots = project.getAllPackageFragmentRoots(); int length = allRoots.length, size = 0; IPackageFragmentRoot[] allSourceFolders = new IPackageFragmentRoot[length]; for (int i=0; i<length; i++) { if (allRoots[i].getKind() == IPackageFragmentRoot.K_SOURCE) { allSourceFolders[size++] = allRoots[i]; } } if (size < length) { System.arraycopy(allSourceFolders, 0, allSourceFolders = new IPackageFragmentRoot[size], 0, size); } // Search all secondary types on scope new BasicSearchEngine().searchAllSecondaryTypeNames(allSourceFolders, nameRequestor, waitForIndexes, monitor); // Build types from paths final Hashtable<String, Map<String, IType>> secondaryTypes = new Hashtable<>(secondaryTypesSearch.size()); for (Entry<String, Map<String, String>> packageEntry : secondaryTypesSearch.entrySet()) { String packageName = packageEntry.getKey(); Map<String, String> types = packageEntry.getValue(); Map<String, IType> tempTypes = new HashMap<>(types.size()); for (Entry<String, String> entry : types.entrySet()) { String typeName = entry.getKey(); String path = entry.getValue(); if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path)) { IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path)); ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom(file, null); IType type = unit.getType(typeName); tempTypes.put(typeName, type); } } secondaryTypes.put(packageName, tempTypes); } // Store result in per project info cache if still null or there's still an indexing cache (may have been set by another thread...) if (projectInfo.secondaryTypes == null || projectInfo.indexingSecondaryCache != null) { projectInfo.secondaryTypes = secondaryTypes; if (VERBOSE || BasicSearchEngine.VERBOSE) { System.out.print(Thread.currentThread() + " -> secondary paths stored in cache: "); //$NON-NLS-1$ System.out.println(); Iterator<Entry<String, Map<String, IType>>> entries = secondaryTypes.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, IType>> entry = entries.next(); String qualifiedName = entry.getKey(); Util.verbose(" - "+qualifiedName+'-'+ entry.getValue()); //$NON-NLS-1$ } } } return projectInfo.secondaryTypes; }
Remove from secondary types cache all types belonging to a given file. Clean secondary types cache built while indexing if requested. Project's secondary types cache is found using file location.
Params:
  • file – File to remove
/** * Remove from secondary types cache all types belonging to a given file. * Clean secondary types cache built while indexing if requested. * * Project's secondary types cache is found using file location. * * @param file File to remove */
public void secondaryTypesRemoving(IFile file, boolean cleanIndexCache) { if (VERBOSE) { StringBuffer buffer = new StringBuffer("JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$ buffer.append(file.getName()); buffer.append(')'); Util.verbose(buffer.toString()); } if (file != null) { PerProjectInfo projectInfo = getPerProjectInfo(file.getProject(), false); if (projectInfo != null && projectInfo.secondaryTypes != null) { if (VERBOSE) { Util.verbose("-> remove file from cache of project: "+file.getProject().getName()); //$NON-NLS-1$ } // Clean current cache secondaryTypesRemoving(projectInfo.secondaryTypes, file); // Clean indexing cache if necessary Map<IFile, Map<String, Map<String, IType>>> indexingCache = projectInfo.indexingSecondaryCache; if (!cleanIndexCache) { if (indexingCache == null) { // Need to signify that secondary types indexing will happen before any request happens // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=152841 projectInfo.indexingSecondaryCache = new HashMap<>(); } return; } if (indexingCache != null) { Set<IFile> keys = indexingCache.keySet(); int filesSize = keys.size(), filesCount = 0; IFile[] removed = null; Iterator<IFile> cachedFiles = keys.iterator(); while (cachedFiles.hasNext()) { IFile cachedFile = cachedFiles.next(); if (file.equals(cachedFile)) { if (removed == null) removed = new IFile[filesSize]; filesSize--; removed[filesCount++] = cachedFile; } } if (removed != null) { for (int i=0; i<filesCount; i++) { indexingCache.remove(removed[i]); } } } } } } /* * Remove from a given cache map all secondary types belonging to a given file. * Note that there can have several secondary types per file... */ private void secondaryTypesRemoving(Map<String, Map<String, IType>> secondaryTypesMap, IFile file) { if (VERBOSE) { StringBuffer buffer = new StringBuffer("JavaModelManager.removeSecondaryTypesFromMap("); //$NON-NLS-1$ Iterator<Entry<String, Map<String, IType>>> entries = secondaryTypesMap.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, IType>> entry = entries.next(); String qualifiedName = entry.getKey(); buffer.append(qualifiedName+':'+ entry.getValue()); } buffer.append(','); buffer.append(file.getFullPath()); buffer.append(')'); Util.verbose(buffer.toString()); } Set<Entry<String, Map<String, IType>>> packageEntries = secondaryTypesMap.entrySet(); int packagesSize = packageEntries.size(), removedPackagesCount = 0; String[] removedPackages = null; Iterator<Entry<String, Map<String, IType>>> packages = packageEntries.iterator(); while (packages.hasNext()) { Entry<String, Map<String, IType>> entry = packages.next(); String packName = entry.getKey(); Map<String, IType> types = entry.getValue(); Set<Entry<String, IType>> nameEntries = types.entrySet(); int namesSize = nameEntries.size(), removedNamesCount = 0; String[] removedNames = null; Iterator<Entry<String, IType>> names = nameEntries.iterator(); while (names.hasNext()) { Entry<String, IType> entry2 = names.next(); String typeName = entry2.getKey(); JavaElement type = (JavaElement) entry2.getValue(); if (file.equals(type.resource())) { if (removedNames == null) removedNames = new String[namesSize]; namesSize--; removedNames[removedNamesCount++] = typeName; } } if (removedNames != null) { for (int i=0; i<removedNamesCount; i++) { types.remove(removedNames[i]); } } if (types.size() == 0) { if (removedPackages == null) removedPackages = new String[packagesSize]; packagesSize--; removedPackages[removedPackagesCount++] = packName; } } if (removedPackages != null) { for (int i=0; i<removedPackagesCount; i++) { secondaryTypesMap.remove(removedPackages[i]); } } if (VERBOSE) { Util.verbose(" - new secondary types map:"); //$NON-NLS-1$ Iterator<Entry<String, Map<String, IType>>> entries = secondaryTypesMap.entrySet().iterator(); while (entries.hasNext()) { Entry<String, Map<String, IType>> entry = entries.next(); String qualifiedName = entry.getKey(); Util.verbose(" + "+qualifiedName+':'+ entry.getValue()); //$NON-NLS-1$ } } }
Record the order in which to build the java projects (batch build). This order is based on the projects classpath settings.
/** * Record the order in which to build the java projects (batch build). This order is based * on the projects classpath settings. */
protected void setBuildOrder(String[] javaBuildOrder) throws JavaModelException { // optional behaviour // possible value of index 0 is Compute if (!JavaCore.COMPUTE.equals(JavaCore.getOption(JavaCore.CORE_JAVA_BUILD_ORDER))) return; // cannot be customized at project level if (javaBuildOrder == null || javaBuildOrder.length <= 1) return; IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceDescription description = workspace.getDescription(); String[] wksBuildOrder = description.getBuildOrder(); String[] newOrder; if (wksBuildOrder == null){ newOrder = javaBuildOrder; } else { // remove projects which are already mentionned in java builder order int javaCount = javaBuildOrder.length; HashMap<String, String> newSet = new HashMap<>(javaCount); // create a set for fast check for (int i = 0; i < javaCount; i++){ newSet.put(javaBuildOrder[i], javaBuildOrder[i]); } int removed = 0; int oldCount = wksBuildOrder.length; for (int i = 0; i < oldCount; i++){ if (newSet.containsKey(wksBuildOrder[i])){ wksBuildOrder[i] = null; removed++; } } // add Java ones first newOrder = new String[oldCount - removed + javaCount]; System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first // copy previous items in their respective order int index = javaCount; for (int i = 0; i < oldCount; i++){ if (wksBuildOrder[i] != null){ newOrder[index++] = wksBuildOrder[i]; } } } // commit the new build order out description.setBuildOrder(newOrder); try { workspace.setDescription(description); } catch(CoreException e){ throw new JavaModelException(e); } }
Sets the last built state for the given project, or null to reset it.
/** * Sets the last built state for the given project, or null to reset it. */
public void setLastBuiltState(IProject project, Object state) { if (JavaProject.hasJavaNature(project)) { // should never be requested on non-Java projects PerProjectInfo info = getPerProjectInfo(project, true /*create if missing*/); info.triedRead = true; // no point trying to re-read once using setter info.savedState = state; } if (state == null) { // delete state file to ensure a full build happens if the workspace crashes try { File file = getSerializationFile(project); if (file != null && file.exists()) file.delete(); } catch(SecurityException se) { // could not delete file: cannot do much more } } }
Store the preferences value for the given option name.
Params:
  • optionName – The name of the option
  • optionValue – The value of the option. If null, then the option will be removed from the preferences instead.
  • eclipsePreferences – The eclipse preferences to be updated
  • otherOptions – more options being stored, used to avoid conflict between deprecated option and its compatible
Returns:true if the preferences have been changed, false otherwise.
/** * Store the preferences value for the given option name. * * @param optionName The name of the option * @param optionValue The value of the option. If <code>null</code>, then * the option will be removed from the preferences instead. * @param eclipsePreferences The eclipse preferences to be updated * @param otherOptions more options being stored, used to avoid conflict between deprecated option and its compatible * @return <code>true</code> if the preferences have been changed, * <code>false</code> otherwise. */
public boolean storePreference(String optionName, String optionValue, IEclipsePreferences eclipsePreferences, Map<String, String> otherOptions) { int optionLevel = this.getOptionLevel(optionName); if (optionLevel == UNKNOWN_OPTION) return false; // unrecognized option // Store option value switch (optionLevel) { case JavaModelManager.VALID_OPTION: if (optionValue == null) { eclipsePreferences.remove(optionName); } else { eclipsePreferences.put(optionName, optionValue); } break; case JavaModelManager.DEPRECATED_OPTION: // Try to migrate deprecated option eclipsePreferences.remove(optionName); // get rid off old preference String[] compatibleOptions = this.deprecatedOptions.get(optionName); for (int co=0, length=compatibleOptions.length; co < length; co++) { if (otherOptions != null && otherOptions.containsKey(compatibleOptions[co])) continue; // don't overwrite explicit value of otherOptions at compatibleOptions[co] if (optionValue == null) { eclipsePreferences.remove(compatibleOptions[co]); } else { eclipsePreferences.put(compatibleOptions[co], optionValue); } } break; default: return false; } return true; } public void setOptions(Hashtable<String, String> newOptions) { Hashtable<String, String> cachedValue = newOptions == null ? null : new Hashtable<>(newOptions); IEclipsePreferences defaultPreferences = getDefaultPreferences(); IEclipsePreferences instancePreferences = getInstancePreferences(); if (newOptions == null){ try { instancePreferences.clear(); } catch(BackingStoreException e) { // ignore } } else { Enumeration<String> keys = newOptions.keys(); while (keys.hasMoreElements()){ String key = keys.nextElement(); int optionLevel = getOptionLevel(key); if (optionLevel == UNKNOWN_OPTION) continue; // unrecognized option if (key.equals(JavaCore.CORE_ENCODING)) { if (cachedValue != null) { cachedValue.put(key, JavaCore.getEncoding()); } continue; // skipped, contributed by resource prefs } String value = newOptions.get(key); String defaultValue = defaultPreferences.get(key, null); // Store value in preferences if (defaultValue != null && defaultValue.equals(value)) { value = null; } storePreference(key, value, instancePreferences, newOptions); } try { // persist options instancePreferences.flush(); } catch(BackingStoreException e) { // ignore } } // update cache Util.fixTaskTags(cachedValue); this.optionsCache = cachedValue; } public void startup() throws CoreException { try { // initialize Java model cache this.cache = new JavaModelCache(); // request state folder creation (workaround 19885) JavaCore.getPlugin().getStateLocation(); // Initialize eclipse preferences initializePreferences(); // Listen to preference changes this.propertyListener = new IEclipsePreferences.IPreferenceChangeListener() { @Override public void preferenceChange(PreferenceChangeEvent event) { JavaModelManager.this.optionsCache = null; } }; InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID).addPreferenceChangeListener(this.propertyListener); // listen for encoding changes (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=255501 ) this.resourcesPropertyListener = new IEclipsePreferences.IPreferenceChangeListener() { @Override public void preferenceChange(PreferenceChangeEvent event) { if (ResourcesPlugin.PREF_ENCODING.equals(event.getKey())) { JavaModelManager.this.optionsCache = null; } } }; String resourcesPluginId = ResourcesPlugin.getPlugin().getBundle().getSymbolicName(); InstanceScope.INSTANCE.getNode(resourcesPluginId).addPreferenceChangeListener(this.resourcesPropertyListener); // Listen to content-type changes Platform.getContentTypeManager().addContentTypeChangeListener(this); // retrieve variable values long start = -1; if (VERBOSE) start = System.currentTimeMillis(); loadVariablesAndContainers(); if (VERBOSE) traceVariableAndContainers("Loaded", start); //$NON-NLS-1$ // listen for resource changes this.deltaState.initializeRootsWithPreviousSession(); final IWorkspace workspace = ResourcesPlugin.getWorkspace(); workspace.addResourceChangeListener( this.deltaState, /* update spec in JavaCore#addPreProcessingResourceChangedListener(...) if adding more event types */ IResourceChangeEvent.PRE_BUILD | IResourceChangeEvent.POST_BUILD | IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_REFRESH); // New index is disabled, see bug 544898 // Indexer.getInstance().addListener(this.deltaState); // listen to resource changes affecting external annotations ExternalAnnotationTracker.start(workspace); startIndexing(); // process deltas since last activated in indexer thread so that indexes are up-to-date. // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658 Job processSavedState = new Job(Messages.savedState_jobName) { @Override protected IStatus run(IProgressMonitor monitor) { try { // add save participant and process delta atomically // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59937 workspace.run( new IWorkspaceRunnable() { @Override public void run(IProgressMonitor progress) throws CoreException { ISavedState savedState = workspace.addSaveParticipant(JavaCore.PLUGIN_ID, JavaModelManager.this); if (savedState != null) { // the event type coming from the saved state is always POST_AUTO_BUILD // force it to be POST_CHANGE so that the delta processor can handle it JavaModelManager.this.deltaState.getDeltaProcessor().overridenEventType = IResourceChangeEvent.POST_CHANGE; savedState.processResourceChangeEvents(JavaModelManager.this.deltaState); } } }, monitor); } catch (CoreException e) { return e.getStatus(); } return Status.OK_STATUS; } }; processSavedState.setSystem(true); processSavedState.setPriority(Job.SHORT); // process asap processSavedState.schedule(); } catch (RuntimeException e) { try { shutdown(); } catch (RuntimeException e2) { e.addSuppressed(e2); } throw e; } }
Initiate the background indexing process. This should be deferred after the plug-in activation.
/** * Initiate the background indexing process. * This should be deferred after the plug-in activation. */
private void startIndexing() { if (this.indexManager != null) this.indexManager.reset(); } public void shutdown () { IEclipsePreferences preferences = InstanceScope.INSTANCE.getNode(JavaCore.PLUGIN_ID); try { preferences.flush(); } catch (BackingStoreException e) { Util.log(e, "Could not save JavaCore preferences"); //$NON-NLS-1$ } IWorkspace workspace = ResourcesPlugin.getWorkspace(); workspace.removeResourceChangeListener(this.deltaState); workspace.removeSaveParticipant(JavaCore.PLUGIN_ID); ExternalAnnotationTracker.shutdown(workspace); // Stop listening to content-type changes IContentTypeManager contentTypeManager = Platform.getContentTypeManager(); if (contentTypeManager != null) { contentTypeManager.removeContentTypeChangeListener(this); } // Stop indexing if (this.indexManager != null) { this.indexManager.shutdown(); } // Stop listening to preferences changes preferences.removePreferenceChangeListener(this.propertyListener); ((IEclipsePreferences) this.preferencesLookup[PREF_DEFAULT].parent()).removeNodeChangeListener(this.defaultNodeListener); this.preferencesLookup[PREF_DEFAULT] = null; ((IEclipsePreferences) this.preferencesLookup[PREF_INSTANCE].parent()).removeNodeChangeListener(this.instanceNodeListener); this.preferencesLookup[PREF_INSTANCE].removePreferenceChangeListener(this.instancePreferencesListener); this.preferencesLookup[PREF_INSTANCE] = null; String resourcesPluginId = ResourcesPlugin.getPlugin().getBundle().getSymbolicName(); InstanceScope.INSTANCE.getNode(resourcesPluginId).removePreferenceChangeListener(this.resourcesPropertyListener); // wait for the initialization job to finish try { Job.getJobManager().join(JavaCore.PLUGIN_ID, null); } catch (InterruptedException e) { // ignore } // Note: no need to close the Java model as this just removes Java element infos from the Java model cache } public synchronized IPath variableGet(String variableName){ // check initialization in progress first Set<String> initializations = variableInitializationInProgress(); if (initializations.contains(variableName)) { return VARIABLE_INITIALIZATION_IN_PROGRESS; } return this.variables.get(variableName); } private synchronized IPath variableGetDefaultToPreviousSession(String variableName){ IPath variablePath = this.variables.get(variableName); if (variablePath == null) return getPreviousSessionVariable(variableName); return variablePath; } /* * Returns the set of variable names that are being initialized in the current thread. */ private Set<String> variableInitializationInProgress() { Set<String> initializations = this.variableInitializationInProgress.get(); if (initializations == null) { initializations = new HashSet<>(); this.variableInitializationInProgress.set(initializations); } return initializations; } public synchronized String[] variableNames(){ int length = this.variables.size(); String[] result = new String[length]; Iterator<String> vars = this.variables.keySet().iterator(); int index = 0; while (vars.hasNext()) { result[index++] = vars.next(); } return result; } public synchronized void variablePut(String variableName, IPath variablePath){ // set/unset the initialization in progress Set<String> initializations = variableInitializationInProgress(); if (variablePath == VARIABLE_INITIALIZATION_IN_PROGRESS) { initializations.add(variableName); // do not write out intermediate initialization value return; } else { initializations.remove(variableName); // update cache - do not only rely on listener refresh if (variablePath == null) { // if path is null, record that the variable was removed to avoid asking the initializer to initialize it again // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=112609 this.variables.put(variableName, CP_ENTRY_IGNORE_PATH); // clean other variables caches this.variablesWithInitializer.remove(variableName); this.deprecatedVariables.remove(variableName); } else { this.variables.put(variableName, variablePath); } // discard obsoleted information about previous session this.previousSessionVariables.remove(variableName); } } public void variablePreferencesPut(String variableName, IPath variablePath) { String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName; if (variablePath == null) { getInstancePreferences().remove(variableKey); } else { getInstancePreferences().put(variableKey, variablePath.toString()); } try { getInstancePreferences().flush(); } catch (BackingStoreException e) { // ignore exception } } /* * Optimize startup case where 1 variable is initialized at a time with the same value as on shutdown. */ public boolean variablePutIfInitializingWithSameValue(String[] variableNames, IPath[] variablePaths) { if (variableNames.length != 1) return false; String variableName = variableNames[0]; IPath oldPath = variableGetDefaultToPreviousSession(variableName); if (oldPath == null) return false; IPath newPath = variablePaths[0]; if (!oldPath.equals(newPath)) return false; variablePut(variableName, newPath); return true; } @Override public void contentTypeChanged(ContentTypeChangeEvent event) { Util.resetJavaLikeExtensions(); // Walk through projects to reset their secondary types cache IJavaProject[] projects; try { projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects(); } catch (JavaModelException e) { return; } for (int i = 0, length = projects.length; i < length; i++) { IJavaProject project = projects[i]; final PerProjectInfo projectInfo = getPerProjectInfo(project.getProject(), false /* don't create info */); if (projectInfo != null) { projectInfo.secondaryTypes = null; } } } public synchronized String cacheToString(String prefix) { return this.cache.toStringFillingRation(prefix); } public ElementCache<ITypeRoot>.Stats debugNewOpenableCacheStats() { return this.cache.openableCache.new Stats(); } public int getOpenableCacheSize() { return this.cache.openableCache.getSpaceLimit(); }
Get a cached access rule, or when the cache did not contain the rule, creates a new one.
Params:
Returns:an access rule
/** * Get a cached access rule, or when the cache did not contain the rule, creates a new one. * * @param filePattern the file pattern this access rule should match * @param kind one of {@link IAccessRule#K_ACCESSIBLE}, {@link IAccessRule#K_DISCOURAGED}, * or {@link IAccessRule#K_NON_ACCESSIBLE}, optionally combined with * {@link IAccessRule#IGNORE_IF_BETTER} * @return an access rule */
public IAccessRule getAccessRule(IPath filePattern, int kind) { ClasspathAccessRule rule = new ClasspathAccessRule(filePattern, kind); return getFromCache(rule); }
Used only for loading rules from disk.
/** * Used only for loading rules from disk. */
public ClasspathAccessRule getAccessRuleForProblemId(char [] filePattern, int problemId) { ClasspathAccessRule rule = new ClasspathAccessRule(filePattern, problemId); return getFromCache(rule); } private ClasspathAccessRule getFromCache(ClasspathAccessRule rule) { ClasspathAccessRule cachedRule = this.cache.accessRuleCache.get(rule); if (cachedRule != null) { return cachedRule; } this.cache.accessRuleCache.put(rule, rule); return rule; } }