0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache
0011: * before its contents
0012: * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422)
0013: *******************************************************************************/package org.eclipse.jdt.internal.core;
0014:
0015: import java.io.*;
0016: import java.net.URI;
0017: import java.text.MessageFormat;
0018: import java.util.*;
0019: import java.util.Map.Entry;
0020: import java.util.zip.ZipFile;
0021:
0022: import javax.xml.parsers.DocumentBuilder;
0023: import javax.xml.parsers.DocumentBuilderFactory;
0024: import javax.xml.parsers.ParserConfigurationException;
0025:
0026: import org.eclipse.core.resources.*;
0027: import org.eclipse.core.runtime.*;
0028: import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent;
0029: import org.eclipse.core.runtime.content.IContentTypeManager.IContentTypeChangeListener;
0030: import org.eclipse.core.runtime.jobs.Job;
0031: import org.eclipse.core.runtime.preferences.DefaultScope;
0032: import org.eclipse.core.runtime.preferences.IEclipsePreferences;
0033: import org.eclipse.core.runtime.preferences.IPreferencesService;
0034: import org.eclipse.core.runtime.preferences.IScopeContext;
0035: import org.eclipse.core.runtime.preferences.InstanceScope;
0036: import org.eclipse.jdt.core.*;
0037: import org.eclipse.jdt.core.compiler.CharOperation;
0038: import org.eclipse.jdt.core.compiler.CompilationParticipant;
0039: import org.eclipse.jdt.core.compiler.IProblem;
0040: import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
0041: import org.eclipse.jdt.internal.codeassist.CompletionEngine;
0042: import org.eclipse.jdt.internal.codeassist.SelectionEngine;
0043: import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
0044: import org.eclipse.jdt.internal.compiler.Compiler;
0045: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
0046: import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
0047: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
0048: import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
0049: import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
0050: import org.eclipse.jdt.internal.core.builder.JavaBuilder;
0051: import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
0052: import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
0053: import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
0054: import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor;
0055: import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
0056: import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
0057: import org.eclipse.jdt.internal.core.search.processing.JobManager;
0058: import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
0059: import org.eclipse.jdt.internal.core.util.LRUCache;
0060: import org.eclipse.jdt.internal.core.util.Messages;
0061: import org.eclipse.jdt.internal.core.util.Util;
0062: import org.eclipse.jdt.internal.core.util.WeakHashSet;
0063: import org.eclipse.jdt.internal.core.util.WeakHashSetOfCharArray;
0064: import org.osgi.service.prefs.BackingStoreException;
0065: import org.w3c.dom.Element;
0066: import org.w3c.dom.Node;
0067: import org.w3c.dom.NodeList;
0068: import org.xml.sax.InputSource;
0069: import org.xml.sax.SAXException;
0070:
0071: /**
0072: * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>.
0073: * <code>IElementChangedListener</code>s register with the <code>JavaModelManager</code>,
0074: * and receive <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
0075: * <p>
0076: * The single instance of <code>JavaModelManager</code> is available from
0077: * the static method <code>JavaModelManager.getJavaModelManager()</code>.
0078: */
0079: public class JavaModelManager implements ISaveParticipant,
0080: IContentTypeChangeListener {
0081:
0082: /**
0083: * Unique handle onto the JavaModel
0084: */
0085: final JavaModel javaModel = new JavaModel();
0086:
0087: /**
0088: * Classpath variables pool
0089: */
0090: public HashMap variables = new HashMap(5);
0091: public HashSet variablesWithInitializer = new HashSet(5);
0092: public HashMap deprecatedVariables = new HashMap(5);
0093: public HashSet readOnlyVariables = new HashSet(5);
0094: public HashMap previousSessionVariables = new HashMap(5);
0095: private ThreadLocal variableInitializationInProgress = new ThreadLocal();
0096:
0097: /**
0098: * Classpath containers pool
0099: */
0100: public HashMap containers = new HashMap(5);
0101: public HashMap previousSessionContainers = new HashMap(5);
0102: private ThreadLocal containerInitializationInProgress = new ThreadLocal();
0103: public boolean batchContainerInitializations = false;
0104: public ThreadLocal batchContainerInitializationsProgress = new ThreadLocal();
0105: public HashMap containerInitializersCache = new HashMap(5);
0106:
0107: /*
0108: * A HashSet that contains the IJavaProject whose classpath is being resolved.
0109: */
0110: private ThreadLocal classpathsBeingResolved = new ThreadLocal();
0111:
0112: /*
0113: * The unique workspace scope
0114: */
0115: public JavaWorkspaceScope workspaceScope;
0116:
0117: /*
0118: * Pools of symbols used in the Java model.
0119: * Used as a replacement for String#intern() that could prevent garbage collection of strings on some VMs.
0120: */
0121: private WeakHashSet stringSymbols = new WeakHashSet(5);
0122: private WeakHashSetOfCharArray charArraySymbols = new WeakHashSetOfCharArray(
0123: 5);
0124:
0125: /*
0126: * Extension used to construct Java 6 annotation processor managers
0127: */
0128: private IConfigurationElement annotationProcessorManagerFactory = null;
0129:
0130: /*
0131: * Map from a package fragment root's path to a source attachment property (source path + ATTACHMENT_PROPERTY_DELIMITER + source root path)
0132: */
0133: public Map rootPathToAttachments = new HashMap();
0134:
0135: public final static String CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID
0136: + ".classpathVariable."; //$NON-NLS-1$
0137: public final static String CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID
0138: + ".classpathContainer."; //$NON-NLS-1$
0139: public final static String CP_USERLIBRARY_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID
0140: + ".userLibrary."; //$NON-NLS-1$
0141: public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
0142: public final static IPath CP_ENTRY_IGNORE_PATH = new Path(
0143: CP_ENTRY_IGNORE);
0144: public final static String TRUE = "true"; //$NON-NLS-1$
0145:
0146: private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 2;
0147:
0148: /**
0149: * Name of the extension point for contributing classpath variable initializers
0150: */
0151: public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID = "classpathVariableInitializer"; //$NON-NLS-1$
0152:
0153: /**
0154: * Name of the extension point for contributing classpath container initializers
0155: */
0156: public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID = "classpathContainerInitializer"; //$NON-NLS-1$
0157:
0158: /**
0159: * Name of the extension point for contributing a source code formatter
0160: */
0161: public static final String FORMATTER_EXTPOINT_ID = "codeFormatter"; //$NON-NLS-1$
0162:
0163: /**
0164: * Name of the extension point for contributing a compilation participant
0165: */
0166: public static final String COMPILATION_PARTICIPANT_EXTPOINT_ID = "compilationParticipant"; //$NON-NLS-1$
0167:
0168: /**
0169: * Name of the extension point for contributing the Java 6 annotation processor manager
0170: */
0171: public static final String ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID = "annotationProcessorManager"; //$NON-NLS-1$
0172:
0173: /**
0174: * Special value used for recognizing ongoing initialization and breaking initialization cycles
0175: */
0176: public final static IPath VARIABLE_INITIALIZATION_IN_PROGRESS = new Path(
0177: "Variable Initialization In Progress"); //$NON-NLS-1$
0178: public final static IClasspathContainer CONTAINER_INITIALIZATION_IN_PROGRESS = new IClasspathContainer() {
0179: public IClasspathEntry[] getClasspathEntries() {
0180: return null;
0181: }
0182:
0183: public String getDescription() {
0184: return "Container Initialization In Progress";} //$NON-NLS-1$
0185:
0186: public int getKind() {
0187: return 0;
0188: }
0189:
0190: public IPath getPath() {
0191: return null;
0192: }
0193:
0194: public String toString() {
0195: return getDescription();
0196: }
0197: };
0198:
0199: private static final String BUFFER_MANAGER_DEBUG = JavaCore.PLUGIN_ID
0200: + "/debug/buffermanager"; //$NON-NLS-1$
0201: private static final String INDEX_MANAGER_DEBUG = JavaCore.PLUGIN_ID
0202: + "/debug/indexmanager"; //$NON-NLS-1$
0203: private static final String COMPILER_DEBUG = JavaCore.PLUGIN_ID
0204: + "/debug/compiler"; //$NON-NLS-1$
0205: private static final String JAVAMODEL_DEBUG = JavaCore.PLUGIN_ID
0206: + "/debug/javamodel"; //$NON-NLS-1$
0207: private static final String JAVAMODELCACHE_DEBUG = JavaCore.PLUGIN_ID
0208: + "/debug/javamodel/cache"; //$NON-NLS-1$
0209: private static final String CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID
0210: + "/debug/cpresolution"; //$NON-NLS-1$
0211: private static final String CP_RESOLVE_ADVANCED_DEBUG = JavaCore.PLUGIN_ID
0212: + "/debug/cpresolution/advanced"; //$NON-NLS-1$
0213: private static final String ZIP_ACCESS_DEBUG = JavaCore.PLUGIN_ID
0214: + "/debug/zipaccess"; //$NON-NLS-1$
0215: private static final String DELTA_DEBUG = JavaCore.PLUGIN_ID
0216: + "/debug/javadelta"; //$NON-NLS-1$
0217: private static final String DELTA_DEBUG_VERBOSE = JavaCore.PLUGIN_ID
0218: + "/debug/javadelta/verbose"; //$NON-NLS-1$
0219: private static final String HIERARCHY_DEBUG = JavaCore.PLUGIN_ID
0220: + "/debug/hierarchy"; //$NON-NLS-1$
0221: private static final String POST_ACTION_DEBUG = JavaCore.PLUGIN_ID
0222: + "/debug/postaction"; //$NON-NLS-1$
0223: private static final String BUILDER_DEBUG = JavaCore.PLUGIN_ID
0224: + "/debug/builder"; //$NON-NLS-1$
0225: private static final String COMPLETION_DEBUG = JavaCore.PLUGIN_ID
0226: + "/debug/completion"; //$NON-NLS-1$
0227: private static final String RESOLUTION_DEBUG = JavaCore.PLUGIN_ID
0228: + "/debug/resolution"; //$NON-NLS-1$
0229: private static final String SELECTION_DEBUG = JavaCore.PLUGIN_ID
0230: + "/debug/selection"; //$NON-NLS-1$
0231: private static final String SEARCH_DEBUG = JavaCore.PLUGIN_ID
0232: + "/debug/search"; //$NON-NLS-1$
0233: private static final String SOURCE_MAPPER_DEBUG_VERBOSE = JavaCore.PLUGIN_ID
0234: + "/debug/sourcemapper"; //$NON-NLS-1$
0235:
0236: public static final String COMPLETION_PERF = JavaCore.PLUGIN_ID
0237: + "/perf/completion"; //$NON-NLS-1$
0238: public static final String SELECTION_PERF = JavaCore.PLUGIN_ID
0239: + "/perf/selection"; //$NON-NLS-1$
0240: public static final String DELTA_LISTENER_PERF = JavaCore.PLUGIN_ID
0241: + "/perf/javadeltalistener"; //$NON-NLS-1$
0242: public static final String VARIABLE_INITIALIZER_PERF = JavaCore.PLUGIN_ID
0243: + "/perf/variableinitializer"; //$NON-NLS-1$
0244: public static final String CONTAINER_INITIALIZER_PERF = JavaCore.PLUGIN_ID
0245: + "/perf/containerinitializer"; //$NON-NLS-1$
0246: public static final String RECONCILE_PERF = JavaCore.PLUGIN_ID
0247: + "/perf/reconcile"; //$NON-NLS-1$
0248:
0249: private final static String INDEXED_SECONDARY_TYPES = "#@*_indexing secondary cache_*@#"; //$NON-NLS-1$
0250:
0251: public static boolean PERF_VARIABLE_INITIALIZER = false;
0252: public static boolean PERF_CONTAINER_INITIALIZER = false;
0253:
0254: public final static ICompilationUnit[] NO_WORKING_COPY = new ICompilationUnit[0];
0255:
0256: // Preferences
0257: HashSet optionNames = new HashSet(20);
0258: Hashtable optionsCache;
0259:
0260: public final IEclipsePreferences[] preferencesLookup = new IEclipsePreferences[2];
0261: static final int PREF_INSTANCE = 0;
0262: static final int PREF_DEFAULT = 1;
0263:
0264: static final Object[][] NO_PARTICIPANTS = new Object[0][];
0265:
0266: public static class CompilationParticipants {
0267:
0268: private final static int MAX_SOURCE_LEVEL = 7; // 1.1 to 1.7
0269:
0270: /*
0271: * The registered compilation participants (a table from int (source level) to Object[])
0272: * The Object array contains first IConfigurationElements when not resolved yet, then
0273: * it contains CompilationParticipants.
0274: */
0275: private Object[][] registeredParticipants = null;
0276: private HashSet managedMarkerTypes;
0277:
0278: public CompilationParticipant[] getCompilationParticipants(
0279: IJavaProject project) {
0280: final Object[][] participantsPerSource = getRegisteredParticipants();
0281: if (participantsPerSource == NO_PARTICIPANTS)
0282: return null;
0283: String sourceLevel = project.getOption(
0284: JavaCore.COMPILER_SOURCE, true/*inherit options*/);
0285: final int sourceLevelIndex = indexForSourceLevel(sourceLevel);
0286: final Object[] participants = participantsPerSource[sourceLevelIndex];
0287: int length = participants.length;
0288: CompilationParticipant[] result = new CompilationParticipant[length];
0289: int index = 0;
0290: for (int i = 0; i < length; i++) {
0291: if (participants[i] instanceof IConfigurationElement) {
0292: final IConfigurationElement configElement = (IConfigurationElement) participants[i];
0293: final int participantIndex = i;
0294: SafeRunner.run(new ISafeRunnable() {
0295: public void handleException(Throwable exception) {
0296: Util
0297: .log(exception,
0298: "Exception occurred while creating compilation participant"); //$NON-NLS-1$
0299: }
0300:
0301: public void run() throws Exception {
0302: Object executableExtension = configElement
0303: .createExecutableExtension("class"); //$NON-NLS-1$
0304: for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++)
0305: participantsPerSource[j][participantIndex] = executableExtension;
0306: }
0307: });
0308: }
0309: CompilationParticipant participant = (CompilationParticipant) participants[i];
0310: if (participant != null
0311: && participant.isActive(project))
0312: result[index++] = participant;
0313: }
0314: if (index == 0)
0315: return null;
0316: if (index < length)
0317: System.arraycopy(result, 0,
0318: result = new CompilationParticipant[index], 0,
0319: index);
0320: return result;
0321: }
0322:
0323: public HashSet managedMarkerTypes() {
0324: if (this .managedMarkerTypes == null) {
0325: // force extension points to be read
0326: getRegisteredParticipants();
0327: }
0328: return this .managedMarkerTypes;
0329: }
0330:
0331: private synchronized Object[][] getRegisteredParticipants() {
0332: if (this .registeredParticipants != null) {
0333: return this .registeredParticipants;
0334: }
0335: this .managedMarkerTypes = new HashSet();
0336: IExtensionPoint extension = Platform.getExtensionRegistry()
0337: .getExtensionPoint(JavaCore.PLUGIN_ID,
0338: COMPILATION_PARTICIPANT_EXTPOINT_ID);
0339: if (extension == null)
0340: return this .registeredParticipants = NO_PARTICIPANTS;
0341: final ArrayList modifyingEnv = new ArrayList();
0342: final ArrayList creatingProblems = new ArrayList();
0343: final ArrayList others = new ArrayList();
0344: IExtension[] extensions = extension.getExtensions();
0345: // for all extensions of this point...
0346: for (int i = 0; i < extensions.length; i++) {
0347: IConfigurationElement[] configElements = extensions[i]
0348: .getConfigurationElements();
0349: // for all config elements named "compilationParticipant"
0350: for (int j = 0; j < configElements.length; j++) {
0351: final IConfigurationElement configElement = configElements[j];
0352: String elementName = configElement.getName();
0353: if (!("compilationParticipant".equals(elementName))) { //$NON-NLS-1$
0354: continue;
0355: }
0356: // add config element in the group it belongs to
0357: if (TRUE.equals(configElement
0358: .getAttribute("modifiesEnvironment"))) //$NON-NLS-1$
0359: modifyingEnv.add(configElement);
0360: else if (TRUE.equals(configElement
0361: .getAttribute("createsProblems"))) //$NON-NLS-1$
0362: creatingProblems.add(configElement);
0363: else
0364: others.add(configElement);
0365: // add managed marker types
0366: IConfigurationElement[] managedMarkers = configElement
0367: .getChildren("managedMarker"); //$NON-NLS-1$
0368: for (int k = 0, length = managedMarkers.length; k < length; k++) {
0369: IConfigurationElement element = managedMarkers[k];
0370: String markerType = element
0371: .getAttribute("markerType"); //$NON-NLS-1$
0372: if (markerType != null)
0373: this .managedMarkerTypes.add(markerType);
0374: }
0375: }
0376: }
0377: int size = modifyingEnv.size() + creatingProblems.size()
0378: + others.size();
0379: if (size == 0)
0380: return this .registeredParticipants = NO_PARTICIPANTS;
0381:
0382: // sort config elements in each group
0383: IConfigurationElement[] configElements = new IConfigurationElement[size];
0384: int index = 0;
0385: index = sortParticipants(modifyingEnv, configElements,
0386: index);
0387: index = sortParticipants(creatingProblems, configElements,
0388: index);
0389: index = sortParticipants(others, configElements, index);
0390:
0391: // create result table
0392: Object[][] result = new Object[MAX_SOURCE_LEVEL][];
0393: int length = configElements.length;
0394: for (int i = 0; i < MAX_SOURCE_LEVEL; i++) {
0395: result[i] = new Object[length];
0396: }
0397: for (int i = 0; i < length; i++) {
0398: String sourceLevel = configElements[i]
0399: .getAttribute("requiredSourceLevel"); //$NON-NLS-1$
0400: int sourceLevelIndex = indexForSourceLevel(sourceLevel);
0401: for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++) {
0402: result[j][i] = configElements[i];
0403: }
0404: }
0405: return this .registeredParticipants = result;
0406: }
0407:
0408: /*
0409: * 1.1 -> 0
0410: * 1.2 -> 1
0411: * ...
0412: * 1.6 -> 5
0413: * 1.7 -> 6
0414: * null -> 0
0415: */
0416: private int indexForSourceLevel(String sourceLevel) {
0417: if (sourceLevel == null)
0418: return 0;
0419: int majVersion = (int) (CompilerOptions
0420: .versionToJdkLevel(sourceLevel) >>> 16);
0421: switch (majVersion) {
0422: case ClassFileConstants.MAJOR_VERSION_1_2:
0423: return 1;
0424: case ClassFileConstants.MAJOR_VERSION_1_3:
0425: return 2;
0426: case ClassFileConstants.MAJOR_VERSION_1_4:
0427: return 3;
0428: case ClassFileConstants.MAJOR_VERSION_1_5:
0429: return 4;
0430: case ClassFileConstants.MAJOR_VERSION_1_6:
0431: return 5;
0432: case ClassFileConstants.MAJOR_VERSION_1_7:
0433: return 6;
0434: default:
0435: // all other cases including ClassFileConstants.MAJOR_VERSION_1_1
0436: return 0;
0437: }
0438: }
0439:
0440: private int sortParticipants(ArrayList group,
0441: IConfigurationElement[] configElements, int index) {
0442: int size = group.size();
0443: if (size == 0)
0444: return index;
0445: Object[] elements = group.toArray();
0446: Util.sort(elements, new Util.Comparer() {
0447: public int compare(Object a, Object b) {
0448: if (a == b)
0449: return 0;
0450: String id = ((IConfigurationElement) a)
0451: .getAttribute("id"); //$NON-NLS-1$
0452: if (id == null)
0453: return -1;
0454: IConfigurationElement[] requiredElements = ((IConfigurationElement) b)
0455: .getChildren("requires"); //$NON-NLS-1$
0456: for (int i = 0, length = requiredElements.length; i < length; i++) {
0457: IConfigurationElement required = requiredElements[i];
0458: if (id.equals(required.getAttribute("id"))) //$NON-NLS-1$
0459: return 1;
0460: }
0461: return -1;
0462: }
0463: });
0464: for (int i = 0; i < size; i++)
0465: configElements[index + i] = (IConfigurationElement) elements[i];
0466: return index + size;
0467: }
0468: }
0469:
0470: public final CompilationParticipants compilationParticipants = new CompilationParticipants();
0471:
0472: /**
0473: * Returns whether the given full path (for a package) conflicts with the output location
0474: * of the given project.
0475: */
0476: public static boolean conflictsWithOutputLocation(IPath folderPath,
0477: JavaProject project) {
0478: try {
0479: IPath outputLocation = project.getOutputLocation();
0480: if (outputLocation == null) {
0481: // in doubt, there is a conflict
0482: return true;
0483: }
0484: if (outputLocation.isPrefixOf(folderPath)) {
0485: // only allow nesting in project's output if there is a corresponding source folder
0486: // or if the project's output is not used (in other words, if all source folders have their custom output)
0487: IClasspathEntry[] classpath = project
0488: .getResolvedClasspath();
0489: boolean isOutputUsed = false;
0490: for (int i = 0, length = classpath.length; i < length; i++) {
0491: IClasspathEntry entry = classpath[i];
0492: if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
0493: if (entry.getPath().equals(outputLocation)) {
0494: return false;
0495: }
0496: if (entry.getOutputLocation() == null) {
0497: isOutputUsed = true;
0498: }
0499: }
0500: }
0501: return isOutputUsed;
0502: }
0503: return false;
0504: } catch (JavaModelException e) {
0505: // in doubt, there is a conflict
0506: return true;
0507: }
0508: }
0509:
0510: public synchronized IClasspathContainer containerGet(
0511: IJavaProject project, IPath containerPath) {
0512: // check initialization in progress first
0513: if (containerIsInitializationInProgress(project, containerPath)) {
0514: return CONTAINER_INITIALIZATION_IN_PROGRESS;
0515: }
0516:
0517: Map projectContainers = (Map) this .containers.get(project);
0518: if (projectContainers == null) {
0519: return null;
0520: }
0521: IClasspathContainer container = (IClasspathContainer) projectContainers
0522: .get(containerPath);
0523: return container;
0524: }
0525:
0526: public synchronized IClasspathContainer containerGetDefaultToPreviousSession(
0527: IJavaProject project, IPath containerPath) {
0528: Map projectContainers = (Map) this .containers.get(project);
0529: if (projectContainers == null)
0530: return getPreviousSessionContainer(containerPath, project);
0531: IClasspathContainer container = (IClasspathContainer) projectContainers
0532: .get(containerPath);
0533: if (container == null)
0534: return getPreviousSessionContainer(containerPath, project);
0535: return container;
0536: }
0537:
0538: private synchronized Map containerClone(IJavaProject project) {
0539: Map originalProjectContainers = (Map) this .containers
0540: .get(project);
0541: if (originalProjectContainers == null)
0542: return null;
0543: Map projectContainers = new HashMap(originalProjectContainers
0544: .size());
0545: projectContainers.putAll(originalProjectContainers);
0546: return projectContainers;
0547: }
0548:
0549: private boolean containerIsInitializationInProgress(
0550: IJavaProject project, IPath containerPath) {
0551: Map initializations = (Map) this .containerInitializationInProgress
0552: .get();
0553: if (initializations == null)
0554: return false;
0555: HashSet projectInitializations = (HashSet) initializations
0556: .get(project);
0557: if (projectInitializations == null)
0558: return false;
0559: return projectInitializations.contains(containerPath);
0560: }
0561:
0562: private void containerAddInitializationInProgress(
0563: IJavaProject project, IPath containerPath) {
0564: Map initializations = (Map) this .containerInitializationInProgress
0565: .get();
0566: if (initializations == null)
0567: this .containerInitializationInProgress
0568: .set(initializations = new HashMap());
0569: HashSet projectInitializations = (HashSet) initializations
0570: .get(project);
0571: if (projectInitializations == null)
0572: initializations.put(project,
0573: projectInitializations = new HashSet());
0574: projectInitializations.add(containerPath);
0575: }
0576:
0577: public synchronized void containerPut(IJavaProject project,
0578: IPath containerPath, IClasspathContainer container) {
0579:
0580: // set/unset the initialization in progress
0581: if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
0582: containerAddInitializationInProgress(project, containerPath);
0583:
0584: // do not write out intermediate initialization value
0585: return;
0586: } else {
0587: containerRemoveInitializationInProgress(project,
0588: containerPath);
0589:
0590: Map projectContainers = (Map) this .containers.get(project);
0591: if (projectContainers == null) {
0592: projectContainers = new HashMap(1);
0593: this .containers.put(project, projectContainers);
0594: }
0595:
0596: if (container == null) {
0597: projectContainers.remove(containerPath);
0598: } else {
0599: projectContainers.put(containerPath, container);
0600: }
0601: // discard obsoleted information about previous session
0602: Map previousContainers = (Map) this .previousSessionContainers
0603: .get(project);
0604: if (previousContainers != null) {
0605: previousContainers.remove(containerPath);
0606: }
0607: }
0608: // container values are persisted in preferences during save operations, see #saving(ISaveContext)
0609: }
0610:
0611: /*
0612: * The given project is being removed. Remove all containers for this project from the cache.
0613: */
0614: public synchronized void containerRemove(IJavaProject project) {
0615: Map initializations = (Map) this .containerInitializationInProgress
0616: .get();
0617: if (initializations != null) {
0618: initializations.remove(project);
0619: }
0620: this .containers.remove(project);
0621: }
0622:
0623: public boolean containerPutIfInitializingWithSameEntries(
0624: IPath containerPath, IJavaProject[] projects,
0625: IClasspathContainer[] respectiveContainers) {
0626: int projectLength = projects.length;
0627: if (projectLength != 1)
0628: return false;
0629: final IClasspathContainer container = respectiveContainers[0];
0630: IJavaProject project = projects[0];
0631: // optimize only if initializing, otherwise we are in a regular setContainer(...) call
0632: if (!containerIsInitializationInProgress(project, containerPath))
0633: return false;
0634: IClasspathContainer previousContainer = containerGetDefaultToPreviousSession(
0635: project, containerPath);
0636: if (container == null) {
0637: if (previousContainer == null) {
0638: containerPut(project, containerPath, null);
0639: return true;
0640: }
0641: return false;
0642: }
0643: final IClasspathEntry[] newEntries = container
0644: .getClasspathEntries();
0645: if (previousContainer == null)
0646: if (newEntries.length == 0) {
0647: containerPut(project, containerPath, container);
0648: return true;
0649: } else {
0650: if (CP_RESOLVE_VERBOSE)
0651: verbose_missbehaving_container(containerPath,
0652: projects, respectiveContainers, container,
0653: newEntries, null/*no old entries*/);
0654: return false;
0655: }
0656: final IClasspathEntry[] oldEntries = previousContainer
0657: .getClasspathEntries();
0658: if (oldEntries.length != newEntries.length) {
0659: if (CP_RESOLVE_VERBOSE)
0660: verbose_missbehaving_container(containerPath, projects,
0661: respectiveContainers, container, newEntries,
0662: oldEntries);
0663: return false;
0664: }
0665: for (int i = 0, length = newEntries.length; i < length; i++) {
0666: if (newEntries[i] == null) {
0667: if (CP_RESOLVE_VERBOSE)
0668: verbose_missbehaving_container(project,
0669: containerPath, newEntries);
0670: return false;
0671: }
0672: if (!newEntries[i].equals(oldEntries[i])) {
0673: if (CP_RESOLVE_VERBOSE)
0674: verbose_missbehaving_container(containerPath,
0675: projects, respectiveContainers, container,
0676: newEntries, oldEntries);
0677: return false;
0678: }
0679: }
0680: containerPut(project, containerPath, container);
0681: return true;
0682: }
0683:
0684: private void verbose_missbehaving_container(IPath containerPath,
0685: IJavaProject[] projects,
0686: IClasspathContainer[] respectiveContainers,
0687: final IClasspathContainer container,
0688: final IClasspathEntry[] newEntries,
0689: final IClasspathEntry[] oldEntries) {
0690: Util
0691: .verbose("CPContainer SET - missbehaving container\n" + //$NON-NLS-1$
0692: " container path: "
0693: + containerPath
0694: + '\n'
0695: + //$NON-NLS-1$
0696: " projects: {"
0697: + //$NON-NLS-1$
0698: org.eclipse.jdt.internal.compiler.util.Util
0699: .toString(
0700: projects,
0701: new org.eclipse.jdt.internal.compiler.util.Util.Displayable() {
0702: public String displayString(
0703: Object o) {
0704: return ((IJavaProject) o)
0705: .getElementName();
0706: }
0707: })
0708: + "}\n values on previous session: {\n" + //$NON-NLS-1$
0709: org.eclipse.jdt.internal.compiler.util.Util
0710: .toString(
0711: respectiveContainers,
0712: new org.eclipse.jdt.internal.compiler.util.Util.Displayable() {
0713: public String displayString(
0714: Object o) {
0715: StringBuffer buffer = new StringBuffer(
0716: " "); //$NON-NLS-1$
0717: if (o == null) {
0718: buffer
0719: .append("<null>"); //$NON-NLS-1$
0720: return buffer
0721: .toString();
0722: }
0723: buffer
0724: .append(container
0725: .getDescription());
0726: buffer.append(" {\n"); //$NON-NLS-1$
0727: if (oldEntries == null) {
0728: buffer
0729: .append(" "); //$NON-NLS-1$
0730: buffer
0731: .append("<null>\n"); //$NON-NLS-1$
0732: } else {
0733: for (int j = 0; j < oldEntries.length; j++) {
0734: buffer
0735: .append(" "); //$NON-NLS-1$
0736: buffer
0737: .append(oldEntries[j]);
0738: buffer
0739: .append('\n');
0740: }
0741: }
0742: buffer.append(" }"); //$NON-NLS-1$
0743: return buffer
0744: .toString();
0745: }
0746: })
0747: + "}\n new values: {\n" + //$NON-NLS-1$
0748: org.eclipse.jdt.internal.compiler.util.Util
0749: .toString(
0750: respectiveContainers,
0751: new org.eclipse.jdt.internal.compiler.util.Util.Displayable() {
0752: public String displayString(
0753: Object o) {
0754: StringBuffer buffer = new StringBuffer(
0755: " "); //$NON-NLS-1$
0756: if (o == null) {
0757: buffer
0758: .append("<null>"); //$NON-NLS-1$
0759: return buffer
0760: .toString();
0761: }
0762: buffer
0763: .append(container
0764: .getDescription());
0765: buffer.append(" {\n"); //$NON-NLS-1$
0766: for (int j = 0; j < newEntries.length; j++) {
0767: buffer
0768: .append(" "); //$NON-NLS-1$
0769: buffer
0770: .append(newEntries[j]);
0771: buffer.append('\n');
0772: }
0773: buffer.append(" }"); //$NON-NLS-1$
0774: return buffer
0775: .toString();
0776: }
0777: }) + "\n }"); //$NON-NLS-1$
0778: }
0779:
0780: void verbose_missbehaving_container(IJavaProject project,
0781: IPath containerPath, IClasspathEntry[] classpathEntries) {
0782: Util
0783: .verbose("CPContainer GET - missbehaving container (returning null classpath entry)\n" + //$NON-NLS-1$
0784: " project: "
0785: + project.getElementName()
0786: + '\n'
0787: + //$NON-NLS-1$
0788: " container path: "
0789: + containerPath
0790: + '\n'
0791: + //$NON-NLS-1$
0792: " classpath entries: {\n"
0793: + //$NON-NLS-1$
0794: org.eclipse.jdt.internal.compiler.util.Util
0795: .toString(
0796: classpathEntries,
0797: new org.eclipse.jdt.internal.compiler.util.Util.Displayable() {
0798: public String displayString(
0799: Object o) {
0800: StringBuffer buffer = new StringBuffer(
0801: " "); //$NON-NLS-1$
0802: if (o == null) {
0803: buffer
0804: .append("<null>"); //$NON-NLS-1$
0805: return buffer
0806: .toString();
0807: }
0808: buffer.append(o);
0809: return buffer
0810: .toString();
0811: }
0812: }) + "\n }" //$NON-NLS-1$
0813: );
0814: }
0815:
0816: private void containerRemoveInitializationInProgress(
0817: IJavaProject project, IPath containerPath) {
0818: Map initializations = (Map) this .containerInitializationInProgress
0819: .get();
0820: if (initializations == null)
0821: return;
0822: HashSet projectInitializations = (HashSet) initializations
0823: .get(project);
0824: if (projectInitializations == null)
0825: return;
0826: projectInitializations.remove(containerPath);
0827: if (projectInitializations.size() == 0)
0828: initializations.remove(project);
0829: if (initializations.size() == 0)
0830: this .containerInitializationInProgress.set(null);
0831: }
0832:
0833: private synchronized void containersReset(String[] containerIDs) {
0834: for (int i = 0; i < containerIDs.length; i++) {
0835: String containerID = containerIDs[i];
0836: Iterator projectIterator = this .containers.values()
0837: .iterator();
0838: while (projectIterator.hasNext()) {
0839: Map projectContainers = (Map) projectIterator.next();
0840: if (projectContainers != null) {
0841: Iterator containerIterator = projectContainers
0842: .keySet().iterator();
0843: while (containerIterator.hasNext()) {
0844: IPath containerPath = (IPath) containerIterator
0845: .next();
0846: if (containerPath.segment(0)
0847: .equals(containerID)) { // registered container
0848: projectContainers.put(containerPath, null); // reset container value, but leave entry in Map
0849: }
0850: }
0851: }
0852: }
0853: }
0854: }
0855:
0856: /**
0857: * Returns the Java element corresponding to the given resource, or
0858: * <code>null</code> if unable to associate the given resource
0859: * with a Java element.
0860: * <p>
0861: * The resource must be one of:<ul>
0862: * <li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
0863: * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
0864: * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
0865: * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
0866: * <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
0867: * or <code>IPackageFragment</code></li>
0868: * <li>the workspace root resource - the element returned is the <code>IJavaModel</code></li>
0869: * </ul>
0870: * <p>
0871: * Creating a Java element has the side effect of creating and opening all of the
0872: * element's parents if they are not yet open.
0873: */
0874: public static IJavaElement create(IResource resource,
0875: IJavaProject project) {
0876: if (resource == null) {
0877: return null;
0878: }
0879: int type = resource.getType();
0880: switch (type) {
0881: case IResource.PROJECT:
0882: return JavaCore.create((IProject) resource);
0883: case IResource.FILE:
0884: return create((IFile) resource, project);
0885: case IResource.FOLDER:
0886: return create((IFolder) resource, project);
0887: case IResource.ROOT:
0888: return JavaCore.create((IWorkspaceRoot) resource);
0889: default:
0890: return null;
0891: }
0892: }
0893:
0894: /**
0895: * Returns the Java element corresponding to the given file, its project being the given
0896: * project.
0897: * Returns <code>null</code> if unable to associate the given file
0898: * with a Java element.
0899: *
0900: * <p>The file must be one of:<ul>
0901: * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
0902: * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
0903: * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
0904: * </ul>
0905: * <p>
0906: * Creating a Java element has the side effect of creating and opening all of the
0907: * element's parents if they are not yet open.
0908: */
0909: public static IJavaElement create(IFile file, IJavaProject project) {
0910: if (file == null) {
0911: return null;
0912: }
0913: if (project == null) {
0914: project = JavaCore.create(file.getProject());
0915: }
0916:
0917: if (file.getFileExtension() != null) {
0918: String name = file.getName();
0919: if (org.eclipse.jdt.internal.core.util.Util
0920: .isJavaLikeFileName(name))
0921: return createCompilationUnitFrom(file, project);
0922: if (org.eclipse.jdt.internal.compiler.util.Util
0923: .isClassFileName(name))
0924: return createClassFileFrom(file, project);
0925: if (org.eclipse.jdt.internal.compiler.util.Util
0926: .isArchiveFileName(name))
0927: return createJarPackageFragmentRootFrom(file, project);
0928: }
0929: return null;
0930: }
0931:
0932: /**
0933: * Returns the package fragment or package fragment root corresponding to the given folder,
0934: * its parent or great parent being the given project.
0935: * or <code>null</code> if unable to associate the given folder with a Java element.
0936: * <p>
0937: * Note that a package fragment root is returned rather than a default package.
0938: * <p>
0939: * Creating a Java element has the side effect of creating and opening all of the
0940: * element's parents if they are not yet open.
0941: */
0942: public static IJavaElement create(IFolder folder,
0943: IJavaProject project) {
0944: if (folder == null) {
0945: return null;
0946: }
0947: IJavaElement element;
0948: if (project == null) {
0949: project = JavaCore.create(folder.getProject());
0950: element = determineIfOnClasspath(folder, project);
0951: if (element == null) {
0952: // walk all projects and find one that have the given folder on its classpath
0953: IJavaProject[] projects;
0954: try {
0955: projects = JavaModelManager.getJavaModelManager()
0956: .getJavaModel().getJavaProjects();
0957: } catch (JavaModelException e) {
0958: return null;
0959: }
0960: for (int i = 0, length = projects.length; i < length; i++) {
0961: project = projects[i];
0962: element = determineIfOnClasspath(folder, project);
0963: if (element != null)
0964: break;
0965: }
0966: }
0967: } else {
0968: element = determineIfOnClasspath(folder, project);
0969: }
0970: return element;
0971: }
0972:
0973: /**
0974: * Creates and returns a class file element for the given <code>.class</code> file,
0975: * its project being the given project. Returns <code>null</code> if unable
0976: * to recognize the class file.
0977: */
0978: public static IClassFile createClassFileFrom(IFile file,
0979: IJavaProject project) {
0980: if (file == null) {
0981: return null;
0982: }
0983: if (project == null) {
0984: project = JavaCore.create(file.getProject());
0985: }
0986: IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(
0987: file, project);
0988: if (pkg == null) {
0989: // fix for 1FVS7WE
0990: // not on classpath - make the root its folder, and a default package
0991: PackageFragmentRoot root = (PackageFragmentRoot) project
0992: .getPackageFragmentRoot(file.getParent());
0993: pkg = root.getPackageFragment(CharOperation.NO_STRINGS);
0994: }
0995: return pkg.getClassFile(file.getName());
0996: }
0997:
0998: /**
0999: * Creates and returns a compilation unit element for the given <code>.java</code>
1000: * file, its project being the given project. Returns <code>null</code> if unable
1001: * to recognize the compilation unit.
1002: */
1003: public static ICompilationUnit createCompilationUnitFrom(
1004: IFile file, IJavaProject project) {
1005:
1006: if (file == null)
1007: return null;
1008:
1009: if (project == null) {
1010: project = JavaCore.create(file.getProject());
1011: }
1012: IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(
1013: file, project);
1014: if (pkg == null) {
1015: // not on classpath - make the root its folder, and a default package
1016: IPackageFragmentRoot root = project
1017: .getPackageFragmentRoot(file.getParent());
1018: pkg = root
1019: .getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
1020:
1021: if (VERBOSE) {
1022: System.out
1023: .println("WARNING : creating unit element outside classpath (" + Thread.currentThread() + "): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
1024: }
1025: }
1026: return pkg.getCompilationUnit(file.getName());
1027: }
1028:
1029: /**
1030: * Creates and returns a handle for the given JAR file, its project being the given project.
1031: * The Java model associated with the JAR's project may be
1032: * created as a side effect.
1033: * Returns <code>null</code> if unable to create a JAR package fragment root.
1034: * (for example, if the JAR file represents a non-Java resource)
1035: */
1036: public static IPackageFragmentRoot createJarPackageFragmentRootFrom(
1037: IFile file, IJavaProject project) {
1038: if (file == null) {
1039: return null;
1040: }
1041: if (project == null) {
1042: project = JavaCore.create(file.getProject());
1043: }
1044:
1045: // Create a jar package fragment root only if on the classpath
1046: IPath resourcePath = file.getFullPath();
1047: try {
1048: IClasspathEntry entry = ((JavaProject) project)
1049: .getClasspathEntryFor(resourcePath);
1050: if (entry != null) {
1051: return project.getPackageFragmentRoot(file);
1052: }
1053: } catch (JavaModelException e) {
1054: // project doesn't exist: return null
1055: }
1056: return null;
1057: }
1058:
1059: /**
1060: * Returns the package fragment root represented by the resource, or
1061: * the package fragment the given resource is located in, or <code>null</code>
1062: * if the given resource is not on the classpath of the given project.
1063: */
1064: public static IJavaElement determineIfOnClasspath(
1065: IResource resource, IJavaProject project) {
1066:
1067: IPath resourcePath = resource.getFullPath();
1068: try {
1069: JavaProjectElementInfo projectInfo = (JavaProjectElementInfo) getJavaModelManager()
1070: .getInfo(project);
1071: ProjectCache projectCache = projectInfo == null ? null
1072: : projectInfo.projectCache;
1073: HashtableOfArrayToObject allPkgFragmentsCache = projectCache == null ? null
1074: : projectCache.allPkgFragmentsCache;
1075: IClasspathEntry[] entries = org.eclipse.jdt.internal.core.util.Util
1076: .isJavaLikeFileName(resourcePath.lastSegment()) ? project
1077: .getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path)
1078: : ((JavaProject) project).getResolvedClasspath();
1079:
1080: int length = entries.length;
1081: if (length > 0) {
1082: String sourceLevel = project.getOption(
1083: JavaCore.COMPILER_SOURCE, true);
1084: String complianceLevel = project.getOption(
1085: JavaCore.COMPILER_COMPLIANCE, true);
1086: for (int i = 0; i < length; i++) {
1087: IClasspathEntry entry = entries[i];
1088: if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
1089: continue;
1090: IPath rootPath = entry.getPath();
1091: if (rootPath.equals(resourcePath)) {
1092: return project.getPackageFragmentRoot(resource);
1093: } else if (rootPath.isPrefixOf(resourcePath)) {
1094: // allow creation of package fragment if it contains a .java file that is included
1095: if (!Util.isExcluded(resource,
1096: ((ClasspathEntry) entry)
1097: .fullInclusionPatternChars(),
1098: ((ClasspathEntry) entry)
1099: .fullExclusionPatternChars())) {
1100: // given we have a resource child of the root, it cannot be a JAR pkg root
1101: PackageFragmentRoot root = (PackageFragmentRoot) ((JavaProject) project)
1102: .getFolderPackageFragmentRoot(rootPath);
1103: if (root == null)
1104: return null;
1105: IPath pkgPath = resourcePath
1106: .removeFirstSegments(rootPath
1107: .segmentCount());
1108:
1109: if (resource.getType() == IResource.FILE) {
1110: // if the resource is a file, then remove the last segment which
1111: // is the file name in the package
1112: pkgPath = pkgPath.removeLastSegments(1);
1113: }
1114: String[] pkgName = pkgPath.segments();
1115:
1116: // if package name is in the cache, then it has already been validated
1117: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=133141)
1118: if (allPkgFragmentsCache != null
1119: && allPkgFragmentsCache
1120: .containsKey(pkgName))
1121: return root.getPackageFragment(pkgName);
1122:
1123: if (pkgName.length != 0
1124: && JavaConventions
1125: .validatePackageName(
1126: Util
1127: .packageName(
1128: pkgPath,
1129: sourceLevel,
1130: complianceLevel),
1131: sourceLevel,
1132: complianceLevel)
1133: .getSeverity() == IStatus.ERROR) {
1134: return null;
1135: }
1136: return root.getPackageFragment(pkgName);
1137: }
1138: }
1139: }
1140: }
1141: } catch (JavaModelException npe) {
1142: return null;
1143: }
1144: return null;
1145: }
1146:
1147: /**
1148: * The singleton manager
1149: */
1150: private static JavaModelManager MANAGER = new JavaModelManager();
1151:
1152: /**
1153: * Infos cache.
1154: */
1155: private JavaModelCache cache;
1156:
1157: /*
1158: * Temporary cache of newly opened elements
1159: */
1160: private ThreadLocal temporaryCache = new ThreadLocal();
1161:
1162: /**
1163: * Set of elements which are out of sync with their buffers.
1164: */
1165: protected HashSet elementsOutOfSynchWithBuffers = new HashSet(11);
1166:
1167: /**
1168: * Holds the state used for delta processing.
1169: */
1170: public DeltaProcessingState deltaState = new DeltaProcessingState();
1171:
1172: public IndexManager indexManager = null;
1173:
1174: /**
1175: * Table from IProject to PerProjectInfo.
1176: * NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos
1177: */
1178: protected Map perProjectInfos = new HashMap(5);
1179:
1180: /**
1181: * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo.
1182: * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos
1183: */
1184: protected Map perWorkingCopyInfos = new HashMap(5);
1185:
1186: /**
1187: * A weak set of the known search scopes.
1188: */
1189: protected WeakHashMap searchScopes = new WeakHashMap();
1190:
1191: public static class PerProjectInfo {
1192: private static final int JAVADOC_CACHE_INITIAL_SIZE = 10;
1193:
1194: public IProject project;
1195: public Object savedState;
1196: public boolean triedRead;
1197: public IClasspathEntry[] rawClasspath;
1198: public IJavaModelStatus rawClasspathStatus;
1199: public IClasspathEntry[] resolvedClasspath;
1200: public IJavaModelStatus unresolvedEntryStatus;
1201: public Map rootPathToRawEntries; // reverse map from a package fragment root's path to the raw entry
1202: public Map rootPathToResolvedEntries; // map from a package fragment root's path to the resolved entry
1203: public IPath outputLocation;
1204:
1205: public IEclipsePreferences preferences;
1206: public Hashtable options;
1207: public Hashtable secondaryTypes;
1208: public LRUCache javadocCache;
1209:
1210: public PerProjectInfo(IProject project) {
1211:
1212: this .triedRead = false;
1213: this .savedState = null;
1214: this .project = project;
1215: this .javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
1216: }
1217:
1218: public void rememberExternalLibTimestamps() {
1219: IClasspathEntry[] classpath = this .resolvedClasspath;
1220: if (classpath == null)
1221: return;
1222: IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace()
1223: .getRoot();
1224: Map externalTimeStamps = JavaModelManager
1225: .getJavaModelManager().deltaState
1226: .getExternalLibTimeStamps();
1227: for (int i = 0, length = classpath.length; i < length; i++) {
1228: IClasspathEntry entry = classpath[i];
1229: if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
1230: IPath path = entry.getPath();
1231: if (externalTimeStamps.get(path) == null) {
1232: Object target = JavaModel.getTarget(wRoot,
1233: path, true);
1234: if (target instanceof java.io.File) {
1235: long timestamp = DeltaProcessor
1236: .getTimeStamp((java.io.File) target);
1237: externalTimeStamps.put(path, new Long(
1238: timestamp));
1239: }
1240: }
1241: }
1242: }
1243: }
1244:
1245: public synchronized void resetResolvedClasspath() {
1246: // null out resolved information
1247: setClasspath(this .rawClasspath, this .outputLocation,
1248: this .rawClasspathStatus, null, null, null, null);
1249: }
1250:
1251: public synchronized void setClasspath(
1252: IClasspathEntry[] newRawClasspath,
1253: IPath newOutputLocation,
1254: IJavaModelStatus newRawClasspathStatus,
1255: IClasspathEntry[] newResolvedClasspath,
1256: Map newRootPathToRawEntries,
1257: Map newRootPathToResolvedEntries,
1258: IJavaModelStatus newUnresolvedEntryStatus) {
1259: // remember old info
1260: JavaModelManager manager = JavaModelManager
1261: .getJavaModelManager();
1262: DeltaProcessor deltaProcessor = manager.deltaState
1263: .getDeltaProcessor();
1264: deltaProcessor.addClasspathChange(this .project,
1265: this .rawClasspath, this .outputLocation,
1266: this .resolvedClasspath);
1267:
1268: this .rawClasspath = newRawClasspath;
1269: this .outputLocation = newOutputLocation;
1270: this .rawClasspathStatus = newRawClasspathStatus;
1271: this .resolvedClasspath = newResolvedClasspath;
1272: this .rootPathToRawEntries = newRootPathToRawEntries;
1273: this .rootPathToResolvedEntries = newRootPathToResolvedEntries;
1274: this .unresolvedEntryStatus = newUnresolvedEntryStatus;
1275: this .javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
1276: }
1277:
1278: /*
1279: * Reads the raw classpath and output location from disk, and remember them.
1280: * Return the raw classpath, or JavaProject#INVALID_CLASSPATH if unable to read it.
1281: */
1282: public synchronized IClasspathEntry[] readAndCacheClasspath(
1283: JavaProject javaProject) {
1284: // read file entries and update status
1285: IClasspathEntry[] classpath;
1286: IJavaModelStatus status;
1287: try {
1288: classpath = javaProject
1289: .readFileEntriesWithException(null/*not interested in unknown elements*/);
1290: status = JavaModelStatus.VERIFIED_OK;
1291: } catch (CoreException e) {
1292: classpath = JavaProject.INVALID_CLASSPATH;
1293: status = new JavaModelStatus(
1294: IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1295: Messages
1296: .bind(
1297: Messages.classpath_cannotReadClasspathFile,
1298: javaProject.getElementName()));
1299: } catch (IOException e) {
1300: classpath = JavaProject.INVALID_CLASSPATH;
1301: if (Messages.file_badFormat.equals(e.getMessage()))
1302: status = new JavaModelStatus(
1303: IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1304: Messages.bind(
1305: Messages.classpath_xmlFormatError,
1306: javaProject.getElementName(),
1307: Messages.file_badFormat));
1308: else
1309: status = new JavaModelStatus(
1310: IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1311: Messages
1312: .bind(
1313: Messages.classpath_cannotReadClasspathFile,
1314: javaProject
1315: .getElementName()));
1316: } catch (AssertionFailedException e) {
1317: classpath = JavaProject.INVALID_CLASSPATH;
1318: status = new JavaModelStatus(
1319: IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1320: Messages
1321: .bind(
1322: Messages.classpath_illegalEntryInClasspathFile,
1323: new String[] {
1324: javaProject
1325: .getElementName(),
1326: e.getMessage() }));
1327: }
1328:
1329: // extract out the output location
1330: IPath output = null;
1331: if (classpath.length > 0) {
1332: IClasspathEntry entry = classpath[classpath.length - 1];
1333: if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1334: output = entry.getPath();
1335: IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
1336: System
1337: .arraycopy(classpath, 0, copy, 0,
1338: copy.length);
1339: classpath = copy;
1340: }
1341: }
1342:
1343: // store new raw classpath, new output and new status, and null out resolved info
1344: setClasspath(classpath, output, status, null, null, null,
1345: null);
1346:
1347: return classpath;
1348: }
1349:
1350: public String toString() {
1351: StringBuffer buffer = new StringBuffer();
1352: buffer.append("Info for "); //$NON-NLS-1$
1353: buffer.append(this .project.getFullPath());
1354: buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
1355: if (this .rawClasspath == null) {
1356: buffer.append(" <null>\n"); //$NON-NLS-1$
1357: } else {
1358: for (int i = 0, length = this .rawClasspath.length; i < length; i++) {
1359: buffer.append(" "); //$NON-NLS-1$
1360: buffer.append(this .rawClasspath[i]);
1361: buffer.append('\n');
1362: }
1363: }
1364: buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
1365: IClasspathEntry[] resolvedCP = this .resolvedClasspath;
1366: if (resolvedCP == null) {
1367: buffer.append(" <null>\n"); //$NON-NLS-1$
1368: } else {
1369: for (int i = 0, length = resolvedCP.length; i < length; i++) {
1370: buffer.append(" "); //$NON-NLS-1$
1371: buffer.append(resolvedCP[i]);
1372: buffer.append('\n');
1373: }
1374: }
1375: buffer.append("Output location:\n "); //$NON-NLS-1$
1376: if (this .outputLocation == null) {
1377: buffer.append("<null>"); //$NON-NLS-1$
1378: } else {
1379: buffer.append(this .outputLocation);
1380: }
1381: return buffer.toString();
1382: }
1383: }
1384:
1385: public static class PerWorkingCopyInfo implements IProblemRequestor {
1386: int useCount = 0;
1387: IProblemRequestor problemRequestor;
1388: CompilationUnit workingCopy;
1389:
1390: public PerWorkingCopyInfo(CompilationUnit workingCopy,
1391: IProblemRequestor problemRequestor) {
1392: this .workingCopy = workingCopy;
1393: this .problemRequestor = problemRequestor;
1394: }
1395:
1396: public void acceptProblem(IProblem problem) {
1397: IProblemRequestor requestor = getProblemRequestor();
1398: if (requestor == null)
1399: return;
1400: requestor.acceptProblem(problem);
1401: }
1402:
1403: public void beginReporting() {
1404: IProblemRequestor requestor = getProblemRequestor();
1405: if (requestor == null)
1406: return;
1407: requestor.beginReporting();
1408: }
1409:
1410: public void endReporting() {
1411: IProblemRequestor requestor = getProblemRequestor();
1412: if (requestor == null)
1413: return;
1414: requestor.endReporting();
1415: }
1416:
1417: public IProblemRequestor getProblemRequestor() {
1418: if (this .problemRequestor == null
1419: && this .workingCopy.owner != null) {
1420: return this .workingCopy.owner
1421: .getProblemRequestor(this .workingCopy);
1422: }
1423: return this .problemRequestor;
1424: }
1425:
1426: public ICompilationUnit getWorkingCopy() {
1427: return this .workingCopy;
1428: }
1429:
1430: public boolean isActive() {
1431: IProblemRequestor requestor = getProblemRequestor();
1432: return requestor != null && requestor.isActive();
1433: }
1434:
1435: public String toString() {
1436: StringBuffer buffer = new StringBuffer();
1437: buffer.append("Info for "); //$NON-NLS-1$
1438: buffer.append(((JavaElement) this .workingCopy)
1439: .toStringWithAncestors());
1440: buffer.append("\nUse count = "); //$NON-NLS-1$
1441: buffer.append(this .useCount);
1442: buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$
1443: buffer.append(this .problemRequestor);
1444: if (this .problemRequestor == null) {
1445: IProblemRequestor requestor = getProblemRequestor();
1446: buffer.append("\nOwner problem requestor:\n "); //$NON-NLS-1$
1447: buffer.append(requestor);
1448: }
1449: return buffer.toString();
1450: }
1451: }
1452:
1453: public static boolean VERBOSE = false;
1454: public static boolean CP_RESOLVE_VERBOSE = false;
1455: public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false;
1456: public static boolean ZIP_ACCESS_VERBOSE = false;
1457:
1458: /**
1459: * A cache of opened zip files per thread.
1460: * (for a given thread, the object value is a HashMap from IPath to java.io.ZipFile)
1461: */
1462: private ThreadLocal zipFiles = new ThreadLocal();
1463:
1464: private UserLibraryManager userLibraryManager;
1465:
1466: /**
1467: * Update the classpath variable cache
1468: */
1469: public static class EclipsePreferencesListener implements
1470: IEclipsePreferences.IPreferenceChangeListener {
1471: /**
1472: * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
1473: */
1474: public void preferenceChange(
1475: IEclipsePreferences.PreferenceChangeEvent event) {
1476: String propertyName = event.getKey();
1477: if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
1478: String varName = propertyName
1479: .substring(CP_VARIABLE_PREFERENCES_PREFIX
1480: .length());
1481: JavaModelManager manager = getJavaModelManager();
1482: if (manager.variablesWithInitializer.contains(varName)) {
1483: // revert preference value as we will not apply it to JavaCore classpath variable
1484: String oldValue = (String) event.getOldValue();
1485: if (oldValue == null) {
1486: // unexpected old value => remove variable from set
1487: manager.variablesWithInitializer
1488: .remove(varName);
1489: } else {
1490: manager.getInstancePreferences().put(varName,
1491: oldValue);
1492: }
1493: } else {
1494: String newValue = (String) event.getNewValue();
1495: IPath newPath;
1496: if (newValue != null
1497: && !(newValue = newValue.trim())
1498: .equals(CP_ENTRY_IGNORE)) {
1499: newPath = new Path(newValue);
1500: } else {
1501: newPath = null;
1502: }
1503: try {
1504: SetVariablesOperation operation = new SetVariablesOperation(
1505: new String[] { varName },
1506: new IPath[] { newPath }, false/*don't update preferences*/);
1507: operation
1508: .runOperation(null/*no progress available*/);
1509: } catch (JavaModelException e) {
1510: Util
1511: .log(
1512: e,
1513: "Could not set classpath variable " + varName + " to " + newPath); //$NON-NLS-1$ //$NON-NLS-2$
1514: }
1515: }
1516: } else if (propertyName
1517: .startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
1518: recreatePersistedContainer(propertyName, (String) event
1519: .getNewValue(), false);
1520: } else if (propertyName
1521: .equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER)
1522: || propertyName
1523: .equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER)
1524: || propertyName
1525: .equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE)
1526: || propertyName
1527: .equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER)
1528: || propertyName
1529: .equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH)
1530: || propertyName
1531: .equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS)
1532: || propertyName
1533: .equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS)
1534: || propertyName
1535: .equals(JavaCore.CORE_INCOMPLETE_CLASSPATH)
1536: || propertyName
1537: .equals(JavaCore.CORE_CIRCULAR_CLASSPATH)
1538: || propertyName
1539: .equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) {
1540: JavaModelManager manager = JavaModelManager
1541: .getJavaModelManager();
1542: IJavaModel model = manager.getJavaModel();
1543: IJavaProject[] projects;
1544: try {
1545: projects = model.getJavaProjects();
1546: for (int i = 0, pl = projects.length; i < pl; i++) {
1547: JavaProject javaProject = (JavaProject) projects[i];
1548: manager.deltaState
1549: .addClasspathValidation(javaProject);
1550: try {
1551: // need to touch the project to force validation by DeltaProcessor
1552: javaProject.getProject().touch(null);
1553: } catch (CoreException e) {
1554: // skip
1555: }
1556: }
1557: } catch (JavaModelException e) {
1558: // skip
1559: }
1560: } else if (propertyName
1561: .startsWith(CP_USERLIBRARY_PREFERENCES_PREFIX)) {
1562: String libName = propertyName
1563: .substring(CP_USERLIBRARY_PREFERENCES_PREFIX
1564: .length());
1565: UserLibraryManager manager = JavaModelManager
1566: .getUserLibraryManager();
1567: manager.updateUserLibrary(libName, (String) event
1568: .getNewValue());
1569: }
1570: }
1571: }
1572:
1573: /**
1574: * Listener on eclipse preferences changes.
1575: */
1576: EclipsePreferencesListener instancePreferencesListener = new EclipsePreferencesListener();
1577: /**
1578: * Listener on eclipse preferences default/instance node changes.
1579: */
1580: IEclipsePreferences.INodeChangeListener instanceNodeListener = new IEclipsePreferences.INodeChangeListener() {
1581: public void added(IEclipsePreferences.NodeChangeEvent event) {
1582: // do nothing
1583: }
1584:
1585: public void removed(IEclipsePreferences.NodeChangeEvent event) {
1586: if (event.getChild() == preferencesLookup[PREF_INSTANCE]) {
1587: preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope())
1588: .getNode(JavaCore.PLUGIN_ID);
1589: preferencesLookup[PREF_INSTANCE]
1590: .addPreferenceChangeListener(new EclipsePreferencesListener());
1591: }
1592: }
1593: };
1594: IEclipsePreferences.INodeChangeListener defaultNodeListener = new IEclipsePreferences.INodeChangeListener() {
1595: public void added(IEclipsePreferences.NodeChangeEvent event) {
1596: // do nothing
1597: }
1598:
1599: public void removed(IEclipsePreferences.NodeChangeEvent event) {
1600: if (event.getChild() == preferencesLookup[PREF_DEFAULT]) {
1601: preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope())
1602: .getNode(JavaCore.PLUGIN_ID);
1603: }
1604: }
1605: };
1606: /**
1607: * Listener on properties changes.
1608: */
1609: Preferences.IPropertyChangeListener propertyListener = new Preferences.IPropertyChangeListener() {
1610: public void propertyChange(Preferences.PropertyChangeEvent event) {
1611: JavaModelManager.this .optionsCache = null;
1612: }
1613: };
1614:
1615: /**
1616: * Constructs a new JavaModelManager
1617: */
1618: private JavaModelManager() {
1619: // singleton: prevent others from creating a new instance
1620: if (Platform.isRunning())
1621: this .indexManager = new IndexManager();
1622: }
1623:
1624: /**
1625: * @deprecated
1626: */
1627: private void addDeprecatedOptions(Hashtable options) {
1628: options
1629: .put(JavaCore.COMPILER_PB_INVALID_IMPORT,
1630: JavaCore.ERROR);
1631: options.put(JavaCore.COMPILER_PB_UNREACHABLE_CODE,
1632: JavaCore.ERROR);
1633: }
1634:
1635: /**
1636: * Starts caching ZipFiles.
1637: * Ignores if there are already clients.
1638: */
1639: public void cacheZipFiles() {
1640: if (this .zipFiles.get() != null)
1641: return;
1642: this .zipFiles.set(new HashMap());
1643: }
1644:
1645: public void closeZipFile(ZipFile zipFile) {
1646: if (zipFile == null)
1647: return;
1648: if (this .zipFiles.get() != null) {
1649: return; // zip file will be closed by call to flushZipFiles
1650: }
1651: try {
1652: if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1653: System.out
1654: .println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$
1655: }
1656: zipFile.close();
1657: } catch (IOException e) {
1658: // problem occured closing zip file: cannot do much more
1659: }
1660: }
1661:
1662: /**
1663: * Configure the plugin with respect to option settings defined in ".options" file
1664: */
1665: public void configurePluginDebugOptions() {
1666: if (JavaCore.getPlugin().isDebugging()) {
1667: String option = Platform
1668: .getDebugOption(BUFFER_MANAGER_DEBUG);
1669: if (option != null)
1670: BufferManager.VERBOSE = option.equalsIgnoreCase(TRUE);
1671:
1672: option = Platform.getDebugOption(BUILDER_DEBUG);
1673: if (option != null)
1674: JavaBuilder.DEBUG = option.equalsIgnoreCase(TRUE);
1675:
1676: option = Platform.getDebugOption(COMPILER_DEBUG);
1677: if (option != null)
1678: Compiler.DEBUG = option.equalsIgnoreCase(TRUE);
1679:
1680: option = Platform.getDebugOption(COMPLETION_DEBUG);
1681: if (option != null)
1682: CompletionEngine.DEBUG = option.equalsIgnoreCase(TRUE);
1683:
1684: option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
1685: if (option != null)
1686: JavaModelManager.CP_RESOLVE_VERBOSE = option
1687: .equalsIgnoreCase(TRUE);
1688:
1689: option = Platform.getDebugOption(CP_RESOLVE_ADVANCED_DEBUG);
1690: if (option != null)
1691: JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED = option
1692: .equalsIgnoreCase(TRUE);
1693:
1694: option = Platform.getDebugOption(DELTA_DEBUG);
1695: if (option != null)
1696: DeltaProcessor.DEBUG = option.equalsIgnoreCase(TRUE);
1697:
1698: option = Platform.getDebugOption(DELTA_DEBUG_VERBOSE);
1699: if (option != null)
1700: DeltaProcessor.VERBOSE = option.equalsIgnoreCase(TRUE);
1701:
1702: option = Platform.getDebugOption(HIERARCHY_DEBUG);
1703: if (option != null)
1704: TypeHierarchy.DEBUG = option.equalsIgnoreCase(TRUE);
1705:
1706: option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
1707: if (option != null)
1708: JobManager.VERBOSE = option.equalsIgnoreCase(TRUE);
1709:
1710: option = Platform.getDebugOption(JAVAMODEL_DEBUG);
1711: if (option != null)
1712: JavaModelManager.VERBOSE = option
1713: .equalsIgnoreCase(TRUE);
1714:
1715: option = Platform.getDebugOption(JAVAMODELCACHE_DEBUG);
1716: if (option != null)
1717: JavaModelCache.VERBOSE = option.equalsIgnoreCase(TRUE);
1718:
1719: option = Platform.getDebugOption(POST_ACTION_DEBUG);
1720: if (option != null)
1721: JavaModelOperation.POST_ACTION_VERBOSE = option
1722: .equalsIgnoreCase(TRUE);
1723:
1724: option = Platform.getDebugOption(RESOLUTION_DEBUG);
1725: if (option != null)
1726: NameLookup.VERBOSE = option.equalsIgnoreCase(TRUE);
1727:
1728: option = Platform.getDebugOption(SEARCH_DEBUG);
1729: if (option != null)
1730: BasicSearchEngine.VERBOSE = option
1731: .equalsIgnoreCase(TRUE);
1732:
1733: option = Platform.getDebugOption(SELECTION_DEBUG);
1734: if (option != null)
1735: SelectionEngine.DEBUG = option.equalsIgnoreCase(TRUE);
1736:
1737: option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
1738: if (option != null)
1739: JavaModelManager.ZIP_ACCESS_VERBOSE = option
1740: .equalsIgnoreCase(TRUE);
1741:
1742: option = Platform
1743: .getDebugOption(SOURCE_MAPPER_DEBUG_VERBOSE);
1744: if (option != null)
1745: SourceMapper.VERBOSE = option.equalsIgnoreCase(TRUE);
1746: }
1747:
1748: // configure performance options
1749: if (PerformanceStats.ENABLED) {
1750: CompletionEngine.PERF = PerformanceStats
1751: .isEnabled(COMPLETION_PERF);
1752: SelectionEngine.PERF = PerformanceStats
1753: .isEnabled(SELECTION_PERF);
1754: DeltaProcessor.PERF = PerformanceStats
1755: .isEnabled(DELTA_LISTENER_PERF);
1756: JavaModelManager.PERF_VARIABLE_INITIALIZER = PerformanceStats
1757: .isEnabled(VARIABLE_INITIALIZER_PERF);
1758: JavaModelManager.PERF_CONTAINER_INITIALIZER = PerformanceStats
1759: .isEnabled(CONTAINER_INITIALIZER_PERF);
1760: ReconcileWorkingCopyOperation.PERF = PerformanceStats
1761: .isEnabled(RECONCILE_PERF);
1762: }
1763: }
1764:
1765: /*
1766: * Return a new Java 6 annotation processor manager. The manager will need to
1767: * be configured before it can be used. Returns null if a manager cannot be
1768: * created, ie if the current VM does not support Java 6 annotation processing.
1769: */
1770: public AbstractAnnotationProcessorManager createAnnotationProcessorManager() {
1771: synchronized (this ) {
1772: if (this .annotationProcessorManagerFactory == null) {
1773: IExtensionPoint extension = Platform
1774: .getExtensionRegistry()
1775: .getExtensionPoint(JavaCore.PLUGIN_ID,
1776: ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID);
1777: if (extension == null)
1778: return null;
1779: IExtension[] extensions = extension.getExtensions();
1780: for (int i = 0; i < extensions.length; i++) {
1781: if (i > 0) {
1782: Util
1783: .log(
1784: null,
1785: "An annotation processor manager is already registered: ignoring " + extensions[i].getUniqueIdentifier()); //$NON-NLS-1$
1786: break;
1787: }
1788: IConfigurationElement[] configElements = extensions[i]
1789: .getConfigurationElements();
1790: for (int j = 0; j < configElements.length; j++) {
1791: final IConfigurationElement configElement = configElements[j];
1792: if ("annotationProcessorManager".equals(configElement.getName())) { //$NON-NLS-1$
1793: this .annotationProcessorManagerFactory = configElement;
1794: break;
1795: }
1796: }
1797: }
1798: }
1799: }
1800:
1801: if (this .annotationProcessorManagerFactory == null) {
1802: return null;
1803: }
1804: final AbstractAnnotationProcessorManager[] apm = new AbstractAnnotationProcessorManager[1];
1805: apm[0] = null;
1806: final IConfigurationElement factory = this .annotationProcessorManagerFactory;
1807: SafeRunner.run(new ISafeRunnable() {
1808: public void handleException(Throwable exception) {
1809: Util
1810: .log(exception,
1811: "Exception occurred while loading annotation processor manager"); //$NON-NLS-1$
1812: }
1813:
1814: public void run() throws Exception {
1815: Object executableExtension = factory
1816: .createExecutableExtension("class"); //$NON-NLS-1$
1817: if (executableExtension instanceof AbstractAnnotationProcessorManager) {
1818: apm[0] = (AbstractAnnotationProcessorManager) executableExtension;
1819: }
1820: }
1821: });
1822: return apm[0];
1823: }
1824:
1825: /*
1826: * Discards the per working copy info for the given working copy (making it a compilation unit)
1827: * if its use count was 1. Otherwise, just decrement the use count.
1828: * If the working copy is primary, computes the delta between its state and the original compilation unit
1829: * and register it.
1830: * Close the working copy, its buffer and remove it from the shared working copy table.
1831: * Ignore if no per-working copy info existed.
1832: * NOTE: it must NOT be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667.
1833: * Returns the new use count (or -1 if it didn't exist).
1834: */
1835: public int discardPerWorkingCopyInfo(CompilationUnit workingCopy)
1836: throws JavaModelException {
1837:
1838: // create the delta builder (this remembers the current content of the working copy)
1839: // outside the perWorkingCopyInfos lock (see bug 50667)
1840: JavaElementDeltaBuilder deltaBuilder = null;
1841: if (workingCopy.isPrimary() && workingCopy.hasUnsavedChanges()) {
1842: deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
1843: }
1844: PerWorkingCopyInfo info = null;
1845: synchronized (this .perWorkingCopyInfos) {
1846: WorkingCopyOwner owner = workingCopy.owner;
1847: Map workingCopyToInfos = (Map) this .perWorkingCopyInfos
1848: .get(owner);
1849: if (workingCopyToInfos == null)
1850: return -1;
1851:
1852: info = (PerWorkingCopyInfo) workingCopyToInfos
1853: .get(workingCopy);
1854: if (info == null)
1855: return -1;
1856:
1857: if (--info.useCount == 0) {
1858: // remove per working copy info
1859: workingCopyToInfos.remove(workingCopy);
1860: if (workingCopyToInfos.isEmpty()) {
1861: this .perWorkingCopyInfos.remove(owner);
1862: }
1863: }
1864: }
1865: if (info.useCount == 0) { // info cannot be null here (check was done above)
1866: // remove infos + close buffer (since no longer working copy)
1867: // outside the perWorkingCopyInfos lock (see bug 50667)
1868: removeInfoAndChildren(workingCopy);
1869: workingCopy.closeBuffer();
1870:
1871: // compute the delta if needed and register it if there are changes
1872: if (deltaBuilder != null) {
1873: deltaBuilder.buildDeltas();
1874: if (deltaBuilder.delta != null) {
1875: getDeltaProcessor().registerJavaModelDelta(
1876: deltaBuilder.delta);
1877: }
1878: }
1879: }
1880: return info.useCount;
1881: }
1882:
1883: /**
1884: * @see ISaveParticipant
1885: */
1886: public void doneSaving(ISaveContext context) {
1887: // nothing to do for jdt.core
1888: }
1889:
1890: /**
1891: * Flushes ZipFiles cache if there are no more clients.
1892: */
1893: public void flushZipFiles() {
1894: Thread currentThread = Thread.currentThread();
1895: HashMap map = (HashMap) this .zipFiles.get();
1896: if (map == null)
1897: return;
1898: this .zipFiles.set(null);
1899: Iterator iterator = map.values().iterator();
1900: while (iterator.hasNext()) {
1901: try {
1902: ZipFile zipFile = (ZipFile) iterator.next();
1903: if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1904: System.out
1905: .println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$
1906: }
1907: zipFile.close();
1908: } catch (IOException e) {
1909: // problem occured closing zip file: cannot do much more
1910: }
1911: }
1912: }
1913:
1914: private synchronized boolean batchContainerInitializations() {
1915: if (this .batchContainerInitializations) {
1916: this .batchContainerInitializations = false;
1917: return true;
1918: }
1919: return false;
1920: }
1921:
1922: public IClasspathContainer getClasspathContainer(
1923: final IPath containerPath, final IJavaProject project)
1924: throws JavaModelException {
1925:
1926: IClasspathContainer container = containerGet(project,
1927: containerPath);
1928:
1929: if (container == null) {
1930: if (batchContainerInitializations()) {
1931: // avoid deep recursion while initializaing container on workspace restart
1932: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=60437)
1933: container = initializeAllContainers(project,
1934: containerPath);
1935: } else {
1936: container = initializeContainer(project, containerPath);
1937: }
1938: }
1939: return container;
1940: }
1941:
1942: public DeltaProcessor getDeltaProcessor() {
1943: return this .deltaState.getDeltaProcessor();
1944: }
1945:
1946: public static DeltaProcessingState getDeltaState() {
1947: return MANAGER.deltaState;
1948: }
1949:
1950: /**
1951: * Returns the set of elements which are out of synch with their buffers.
1952: */
1953: protected HashSet getElementsOutOfSynchWithBuffers() {
1954: return this .elementsOutOfSynchWithBuffers;
1955: }
1956:
1957: public static IndexManager getIndexManager() {
1958: return MANAGER.indexManager;
1959: }
1960:
1961: /**
1962: * Returns the info for the element.
1963: */
1964: public synchronized Object getInfo(IJavaElement element) {
1965: HashMap tempCache = (HashMap) this .temporaryCache.get();
1966: if (tempCache != null) {
1967: Object result = tempCache.get(element);
1968: if (result != null) {
1969: return result;
1970: }
1971: }
1972: return this .cache.getInfo(element);
1973: }
1974:
1975: /**
1976: * Get workspace eclipse preference for JavaCore plug-in.
1977: */
1978: public IEclipsePreferences getInstancePreferences() {
1979: return preferencesLookup[PREF_INSTANCE];
1980: }
1981:
1982: // If modified, also modify the method getDefaultOptionsNoInitialization()
1983: public Hashtable getDefaultOptions() {
1984:
1985: Hashtable defaultOptions = new Hashtable(10);
1986:
1987: // see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings
1988: // If modified, also modify the method getDefaultOptionsNoInitialization()
1989: IEclipsePreferences defaultPreferences = getDefaultPreferences();
1990:
1991: // initialize preferences to their default
1992: Iterator iterator = this .optionNames.iterator();
1993: while (iterator.hasNext()) {
1994: String propertyName = (String) iterator.next();
1995: String value = defaultPreferences.get(propertyName, null);
1996: if (value != null)
1997: defaultOptions.put(propertyName, value);
1998: }
1999: // get encoding through resource plugin
2000: defaultOptions.put(JavaCore.CORE_ENCODING, JavaCore
2001: .getEncoding());
2002: // backward compatibility
2003: addDeprecatedOptions(defaultOptions);
2004:
2005: return defaultOptions;
2006: }
2007:
2008: /**
2009: * Get default eclipse preference for JavaCore plugin.
2010: */
2011: public IEclipsePreferences getDefaultPreferences() {
2012: return preferencesLookup[PREF_DEFAULT];
2013: }
2014:
2015: /**
2016: * Returns the handle to the active Java Model.
2017: */
2018: public final JavaModel getJavaModel() {
2019: return this .javaModel;
2020: }
2021:
2022: /**
2023: * Returns the singleton JavaModelManager
2024: */
2025: public final static JavaModelManager getJavaModelManager() {
2026: return MANAGER;
2027: }
2028:
2029: /**
2030: * Returns the last built state for the given project, or null if there is none.
2031: * Deserializes the state if necessary.
2032: *
2033: * For use by image builder and evaluation support only
2034: */
2035: public Object getLastBuiltState(IProject project,
2036: IProgressMonitor monitor) {
2037: if (!JavaProject.hasJavaNature(project)) {
2038: if (JavaBuilder.DEBUG)
2039: System.out.println(project + " is not a Java project"); //$NON-NLS-1$
2040: return null; // should never be requested on non-Java projects
2041: }
2042: PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/);
2043: if (!info.triedRead) {
2044: info.triedRead = true;
2045: try {
2046: if (monitor != null)
2047: monitor.subTask(Messages.bind(
2048: Messages.build_readStateProgress, project
2049: .getName()));
2050: info.savedState = readState(project);
2051: } catch (CoreException e) {
2052: e.printStackTrace();
2053: }
2054: }
2055: return info.savedState;
2056: }
2057:
2058: public String getOption(String optionName) {
2059:
2060: if (JavaCore.CORE_ENCODING.equals(optionName)) {
2061: return JavaCore.getEncoding();
2062: }
2063: // backward compatibility
2064: if (isDeprecatedOption(optionName)) {
2065: return JavaCore.ERROR;
2066: }
2067: String propertyName = optionName;
2068: if (this .optionNames.contains(propertyName)) {
2069: IPreferencesService service = Platform
2070: .getPreferencesService();
2071: String value = service.get(optionName, null,
2072: this .preferencesLookup);
2073: return value == null ? null : value.trim();
2074: }
2075: return null;
2076: }
2077:
2078: public Hashtable getOptions() {
2079:
2080: // return cached options if already computed
2081: if (this .optionsCache != null)
2082: return new Hashtable(this .optionsCache);
2083:
2084: if (!Platform.isRunning()) {
2085: return this .optionsCache = getDefaultOptionsNoInitialization();
2086: }
2087: // init
2088: Hashtable options = new Hashtable(10);
2089: IPreferencesService service = Platform.getPreferencesService();
2090:
2091: // set options using preferences service lookup
2092: Iterator iterator = optionNames.iterator();
2093: while (iterator.hasNext()) {
2094: String propertyName = (String) iterator.next();
2095: String propertyValue = service.get(propertyName, null,
2096: this .preferencesLookup);
2097: if (propertyValue != null) {
2098: options.put(propertyName, propertyValue);
2099: }
2100: }
2101:
2102: // get encoding through resource plugin
2103: options.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding());
2104:
2105: // backward compatibility
2106: addDeprecatedOptions(options);
2107:
2108: // store built map in cache
2109: this .optionsCache = new Hashtable(options);
2110:
2111: // return built map
2112: return options;
2113: }
2114:
2115: // Do not modify without modifying getDefaultOptions()
2116: private Hashtable getDefaultOptionsNoInitialization() {
2117: Map defaultOptionsMap = new CompilerOptions().getMap(); // compiler defaults
2118:
2119: // Override some compiler defaults
2120: defaultOptionsMap.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR,
2121: JavaCore.GENERATE);
2122: defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL,
2123: JavaCore.PRESERVE);
2124: defaultOptionsMap.put(JavaCore.COMPILER_TASK_TAGS,
2125: JavaCore.DEFAULT_TASK_TAGS);
2126: defaultOptionsMap.put(JavaCore.COMPILER_TASK_PRIORITIES,
2127: JavaCore.DEFAULT_TASK_PRIORITIES);
2128: defaultOptionsMap.put(JavaCore.COMPILER_TASK_CASE_SENSITIVE,
2129: JavaCore.ENABLED);
2130: defaultOptionsMap.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT,
2131: JavaCore.ENABLED);
2132: defaultOptionsMap.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE,
2133: JavaCore.ERROR);
2134:
2135: // Builder settings
2136: defaultOptionsMap.put(
2137: JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$
2138: defaultOptionsMap.put(
2139: JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH,
2140: JavaCore.ABORT);
2141: defaultOptionsMap.put(
2142: JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE,
2143: JavaCore.WARNING);
2144: defaultOptionsMap.put(
2145: JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER,
2146: JavaCore.CLEAN);
2147:
2148: // JavaCore settings
2149: defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER,
2150: JavaCore.IGNORE);
2151: defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH,
2152: JavaCore.ERROR);
2153: defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH,
2154: JavaCore.ERROR);
2155: defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL,
2156: JavaCore.IGNORE);
2157: defaultOptionsMap.put(
2158: JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS,
2159: JavaCore.ENABLED);
2160: defaultOptionsMap
2161: .put(
2162: JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS,
2163: JavaCore.ENABLED);
2164:
2165: // Formatter settings
2166: defaultOptionsMap.putAll(DefaultCodeFormatterConstants
2167: .getEclipseDefaultSettings());
2168:
2169: // CodeAssist settings
2170: defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK,
2171: JavaCore.DISABLED);
2172: defaultOptionsMap.put(JavaCore.CODEASSIST_DEPRECATION_CHECK,
2173: JavaCore.DISABLED);
2174: defaultOptionsMap.put(
2175: JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION,
2176: JavaCore.DISABLED);
2177: defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$
2178: defaultOptionsMap.put(
2179: JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$
2180: defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$
2181: defaultOptionsMap
2182: .put(JavaCore.CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$
2183: defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$
2184: defaultOptionsMap.put(
2185: JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$
2186: defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$
2187: defaultOptionsMap
2188: .put(JavaCore.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$
2189: defaultOptionsMap.put(
2190: JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK,
2191: JavaCore.ENABLED);
2192: defaultOptionsMap.put(
2193: JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK,
2194: JavaCore.DISABLED);
2195: defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH,
2196: JavaCore.ENABLED);
2197: defaultOptionsMap.put(
2198: JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS,
2199: JavaCore.ENABLED);
2200:
2201: // Time out for parameter names
2202: defaultOptionsMap
2203: .put(
2204: JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC,
2205: "50"); //$NON-NLS-1$
2206:
2207: return new Hashtable(defaultOptionsMap);
2208: }
2209:
2210: /*
2211: * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist.
2212: */
2213: public PerProjectInfo getPerProjectInfo(IProject project,
2214: boolean create) {
2215: synchronized (this .perProjectInfos) { // use the perProjectInfo collection as its own lock
2216: PerProjectInfo info = (PerProjectInfo) this .perProjectInfos
2217: .get(project);
2218: if (info == null && create) {
2219: info = new PerProjectInfo(project);
2220: this .perProjectInfos.put(project, info);
2221: }
2222: return info;
2223: }
2224: }
2225:
2226: /*
2227: * Returns the per-project info for the given project.
2228: * If the info doesn't exist, check for the project existence and create the info.
2229: * @throws JavaModelException if the project doesn't exist.
2230: */
2231: public PerProjectInfo getPerProjectInfoCheckExistence(
2232: IProject project) throws JavaModelException {
2233: JavaModelManager.PerProjectInfo info = getPerProjectInfo(
2234: project, false /* don't create info */);
2235: if (info == null) {
2236: if (!JavaProject.hasJavaNature(project)) {
2237: throw ((JavaProject) JavaCore.create(project))
2238: .newNotPresentException();
2239: }
2240: info = getPerProjectInfo(project, true /* create info */);
2241: }
2242: return info;
2243: }
2244:
2245: /*
2246: * Returns the per-working copy info for the given working copy at the given path.
2247: * If it doesn't exist and if create, add a new per-working copy info with the given problem requestor.
2248: * If recordUsage, increment the per-working copy info's use count.
2249: * Returns null if it doesn't exist and not create.
2250: */
2251: public PerWorkingCopyInfo getPerWorkingCopyInfo(
2252: CompilationUnit workingCopy, boolean create,
2253: boolean recordUsage, IProblemRequestor problemRequestor) {
2254: synchronized (this .perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock
2255: WorkingCopyOwner owner = workingCopy.owner;
2256: Map workingCopyToInfos = (Map) this .perWorkingCopyInfos
2257: .get(owner);
2258: if (workingCopyToInfos == null && create) {
2259: workingCopyToInfos = new HashMap();
2260: this .perWorkingCopyInfos.put(owner, workingCopyToInfos);
2261: }
2262:
2263: PerWorkingCopyInfo info = workingCopyToInfos == null ? null
2264: : (PerWorkingCopyInfo) workingCopyToInfos
2265: .get(workingCopy);
2266: if (info == null && create) {
2267: info = new PerWorkingCopyInfo(workingCopy,
2268: problemRequestor);
2269: workingCopyToInfos.put(workingCopy, info);
2270: }
2271: if (info != null && recordUsage)
2272: info.useCount++;
2273: return info;
2274: }
2275: }
2276:
2277: /**
2278: * Returns a persisted container from previous session if any. Note that it is not the original container from previous
2279: * session (i.e. it did not get serialized) but rather a summary of its entries recreated for CP initialization purpose.
2280: * As such it should not be stored into container caches.
2281: */
2282: public IClasspathContainer getPreviousSessionContainer(
2283: IPath containerPath, IJavaProject project) {
2284: Map previousContainerValues = (Map) this .previousSessionContainers
2285: .get(project);
2286: if (previousContainerValues != null) {
2287: IClasspathContainer previousContainer = (IClasspathContainer) previousContainerValues
2288: .get(containerPath);
2289: if (previousContainer != null) {
2290: if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
2291: verbose_reentering_project_container_access(
2292: containerPath, project, previousContainer);
2293: return previousContainer;
2294: }
2295: }
2296: return null; // break cycle if none found
2297: }
2298:
2299: private void verbose_reentering_project_container_access(
2300: IPath containerPath, IJavaProject project,
2301: IClasspathContainer previousContainer) {
2302: StringBuffer buffer = new StringBuffer();
2303: buffer
2304: .append("CPContainer INIT - reentering access to project container during its initialization, will see previous value\n"); //$NON-NLS-1$
2305: buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$
2306: buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$
2307: buffer.append(" previous value: "); //$NON-NLS-1$
2308: buffer.append(previousContainer.getDescription());
2309: buffer.append(" {\n"); //$NON-NLS-1$
2310: IClasspathEntry[] entries = previousContainer
2311: .getClasspathEntries();
2312: if (entries != null) {
2313: for (int j = 0; j < entries.length; j++) {
2314: buffer.append(" "); //$NON-NLS-1$
2315: buffer.append(entries[j]);
2316: buffer.append('\n');
2317: }
2318: }
2319: buffer.append(" }"); //$NON-NLS-1$
2320: Util.verbose(buffer.toString());
2321: new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2322: }
2323:
2324: /**
2325: * Returns a persisted container from previous session if any
2326: */
2327: public IPath getPreviousSessionVariable(String variableName) {
2328: IPath previousPath = (IPath) this .previousSessionVariables
2329: .get(variableName);
2330: if (previousPath != null) {
2331: if (CP_RESOLVE_VERBOSE_ADVANCED)
2332: verbose_reentering_variable_access(variableName,
2333: previousPath);
2334: return previousPath;
2335: }
2336: return null; // break cycle
2337: }
2338:
2339: private void verbose_reentering_variable_access(
2340: String variableName, IPath previousPath) {
2341: Util
2342: .verbose("CPVariable INIT - reentering access to variable during its initialization, will see previous value\n" + //$NON-NLS-1$
2343: " variable: " + variableName + '\n' + //$NON-NLS-1$
2344: " previous value: " + previousPath); //$NON-NLS-1$
2345: new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2346: }
2347:
2348: /**
2349: * Returns the temporary cache for newly opened elements for the current thread.
2350: * Creates it if not already created.
2351: */
2352: public HashMap getTemporaryCache() {
2353: HashMap result = (HashMap) this .temporaryCache.get();
2354: if (result == null) {
2355: result = new HashMap();
2356: this .temporaryCache.set(result);
2357: }
2358: return result;
2359: }
2360:
2361: private File getVariableAndContainersFile() {
2362: return JavaCore.getPlugin().getStateLocation().append(
2363: "variablesAndContainers.dat").toFile(); //$NON-NLS-1$
2364: }
2365:
2366: /**
2367: * Returns the name of the variables for which an CP variable initializer is registered through an extension point
2368: */
2369: public static String[] getRegisteredVariableNames() {
2370:
2371: Plugin jdtCorePlugin = JavaCore.getPlugin();
2372: if (jdtCorePlugin == null)
2373: return null;
2374:
2375: ArrayList variableList = new ArrayList(5);
2376: IExtensionPoint extension = Platform
2377: .getExtensionRegistry()
2378: .getExtensionPoint(
2379: JavaCore.PLUGIN_ID,
2380: JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
2381: if (extension != null) {
2382: IExtension[] extensions = extension.getExtensions();
2383: for (int i = 0; i < extensions.length; i++) {
2384: IConfigurationElement[] configElements = extensions[i]
2385: .getConfigurationElements();
2386: for (int j = 0; j < configElements.length; j++) {
2387: String varAttribute = configElements[j]
2388: .getAttribute("variable"); //$NON-NLS-1$
2389: if (varAttribute != null)
2390: variableList.add(varAttribute);
2391: }
2392: }
2393: }
2394: String[] variableNames = new String[variableList.size()];
2395: variableList.toArray(variableNames);
2396: return variableNames;
2397: }
2398:
2399: /**
2400: * Returns the name of the container IDs for which an CP container initializer is registered through an extension point
2401: */
2402: public static String[] getRegisteredContainerIDs() {
2403:
2404: Plugin jdtCorePlugin = JavaCore.getPlugin();
2405: if (jdtCorePlugin == null)
2406: return null;
2407:
2408: ArrayList containerIDList = new ArrayList(5);
2409: IExtensionPoint extension = Platform
2410: .getExtensionRegistry()
2411: .getExtensionPoint(
2412: JavaCore.PLUGIN_ID,
2413: JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
2414: if (extension != null) {
2415: IExtension[] extensions = extension.getExtensions();
2416: for (int i = 0; i < extensions.length; i++) {
2417: IConfigurationElement[] configElements = extensions[i]
2418: .getConfigurationElements();
2419: for (int j = 0; j < configElements.length; j++) {
2420: String idAttribute = configElements[j]
2421: .getAttribute("id"); //$NON-NLS-1$
2422: if (idAttribute != null)
2423: containerIDList.add(idAttribute);
2424: }
2425: }
2426: }
2427: String[] containerIDs = new String[containerIDList.size()];
2428: containerIDList.toArray(containerIDs);
2429: return containerIDs;
2430: }
2431:
2432: /**
2433: * Returns the File to use for saving and restoring the last built state for the given project.
2434: */
2435: private File getSerializationFile(IProject project) {
2436: if (!project.exists())
2437: return null;
2438: IPath workingLocation = project
2439: .getWorkingLocation(JavaCore.PLUGIN_ID);
2440: return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
2441: }
2442:
2443: public static UserLibraryManager getUserLibraryManager() {
2444: if (MANAGER.userLibraryManager == null) {
2445: UserLibraryManager libraryManager = new UserLibraryManager();
2446: synchronized (MANAGER) {
2447: if (MANAGER.userLibraryManager == null) { // ensure another library manager was not set while creating the instance above
2448: MANAGER.userLibraryManager = libraryManager;
2449: }
2450: }
2451: }
2452: return MANAGER.userLibraryManager;
2453: }
2454:
2455: /*
2456: * Returns all the working copies which have the given owner.
2457: * Adds the working copies of the primary owner if specified.
2458: * Returns null if it has none.
2459: */
2460: public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner,
2461: boolean addPrimary) {
2462: synchronized (this .perWorkingCopyInfos) {
2463: ICompilationUnit[] primaryWCs = addPrimary
2464: && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies(
2465: DefaultWorkingCopyOwner.PRIMARY, false)
2466: : null;
2467: Map workingCopyToInfos = (Map) this .perWorkingCopyInfos
2468: .get(owner);
2469: if (workingCopyToInfos == null)
2470: return primaryWCs;
2471: int primaryLength = primaryWCs == null ? 0
2472: : primaryWCs.length;
2473: int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
2474: ICompilationUnit[] result = new ICompilationUnit[primaryLength
2475: + size];
2476: int index = 0;
2477: if (primaryWCs != null) {
2478: for (int i = 0; i < primaryLength; i++) {
2479: ICompilationUnit primaryWorkingCopy = primaryWCs[i];
2480: ICompilationUnit workingCopy = new CompilationUnit(
2481: (PackageFragment) primaryWorkingCopy
2482: .getParent(), primaryWorkingCopy
2483: .getElementName(), owner);
2484: if (!workingCopyToInfos.containsKey(workingCopy))
2485: result[index++] = primaryWorkingCopy;
2486: }
2487: if (index != primaryLength)
2488: System
2489: .arraycopy(result, 0,
2490: result = new ICompilationUnit[index
2491: + size], 0, index);
2492: }
2493: Iterator iterator = workingCopyToInfos.values().iterator();
2494: while (iterator.hasNext()) {
2495: result[index++] = ((JavaModelManager.PerWorkingCopyInfo) iterator
2496: .next()).getWorkingCopy();
2497: }
2498: return result;
2499: }
2500: }
2501:
2502: public JavaWorkspaceScope getWorkspaceScope() {
2503: if (this .workspaceScope == null) {
2504: this .workspaceScope = new JavaWorkspaceScope();
2505: }
2506: return this .workspaceScope;
2507: }
2508:
2509: /**
2510: * Returns the open ZipFile at the given path. If the ZipFile
2511: * does not yet exist, it is created, opened, and added to the cache
2512: * of open ZipFiles.
2513: *
2514: * The path must be a file system path if representing an external
2515: * zip/jar, or it must be an absolute workspace relative path if
2516: * representing a zip/jar inside the workspace.
2517: *
2518: * @exception CoreException If unable to create/open the ZipFile
2519: */
2520: public ZipFile getZipFile(IPath path) throws CoreException {
2521:
2522: HashMap map;
2523: ZipFile zipFile;
2524: if ((map = (HashMap) this .zipFiles.get()) != null
2525: && (zipFile = (ZipFile) map.get(path)) != null) {
2526:
2527: return zipFile;
2528: }
2529: File localFile = null;
2530: IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2531: IResource file = root.findMember(path);
2532: if (file != null) {
2533: // internal resource
2534: URI location;
2535: if (file.getType() != IResource.FILE
2536: || (location = file.getLocationURI()) == null) {
2537: throw new CoreException(new Status(IStatus.ERROR,
2538: JavaCore.PLUGIN_ID, -1, Messages
2539: .bind(Messages.file_notFound, path
2540: .toString()), null));
2541: }
2542: localFile = Util
2543: .toLocalFile(location, null/*no progress availaible*/);
2544: if (localFile == null)
2545: throw new CoreException(new Status(IStatus.ERROR,
2546: JavaCore.PLUGIN_ID, -1, Messages
2547: .bind(Messages.file_notFound, path
2548: .toString()), null));
2549: } else {
2550: // external resource -> it is ok to use toFile()
2551: localFile = path.toFile();
2552: }
2553:
2554: try {
2555: if (ZIP_ACCESS_VERBOSE) {
2556: System.out
2557: .println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile); //$NON-NLS-1$ //$NON-NLS-2$
2558: }
2559: zipFile = new ZipFile(localFile);
2560: if (map != null) {
2561: map.put(path, zipFile);
2562: }
2563: return zipFile;
2564: } catch (IOException e) {
2565: throw new CoreException(new Status(IStatus.ERROR,
2566: JavaCore.PLUGIN_ID, -1,
2567: Messages.status_IOException, e));
2568: }
2569: }
2570:
2571: /*
2572: * Returns whether there is a temporary cache for the current thread.
2573: */
2574: public boolean hasTemporaryCache() {
2575: return this .temporaryCache.get() != null;
2576: }
2577:
2578: /*
2579: * Initialize all container at the same time as the given container.
2580: * Return the container for the given path and project.
2581: */
2582: private IClasspathContainer initializeAllContainers(
2583: IJavaProject javaProjectToInit, IPath containerToInit)
2584: throws JavaModelException {
2585: if (CP_RESOLVE_VERBOSE_ADVANCED)
2586: verbose_batching_containers_initialization(
2587: javaProjectToInit, containerToInit);
2588:
2589: // collect all container paths
2590: final HashMap allContainerPaths = new HashMap();
2591: IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
2592: .getProjects();
2593: for (int i = 0, length = projects.length; i < length; i++) {
2594: IProject project = projects[i];
2595: if (!JavaProject.hasJavaNature(project))
2596: continue;
2597: IJavaProject javaProject = new JavaProject(project,
2598: getJavaModel());
2599: HashSet paths = (HashSet) allContainerPaths
2600: .get(javaProject);
2601: IClasspathEntry[] rawClasspath = javaProject
2602: .getRawClasspath();
2603: for (int j = 0, length2 = rawClasspath.length; j < length2; j++) {
2604: IClasspathEntry entry = rawClasspath[j];
2605: IPath path = entry.getPath();
2606: if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER
2607: && containerGet(javaProject, path) == null) {
2608: if (paths == null) {
2609: paths = new HashSet();
2610: allContainerPaths.put(javaProject, paths);
2611: }
2612: paths.add(path);
2613: // mark container as being initialized
2614: containerAddInitializationInProgress(javaProject,
2615: path);
2616: }
2617: }
2618: /* TODO (frederic) put back when JDT/UI dummy project will be thrown away...
2619: * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97524
2620: *
2621: if (javaProject.equals(javaProjectToInit)) {
2622: if (paths == null) {
2623: paths = new HashSet();
2624: allContainerPaths.put(javaProject, paths);
2625: }
2626: paths.add(containerToInit);
2627: }
2628: */
2629: }
2630: // TODO (frederic) remove following block when JDT/UI dummy project will be thrown away...
2631: HashSet containerPaths = (HashSet) allContainerPaths
2632: .get(javaProjectToInit);
2633: if (containerPaths == null) {
2634: containerPaths = new HashSet();
2635: allContainerPaths.put(javaProjectToInit, containerPaths);
2636: }
2637: containerPaths.add(containerToInit);
2638: // mark container as being initialized
2639: containerAddInitializationInProgress(javaProjectToInit,
2640: containerToInit);
2641: // end block
2642:
2643: // initialize all containers
2644: boolean ok = false;
2645: try {
2646: // if possible run inside an IWokspaceRunnable with AVOID_UPATE to avoid unwanted builds
2647: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=118507)
2648: IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
2649: public void run(IProgressMonitor monitor)
2650: throws CoreException {
2651: try {
2652: Set entrySet = allContainerPaths.entrySet();
2653: int length = entrySet.size();
2654: if (monitor != null)
2655: monitor.beginTask("", length); //$NON-NLS-1$
2656: Map.Entry[] entries = new Map.Entry[length]; // clone as the following will have a side effect
2657: entrySet.toArray(entries);
2658: for (int i = 0; i < length; i++) {
2659: Map.Entry entry = entries[i];
2660: IJavaProject javaProject = (IJavaProject) entry
2661: .getKey();
2662: HashSet pathSet = (HashSet) entry
2663: .getValue();
2664: if (pathSet == null)
2665: continue;
2666: int length2 = pathSet.size();
2667: IPath[] paths = new IPath[length2];
2668: pathSet.toArray(paths); // clone as the following will have a side effect
2669: for (int j = 0; j < length2; j++) {
2670: IPath path = paths[j];
2671: initializeContainer(javaProject, path);
2672: }
2673: if (monitor != null)
2674: monitor.worked(1);
2675: }
2676: } finally {
2677: if (monitor != null)
2678: monitor.done();
2679: }
2680: }
2681: };
2682: IProgressMonitor monitor = (IProgressMonitor) this .batchContainerInitializationsProgress
2683: .get();
2684: IWorkspace workspace = ResourcesPlugin.getWorkspace();
2685: if (workspace.isTreeLocked())
2686: runnable.run(monitor);
2687: else
2688: workspace.run(runnable, null/*don't take any lock*/,
2689: IWorkspace.AVOID_UPDATE, monitor);
2690: ok = true;
2691: } catch (CoreException e) {
2692: // ignore
2693: Util.log(e, "Exception while initializing all containers"); //$NON-NLS-1$
2694: } finally {
2695: if (!ok) {
2696: // if we're being traversed by an exception, ensure that that containers are
2697: // no longer marked as initialization in progress
2698: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=66437)
2699: this .containerInitializationInProgress.set(null);
2700: }
2701: }
2702:
2703: return containerGet(javaProjectToInit, containerToInit);
2704: }
2705:
2706: private void verbose_batching_containers_initialization(
2707: IJavaProject javaProjectToInit, IPath containerToInit) {
2708: Util
2709: .verbose("CPContainer INIT - batching containers initialization\n" + //$NON-NLS-1$
2710: " project to init: "
2711: + javaProjectToInit.getElementName() + '\n' + //$NON-NLS-1$
2712: " container path to init: " + containerToInit); //$NON-NLS-1$
2713: }
2714:
2715: IClasspathContainer initializeContainer(IJavaProject project,
2716: IPath containerPath) throws JavaModelException {
2717:
2718: IProgressMonitor monitor = (IProgressMonitor) this .batchContainerInitializationsProgress
2719: .get();
2720: if (monitor != null && monitor.isCanceled())
2721: throw new OperationCanceledException();
2722:
2723: IClasspathContainer container = null;
2724: final ClasspathContainerInitializer initializer = JavaCore
2725: .getClasspathContainerInitializer(containerPath
2726: .segment(0));
2727: if (initializer != null) {
2728: if (CP_RESOLVE_VERBOSE)
2729: verbose_triggering_container_initialization(project,
2730: containerPath, initializer);
2731: if (CP_RESOLVE_VERBOSE_ADVANCED)
2732: verbose_triggering_container_initialization_invocation_trace();
2733: PerformanceStats stats = null;
2734: if (JavaModelManager.PERF_CONTAINER_INITIALIZER) {
2735: stats = PerformanceStats.getStats(
2736: JavaModelManager.CONTAINER_INITIALIZER_PERF,
2737: this );
2738: stats.startRun(containerPath
2739: + " of " + project.getPath()); //$NON-NLS-1$
2740: }
2741: containerPut(project, containerPath,
2742: CONTAINER_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles
2743: boolean ok = false;
2744: try {
2745: if (monitor != null)
2746: monitor.subTask(Messages.bind(
2747: Messages.javamodel_configuring, initializer
2748: .getDescription(containerPath,
2749: project)));
2750:
2751: // let OperationCanceledException go through
2752: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59363)
2753: initializer.initialize(containerPath, project);
2754:
2755: if (monitor != null)
2756: monitor.subTask(""); //$NON-NLS-1$
2757:
2758: // retrieve value (if initialization was successful)
2759: container = containerGet(project, containerPath);
2760: if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
2761: // initializer failed to do its job: redirect to the failure container
2762: container = initializer.getFailureContainer(
2763: containerPath, project);
2764: if (container == null) {
2765: if (CP_RESOLVE_VERBOSE)
2766: verbose_container_null_failure_container(
2767: project, containerPath, initializer);
2768: return null; // break cycle
2769: }
2770: if (CP_RESOLVE_VERBOSE)
2771: verbose_container_using_failure_container(
2772: project, containerPath, initializer);
2773: containerPut(project, containerPath, container);
2774: }
2775: ok = true;
2776: } catch (CoreException e) {
2777: if (e instanceof JavaModelException) {
2778: throw (JavaModelException) e;
2779: } else {
2780: throw new JavaModelException(e);
2781: }
2782: } catch (RuntimeException e) {
2783: if (JavaModelManager.CP_RESOLVE_VERBOSE)
2784: e.printStackTrace();
2785: throw e;
2786: } catch (Error e) {
2787: if (JavaModelManager.CP_RESOLVE_VERBOSE)
2788: e.printStackTrace();
2789: throw e;
2790: } finally {
2791: if (JavaModelManager.PERF_CONTAINER_INITIALIZER) {
2792: stats.endRun();
2793: }
2794: if (!ok) {
2795: // just remove initialization in progress and keep previous session container so as to avoid a full build
2796: // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92588
2797: containerRemoveInitializationInProgress(project,
2798: containerPath);
2799: if (CP_RESOLVE_VERBOSE)
2800: verbose_container_initialization_failed(
2801: project, containerPath, container,
2802: initializer);
2803: }
2804: }
2805: if (CP_RESOLVE_VERBOSE_ADVANCED)
2806: verbose_container_value_after_initialization(project,
2807: containerPath, container);
2808: } else {
2809: // create a dummy initializer and get the default failure container
2810: container = (new ClasspathContainerInitializer() {
2811: public void initialize(IPath path,
2812: IJavaProject javaProject) throws CoreException {
2813: // not used
2814: }
2815: }).getFailureContainer(containerPath, project);
2816: if (CP_RESOLVE_VERBOSE_ADVANCED)
2817: verbose_no_container_initializer_found(project,
2818: containerPath);
2819: }
2820: return container;
2821: }
2822:
2823: private void verbose_no_container_initializer_found(
2824: IJavaProject project, IPath containerPath) {
2825: Util.verbose("CPContainer INIT - no initializer found\n" + //$NON-NLS-1$
2826: " project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2827: " container path: " + containerPath); //$NON-NLS-1$
2828: }
2829:
2830: private void verbose_container_value_after_initialization(
2831: IJavaProject project, IPath containerPath,
2832: IClasspathContainer container) {
2833: StringBuffer buffer = new StringBuffer();
2834: buffer.append("CPContainer INIT - after resolution\n"); //$NON-NLS-1$
2835: buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$
2836: buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$
2837: if (container != null) {
2838: buffer
2839: .append(" container: " + container.getDescription() + " {\n"); //$NON-NLS-2$//$NON-NLS-1$
2840: IClasspathEntry[] entries = container.getClasspathEntries();
2841: if (entries != null) {
2842: for (int i = 0; i < entries.length; i++) {
2843: buffer.append(" " + entries[i] + '\n'); //$NON-NLS-1$
2844: }
2845: }
2846: buffer.append(" }");//$NON-NLS-1$
2847: } else {
2848: buffer.append(" container: {unbound}");//$NON-NLS-1$
2849: }
2850: Util.verbose(buffer.toString());
2851: }
2852:
2853: private void verbose_container_initialization_failed(
2854: IJavaProject project, IPath containerPath,
2855: IClasspathContainer container,
2856: ClasspathContainerInitializer initializer) {
2857: if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
2858: Util
2859: .verbose("CPContainer INIT - FAILED (initializer did not initialize container)\n" + //$NON-NLS-1$
2860: " project: "
2861: + project.getElementName()
2862: + '\n' + //$NON-NLS-1$
2863: " container path: " + containerPath + '\n' + //$NON-NLS-1$
2864: " initializer: " + initializer); //$NON-NLS-1$
2865:
2866: } else {
2867: Util
2868: .verbose("CPContainer INIT - FAILED (see exception above)\n" + //$NON-NLS-1$
2869: " project: "
2870: + project.getElementName()
2871: + '\n' + //$NON-NLS-1$
2872: " container path: " + containerPath + '\n' + //$NON-NLS-1$
2873: " initializer: " + initializer); //$NON-NLS-1$
2874: }
2875: }
2876:
2877: private void verbose_container_null_failure_container(
2878: IJavaProject project, IPath containerPath,
2879: ClasspathContainerInitializer initializer) {
2880: Util
2881: .verbose("CPContainer INIT - FAILED (and failure container is null)\n" + //$NON-NLS-1$
2882: " project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2883: " container path: " + containerPath + '\n' + //$NON-NLS-1$
2884: " initializer: " + initializer); //$NON-NLS-1$
2885: }
2886:
2887: private void verbose_container_using_failure_container(
2888: IJavaProject project, IPath containerPath,
2889: ClasspathContainerInitializer initializer) {
2890: Util
2891: .verbose("CPContainer INIT - FAILED (using failure container)\n" + //$NON-NLS-1$
2892: " project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2893: " container path: " + containerPath + '\n' + //$NON-NLS-1$
2894: " initializer: " + initializer); //$NON-NLS-1$
2895: }
2896:
2897: private void verbose_triggering_container_initialization(
2898: IJavaProject project, IPath containerPath,
2899: ClasspathContainerInitializer initializer) {
2900: Util.verbose("CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
2901: " project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2902: " container path: " + containerPath + '\n' + //$NON-NLS-1$
2903: " initializer: " + initializer); //$NON-NLS-1$
2904: }
2905:
2906: private void verbose_triggering_container_initialization_invocation_trace() {
2907: Util.verbose("CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
2908: " invocation trace:"); //$NON-NLS-1$
2909: new Exception("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2910: }
2911:
2912: /**
2913: * Initialize preferences lookups for JavaCore plug-in.
2914: */
2915: public void initializePreferences() {
2916:
2917: // Create lookups
2918: preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope())
2919: .getNode(JavaCore.PLUGIN_ID);
2920: preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope())
2921: .getNode(JavaCore.PLUGIN_ID);
2922:
2923: // Listen to instance preferences node removal from parent in order to refresh stored one
2924: this .instanceNodeListener = new IEclipsePreferences.INodeChangeListener() {
2925: public void added(IEclipsePreferences.NodeChangeEvent event) {
2926: // do nothing
2927: }
2928:
2929: public void removed(
2930: IEclipsePreferences.NodeChangeEvent event) {
2931: if (event.getChild() == preferencesLookup[PREF_INSTANCE]) {
2932: preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope())
2933: .getNode(JavaCore.PLUGIN_ID);
2934: preferencesLookup[PREF_INSTANCE]
2935: .addPreferenceChangeListener(new EclipsePreferencesListener());
2936: }
2937: }
2938: };
2939: ((IEclipsePreferences) preferencesLookup[PREF_INSTANCE]
2940: .parent())
2941: .addNodeChangeListener(this .instanceNodeListener);
2942: preferencesLookup[PREF_INSTANCE]
2943: .addPreferenceChangeListener(this .instancePreferencesListener = new EclipsePreferencesListener());
2944:
2945: // Listen to default preferences node removal from parent in order to refresh stored one
2946: this .defaultNodeListener = new IEclipsePreferences.INodeChangeListener() {
2947: public void added(IEclipsePreferences.NodeChangeEvent event) {
2948: // do nothing
2949: }
2950:
2951: public void removed(
2952: IEclipsePreferences.NodeChangeEvent event) {
2953: if (event.getChild() == preferencesLookup[PREF_DEFAULT]) {
2954: preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope())
2955: .getNode(JavaCore.PLUGIN_ID);
2956: }
2957: }
2958: };
2959: ((IEclipsePreferences) preferencesLookup[PREF_DEFAULT].parent())
2960: .addNodeChangeListener(this .defaultNodeListener);
2961: }
2962:
2963: public synchronized char[] intern(char[] array) {
2964: return this .charArraySymbols.add(array);
2965: }
2966:
2967: public synchronized String intern(String s) {
2968: // make sure to copy the string (so that it doesn't hold on the underlying char[] that might be much bigger than necessary)
2969: return (String) this .stringSymbols.add(new String(s));
2970:
2971: // Note1: String#intern() cannot be used as on some VMs this prevents the string from being garbage collected
2972: // Note 2: Instead of using a WeakHashset, one could use a WeakHashMap with the following implementation
2973: // This would costs more per entry (one Entry object and one WeakReference more))
2974:
2975: /*
2976: WeakReference reference = (WeakReference) this.symbols.get(s);
2977: String existing;
2978: if (reference != null && (existing = (String) reference.get()) != null)
2979: return existing;
2980: this.symbols.put(s, new WeakReference(s));
2981: return s;
2982: */
2983: }
2984:
2985: private HashSet getClasspathBeingResolved() {
2986: HashSet result = (HashSet) this .classpathsBeingResolved.get();
2987: if (result == null) {
2988: result = new HashSet();
2989: this .classpathsBeingResolved.set(result);
2990: }
2991: return result;
2992: }
2993:
2994: public boolean isClasspathBeingResolved(IJavaProject project) {
2995: return getClasspathBeingResolved().contains(project);
2996: }
2997:
2998: /**
2999: * @deprecated
3000: */
3001: private boolean isDeprecatedOption(String optionName) {
3002: return JavaCore.COMPILER_PB_INVALID_IMPORT.equals(optionName)
3003: || JavaCore.COMPILER_PB_UNREACHABLE_CODE
3004: .equals(optionName);
3005: }
3006:
3007: public void setClasspathBeingResolved(IJavaProject project,
3008: boolean classpathIsResolved) {
3009: if (classpathIsResolved) {
3010: getClasspathBeingResolved().add(project);
3011: } else {
3012: getClasspathBeingResolved().remove(project);
3013: }
3014: }
3015:
3016: public void loadVariablesAndContainers() throws CoreException {
3017: // backward compatibility, consider persistent property
3018: QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID,
3019: "variables"); //$NON-NLS-1$
3020: String xmlString = ResourcesPlugin.getWorkspace().getRoot()
3021: .getPersistentProperty(qName);
3022:
3023: try {
3024: if (xmlString != null) {
3025: StringReader reader = new StringReader(xmlString);
3026: Element cpElement;
3027: try {
3028: DocumentBuilder parser = DocumentBuilderFactory
3029: .newInstance().newDocumentBuilder();
3030: cpElement = parser.parse(new InputSource(reader))
3031: .getDocumentElement();
3032: } catch (SAXException e) {
3033: return;
3034: } catch (ParserConfigurationException e) {
3035: return;
3036: } finally {
3037: reader.close();
3038: }
3039: if (cpElement == null)
3040: return;
3041: if (!cpElement.getNodeName().equalsIgnoreCase(
3042: "variables")) { //$NON-NLS-1$
3043: return;
3044: }
3045:
3046: NodeList list = cpElement.getChildNodes();
3047: int length = list.getLength();
3048: for (int i = 0; i < length; ++i) {
3049: Node node = list.item(i);
3050: short type = node.getNodeType();
3051: if (type == Node.ELEMENT_NODE) {
3052: Element element = (Element) node;
3053: if (element.getNodeName().equalsIgnoreCase(
3054: "variable")) { //$NON-NLS-1$
3055: variablePut(element.getAttribute("name"), //$NON-NLS-1$
3056: new Path(element
3057: .getAttribute("path"))); //$NON-NLS-1$
3058: }
3059: }
3060: }
3061: }
3062: } catch (IOException e) {
3063: // problem loading xml file: nothing we can do
3064: } finally {
3065: if (xmlString != null) {
3066: ResourcesPlugin.getWorkspace().getRoot()
3067: .setPersistentProperty(qName, null); // flush old one
3068: }
3069: }
3070:
3071: // backward compatibility, load variables and containers from preferences into cache
3072: loadVariablesAndContainers(getDefaultPreferences());
3073: loadVariablesAndContainers(getInstancePreferences());
3074:
3075: // load variables and containers from saved file into cache
3076: File file = getVariableAndContainersFile();
3077: DataInputStream in = null;
3078: try {
3079: in = new DataInputStream(new BufferedInputStream(
3080: new FileInputStream(file)));
3081: switch (in.readInt()) {
3082: case 2:
3083: new VariablesAndContainersLoadHelper(in).load();
3084: break;
3085: case 1: // backward compatibility, load old format
3086: // variables
3087: int size = in.readInt();
3088: while (size-- > 0) {
3089: String varName = in.readUTF();
3090: String pathString = in.readUTF();
3091: if (CP_ENTRY_IGNORE.equals(pathString))
3092: continue;
3093: IPath varPath = Path.fromPortableString(pathString);
3094: this .variables.put(varName, varPath);
3095: this .previousSessionVariables.put(varName, varPath);
3096: }
3097:
3098: // containers
3099: IJavaModel model = getJavaModel();
3100: int projectSize = in.readInt();
3101: while (projectSize-- > 0) {
3102: String projectName = in.readUTF();
3103: IJavaProject project = model
3104: .getJavaProject(projectName);
3105: int containerSize = in.readInt();
3106: while (containerSize-- > 0) {
3107: IPath containerPath = Path
3108: .fromPortableString(in.readUTF());
3109: int length = in.readInt();
3110: byte[] containerString = new byte[length];
3111: in.readFully(containerString);
3112: recreatePersistedContainer(project,
3113: containerPath, new String(
3114: containerString), true/*add to container values*/);
3115: }
3116: }
3117: break;
3118: }
3119: } catch (IOException e) {
3120: if (file.exists())
3121: Util.log(e,
3122: "Unable to read variable and containers file"); //$NON-NLS-1$
3123: } catch (RuntimeException e) {
3124: if (file.exists())
3125: Util
3126: .log(e,
3127: "Unable to read variable and containers file (file is corrupt)"); //$NON-NLS-1$
3128: } finally {
3129: if (in != null) {
3130: try {
3131: in.close();
3132: } catch (IOException e) {
3133: // nothing we can do: ignore
3134: }
3135: }
3136: }
3137:
3138: // override persisted values for variables which have a registered initializer
3139: String[] registeredVariables = getRegisteredVariableNames();
3140: for (int i = 0; i < registeredVariables.length; i++) {
3141: String varName = registeredVariables[i];
3142: this .variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
3143: }
3144: // override persisted values for containers which have a registered initializer
3145: containersReset(getRegisteredContainerIDs());
3146: }
3147:
3148: private void loadVariablesAndContainers(
3149: IEclipsePreferences preferences) {
3150: try {
3151: // only get variable from preferences not set to their default
3152: String[] propertyNames = preferences.keys();
3153: int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX
3154: .length();
3155: for (int i = 0; i < propertyNames.length; i++) {
3156: String propertyName = propertyNames[i];
3157: if (propertyName
3158: .startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
3159: String varName = propertyName
3160: .substring(variablePrefixLength);
3161: String propertyValue = preferences.get(
3162: propertyName, null);
3163: if (propertyValue != null) {
3164: String pathString = propertyValue.trim();
3165:
3166: if (CP_ENTRY_IGNORE.equals(pathString)) {
3167: // cleanup old preferences
3168: preferences.remove(propertyName);
3169: continue;
3170: }
3171:
3172: // add variable to table
3173: IPath varPath = new Path(pathString);
3174: this .variables.put(varName, varPath);
3175: this .previousSessionVariables.put(varName,
3176: varPath);
3177: }
3178: } else if (propertyName
3179: .startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
3180: String propertyValue = preferences.get(
3181: propertyName, null);
3182: if (propertyValue != null) {
3183: // cleanup old preferences
3184: preferences.remove(propertyName);
3185:
3186: // recreate container
3187: recreatePersistedContainer(propertyName,
3188: propertyValue, true/*add to container values*/);
3189: }
3190: }
3191: }
3192: } catch (BackingStoreException e1) {
3193: // TODO (frederic) see if it's necessary to report this failure...
3194: }
3195: }
3196:
3197: private static final class PersistedClasspathContainer implements
3198: IClasspathContainer {
3199:
3200: private final IPath containerPath;
3201:
3202: private final IClasspathEntry[] entries;
3203:
3204: private final IJavaProject project;
3205:
3206: PersistedClasspathContainer(IJavaProject project,
3207: IPath containerPath, IClasspathEntry[] entries) {
3208: super ();
3209: this .containerPath = containerPath;
3210: this .entries = entries;
3211: this .project = project;
3212: }
3213:
3214: public IClasspathEntry[] getClasspathEntries() {
3215: return entries;
3216: }
3217:
3218: public String getDescription() {
3219: return "Persisted container [" + containerPath //$NON-NLS-1$
3220: + " for project [" + project.getElementName() //$NON-NLS-1$
3221: + "]]"; //$NON-NLS-1$
3222: }
3223:
3224: public int getKind() {
3225: return 0;
3226: }
3227:
3228: public IPath getPath() {
3229: return containerPath;
3230: }
3231:
3232: public String toString() {
3233: return getDescription();
3234: }
3235: }
3236:
3237: private final class VariablesAndContainersLoadHelper {
3238:
3239: private static final int ARRAY_INCREMENT = 200;
3240:
3241: private IClasspathEntry[] allClasspathEntries;
3242: private int allClasspathEntryCount;
3243:
3244: private final Map allPaths; // String -> IPath
3245:
3246: private String[] allStrings;
3247: private int allStringsCount;
3248:
3249: private final DataInputStream in;
3250:
3251: VariablesAndContainersLoadHelper(DataInputStream in) {
3252: super ();
3253: this .allClasspathEntries = null;
3254: this .allClasspathEntryCount = 0;
3255: this .allPaths = new HashMap();
3256: this .allStrings = null;
3257: this .allStringsCount = 0;
3258: this .in = in;
3259: }
3260:
3261: void load() throws IOException {
3262: loadProjects(JavaModelManager.this .getJavaModel());
3263: loadVariables();
3264: }
3265:
3266: private IAccessRule loadAccessRule() throws IOException {
3267: int problemId = loadInt();
3268: IPath pattern = loadPath();
3269: return new ClasspathAccessRule(pattern.toString()
3270: .toCharArray(), problemId);
3271: }
3272:
3273: private IAccessRule[] loadAccessRules() throws IOException {
3274: int count = loadInt();
3275:
3276: if (count == 0)
3277: return ClasspathEntry.NO_ACCESS_RULES;
3278:
3279: IAccessRule[] rules = new IAccessRule[count];
3280:
3281: for (int i = 0; i < count; ++i)
3282: rules[i] = loadAccessRule();
3283:
3284: return rules;
3285: }
3286:
3287: private IClasspathAttribute loadAttribute() throws IOException {
3288: String name = loadString();
3289: String value = loadString();
3290:
3291: return new ClasspathAttribute(name, value);
3292: }
3293:
3294: private IClasspathAttribute[] loadAttributes()
3295: throws IOException {
3296: int count = loadInt();
3297:
3298: if (count == 0)
3299: return ClasspathEntry.NO_EXTRA_ATTRIBUTES;
3300:
3301: IClasspathAttribute[] attributes = new IClasspathAttribute[count];
3302:
3303: for (int i = 0; i < count; ++i)
3304: attributes[i] = loadAttribute();
3305:
3306: return attributes;
3307: }
3308:
3309: private boolean loadBoolean() throws IOException {
3310: return this .in.readBoolean();
3311: }
3312:
3313: private IClasspathEntry[] loadClasspathEntries()
3314: throws IOException {
3315: int count = loadInt();
3316: IClasspathEntry[] entries = new IClasspathEntry[count];
3317:
3318: for (int i = 0; i < count; ++i)
3319: entries[i] = loadClasspathEntry();
3320:
3321: return entries;
3322: }
3323:
3324: private IClasspathEntry loadClasspathEntry() throws IOException {
3325: int id = loadInt();
3326:
3327: if (id < 0 || id > this .allClasspathEntryCount)
3328: throw new IOException("Unexpected classpathentry id"); //$NON-NLS-1$
3329:
3330: if (id < this .allClasspathEntryCount)
3331: return this .allClasspathEntries[id];
3332:
3333: int contentKind = loadInt();
3334: int entryKind = loadInt();
3335: IPath path = loadPath();
3336: IPath[] inclusionPatterns = loadPaths();
3337: IPath[] exclusionPatterns = loadPaths();
3338: IPath sourceAttachmentPath = loadPath();
3339: IPath sourceAttachmentRootPath = loadPath();
3340: IPath specificOutputLocation = loadPath();
3341: boolean isExported = loadBoolean();
3342: IAccessRule[] accessRules = loadAccessRules();
3343: boolean combineAccessRules = loadBoolean();
3344: IClasspathAttribute[] extraAttributes = loadAttributes();
3345:
3346: IClasspathEntry entry = new ClasspathEntry(contentKind,
3347: entryKind, path, inclusionPatterns,
3348: exclusionPatterns, sourceAttachmentPath,
3349: sourceAttachmentRootPath, specificOutputLocation,
3350: isExported, accessRules, combineAccessRules,
3351: extraAttributes);
3352:
3353: IClasspathEntry[] array = this .allClasspathEntries;
3354:
3355: if (array == null || id == array.length) {
3356: array = new IClasspathEntry[id + ARRAY_INCREMENT];
3357:
3358: if (id != 0)
3359: System.arraycopy(this .allClasspathEntries, 0,
3360: array, 0, id);
3361:
3362: this .allClasspathEntries = array;
3363: }
3364:
3365: array[id] = entry;
3366: this .allClasspathEntryCount = id + 1;
3367:
3368: return entry;
3369: }
3370:
3371: private void loadContainers(IJavaProject project)
3372: throws IOException {
3373: boolean projectIsAccessible = project.getProject()
3374: .isAccessible();
3375: int count = loadInt();
3376: for (int i = 0; i < count; ++i) {
3377: IPath path = loadPath();
3378: IClasspathEntry[] entries = loadClasspathEntries();
3379:
3380: if (!projectIsAccessible)
3381: // avoid leaking deleted project's persisted container,
3382: // but still read the container as it is is part of the file format
3383: continue;
3384:
3385: IClasspathContainer container = new PersistedClasspathContainer(
3386: project, path, entries);
3387:
3388: JavaModelManager.this .containerPut(project, path,
3389: container);
3390:
3391: Map oldContainers = (Map) JavaModelManager.this .previousSessionContainers
3392: .get(project);
3393:
3394: if (oldContainers == null) {
3395: oldContainers = new HashMap();
3396: JavaModelManager.this .previousSessionContainers
3397: .put(project, oldContainers);
3398: }
3399:
3400: oldContainers.put(path, container);
3401: }
3402: }
3403:
3404: private int loadInt() throws IOException {
3405: return this .in.readInt();
3406: }
3407:
3408: private IPath loadPath() throws IOException {
3409: if (loadBoolean())
3410: return null;
3411:
3412: String portableString = loadString();
3413: IPath path = (IPath) this .allPaths.get(portableString);
3414:
3415: if (path == null) {
3416: path = Path.fromPortableString(portableString);
3417: this .allPaths.put(portableString, path);
3418: }
3419:
3420: return path;
3421: }
3422:
3423: private IPath[] loadPaths() throws IOException {
3424: int count = loadInt();
3425: IPath[] pathArray = new IPath[count];
3426:
3427: for (int i = 0; i < count; ++i)
3428: pathArray[i] = loadPath();
3429:
3430: return pathArray;
3431: }
3432:
3433: private void loadProjects(IJavaModel model) throws IOException {
3434: int count = loadInt();
3435:
3436: for (int i = 0; i < count; ++i) {
3437: String projectName = loadString();
3438:
3439: loadContainers(model.getJavaProject(projectName));
3440: }
3441: }
3442:
3443: private String loadString() throws IOException {
3444: int id = loadInt();
3445:
3446: if (id < 0 || id > this .allStringsCount)
3447: throw new IOException("Unexpected string id"); //$NON-NLS-1$
3448:
3449: if (id < this .allStringsCount)
3450: return this .allStrings[id];
3451:
3452: String string = this .in.readUTF();
3453: String[] array = this .allStrings;
3454:
3455: if (array == null || id == array.length) {
3456: array = new String[id + ARRAY_INCREMENT];
3457:
3458: if (id != 0)
3459: System.arraycopy(this .allStrings, 0, array, 0, id);
3460:
3461: this .allStrings = array;
3462: }
3463:
3464: array[id] = string;
3465: this .allStringsCount = id + 1;
3466:
3467: return string;
3468: }
3469:
3470: private void loadVariables() throws IOException {
3471: int size = loadInt();
3472: Map loadedVars = new HashMap(size);
3473:
3474: for (int i = 0; i < size; ++i) {
3475: String varName = loadString();
3476: IPath varPath = loadPath();
3477:
3478: if (varPath != null)
3479: loadedVars.put(varName, varPath);
3480: }
3481:
3482: JavaModelManager.this .previousSessionVariables
3483: .putAll(loadedVars);
3484: JavaModelManager.this .variables.putAll(loadedVars);
3485: }
3486: }
3487:
3488: /**
3489: * Returns the info for this element without
3490: * disturbing the cache ordering.
3491: */
3492: protected synchronized Object peekAtInfo(IJavaElement element) {
3493: HashMap tempCache = (HashMap) this .temporaryCache.get();
3494: if (tempCache != null) {
3495: Object result = tempCache.get(element);
3496: if (result != null) {
3497: return result;
3498: }
3499: }
3500: return this .cache.peekAtInfo(element);
3501: }
3502:
3503: /**
3504: * @see ISaveParticipant
3505: */
3506: public void prepareToSave(ISaveContext context) /*throws CoreException*/{
3507: // nothing to do
3508: }
3509:
3510: /*
3511: * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos)
3512: * in the Java model cache in an atomic way.
3513: * First checks that the info for the opened element (or one of its ancestors) has not been
3514: * added to the cache. If it is the case, another thread has opened the element (or one of
3515: * its ancestors). So returns without updating the cache.
3516: */
3517: protected synchronized void putInfos(IJavaElement openedElement,
3518: Map newElements) {
3519: // remove children
3520: Object existingInfo = this .cache.peekAtInfo(openedElement);
3521: if (openedElement instanceof IParent
3522: && existingInfo instanceof JavaElementInfo) {
3523: IJavaElement[] children = ((JavaElementInfo) existingInfo)
3524: .getChildren();
3525: for (int i = 0, size = children.length; i < size; ++i) {
3526: JavaElement child = (JavaElement) children[i];
3527: try {
3528: child.close();
3529: } catch (JavaModelException e) {
3530: // ignore
3531: }
3532: }
3533: }
3534:
3535: // Need to put any JarPackageFragmentRoot in first.
3536: // This is due to the way the LRU cache flushes entries.
3537: // When a JarPackageFragment is flused from the LRU cache, the entire
3538: // jar is flushed by removing the JarPackageFragmentRoot and all of its
3539: // children (see ElementCache.close()). If we flush the JarPackageFragment
3540: // when its JarPackageFragmentRoot is not in the cache and the root is about to be
3541: // added (during the 'while' loop), we will end up in an inconsist state.
3542: // Subsequent resolution against package in the jar would fail as a result.
3543: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422
3544: // (theodora)
3545: for (Iterator it = newElements.entrySet().iterator(); it
3546: .hasNext();) {
3547: Map.Entry entry = (Map.Entry) it.next();
3548: IJavaElement element = (IJavaElement) entry.getKey();
3549: if (element instanceof JarPackageFragmentRoot) {
3550: Object info = entry.getValue();
3551: it.remove();
3552: this .cache.putInfo(element, info);
3553: }
3554: }
3555:
3556: Iterator iterator = newElements.entrySet().iterator();
3557: while (iterator.hasNext()) {
3558: Map.Entry entry = (Map.Entry) iterator.next();
3559: this .cache.putInfo((IJavaElement) entry.getKey(), entry
3560: .getValue());
3561: }
3562: }
3563:
3564: /*
3565: * Remember the info for the jar binary type
3566: */
3567: protected synchronized void putJarTypeInfo(IJavaElement type,
3568: Object info) {
3569: this .cache.jarTypeCache.put(type, info);
3570: }
3571:
3572: /**
3573: * Reads the build state for the relevant project.
3574: */
3575: protected Object readState(IProject project) throws CoreException {
3576: File file = getSerializationFile(project);
3577: if (file != null && file.exists()) {
3578: try {
3579: DataInputStream in = new DataInputStream(
3580: new BufferedInputStream(new FileInputStream(
3581: file)));
3582: try {
3583: String pluginID = in.readUTF();
3584: if (!pluginID.equals(JavaCore.PLUGIN_ID))
3585: throw new IOException(
3586: Messages.build_wrongFileFormat);
3587: String kind = in.readUTF();
3588: if (!kind.equals("STATE")) //$NON-NLS-1$
3589: throw new IOException(
3590: Messages.build_wrongFileFormat);
3591: if (in.readBoolean())
3592: return JavaBuilder.readState(project, in);
3593: if (JavaBuilder.DEBUG)
3594: System.out
3595: .println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$
3596: } finally {
3597: in.close();
3598: }
3599: } catch (Exception e) {
3600: e.printStackTrace();
3601: throw new CoreException(
3602: new Status(
3603: IStatus.ERROR,
3604: JavaCore.PLUGIN_ID,
3605: Platform.PLUGIN_ERROR,
3606: "Error reading last build state for project " + project.getName(), e)); //$NON-NLS-1$
3607: }
3608: } else if (JavaBuilder.DEBUG) {
3609: if (file == null)
3610: System.out
3611: .println("Project does not exist: " + project); //$NON-NLS-1$
3612: else
3613: System.out
3614: .println("Build state file " + file.getPath() + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
3615: }
3616: return null;
3617: }
3618:
3619: public static void recreatePersistedContainer(String propertyName,
3620: String containerString, boolean addToContainerValues) {
3621: int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX
3622: .length();
3623: int index = propertyName.indexOf('|', containerPrefixLength);
3624: if (containerString != null)
3625: containerString = containerString.trim();
3626: if (index > 0) {
3627: String projectName = propertyName.substring(
3628: containerPrefixLength, index).trim();
3629: IJavaProject project = getJavaModelManager().getJavaModel()
3630: .getJavaProject(projectName);
3631: IPath containerPath = new Path(propertyName.substring(
3632: index + 1).trim());
3633: recreatePersistedContainer(project, containerPath,
3634: containerString, addToContainerValues);
3635: }
3636: }
3637:
3638: private static void recreatePersistedContainer(
3639: final IJavaProject project, final IPath containerPath,
3640: String containerString, boolean addToContainerValues) {
3641: if (!project.getProject().isAccessible())
3642: return; // avoid leaking deleted project's persisted container
3643: if (containerString == null) {
3644: getJavaModelManager().containerPut(project, containerPath,
3645: null);
3646: } else {
3647: IClasspathEntry[] entries;
3648: try {
3649: entries = ((JavaProject) project)
3650: .decodeClasspath(containerString, null/*not interested in unknown elements*/);
3651: } catch (IOException e) {
3652: Util
3653: .log(
3654: e,
3655: "Could not recreate persisted container: \n" + containerString); //$NON-NLS-1$
3656: entries = JavaProject.INVALID_CLASSPATH;
3657: }
3658: if (entries != JavaProject.INVALID_CLASSPATH) {
3659: final IClasspathEntry[] containerEntries = entries;
3660: IClasspathContainer container = new IClasspathContainer() {
3661: public IClasspathEntry[] getClasspathEntries() {
3662: return containerEntries;
3663: }
3664:
3665: public String getDescription() {
3666: return "Persisted container [" + containerPath + " for project [" + project.getElementName() + "]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
3667: }
3668:
3669: public int getKind() {
3670: return 0;
3671: }
3672:
3673: public IPath getPath() {
3674: return containerPath;
3675: }
3676:
3677: public String toString() {
3678: return getDescription();
3679: }
3680:
3681: };
3682: if (addToContainerValues) {
3683: getJavaModelManager().containerPut(project,
3684: containerPath, container);
3685: }
3686: Map projectContainers = (Map) getJavaModelManager().previousSessionContainers
3687: .get(project);
3688: if (projectContainers == null) {
3689: projectContainers = new HashMap(1);
3690: getJavaModelManager().previousSessionContainers
3691: .put(project, projectContainers);
3692: }
3693: projectContainers.put(containerPath, container);
3694: }
3695: }
3696: }
3697:
3698: /**
3699: * Remembers the given scope in a weak set
3700: * (so no need to remove it: it will be removed by the garbage collector)
3701: */
3702: public void rememberScope(AbstractSearchScope scope) {
3703: // NB: The value has to be null so as to not create a strong reference on the scope
3704: this .searchScopes.put(scope, null);
3705: }
3706:
3707: /*
3708: * Removes all cached info for the given element (including all children)
3709: * from the cache.
3710: * Returns the info for the given element, or null if it was closed.
3711: */
3712: public synchronized Object removeInfoAndChildren(JavaElement element)
3713: throws JavaModelException {
3714: Object info = this .cache.peekAtInfo(element);
3715: if (info != null) {
3716: boolean wasVerbose = false;
3717: try {
3718: if (JavaModelCache.VERBOSE) {
3719: String elementType;
3720: switch (element.getElementType()) {
3721: case IJavaElement.JAVA_PROJECT:
3722: elementType = "project"; //$NON-NLS-1$
3723: break;
3724: case IJavaElement.PACKAGE_FRAGMENT_ROOT:
3725: elementType = "root"; //$NON-NLS-1$
3726: break;
3727: case IJavaElement.PACKAGE_FRAGMENT:
3728: elementType = "package"; //$NON-NLS-1$
3729: break;
3730: case IJavaElement.CLASS_FILE:
3731: elementType = "class file"; //$NON-NLS-1$
3732: break;
3733: case IJavaElement.COMPILATION_UNIT:
3734: elementType = "compilation unit"; //$NON-NLS-1$
3735: break;
3736: default:
3737: elementType = "element"; //$NON-NLS-1$
3738: }
3739: System.out
3740: .println(Thread.currentThread()
3741: + " CLOSING " + elementType + " " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
3742: wasVerbose = true;
3743: JavaModelCache.VERBOSE = false;
3744: }
3745: element.closing(info);
3746: if (element instanceof IParent
3747: && info instanceof JavaElementInfo) {
3748: IJavaElement[] children = ((JavaElementInfo) info)
3749: .getChildren();
3750: for (int i = 0, size = children.length; i < size; ++i) {
3751: JavaElement child = (JavaElement) children[i];
3752: child.close();
3753: }
3754: }
3755: this .cache.removeInfo(element);
3756: if (wasVerbose) {
3757: System.out.println(this .cache
3758: .toStringFillingRation("-> ")); //$NON-NLS-1$
3759: }
3760: } finally {
3761: JavaModelCache.VERBOSE = wasVerbose;
3762: }
3763: return info;
3764: }
3765: return null;
3766: }
3767:
3768: public void removePerProjectInfo(JavaProject javaProject) {
3769: synchronized (this .perProjectInfos) { // use the perProjectInfo collection as its own lock
3770: IProject project = javaProject.getProject();
3771: PerProjectInfo info = (PerProjectInfo) this .perProjectInfos
3772: .get(project);
3773: if (info != null) {
3774: this .perProjectInfos.remove(project);
3775: }
3776: }
3777: }
3778:
3779: /*
3780: * Reset project options stored in info cache.
3781: */
3782: public void resetProjectOptions(JavaProject javaProject) {
3783: synchronized (this .perProjectInfos) { // use the perProjectInfo collection as its own lock
3784: IProject project = javaProject.getProject();
3785: PerProjectInfo info = (PerProjectInfo) this .perProjectInfos
3786: .get(project);
3787: if (info != null) {
3788: info.options = null;
3789: }
3790: }
3791: }
3792:
3793: /*
3794: * Reset project preferences stored in info cache.
3795: */
3796: public void resetProjectPreferences(JavaProject javaProject) {
3797: synchronized (this .perProjectInfos) { // use the perProjectInfo collection as its own lock
3798: IProject project = javaProject.getProject();
3799: PerProjectInfo info = (PerProjectInfo) this .perProjectInfos
3800: .get(project);
3801: if (info != null) {
3802: info.preferences = null;
3803: }
3804: }
3805: }
3806:
3807: public static final void doNotUse() {
3808: // used by tests to simulate a startup
3809: MANAGER = new JavaModelManager();
3810: }
3811:
3812: /*
3813: * Resets the cache that holds on binary type in jar files
3814: */
3815: protected synchronized void resetJarTypeCache() {
3816: this .cache.resetJarTypeCache();
3817: }
3818:
3819: /*
3820: * Resets the temporary cache for newly created elements to null.
3821: */
3822: public void resetTemporaryCache() {
3823: this .temporaryCache.set(null);
3824: }
3825:
3826: /**
3827: * @see ISaveParticipant
3828: */
3829: public void rollback(ISaveContext context) {
3830: // nothing to do
3831: }
3832:
3833: private void saveState(PerProjectInfo info, ISaveContext context)
3834: throws CoreException {
3835:
3836: // passed this point, save actions are non trivial
3837: if (context.getKind() == ISaveContext.SNAPSHOT)
3838: return;
3839:
3840: // save built state
3841: if (info.triedRead)
3842: saveBuiltState(info);
3843: }
3844:
3845: /**
3846: * Saves the built state for the project.
3847: */
3848: private void saveBuiltState(PerProjectInfo info)
3849: throws CoreException {
3850: if (JavaBuilder.DEBUG)
3851: System.out.println(Messages.bind(
3852: Messages.build_saveStateProgress, info.project
3853: .getName()));
3854: File file = getSerializationFile(info.project);
3855: if (file == null)
3856: return;
3857: long t = System.currentTimeMillis();
3858: try {
3859: DataOutputStream out = new DataOutputStream(
3860: new BufferedOutputStream(new FileOutputStream(file)));
3861: try {
3862: out.writeUTF(JavaCore.PLUGIN_ID);
3863: out.writeUTF("STATE"); //$NON-NLS-1$
3864: if (info.savedState == null) {
3865: out.writeBoolean(false);
3866: } else {
3867: out.writeBoolean(true);
3868: JavaBuilder.writeState(info.savedState, out);
3869: }
3870: } finally {
3871: out.close();
3872: }
3873: } catch (RuntimeException e) {
3874: try {
3875: file.delete();
3876: } catch (SecurityException se) {
3877: // could not delete file: cannot do much more
3878: }
3879: throw new CoreException(new Status(IStatus.ERROR,
3880: JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, Messages
3881: .bind(Messages.build_cannotSaveState,
3882: info.project.getName()), e));
3883: } catch (IOException e) {
3884: try {
3885: file.delete();
3886: } catch (SecurityException se) {
3887: // could not delete file: cannot do much more
3888: }
3889: throw new CoreException(new Status(IStatus.ERROR,
3890: JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, Messages
3891: .bind(Messages.build_cannotSaveState,
3892: info.project.getName()), e));
3893: }
3894: if (JavaBuilder.DEBUG) {
3895: t = System.currentTimeMillis() - t;
3896: System.out.println(Messages
3897: .bind(Messages.build_saveStateComplete, String
3898: .valueOf(t)));
3899: }
3900: }
3901:
3902: private void saveVariablesAndContainers(ISaveContext context)
3903: throws CoreException {
3904: File file = getVariableAndContainersFile();
3905: DataOutputStream out = null;
3906: try {
3907: out = new DataOutputStream(new BufferedOutputStream(
3908: new FileOutputStream(file)));
3909: out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION);
3910: if (VARIABLES_AND_CONTAINERS_FILE_VERSION != 1)
3911: new VariablesAndContainersSaveHelper(out).save(context);
3912: else {
3913: // old code retained for performance comparisons
3914:
3915: // variables
3916: out.writeInt(this .variables.size());
3917: Iterator iterator = this .variables.entrySet()
3918: .iterator();
3919: while (iterator.hasNext()) {
3920: Map.Entry entry = (Map.Entry) iterator.next();
3921: String variableName = (String) entry.getKey();
3922: out.writeUTF(variableName);
3923: IPath path = (IPath) entry.getValue();
3924: out.writeUTF(path == null ? CP_ENTRY_IGNORE : path
3925: .toPortableString());
3926: }
3927:
3928: // containers
3929: IJavaProject[] projects = getJavaModel()
3930: .getJavaProjects();
3931: int length = projects.length;
3932: out.writeInt(length);
3933: for (int i = 0; i < length; i++) {
3934: IJavaProject project = projects[i];
3935: // clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
3936: Map projectContainers = containerClone(project);
3937: out.writeUTF(project.getElementName());
3938: if (projectContainers == null) {
3939: out.writeInt(0);
3940: continue;
3941: }
3942: HashMap containersToSave = new HashMap();
3943: for (iterator = projectContainers.entrySet()
3944: .iterator(); iterator.hasNext();) {
3945: Map.Entry entry = (Map.Entry) iterator.next();
3946: IPath containerPath = (IPath) entry.getKey();
3947: IClasspathContainer container = (IClasspathContainer) entry
3948: .getValue();
3949: String containerString = null;
3950: try {
3951: if (container == null) {
3952: // container has not been initialized yet, use previous session value
3953: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
3954: container = getPreviousSessionContainer(
3955: containerPath, project);
3956: }
3957: if (container != null) {
3958: IClasspathEntry[] entries = container
3959: .getClasspathEntries();
3960: containerString = ((JavaProject) project)
3961: .encodeClasspath(entries, null,
3962: false, null/*not interested in unknown elements*/);
3963: }
3964: } catch (JavaModelException e) {
3965: // could not encode entry: will not persist
3966: Util
3967: .log(
3968: e,
3969: "Could not persist container " + containerPath + " for project " + project.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
3970: }
3971: if (containerString != null)
3972: containersToSave.put(containerPath,
3973: containerString);
3974: }
3975: out.writeInt(containersToSave.size());
3976: iterator = containersToSave.entrySet().iterator();
3977: while (iterator.hasNext()) {
3978: Map.Entry entry = (Map.Entry) iterator.next();
3979: IPath containerPath = (IPath) entry.getKey();
3980: out.writeUTF(containerPath.toPortableString());
3981: String containerString = (String) entry
3982: .getValue();
3983: out.writeInt(containerString.length());
3984: out.writeBytes(containerString);
3985: }
3986: }
3987: }
3988: } catch (IOException e) {
3989: IStatus status = new Status(IStatus.ERROR,
3990: JavaCore.PLUGIN_ID, IStatus.ERROR,
3991: "Problems while saving variables and containers", e); //$NON-NLS-1$
3992: throw new CoreException(status);
3993: } finally {
3994: if (out != null) {
3995: try {
3996: out.close();
3997: } catch (IOException e) {
3998: // nothing we can do: ignore
3999: }
4000: }
4001: }
4002: }
4003:
4004: private final class VariablesAndContainersSaveHelper {
4005:
4006: private final HashtableOfObjectToInt classpathEntryIds; // IClasspathEntry -> int
4007: private final DataOutputStream out;
4008: private final HashtableOfObjectToInt stringIds; // Strings -> int
4009:
4010: VariablesAndContainersSaveHelper(DataOutputStream out) {
4011: super ();
4012: this .classpathEntryIds = new HashtableOfObjectToInt();
4013: this .out = out;
4014: this .stringIds = new HashtableOfObjectToInt();
4015: }
4016:
4017: void save(ISaveContext context) throws IOException,
4018: JavaModelException {
4019: IProject project = context.getProject();
4020: if (project == null) { // save all projects if none specified (snapshot or full save)
4021: saveProjects(JavaModelManager.this .getJavaModel()
4022: .getJavaProjects());
4023: } else {
4024: saveProjects(new IJavaProject[] { JavaCore
4025: .create(project) });
4026: }
4027:
4028: switch (context.getKind()) {
4029: case ISaveContext.FULL_SAVE:
4030: // TODO (eric) - investigate after 3.3 if variables should be saved for a SNAPSHOT
4031: case ISaveContext.SNAPSHOT:
4032: // remove variables that should not be saved
4033: HashMap varsToSave = null;
4034: Iterator iterator = JavaModelManager.this .variables
4035: .entrySet().iterator();
4036: IEclipsePreferences defaultPreferences = getDefaultPreferences();
4037: while (iterator.hasNext()) {
4038: Map.Entry entry = (Map.Entry) iterator.next();
4039: String varName = (String) entry.getKey();
4040: if (defaultPreferences.get(
4041: CP_VARIABLE_PREFERENCES_PREFIX + varName,
4042: null) != null // don't save classpath variables from the default preferences as there is no delta if they are removed
4043: || CP_ENTRY_IGNORE_PATH.equals(entry
4044: .getValue())) {
4045:
4046: if (varsToSave == null)
4047: varsToSave = new HashMap(
4048: JavaModelManager.this .variables);
4049: varsToSave.remove(varName);
4050: }
4051: }
4052: saveVariables(varsToSave != null ? varsToSave
4053: : JavaModelManager.this .variables);
4054: break;
4055: default:
4056: // do nothing
4057: }
4058: }
4059:
4060: private void saveAccessRule(ClasspathAccessRule rule)
4061: throws IOException {
4062: saveInt(rule.problemId);
4063: savePath(rule.getPattern());
4064: }
4065:
4066: private void saveAccessRules(IAccessRule[] rules)
4067: throws IOException {
4068: int count = rules == null ? 0 : rules.length;
4069:
4070: saveInt(count);
4071: for (int i = 0; i < count; ++i)
4072: saveAccessRule((ClasspathAccessRule) rules[i]);
4073: }
4074:
4075: private void saveAttribute(IClasspathAttribute attribute)
4076: throws IOException {
4077: saveString(attribute.getName());
4078: saveString(attribute.getValue());
4079: }
4080:
4081: private void saveAttributes(IClasspathAttribute[] attributes)
4082: throws IOException {
4083: int count = attributes == null ? 0 : attributes.length;
4084:
4085: saveInt(count);
4086: for (int i = 0; i < count; ++i)
4087: saveAttribute(attributes[i]);
4088: }
4089:
4090: private void saveClasspathEntries(IClasspathEntry[] entries)
4091: throws IOException {
4092: int count = entries == null ? 0 : entries.length;
4093:
4094: saveInt(count);
4095: for (int i = 0; i < count; ++i)
4096: saveClasspathEntry(entries[i]);
4097: }
4098:
4099: private void saveClasspathEntry(IClasspathEntry entry)
4100: throws IOException {
4101: if (saveNewId(entry, this .classpathEntryIds)) {
4102: saveInt(entry.getContentKind());
4103: saveInt(entry.getEntryKind());
4104: savePath(entry.getPath());
4105: savePaths(entry.getInclusionPatterns());
4106: savePaths(entry.getExclusionPatterns());
4107: savePath(entry.getSourceAttachmentPath());
4108: savePath(entry.getSourceAttachmentRootPath());
4109: savePath(entry.getOutputLocation());
4110: this .out.writeBoolean(entry.isExported());
4111: saveAccessRules(entry.getAccessRules());
4112: this .out.writeBoolean(entry.combineAccessRules());
4113: saveAttributes(entry.getExtraAttributes());
4114: }
4115: }
4116:
4117: private void saveContainers(IJavaProject project,
4118: Map containerMap) throws IOException {
4119: saveInt(containerMap.size());
4120:
4121: for (Iterator i = containerMap.entrySet().iterator(); i
4122: .hasNext();) {
4123: Entry entry = (Entry) i.next();
4124: IPath path = (IPath) entry.getKey();
4125: IClasspathContainer container = (IClasspathContainer) entry
4126: .getValue();
4127: IClasspathEntry[] cpEntries = null;
4128:
4129: if (container == null) {
4130: // container has not been initialized yet, use previous
4131: // session value
4132: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
4133: container = JavaModelManager.this
4134: .getPreviousSessionContainer(path, project);
4135: }
4136:
4137: if (container != null)
4138: cpEntries = container.getClasspathEntries();
4139:
4140: savePath(path);
4141: saveClasspathEntries(cpEntries);
4142: }
4143: }
4144:
4145: private void saveInt(int value) throws IOException {
4146: this .out.writeInt(value);
4147: }
4148:
4149: private boolean saveNewId(Object key, HashtableOfObjectToInt map)
4150: throws IOException {
4151: int id = map.get(key);
4152:
4153: if (id == -1) {
4154: int newId = map.size();
4155:
4156: map.put(key, newId);
4157:
4158: saveInt(newId);
4159:
4160: return true;
4161: } else {
4162: saveInt(id);
4163:
4164: return false;
4165: }
4166: }
4167:
4168: private void savePath(IPath path) throws IOException {
4169: if (path == null) {
4170: this .out.writeBoolean(true);
4171: } else {
4172: this .out.writeBoolean(false);
4173: saveString(path.toPortableString());
4174: }
4175: }
4176:
4177: private void savePaths(IPath[] paths) throws IOException {
4178: int count = paths == null ? 0 : paths.length;
4179:
4180: saveInt(count);
4181: for (int i = 0; i < count; ++i)
4182: savePath(paths[i]);
4183: }
4184:
4185: private void saveProjects(IJavaProject[] projects)
4186: throws IOException, JavaModelException {
4187: int count = projects.length;
4188:
4189: saveInt(count);
4190:
4191: for (int i = 0; i < count; ++i) {
4192: IJavaProject project = projects[i];
4193:
4194: saveString(project.getElementName());
4195:
4196: Map containerMap = (Map) JavaModelManager.this .containers
4197: .get(project);
4198:
4199: if (containerMap == null) {
4200: containerMap = Collections.EMPTY_MAP;
4201: } else {
4202: // clone while iterating
4203: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
4204: containerMap = new HashMap(containerMap);
4205: }
4206:
4207: saveContainers(project, containerMap);
4208: }
4209: }
4210:
4211: private void saveString(String string) throws IOException {
4212: if (saveNewId(string, this .stringIds))
4213: this .out.writeUTF(string);
4214: }
4215:
4216: private void saveVariables(Map map) throws IOException {
4217: saveInt(map.size());
4218:
4219: for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
4220: Entry entry = (Entry) i.next();
4221: String varName = (String) entry.getKey();
4222: IPath varPath = (IPath) entry.getValue();
4223:
4224: saveString(varName);
4225: savePath(varPath);
4226: }
4227: }
4228: }
4229:
4230: private void traceVariableAndContainers(String action, long start) {
4231:
4232: Long delta = new Long(System.currentTimeMillis() - start);
4233: Long length = new Long(getVariableAndContainersFile().length());
4234: String pattern = "{0} {1} bytes in variablesAndContainers.dat in {2}ms"; //$NON-NLS-1$
4235: String message = MessageFormat.format(pattern, new Object[] {
4236: action, length, delta });
4237:
4238: System.out.println(message);
4239: }
4240:
4241: /**
4242: * @see ISaveParticipant
4243: */
4244: public void saving(ISaveContext context) throws CoreException {
4245:
4246: long start = -1;
4247: if (VERBOSE)
4248: start = System.currentTimeMillis();
4249:
4250: // save variable and container values on snapshot/full save
4251: saveVariablesAndContainers(context);
4252:
4253: if (VERBOSE)
4254: traceVariableAndContainers("Saved", start); //$NON-NLS-1$
4255:
4256: if (context.getKind() == ISaveContext.FULL_SAVE) {
4257: // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
4258: context.needDelta();
4259:
4260: // clean up indexes on workspace full save
4261: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
4262: IndexManager manager = this .indexManager;
4263: if (manager != null
4264: // don't force initialization of workspace scope as we could be shutting down
4265: // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93941)
4266: && this .workspaceScope != null) {
4267: manager.cleanUpIndexes();
4268: }
4269: }
4270:
4271: IProject savedProject = context.getProject();
4272: if (savedProject != null) {
4273: if (!JavaProject.hasJavaNature(savedProject))
4274: return; // ignore
4275: PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
4276: saveState(info, context);
4277: info.rememberExternalLibTimestamps();
4278: return;
4279: }
4280:
4281: ArrayList vStats = null; // lazy initialized
4282: ArrayList values = null;
4283: synchronized (this .perProjectInfos) {
4284: values = new ArrayList(this .perProjectInfos.values());
4285: }
4286: Iterator iterator = values.iterator();
4287: while (iterator.hasNext()) {
4288: try {
4289: PerProjectInfo info = (PerProjectInfo) iterator.next();
4290: saveState(info, context);
4291: info.rememberExternalLibTimestamps();
4292: } catch (CoreException e) {
4293: if (vStats == null)
4294: vStats = new ArrayList();
4295: vStats.add(e.getStatus());
4296: }
4297: }
4298: if (vStats != null) {
4299: IStatus[] stats = new IStatus[vStats.size()];
4300: vStats.toArray(stats);
4301: throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID,
4302: IStatus.ERROR, stats,
4303: Messages.build_cannotSaveStates, null));
4304: }
4305:
4306: // save external libs timestamps
4307: this .deltaState.saveExternalLibTimeStamps();
4308: }
4309:
4310: /**
4311: * Add a secondary type in temporary indexing cache for a project got from given path.
4312: *
4313: * Current secondary types cache is not modified as we want to wait that indexing
4314: * was finished before taking new secondary types into account.
4315: *
4316: * Indexing cache is a specific entry in secondary types cache which key is
4317: * {@link #INDEXED_SECONDARY_TYPES } and value a map with same structure than
4318: * secondary types cache itself.
4319: *
4320: * @see #secondaryTypes(IJavaProject, boolean, IProgressMonitor)
4321: */
4322: public void secondaryTypeAdding(String path, char[] typeName,
4323: char[] packageName) {
4324: if (VERBOSE) {
4325: StringBuffer buffer = new StringBuffer(
4326: "JavaModelManager.addSecondaryType("); //$NON-NLS-1$
4327: buffer.append(path);
4328: buffer.append(',');
4329: buffer.append('[');
4330: buffer.append(new String(packageName));
4331: buffer.append('.');
4332: buffer.append(new String(typeName));
4333: buffer.append(']');
4334: buffer.append(')');
4335: Util.verbose(buffer.toString());
4336: }
4337: IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot();
4338: IResource resource = wRoot.findMember(path);
4339: if (resource != null) {
4340: if (org.eclipse.jdt.internal.core.util.Util
4341: .isJavaLikeFileName(path)
4342: && resource.getType() == IResource.FILE) {
4343: IProject project = resource.getProject();
4344: try {
4345: PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project);
4346: // Get or create map to cache secondary types while indexing (can be not synchronized as indexing insure a non-concurrent usage)
4347: HashMap indexedSecondaryTypes = null;
4348: if (projectInfo.secondaryTypes == null) {
4349: projectInfo.secondaryTypes = new Hashtable(3);
4350: indexedSecondaryTypes = new HashMap(3);
4351: projectInfo.secondaryTypes.put(
4352: INDEXED_SECONDARY_TYPES,
4353: indexedSecondaryTypes);
4354: } else {
4355: indexedSecondaryTypes = (HashMap) projectInfo.secondaryTypes
4356: .get(INDEXED_SECONDARY_TYPES);
4357: if (indexedSecondaryTypes == null) {
4358: indexedSecondaryTypes = new HashMap(3);
4359: projectInfo.secondaryTypes.put(
4360: INDEXED_SECONDARY_TYPES,
4361: indexedSecondaryTypes);
4362: }
4363: }
4364: // Store the secondary type in temporary cache (these are just handles => no problem to create it now...)
4365: HashMap allTypes = (HashMap) indexedSecondaryTypes
4366: .get(resource);
4367: if (allTypes == null) {
4368: allTypes = new HashMap(3);
4369: indexedSecondaryTypes.put(resource, allTypes);
4370: }
4371: ICompilationUnit unit = JavaModelManager
4372: .createCompilationUnitFrom(
4373: (IFile) resource, null);
4374: if (unit != null) {
4375: String typeString = new String(typeName);
4376: IType type = unit.getType(typeString);
4377: // String packageString = new String(packageName);
4378: // use package fragment name instead of parameter as it may be invalid...
4379: // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=186781
4380: String packageString = type
4381: .getPackageFragment().getElementName();
4382: HashMap packageTypes = (HashMap) allTypes
4383: .get(packageString);
4384: if (packageTypes == null) {
4385: packageTypes = new HashMap(3);
4386: allTypes.put(packageString, packageTypes);
4387: }
4388: packageTypes.put(typeString, type);
4389: }
4390: if (VERBOSE) {
4391: Util.verbose(" - indexing cache:"); //$NON-NLS-1$
4392: Iterator entries = indexedSecondaryTypes
4393: .entrySet().iterator();
4394: while (entries.hasNext()) {
4395: Map.Entry entry = (Map.Entry) entries
4396: .next();
4397: IFile file = (IFile) entry.getKey();
4398: Util
4399: .verbose(" + " + file.getFullPath() + ':' + entry.getValue()); //$NON-NLS-1$
4400: }
4401: }
4402: } catch (JavaModelException jme) {
4403: // do nothing
4404: }
4405: }
4406: }
4407: }
4408:
4409: /**
4410: * Get all secondary types for a project and store result in per project info cache.
4411: *
4412: * This cache is an Hashtable<String, HashMap<String, IType>>:
4413: * - key: package name
4414: * - value:
4415: * + key: type name
4416: * + value: java model handle for the secondary type
4417: * Hashtable was used to protect callers from possible concurrent access.
4418: *
4419: * Note that this map may have a specific entry which key is {@link #INDEXED_SECONDARY_TYPES }
4420: * and value is a map containing all secondary types created during indexing.
4421: * When this key is in cache and indexing is finished, returned map is merged
4422: * with the value of this special key. If indexing is not finished and caller does
4423: * not wait for the end of indexing, returned map is the current secondary
4424: * types cache content which may be invalid...
4425: *
4426: * @param project Project we want get secondary types from
4427: * @return HashMap Table of secondary type names->path for given project
4428: */
4429: public Map secondaryTypes(IJavaProject project,
4430: boolean waitForIndexes, IProgressMonitor monitor)
4431: throws JavaModelException {
4432: if (VERBOSE) {
4433: StringBuffer buffer = new StringBuffer(
4434: "JavaModelManager.secondaryTypes("); //$NON-NLS-1$
4435: buffer.append(project.getElementName());
4436: buffer.append(',');
4437: buffer.append(waitForIndexes);
4438: buffer.append(')');
4439: Util.verbose(buffer.toString());
4440: }
4441:
4442: // Return cache if not empty and there's no new secondary types created during indexing
4443: final PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project
4444: .getProject());
4445: Map indexingSecondaryCache = projectInfo.secondaryTypes == null ? null
4446: : (Map) projectInfo.secondaryTypes
4447: .get(INDEXED_SECONDARY_TYPES);
4448: if (projectInfo.secondaryTypes != null
4449: && indexingSecondaryCache == null) {
4450: return projectInfo.secondaryTypes;
4451: }
4452:
4453: // Perform search request only if secondary types cache is not initialized yet (this will happen only once!)
4454: if (projectInfo.secondaryTypes == null) {
4455: return secondaryTypesSearching(project, waitForIndexes,
4456: monitor, projectInfo);
4457: }
4458:
4459: // New secondary types have been created while indexing secondary types cache
4460: // => need to know whether the indexing is finished or not
4461: boolean indexing = this .indexManager.awaitingJobsCount() > 0;
4462: if (indexing) {
4463: if (!waitForIndexes) {
4464: // Indexing is running but caller cannot wait => return current cache
4465: return projectInfo.secondaryTypes;
4466: }
4467:
4468: // Wait for the end of indexing or a cancel
4469: while (this .indexManager.awaitingJobsCount() > 0) {
4470: if (monitor != null && monitor.isCanceled()) {
4471: return projectInfo.secondaryTypes;
4472: }
4473: try {
4474: Thread.sleep(10);
4475: } catch (InterruptedException e) {
4476: return projectInfo.secondaryTypes;
4477: }
4478: }
4479: }
4480:
4481: // Indexing is finished => merge caches and return result
4482: return secondaryTypesMerging(projectInfo.secondaryTypes);
4483: }
4484:
4485: /*
4486: * Return secondary types cache merged with new secondary types created while indexing
4487: * Note that merge result is directly stored in given parameter map.
4488: */
4489: private Hashtable secondaryTypesMerging(Hashtable secondaryTypes) {
4490: if (VERBOSE) {
4491: Util.verbose("JavaModelManager.getSecondaryTypesMerged()"); //$NON-NLS-1$
4492: Util.verbose(" - current cache to merge:"); //$NON-NLS-1$
4493: Iterator entries = secondaryTypes.entrySet().iterator();
4494: while (entries.hasNext()) {
4495: Map.Entry entry = (Map.Entry) entries.next();
4496: String packName = (String) entry.getKey();
4497: Util
4498: .verbose(" + " + packName + ':' + entry.getValue()); //$NON-NLS-1$
4499: }
4500: }
4501:
4502: // Return current cache if there's no indexing cache (double check, this should not happen)
4503: HashMap indexedSecondaryTypes = (HashMap) secondaryTypes
4504: .remove(INDEXED_SECONDARY_TYPES);
4505: if (indexedSecondaryTypes == null) {
4506: return secondaryTypes;
4507: }
4508:
4509: // Merge indexing cache in secondary types one
4510: Iterator entries = indexedSecondaryTypes.entrySet().iterator();
4511: while (entries.hasNext()) {
4512: Map.Entry entry = (Map.Entry) entries.next();
4513: IFile file = (IFile) entry.getKey();
4514:
4515: // Remove all secondary types of indexed file from cache
4516: secondaryTypesRemoving(secondaryTypes, file);
4517:
4518: // Add all indexing file secondary types in given secondary types cache
4519: HashMap fileSecondaryTypes = (HashMap) entry.getValue();
4520: Iterator entries2 = fileSecondaryTypes.entrySet()
4521: .iterator();
4522: while (entries2.hasNext()) {
4523: Map.Entry entry2 = (Map.Entry) entries2.next();
4524: String packageName = (String) entry2.getKey();
4525: HashMap cachedTypes = (HashMap) secondaryTypes
4526: .get(packageName);
4527: if (cachedTypes == null) {
4528: secondaryTypes.put(packageName, entry2.getValue());
4529: } else {
4530: HashMap types = (HashMap) entry2.getValue();
4531: Iterator entries3 = types.entrySet().iterator();
4532: while (entries3.hasNext()) {
4533: Map.Entry entry3 = (Map.Entry) entries3.next();
4534: String typeName = (String) entry3.getKey();
4535: cachedTypes.put(typeName, entry3.getValue());
4536: }
4537: }
4538: }
4539: }
4540: if (VERBOSE) {
4541: Util.verbose(" - secondary types cache merged:"); //$NON-NLS-1$
4542: entries = secondaryTypes.entrySet().iterator();
4543: while (entries.hasNext()) {
4544: Map.Entry entry = (Map.Entry) entries.next();
4545: String packName = (String) entry.getKey();
4546: Util
4547: .verbose(" + " + packName + ':' + entry.getValue()); //$NON-NLS-1$
4548: }
4549: }
4550: return secondaryTypes;
4551: }
4552:
4553: /*
4554: * Perform search request to get all secondary types of a given project.
4555: * If not waiting for indexes and indexing is running, will return types found in current built indexes...
4556: */
4557: private Map secondaryTypesSearching(IJavaProject project,
4558: boolean waitForIndexes, IProgressMonitor monitor,
4559: final PerProjectInfo projectInfo) throws JavaModelException {
4560: if (VERBOSE || BasicSearchEngine.VERBOSE) {
4561: StringBuffer buffer = new StringBuffer(
4562: "JavaModelManager.secondaryTypesSearch("); //$NON-NLS-1$
4563: buffer.append(project.getElementName());
4564: buffer.append(',');
4565: buffer.append(waitForIndexes);
4566: buffer.append(')');
4567: Util.verbose(buffer.toString());
4568: }
4569:
4570: final Hashtable secondaryTypes = new Hashtable(3);
4571: IRestrictedAccessTypeRequestor nameRequestor = new IRestrictedAccessTypeRequestor() {
4572: public void acceptType(int modifiers, char[] packageName,
4573: char[] simpleTypeName, char[][] enclosingTypeNames,
4574: String path, AccessRestriction access) {
4575: String key = packageName == null ? "" : new String(packageName); //$NON-NLS-1$
4576: HashMap types = (HashMap) secondaryTypes.get(key);
4577: if (types == null)
4578: types = new HashMap(3);
4579: types.put(new String(simpleTypeName), path);
4580: secondaryTypes.put(key, types);
4581: }
4582: };
4583:
4584: // Build scope using prereq projects but only source folders
4585: IPackageFragmentRoot[] allRoots = project
4586: .getAllPackageFragmentRoots();
4587: int length = allRoots.length, size = 0;
4588: IPackageFragmentRoot[] allSourceFolders = new IPackageFragmentRoot[length];
4589: for (int i = 0; i < length; i++) {
4590: if (allRoots[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
4591: allSourceFolders[size++] = allRoots[i];
4592: }
4593: }
4594: if (size < length) {
4595: System.arraycopy(allSourceFolders, 0,
4596: allSourceFolders = new IPackageFragmentRoot[size],
4597: 0, size);
4598: }
4599:
4600: // Search all secondary types on scope
4601: new BasicSearchEngine().searchAllSecondaryTypeNames(
4602: allSourceFolders, nameRequestor, waitForIndexes,
4603: monitor);
4604:
4605: // Build types from paths
4606: Iterator packages = secondaryTypes.values().iterator();
4607: while (packages.hasNext()) {
4608: HashMap types = (HashMap) packages.next();
4609: Iterator names = types.entrySet().iterator();
4610: while (names.hasNext()) {
4611: Map.Entry entry = (Map.Entry) names.next();
4612: String typeName = (String) entry.getKey();
4613: String path = (String) entry.getValue();
4614: if (org.eclipse.jdt.internal.core.util.Util
4615: .isJavaLikeFileName(path)) {
4616: IFile file = ResourcesPlugin.getWorkspace()
4617: .getRoot().getFile(new Path(path));
4618: ICompilationUnit unit = JavaModelManager
4619: .createCompilationUnitFrom(file, null);
4620: IType type = unit.getType(typeName);
4621: types.put(typeName, type); // replace stored path with type itself
4622: }
4623: }
4624: }
4625:
4626: // Store result in per project info cache if still null or there's still an indexing cache (may have been set by another thread...)
4627: if (projectInfo.secondaryTypes == null
4628: || projectInfo.secondaryTypes
4629: .get(INDEXED_SECONDARY_TYPES) != null) {
4630: projectInfo.secondaryTypes = secondaryTypes;
4631: if (VERBOSE || BasicSearchEngine.VERBOSE) {
4632: System.out.print(Thread.currentThread()
4633: + " -> secondary paths stored in cache: "); //$NON-NLS-1$
4634: System.out.println();
4635: Iterator entries = secondaryTypes.entrySet().iterator();
4636: while (entries.hasNext()) {
4637: Map.Entry entry = (Map.Entry) entries.next();
4638: String qualifiedName = (String) entry.getKey();
4639: Util
4640: .verbose(" - " + qualifiedName + '-' + entry.getValue()); //$NON-NLS-1$
4641: }
4642: }
4643: }
4644: return projectInfo.secondaryTypes;
4645: }
4646:
4647: /**
4648: * Remove from secondary types cache all types belonging to a given file.
4649: * Clean secondary types cache built while indexing if requested.
4650: *
4651: * Project's secondary types cache is found using file location.
4652: *
4653: * @param file File to remove
4654: */
4655: public void secondaryTypesRemoving(IFile file,
4656: boolean cleanIndexCache) {
4657: if (VERBOSE) {
4658: StringBuffer buffer = new StringBuffer(
4659: "JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$
4660: buffer.append(file.getName());
4661: buffer.append(')');
4662: Util.verbose(buffer.toString());
4663: }
4664: if (file != null) {
4665: PerProjectInfo projectInfo = getPerProjectInfo(file
4666: .getProject(), false);
4667: if (projectInfo != null
4668: && projectInfo.secondaryTypes != null) {
4669: if (VERBOSE) {
4670: Util
4671: .verbose("-> remove file from cache of project: " + file.getProject().getName()); //$NON-NLS-1$
4672: }
4673:
4674: // Clean current cache
4675: secondaryTypesRemoving(projectInfo.secondaryTypes, file);
4676:
4677: // Clean indexing cache if necessary
4678: HashMap indexingCache = (HashMap) projectInfo.secondaryTypes
4679: .get(INDEXED_SECONDARY_TYPES);
4680: if (!cleanIndexCache) {
4681: if (indexingCache == null) {
4682: // Need to signify that secondary types indexing will happen before any request happens
4683: // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=152841
4684: projectInfo.secondaryTypes.put(
4685: INDEXED_SECONDARY_TYPES, new HashMap());
4686: }
4687: return;
4688: }
4689: if (indexingCache != null) {
4690: Set keys = indexingCache.keySet();
4691: int filesSize = keys.size(), filesCount = 0;
4692: IFile[] removed = null;
4693: Iterator cachedFiles = keys.iterator();
4694: while (cachedFiles.hasNext()) {
4695: IFile cachedFile = (IFile) cachedFiles.next();
4696: if (file.equals(cachedFile)) {
4697: if (removed == null)
4698: removed = new IFile[filesSize];
4699: filesSize--;
4700: removed[filesCount++] = cachedFile;
4701: }
4702: }
4703: if (removed != null) {
4704: for (int i = 0; i < filesCount; i++) {
4705: indexingCache.remove(removed[i]);
4706: }
4707: }
4708: }
4709: }
4710: }
4711: }
4712:
4713: /*
4714: * Remove from a given cache map all secondary types belonging to a given file.
4715: * Note that there can have several secondary types per file...
4716: */
4717: private void secondaryTypesRemoving(Hashtable secondaryTypesMap,
4718: IFile file) {
4719: if (VERBOSE) {
4720: StringBuffer buffer = new StringBuffer(
4721: "JavaModelManager.removeSecondaryTypesFromMap("); //$NON-NLS-1$
4722: Iterator entries = secondaryTypesMap.entrySet().iterator();
4723: while (entries.hasNext()) {
4724: Map.Entry entry = (Map.Entry) entries.next();
4725: String qualifiedName = (String) entry.getKey();
4726: buffer.append(qualifiedName + ':' + entry.getValue());
4727: }
4728: buffer.append(',');
4729: buffer.append(file.getFullPath());
4730: buffer.append(')');
4731: Util.verbose(buffer.toString());
4732: }
4733: Set packageEntries = secondaryTypesMap.entrySet();
4734: int packagesSize = packageEntries.size(), removedPackagesCount = 0;
4735: String[] removedPackages = null;
4736: Iterator packages = packageEntries.iterator();
4737: while (packages.hasNext()) {
4738: Map.Entry entry = (Map.Entry) packages.next();
4739: String packName = (String) entry.getKey();
4740: if (packName != INDEXED_SECONDARY_TYPES) { // skip indexing cache entry if present (!= is intentional)
4741: HashMap types = (HashMap) entry.getValue();
4742: Set nameEntries = types.entrySet();
4743: int namesSize = nameEntries.size(), removedNamesCount = 0;
4744: String[] removedNames = null;
4745: Iterator names = nameEntries.iterator();
4746: while (names.hasNext()) {
4747: Map.Entry entry2 = (Map.Entry) names.next();
4748: String typeName = (String) entry2.getKey();
4749: IType type = (IType) entry2.getValue();
4750: if (file.equals(type.getResource())) {
4751: if (removedNames == null)
4752: removedNames = new String[namesSize];
4753: namesSize--;
4754: removedNames[removedNamesCount++] = typeName;
4755: }
4756: }
4757: if (removedNames != null) {
4758: for (int i = 0; i < removedNamesCount; i++) {
4759: types.remove(removedNames[i]);
4760: }
4761: }
4762: if (types.size() == 0) {
4763: if (removedPackages == null)
4764: removedPackages = new String[packagesSize];
4765: packagesSize--;
4766: removedPackages[removedPackagesCount++] = packName;
4767: }
4768: }
4769: }
4770: if (removedPackages != null) {
4771: for (int i = 0; i < removedPackagesCount; i++) {
4772: secondaryTypesMap.remove(removedPackages[i]);
4773: }
4774: }
4775: if (VERBOSE) {
4776: Util.verbose(" - new secondary types map:"); //$NON-NLS-1$
4777: Iterator entries = secondaryTypesMap.entrySet().iterator();
4778: while (entries.hasNext()) {
4779: Map.Entry entry = (Map.Entry) entries.next();
4780: String qualifiedName = (String) entry.getKey();
4781: Util
4782: .verbose(" + " + qualifiedName + ':' + entry.getValue()); //$NON-NLS-1$
4783: }
4784: }
4785: }
4786:
4787: /**
4788: * Record the order in which to build the java projects (batch build). This order is based
4789: * on the projects classpath settings.
4790: */
4791: protected void setBuildOrder(String[] javaBuildOrder)
4792: throws JavaModelException {
4793:
4794: // optional behaviour
4795: // possible value of index 0 is Compute
4796: if (!JavaCore.COMPUTE.equals(JavaCore
4797: .getOption(JavaCore.CORE_JAVA_BUILD_ORDER)))
4798: return; // cannot be customized at project level
4799:
4800: if (javaBuildOrder == null || javaBuildOrder.length <= 1)
4801: return;
4802:
4803: IWorkspace workspace = ResourcesPlugin.getWorkspace();
4804: IWorkspaceDescription description = workspace.getDescription();
4805: String[] wksBuildOrder = description.getBuildOrder();
4806:
4807: String[] newOrder;
4808: if (wksBuildOrder == null) {
4809: newOrder = javaBuildOrder;
4810: } else {
4811: // remove projects which are already mentionned in java builder order
4812: int javaCount = javaBuildOrder.length;
4813: HashMap newSet = new HashMap(javaCount); // create a set for fast check
4814: for (int i = 0; i < javaCount; i++) {
4815: newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
4816: }
4817: int removed = 0;
4818: int oldCount = wksBuildOrder.length;
4819: for (int i = 0; i < oldCount; i++) {
4820: if (newSet.containsKey(wksBuildOrder[i])) {
4821: wksBuildOrder[i] = null;
4822: removed++;
4823: }
4824: }
4825: // add Java ones first
4826: newOrder = new String[oldCount - removed + javaCount];
4827: System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first
4828:
4829: // copy previous items in their respective order
4830: int index = javaCount;
4831: for (int i = 0; i < oldCount; i++) {
4832: if (wksBuildOrder[i] != null) {
4833: newOrder[index++] = wksBuildOrder[i];
4834: }
4835: }
4836: }
4837: // commit the new build order out
4838: description.setBuildOrder(newOrder);
4839: try {
4840: workspace.setDescription(description);
4841: } catch (CoreException e) {
4842: throw new JavaModelException(e);
4843: }
4844: }
4845:
4846: /**
4847: * Sets the last built state for the given project, or null to reset it.
4848: */
4849: public void setLastBuiltState(IProject project, Object state) {
4850: if (JavaProject.hasJavaNature(project)) {
4851: // should never be requested on non-Java projects
4852: PerProjectInfo info = getPerProjectInfo(project, true /*create if missing*/);
4853: info.triedRead = true; // no point trying to re-read once using setter
4854: info.savedState = state;
4855: }
4856: if (state == null) { // delete state file to ensure a full build happens if the workspace crashes
4857: try {
4858: File file = getSerializationFile(project);
4859: if (file != null && file.exists())
4860: file.delete();
4861: } catch (SecurityException se) {
4862: // could not delete file: cannot do much more
4863: }
4864: }
4865: }
4866:
4867: public void setOptions(Hashtable newOptions) {
4868:
4869: try {
4870: IEclipsePreferences defaultPreferences = getDefaultPreferences();
4871: IEclipsePreferences instancePreferences = getInstancePreferences();
4872:
4873: if (newOptions == null) {
4874: instancePreferences.clear();
4875: } else {
4876: Enumeration keys = newOptions.keys();
4877: while (keys.hasMoreElements()) {
4878: String key = (String) keys.nextElement();
4879: if (!this .optionNames.contains(key))
4880: continue; // unrecognized option
4881: if (key.equals(JavaCore.CORE_ENCODING))
4882: continue; // skipped, contributed by resource prefs
4883: String value = (String) newOptions.get(key);
4884: String defaultValue = defaultPreferences.get(key,
4885: null);
4886: if (defaultValue != null
4887: && defaultValue.equals(value)) {
4888: instancePreferences.remove(key);
4889: } else {
4890: instancePreferences.put(key, value);
4891: }
4892: }
4893: }
4894:
4895: // persist options
4896: instancePreferences.flush();
4897:
4898: // update cache
4899: this .optionsCache = newOptions == null ? null
4900: : new Hashtable(newOptions);
4901: } catch (BackingStoreException e) {
4902: // ignore
4903: }
4904: }
4905:
4906: public void startup() throws CoreException {
4907: try {
4908: configurePluginDebugOptions();
4909:
4910: // initialize Java model cache
4911: this .cache = new JavaModelCache();
4912:
4913: // request state folder creation (workaround 19885)
4914: JavaCore.getPlugin().getStateLocation();
4915:
4916: // Initialize eclipse preferences
4917: initializePreferences();
4918:
4919: // Listen to preference changes
4920: this .propertyListener = new Preferences.IPropertyChangeListener() {
4921: public void propertyChange(
4922: Preferences.PropertyChangeEvent event) {
4923: JavaModelManager.this .optionsCache = null;
4924: }
4925: };
4926: JavaCore.getPlugin().getPluginPreferences()
4927: .addPropertyChangeListener(this .propertyListener);
4928:
4929: // Listen to content-type changes
4930: Platform.getContentTypeManager()
4931: .addContentTypeChangeListener(this );
4932:
4933: // retrieve variable values
4934: long start = -1;
4935: if (VERBOSE)
4936: start = System.currentTimeMillis();
4937: loadVariablesAndContainers();
4938: if (VERBOSE)
4939: traceVariableAndContainers("Loaded", start); //$NON-NLS-1$
4940:
4941: final IWorkspace workspace = ResourcesPlugin.getWorkspace();
4942: workspace.addResourceChangeListener(this .deltaState,
4943: /* update spec in JavaCore#addPreProcessingResourceChangedListener(...) if adding more event types */
4944: IResourceChangeEvent.PRE_BUILD
4945: | IResourceChangeEvent.POST_BUILD
4946: | IResourceChangeEvent.POST_CHANGE
4947: | IResourceChangeEvent.PRE_DELETE
4948: | IResourceChangeEvent.PRE_CLOSE);
4949:
4950: startIndexing();
4951:
4952: // process deltas since last activated in indexer thread so that indexes are up-to-date.
4953: // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658
4954: Job processSavedState = new Job(Messages.savedState_jobName) {
4955: protected IStatus run(IProgressMonitor monitor) {
4956: try {
4957: // add save participant and process delta atomically
4958: // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59937
4959: workspace.run(new IWorkspaceRunnable() {
4960: public void run(IProgressMonitor progress)
4961: throws CoreException {
4962: ISavedState savedState = workspace
4963: .addSaveParticipant(JavaCore
4964: .getJavaCore(),
4965: JavaModelManager.this );
4966: if (savedState != null) {
4967: // the event type coming from the saved state is always POST_AUTO_BUILD
4968: // force it to be POST_CHANGE so that the delta processor can handle it
4969: JavaModelManager.this .deltaState
4970: .getDeltaProcessor().overridenEventType = IResourceChangeEvent.POST_CHANGE;
4971: savedState
4972: .processResourceChangeEvents(JavaModelManager.this .deltaState);
4973: }
4974: }
4975: }, monitor);
4976: } catch (CoreException e) {
4977: return e.getStatus();
4978: }
4979: return Status.OK_STATUS;
4980: }
4981: };
4982: processSavedState.setSystem(true);
4983: processSavedState.setPriority(Job.SHORT); // process asap
4984: processSavedState.schedule();
4985: } catch (RuntimeException e) {
4986: shutdown();
4987: throw e;
4988: }
4989: }
4990:
4991: /**
4992: * Initiate the background indexing process.
4993: * This should be deferred after the plug-in activation.
4994: */
4995: private void startIndexing() {
4996: if (this .indexManager != null)
4997: this .indexManager.reset();
4998: }
4999:
5000: public void shutdown() {
5001: JavaCore javaCore = JavaCore.getJavaCore();
5002: javaCore.savePluginPreferences();
5003: IWorkspace workspace = ResourcesPlugin.getWorkspace();
5004: workspace.removeResourceChangeListener(this .deltaState);
5005: workspace.removeSaveParticipant(javaCore);
5006:
5007: // Stop listening to content-type changes
5008: Platform.getContentTypeManager()
5009: .removeContentTypeChangeListener(this );
5010:
5011: // Stop indexing
5012: if (this .indexManager != null) {
5013: this .indexManager.shutdown();
5014: }
5015:
5016: // Stop listening to preferences changes
5017: JavaCore.getPlugin().getPluginPreferences()
5018: .removePropertyChangeListener(this .propertyListener);
5019: ((IEclipsePreferences) preferencesLookup[PREF_DEFAULT].parent())
5020: .removeNodeChangeListener(this .defaultNodeListener);
5021: preferencesLookup[PREF_DEFAULT] = null;
5022: ((IEclipsePreferences) preferencesLookup[PREF_INSTANCE]
5023: .parent())
5024: .removeNodeChangeListener(this .instanceNodeListener);
5025: preferencesLookup[PREF_INSTANCE]
5026: .removePreferenceChangeListener(this .instancePreferencesListener);
5027: preferencesLookup[PREF_INSTANCE] = null;
5028:
5029: // wait for the initialization job to finish
5030: try {
5031: Job.getJobManager().join(JavaCore.PLUGIN_ID, null);
5032: } catch (InterruptedException e) {
5033: // ignore
5034: }
5035:
5036: // Note: no need to close the Java model as this just removes Java element infos from the Java model cache
5037: }
5038:
5039: public synchronized IPath variableGet(String variableName) {
5040: // check initialization in progress first
5041: HashSet initializations = variableInitializationInProgress();
5042: if (initializations.contains(variableName)) {
5043: return VARIABLE_INITIALIZATION_IN_PROGRESS;
5044: }
5045: return (IPath) this .variables.get(variableName);
5046: }
5047:
5048: private synchronized IPath variableGetDefaultToPreviousSession(
5049: String variableName) {
5050: IPath variablePath = (IPath) this .variables.get(variableName);
5051: if (variablePath == null)
5052: return getPreviousSessionVariable(variableName);
5053: return variablePath;
5054: }
5055:
5056: /*
5057: * Returns the set of variable names that are being initialized in the current thread.
5058: */
5059: private HashSet variableInitializationInProgress() {
5060: HashSet initializations = (HashSet) this .variableInitializationInProgress
5061: .get();
5062: if (initializations == null) {
5063: initializations = new HashSet();
5064: this .variableInitializationInProgress.set(initializations);
5065: }
5066: return initializations;
5067: }
5068:
5069: public synchronized String[] variableNames() {
5070: int length = this .variables.size();
5071: String[] result = new String[length];
5072: Iterator vars = this .variables.keySet().iterator();
5073: int index = 0;
5074: while (vars.hasNext()) {
5075: result[index++] = (String) vars.next();
5076: }
5077: return result;
5078: }
5079:
5080: public synchronized void variablePut(String variableName,
5081: IPath variablePath) {
5082:
5083: // set/unset the initialization in progress
5084: HashSet initializations = variableInitializationInProgress();
5085: if (variablePath == VARIABLE_INITIALIZATION_IN_PROGRESS) {
5086: initializations.add(variableName);
5087:
5088: // do not write out intermediate initialization value
5089: return;
5090: } else {
5091: initializations.remove(variableName);
5092:
5093: // update cache - do not only rely on listener refresh
5094: if (variablePath == null) {
5095: // if path is null, record that the variable was removed to avoid asking the initializer to initialize it again
5096: // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=112609
5097: this .variables.put(variableName, CP_ENTRY_IGNORE_PATH);
5098: // clean other variables caches
5099: this .variablesWithInitializer.remove(variableName);
5100: this .deprecatedVariables.remove(variableName);
5101: } else {
5102: this .variables.put(variableName, variablePath);
5103: }
5104: // discard obsoleted information about previous session
5105: this .previousSessionVariables.remove(variableName);
5106: }
5107: }
5108:
5109: public void variablePreferencesPut(String variableName,
5110: IPath variablePath) {
5111: String variableKey = CP_VARIABLE_PREFERENCES_PREFIX
5112: + variableName;
5113: if (variablePath == null) {
5114: getInstancePreferences().remove(variableKey);
5115: } else {
5116: getInstancePreferences().put(variableKey,
5117: variablePath.toString());
5118: }
5119: try {
5120: getInstancePreferences().flush();
5121: } catch (BackingStoreException e) {
5122: // ignore exception
5123: }
5124: }
5125:
5126: /*
5127: * Optimize startup case where 1 variable is initialized at a time with the same value as on shutdown.
5128: */
5129: public boolean variablePutIfInitializingWithSameValue(
5130: String[] variableNames, IPath[] variablePaths) {
5131: if (variableNames.length != 1)
5132: return false;
5133: String variableName = variableNames[0];
5134: IPath oldPath = variableGetDefaultToPreviousSession(variableName);
5135: if (oldPath == null)
5136: return false;
5137: IPath newPath = variablePaths[0];
5138: if (!oldPath.equals(newPath))
5139: return false;
5140: variablePut(variableName, newPath);
5141: return true;
5142: }
5143:
5144: public void contentTypeChanged(ContentTypeChangeEvent event) {
5145: Util.resetJavaLikeExtensions();
5146:
5147: }
5148:
5149: public synchronized String cacheToString(String prefix) {
5150: return this.cache.toStringFillingRation(prefix);
5151: }
5152: }
|