KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > JavaModelManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Theodora Yeung (tyeung@bea.com) - ensure that JarPackageFragmentRoot make it into cache
11  * before its contents
12  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422)
13  *******************************************************************************/

14 package org.eclipse.jdt.internal.core;
15
16 import java.io.*;
17 import java.net.URI JavaDoc;
18 import java.text.MessageFormat JavaDoc;
19 import java.util.*;
20 import java.util.Map.Entry;
21 import java.util.zip.ZipFile JavaDoc;
22
23 import javax.xml.parsers.DocumentBuilder JavaDoc;
24 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
25 import javax.xml.parsers.ParserConfigurationException JavaDoc;
26
27 import org.eclipse.core.resources.*;
28 import org.eclipse.core.runtime.*;
29 import org.eclipse.core.runtime.content.IContentTypeManager.ContentTypeChangeEvent;
30 import org.eclipse.core.runtime.content.IContentTypeManager.IContentTypeChangeListener;
31 import org.eclipse.core.runtime.jobs.Job;
32 import org.eclipse.core.runtime.preferences.DefaultScope;
33 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
34 import org.eclipse.core.runtime.preferences.IPreferencesService;
35 import org.eclipse.core.runtime.preferences.IScopeContext;
36 import org.eclipse.core.runtime.preferences.InstanceScope;
37 import org.eclipse.jdt.core.*;
38 import org.eclipse.jdt.core.compiler.CharOperation;
39 import org.eclipse.jdt.core.compiler.CompilationParticipant;
40 import org.eclipse.jdt.core.compiler.IProblem;
41 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
42 import org.eclipse.jdt.internal.codeassist.CompletionEngine;
43 import org.eclipse.jdt.internal.codeassist.SelectionEngine;
44 import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
45 import org.eclipse.jdt.internal.compiler.Compiler;
46 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
47 import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
48 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
49 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
50 import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
51 import org.eclipse.jdt.internal.core.builder.JavaBuilder;
52 import org.eclipse.jdt.internal.core.hierarchy.TypeHierarchy;
53 import org.eclipse.jdt.internal.core.search.AbstractSearchScope;
54 import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
55 import org.eclipse.jdt.internal.core.search.IRestrictedAccessTypeRequestor;
56 import org.eclipse.jdt.internal.core.search.JavaWorkspaceScope;
57 import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
58 import org.eclipse.jdt.internal.core.search.processing.JobManager;
59 import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
60 import org.eclipse.jdt.internal.core.util.LRUCache;
61 import org.eclipse.jdt.internal.core.util.Messages;
62 import org.eclipse.jdt.internal.core.util.Util;
63 import org.eclipse.jdt.internal.core.util.WeakHashSet;
64 import org.eclipse.jdt.internal.core.util.WeakHashSetOfCharArray;
65 import org.osgi.service.prefs.BackingStoreException;
66 import org.w3c.dom.Element JavaDoc;
67 import org.w3c.dom.Node JavaDoc;
68 import org.w3c.dom.NodeList JavaDoc;
69 import org.xml.sax.InputSource JavaDoc;
70 import org.xml.sax.SAXException JavaDoc;
71
72 /**
73  * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>.
74  * <code>IElementChangedListener</code>s register with the <code>JavaModelManager</code>,
75  * and receive <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
76  * <p>
77  * The single instance of <code>JavaModelManager</code> is available from
78  * the static method <code>JavaModelManager.getJavaModelManager()</code>.
79  */

80 public class JavaModelManager implements ISaveParticipant, IContentTypeChangeListener {
81  
82     /**
83      * Unique handle onto the JavaModel
84      */

85     final JavaModel javaModel = new JavaModel();
86     
87     /**
88      * Classpath variables pool
89      */

90     public HashMap variables = new HashMap(5);
91     public HashSet variablesWithInitializer = new HashSet(5);
92     public HashMap deprecatedVariables = new HashMap(5);
93     public HashSet readOnlyVariables = new HashSet(5);
94     public HashMap previousSessionVariables = new HashMap(5);
95     private ThreadLocal JavaDoc variableInitializationInProgress = new ThreadLocal JavaDoc();
96
97     /**
98      * Classpath containers pool
99      */

100     public HashMap containers = new HashMap(5);
101     public HashMap previousSessionContainers = new HashMap(5);
102     private ThreadLocal JavaDoc containerInitializationInProgress = new ThreadLocal JavaDoc();
103     public boolean batchContainerInitializations = false;
104     public ThreadLocal JavaDoc batchContainerInitializationsProgress = new ThreadLocal JavaDoc();
105     public HashMap containerInitializersCache = new HashMap(5);
106     
107     /*
108      * A HashSet that contains the IJavaProject whose classpath is being resolved.
109      */

110     private ThreadLocal JavaDoc classpathsBeingResolved = new ThreadLocal JavaDoc();
111     
112     /*
113      * The unique workspace scope
114      */

115     public JavaWorkspaceScope workspaceScope;
116     
117     /*
118      * Pools of symbols used in the Java model.
119      * Used as a replacement for String#intern() that could prevent garbage collection of strings on some VMs.
120      */

121     private WeakHashSet stringSymbols = new WeakHashSet(5);
122     private WeakHashSetOfCharArray charArraySymbols = new WeakHashSetOfCharArray(5);
123     
124     /*
125      * Extension used to construct Java 6 annotation processor managers
126      */

127     private IConfigurationElement annotationProcessorManagerFactory = null;
128     
129     /*
130      * Map from a package fragment root's path to a source attachment property (source path + ATTACHMENT_PROPERTY_DELIMITER + source root path)
131      */

132     public Map rootPathToAttachments = new HashMap();
133
134     public final static String JavaDoc CP_VARIABLE_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$
135
public final static String JavaDoc CP_CONTAINER_PREFERENCES_PREFIX = JavaCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
136
public final static String JavaDoc CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
137
public final static IPath CP_ENTRY_IGNORE_PATH = new Path(CP_ENTRY_IGNORE);
138     public final static String JavaDoc TRUE = "true"; //$NON-NLS-1$
139

140     private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 2;
141
142     /**
143      * Name of the extension point for contributing classpath variable initializers
144      */

145     public static final String JavaDoc CPVARIABLE_INITIALIZER_EXTPOINT_ID = "classpathVariableInitializer" ; //$NON-NLS-1$
146

147     /**
148      * Name of the extension point for contributing classpath container initializers
149      */

150     public static final String JavaDoc CPCONTAINER_INITIALIZER_EXTPOINT_ID = "classpathContainerInitializer" ; //$NON-NLS-1$
151

152     /**
153      * Name of the extension point for contributing a source code formatter
154      */

155     public static final String JavaDoc FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$NON-NLS-1$
156

157     /**
158      * Name of the extension point for contributing a compilation participant
159      */

160     public static final String JavaDoc COMPILATION_PARTICIPANT_EXTPOINT_ID = "compilationParticipant" ; //$NON-NLS-1$
161

162     /**
163      * Name of the extension point for contributing the Java 6 annotation processor manager
164      */

165     public static final String JavaDoc ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID = "annotationProcessorManager" ; //$NON-NLS-1$
166

167     /**
168      * Special value used for recognizing ongoing initialization and breaking initialization cycles
169      */

170     public final static IPath VARIABLE_INITIALIZATION_IN_PROGRESS = new Path("Variable Initialization In Progress"); //$NON-NLS-1$
171
public final static IClasspathContainer CONTAINER_INITIALIZATION_IN_PROGRESS = new IClasspathContainer() {
172         public IClasspathEntry[] getClasspathEntries() { return null; }
173         public String JavaDoc getDescription() { return "Container Initialization In Progress"; } //$NON-NLS-1$
174
public int getKind() { return 0; }
175         public IPath getPath() { return null; }
176         public String JavaDoc toString() { return getDescription(); }
177     };
178     
179     private static final String JavaDoc BUFFER_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/buffermanager" ; //$NON-NLS-1$
180
private static final String JavaDoc INDEX_MANAGER_DEBUG = JavaCore.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$
181
private static final String JavaDoc COMPILER_DEBUG = JavaCore.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$
182
private static final String JavaDoc JAVAMODEL_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$
183
private static final String JavaDoc JAVAMODELCACHE_DEBUG = JavaCore.PLUGIN_ID + "/debug/javamodel/cache" ; //$NON-NLS-1$
184
private static final String JavaDoc CP_RESOLVE_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$
185
private static final String JavaDoc CP_RESOLVE_ADVANCED_DEBUG = JavaCore.PLUGIN_ID + "/debug/cpresolution/advanced" ; //$NON-NLS-1$
186
private static final String JavaDoc ZIP_ACCESS_DEBUG = JavaCore.PLUGIN_ID + "/debug/zipaccess" ; //$NON-NLS-1$
187
private static final String JavaDoc DELTA_DEBUG =JavaCore.PLUGIN_ID + "/debug/javadelta" ; //$NON-NLS-1$
188
private static final String JavaDoc DELTA_DEBUG_VERBOSE =JavaCore.PLUGIN_ID + "/debug/javadelta/verbose" ; //$NON-NLS-1$
189
private static final String JavaDoc HIERARCHY_DEBUG = JavaCore.PLUGIN_ID + "/debug/hierarchy" ; //$NON-NLS-1$
190
private static final String JavaDoc POST_ACTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/postaction" ; //$NON-NLS-1$
191
private static final String JavaDoc BUILDER_DEBUG = JavaCore.PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$
192
private static final String JavaDoc COMPLETION_DEBUG = JavaCore.PLUGIN_ID + "/debug/completion" ; //$NON-NLS-1$
193
private static final String JavaDoc RESOLUTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/resolution" ; //$NON-NLS-1$
194
private static final String JavaDoc SELECTION_DEBUG = JavaCore.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$
195
private static final String JavaDoc SEARCH_DEBUG = JavaCore.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
196
private static final String JavaDoc SOURCE_MAPPER_DEBUG_VERBOSE = JavaCore.PLUGIN_ID + "/debug/sourcemapper" ; //$NON-NLS-1$
197

198     public static final String JavaDoc COMPLETION_PERF = JavaCore.PLUGIN_ID + "/perf/completion" ; //$NON-NLS-1$
199
public static final String JavaDoc SELECTION_PERF = JavaCore.PLUGIN_ID + "/perf/selection" ; //$NON-NLS-1$
200
public static final String JavaDoc DELTA_LISTENER_PERF = JavaCore.PLUGIN_ID + "/perf/javadeltalistener" ; //$NON-NLS-1$
201
public static final String JavaDoc VARIABLE_INITIALIZER_PERF = JavaCore.PLUGIN_ID + "/perf/variableinitializer" ; //$NON-NLS-1$
202
public static final String JavaDoc CONTAINER_INITIALIZER_PERF = JavaCore.PLUGIN_ID + "/perf/containerinitializer" ; //$NON-NLS-1$
203
public static final String JavaDoc RECONCILE_PERF = JavaCore.PLUGIN_ID + "/perf/reconcile" ; //$NON-NLS-1$
204

205     private final static String JavaDoc INDEXED_SECONDARY_TYPES = "#@*_indexing secondary cache_*@#"; //$NON-NLS-1$
206

207     public static boolean PERF_VARIABLE_INITIALIZER = false;
208     public static boolean PERF_CONTAINER_INITIALIZER = false;
209     
210     public final static ICompilationUnit[] NO_WORKING_COPY = new ICompilationUnit[0];
211     
212     // Preferences
213
HashSet optionNames = new HashSet(20);
214     Hashtable optionsCache;
215
216     public final IEclipsePreferences[] preferencesLookup = new IEclipsePreferences[2];
217     static final int PREF_INSTANCE = 0;
218     static final int PREF_DEFAULT = 1;
219
220     static final Object JavaDoc[][] NO_PARTICIPANTS = new Object JavaDoc[0][];
221     
222     public static class CompilationParticipants {
223         
224         private final static int MAX_SOURCE_LEVEL = 7; // 1.1 to 1.7
225

226         /*
227          * The registered compilation participants (a table from int (source level) to Object[])
228          * The Object array contains first IConfigurationElements when not resolved yet, then
229          * it contains CompilationParticipants.
230          */

231         private Object JavaDoc[][] registeredParticipants = null;
232         private HashSet managedMarkerTypes;
233                 
234         public CompilationParticipant[] getCompilationParticipants(IJavaProject project) {
235             final Object JavaDoc[][] participantsPerSource = getRegisteredParticipants();
236             if (participantsPerSource == NO_PARTICIPANTS)
237                 return null;
238             String JavaDoc sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true/*inherit options*/);
239             final int sourceLevelIndex = indexForSourceLevel(sourceLevel);
240             final Object JavaDoc[] participants = participantsPerSource[sourceLevelIndex];
241             int length = participants.length;
242             CompilationParticipant[] result = new CompilationParticipant[length];
243             int index = 0;
244             for (int i = 0; i < length; i++) {
245                 if (participants[i] instanceof IConfigurationElement) {
246                     final IConfigurationElement configElement = (IConfigurationElement) participants[i];
247                     final int participantIndex = i;
248                     SafeRunner.run(new ISafeRunnable() {
249                         public void handleException(Throwable JavaDoc exception) {
250                             Util.log(exception, "Exception occurred while creating compilation participant"); //$NON-NLS-1$
251
}
252                         public void run() throws Exception JavaDoc {
253                             Object JavaDoc executableExtension = configElement.createExecutableExtension("class"); //$NON-NLS-1$
254
for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++)
255                                 participantsPerSource[j][participantIndex] = executableExtension;
256                         }
257                     });
258                 }
259                 CompilationParticipant participant = (CompilationParticipant) participants[i];
260                 if (participant != null && participant.isActive(project))
261                     result[index++] = participant;
262             }
263             if (index == 0)
264                 return null;
265             if (index < length)
266                 System.arraycopy(result, 0, result = new CompilationParticipant[index], 0, index);
267             return result;
268         }
269         
270         public HashSet managedMarkerTypes() {
271             if (this.managedMarkerTypes == null) {
272                 // force extension points to be read
273
getRegisteredParticipants();
274             }
275             return this.managedMarkerTypes;
276         }
277         
278         private synchronized Object JavaDoc[][] getRegisteredParticipants() {
279             if (this.registeredParticipants != null) {
280                 return this.registeredParticipants;
281             }
282             this.managedMarkerTypes = new HashSet();
283             IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, COMPILATION_PARTICIPANT_EXTPOINT_ID);
284             if (extension == null)
285                 return this.registeredParticipants = NO_PARTICIPANTS;
286             final ArrayList modifyingEnv = new ArrayList();
287             final ArrayList creatingProblems = new ArrayList();
288             final ArrayList others = new ArrayList();
289             IExtension[] extensions = extension.getExtensions();
290             // for all extensions of this point...
291
for(int i = 0; i < extensions.length; i++) {
292                 IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
293                 // for all config elements named "compilationParticipant"
294
for(int j = 0; j < configElements.length; j++) {
295                     final IConfigurationElement configElement = configElements[j];
296                     String JavaDoc elementName =configElement.getName();
297                     if (!("compilationParticipant".equals(elementName))) { //$NON-NLS-1$
298
continue;
299                     }
300                     // add config element in the group it belongs to
301
if (TRUE.equals(configElement.getAttribute("modifiesEnvironment"))) //$NON-NLS-1$
302
modifyingEnv.add(configElement);
303                     else if (TRUE.equals(configElement.getAttribute("createsProblems"))) //$NON-NLS-1$
304
creatingProblems.add(configElement);
305                     else
306                         others.add(configElement);
307                     // add managed marker types
308
IConfigurationElement[] managedMarkers = configElement.getChildren("managedMarker"); //$NON-NLS-1$
309
for (int k = 0, length = managedMarkers.length; k < length; k++) {
310                         IConfigurationElement element = managedMarkers[k];
311                         String JavaDoc markerType = element.getAttribute("markerType"); //$NON-NLS-1$
312
if (markerType != null)
313                             this.managedMarkerTypes.add(markerType);
314                     }
315                 }
316             }
317             int size = modifyingEnv.size() + creatingProblems.size() + others.size();
318             if (size == 0)
319                 return this.registeredParticipants = NO_PARTICIPANTS;
320             
321             // sort config elements in each group
322
IConfigurationElement[] configElements = new IConfigurationElement[size];
323             int index = 0;
324             index = sortParticipants(modifyingEnv, configElements, index);
325             index = sortParticipants(creatingProblems, configElements, index);
326             index = sortParticipants(others, configElements, index);
327             
328             // create result table
329
Object JavaDoc[][] result = new Object JavaDoc[MAX_SOURCE_LEVEL][];
330             int length = configElements.length;
331             for (int i = 0; i < MAX_SOURCE_LEVEL; i++) {
332                 result[i] = new Object JavaDoc[length];
333             }
334             for (int i = 0; i < length; i++) {
335                 String JavaDoc sourceLevel = configElements[i].getAttribute("requiredSourceLevel"); //$NON-NLS-1$
336
int sourceLevelIndex = indexForSourceLevel(sourceLevel);
337                 for (int j = sourceLevelIndex; j < MAX_SOURCE_LEVEL; j++) {
338                     result[j][i] = configElements[i];
339                 }
340             }
341             return this.registeredParticipants = result;
342         }
343         
344         /*
345          * 1.1 -> 0
346          * 1.2 -> 1
347          * ...
348          * 1.6 -> 5
349          * 1.7 -> 6
350          * null -> 0
351          */

352         private int indexForSourceLevel(String JavaDoc sourceLevel) {
353             if (sourceLevel == null) return 0;
354             int majVersion = (int) (CompilerOptions.versionToJdkLevel(sourceLevel) >>> 16);
355             switch (majVersion) {
356                 case ClassFileConstants.MAJOR_VERSION_1_2:
357                     return 1;
358                 case ClassFileConstants.MAJOR_VERSION_1_3:
359                     return 2;
360                 case ClassFileConstants.MAJOR_VERSION_1_4:
361                     return 3;
362                 case ClassFileConstants.MAJOR_VERSION_1_5:
363                     return 4;
364                 case ClassFileConstants.MAJOR_VERSION_1_6:
365                     return 5;
366                 case ClassFileConstants.MAJOR_VERSION_1_7:
367                     return 6;
368                 default:
369                     // all other cases including ClassFileConstants.MAJOR_VERSION_1_1
370
return 0;
371             }
372         }
373         
374         private int sortParticipants(ArrayList group, IConfigurationElement[] configElements, int index) {
375             int size = group.size();
376             if (size == 0) return index;
377             Object JavaDoc[] elements = group.toArray();
378             Util.sort(elements, new Util.Comparer() {
379                 public int compare(Object JavaDoc a, Object JavaDoc b) {
380                     if (a == b) return 0;
381                     String JavaDoc id = ((IConfigurationElement) a).getAttribute("id"); //$NON-NLS-1$
382
if (id == null) return -1;
383                     IConfigurationElement[] requiredElements = ((IConfigurationElement) b).getChildren("requires"); //$NON-NLS-1$
384
for (int i = 0, length = requiredElements.length; i < length; i++) {
385                         IConfigurationElement required = requiredElements[i];
386                         if (id.equals(required.getAttribute("id"))) //$NON-NLS-1$
387
return 1;
388                     }
389                     return -1;
390                 }
391             });
392             for (int i = 0; i < size; i++)
393                 configElements[index+i] = (IConfigurationElement) elements[i];
394             return index + size;
395         }
396     }
397             
398     public final CompilationParticipants compilationParticipants = new CompilationParticipants();
399     
400     /**
401      * Returns whether the given full path (for a package) conflicts with the output location
402      * of the given project.
403      */

404     public static boolean conflictsWithOutputLocation(IPath folderPath, JavaProject project) {
405         try {
406             IPath outputLocation = project.getOutputLocation();
407             if (outputLocation == null) {
408                 // in doubt, there is a conflict
409
return true;
410             }
411             if (outputLocation.isPrefixOf(folderPath)) {
412                 // only allow nesting in project's output if there is a corresponding source folder
413
// or if the project's output is not used (in other words, if all source folders have their custom output)
414
IClasspathEntry[] classpath = project.getResolvedClasspath();
415                 boolean isOutputUsed = false;
416                 for (int i = 0, length = classpath.length; i < length; i++) {
417                     IClasspathEntry entry = classpath[i];
418                     if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
419                         if (entry.getPath().equals(outputLocation)) {
420                             return false;
421                         }
422                         if (entry.getOutputLocation() == null) {
423                             isOutputUsed = true;
424                         }
425                     }
426                 }
427                 return isOutputUsed;
428             }
429             return false;
430         } catch (JavaModelException e) {
431             // in doubt, there is a conflict
432
return true;
433         }
434     }
435
436     public synchronized IClasspathContainer containerGet(IJavaProject project, IPath containerPath) {
437         // check initialization in progress first
438
if (containerIsInitializationInProgress(project, containerPath)) {
439             return CONTAINER_INITIALIZATION_IN_PROGRESS;
440         }
441         
442         Map projectContainers = (Map)this.containers.get(project);
443         if (projectContainers == null){
444             return null;
445         }
446         IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath);
447         return container;
448     }
449     
450     public synchronized IClasspathContainer containerGetDefaultToPreviousSession(IJavaProject project, IPath containerPath) {
451         Map projectContainers = (Map)this.containers.get(project);
452         if (projectContainers == null)
453             return getPreviousSessionContainer(containerPath, project);
454         IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath);
455         if (container == null)
456             return getPreviousSessionContainer(containerPath, project);
457         return container;
458     }
459     
460     private synchronized Map containerClone(IJavaProject project) {
461         Map originalProjectContainers = (Map)this.containers.get(project);
462         if (originalProjectContainers == null) return null;
463         Map projectContainers = new HashMap(originalProjectContainers.size());
464         projectContainers.putAll(originalProjectContainers);
465         return projectContainers;
466     }
467     
468     private boolean containerIsInitializationInProgress(IJavaProject project, IPath containerPath) {
469         Map initializations = (Map)this.containerInitializationInProgress.get();
470         if (initializations == null)
471             return false;
472         HashSet projectInitializations = (HashSet) initializations.get(project);
473         if (projectInitializations == null)
474             return false;
475         return projectInitializations.contains(containerPath);
476     }
477
478     private void containerAddInitializationInProgress(IJavaProject project, IPath containerPath) {
479         Map initializations = (Map)this.containerInitializationInProgress.get();
480         if (initializations == null)
481             this.containerInitializationInProgress.set(initializations = new HashMap());
482         HashSet projectInitializations = (HashSet) initializations.get(project);
483         if (projectInitializations == null)
484             initializations.put(project, projectInitializations = new HashSet());
485         projectInitializations.add(containerPath);
486     }
487     
488     public synchronized void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
489
490         // set/unset the initialization in progress
491
if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
492             containerAddInitializationInProgress(project, containerPath);
493             
494             // do not write out intermediate initialization value
495
return;
496         } else {
497             containerRemoveInitializationInProgress(project, containerPath);
498
499             Map projectContainers = (Map)this.containers.get(project);
500             if (projectContainers == null){
501                 projectContainers = new HashMap(1);
502                 this.containers.put(project, projectContainers);
503             }
504     
505             if (container == null) {
506                 projectContainers.remove(containerPath);
507             } else {
508                 projectContainers.put(containerPath, container);
509             }
510             // discard obsoleted information about previous session
511
Map previousContainers = (Map)this.previousSessionContainers.get(project);
512             if (previousContainers != null){
513                 previousContainers.remove(containerPath);
514             }
515         }
516         // container values are persisted in preferences during save operations, see #saving(ISaveContext)
517
}
518     
519     /*
520      * The given project is being removed. Remove all containers for this project from the cache.
521      */

522     public synchronized void containerRemove(IJavaProject project) {
523         Map initializations = (Map) this.containerInitializationInProgress.get();
524         if (initializations != null) {
525             initializations.remove(project);
526         }
527         this.containers.remove(project);
528     }
529     
530     public boolean containerPutIfInitializingWithSameEntries(IPath containerPath, IJavaProject[] projects, IClasspathContainer[] respectiveContainers) {
531         int projectLength = projects.length;
532         if (projectLength != 1)
533             return false;
534         final IClasspathContainer container = respectiveContainers[0];
535         IJavaProject project = projects[0];
536         // optimize only if initializing, otherwise we are in a regular setContainer(...) call
537
if (!containerIsInitializationInProgress(project, containerPath))
538             return false;
539         IClasspathContainer previousContainer = containerGetDefaultToPreviousSession(project, containerPath);
540         if (container == null) {
541             if (previousContainer == null) {
542                 containerPut(project, containerPath, null);
543                 return true;
544             }
545             return false;
546         }
547         final IClasspathEntry[] newEntries = container.getClasspathEntries();
548         if (previousContainer == null)
549             if (newEntries.length == 0) {
550                 containerPut(project, containerPath, container);
551                 return true;
552             } else {
553                 if (CP_RESOLVE_VERBOSE)
554                     verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, null/*no old entries*/);
555                 return false;
556             }
557         final IClasspathEntry[] oldEntries = previousContainer.getClasspathEntries();
558         if (oldEntries.length != newEntries.length) {
559             if (CP_RESOLVE_VERBOSE)
560                 verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries);
561             return false;
562         }
563         for (int i = 0, length = newEntries.length; i < length; i++) {
564             if (newEntries[i] == null) {
565                 if (CP_RESOLVE_VERBOSE)
566                     verbose_missbehaving_container(project, containerPath, newEntries);
567                 return false;
568             }
569             if (!newEntries[i].equals(oldEntries[i])) {
570                 if (CP_RESOLVE_VERBOSE)
571                     verbose_missbehaving_container(containerPath, projects, respectiveContainers, container, newEntries, oldEntries);
572                 return false;
573             }
574         }
575         containerPut(project, containerPath, container);
576         return true;
577     }
578
579     private void verbose_missbehaving_container(
580             IPath containerPath,
581             IJavaProject[] projects,
582             IClasspathContainer[] respectiveContainers,
583             final IClasspathContainer container,
584             final IClasspathEntry[] newEntries,
585             final IClasspathEntry[] oldEntries) {
586         Util.verbose(
587             "CPContainer SET - missbehaving container\n" + //$NON-NLS-1$
588
" container path: " + containerPath + '\n' + //$NON-NLS-1$
589
" projects: {" +//$NON-NLS-1$
590
org.eclipse.jdt.internal.compiler.util.Util.toString(
591                 projects,
592                 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){
593                     public String JavaDoc displayString(Object JavaDoc o) { return ((IJavaProject) o).getElementName(); }
594                 }) +
595             "}\n values on previous session: {\n" +//$NON-NLS-1$
596
org.eclipse.jdt.internal.compiler.util.Util.toString(
597                 respectiveContainers,
598                 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){
599                     public String JavaDoc displayString(Object JavaDoc o) {
600                         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(" "); //$NON-NLS-1$
601
if (o == null) {
602                             buffer.append("<null>"); //$NON-NLS-1$
603
return buffer.toString();
604                         }
605                         buffer.append(container.getDescription());
606                         buffer.append(" {\n"); //$NON-NLS-1$
607
if (oldEntries == null) {
608                             buffer.append(" "); //$NON-NLS-1$
609
buffer.append("<null>\n"); //$NON-NLS-1$
610
} else {
611                             for (int j = 0; j < oldEntries.length; j++){
612                                 buffer.append(" "); //$NON-NLS-1$
613
buffer.append(oldEntries[j]);
614                                 buffer.append('\n');
615                             }
616                         }
617                         buffer.append(" }"); //$NON-NLS-1$
618
return buffer.toString();
619                     }
620                 }) +
621             "}\n new values: {\n" +//$NON-NLS-1$
622
org.eclipse.jdt.internal.compiler.util.Util.toString(
623                 respectiveContainers,
624                 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){
625                     public String JavaDoc displayString(Object JavaDoc o) {
626                         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(" "); //$NON-NLS-1$
627
if (o == null) {
628                             buffer.append("<null>"); //$NON-NLS-1$
629
return buffer.toString();
630                         }
631                         buffer.append(container.getDescription());
632                         buffer.append(" {\n"); //$NON-NLS-1$
633
for (int j = 0; j < newEntries.length; j++){
634                             buffer.append(" "); //$NON-NLS-1$
635
buffer.append(newEntries[j]);
636                             buffer.append('\n');
637                         }
638                         buffer.append(" }"); //$NON-NLS-1$
639
return buffer.toString();
640                     }
641                 }) +
642             "\n }"); //$NON-NLS-1$
643
}
644     
645     void verbose_missbehaving_container(IJavaProject project, IPath containerPath, IClasspathEntry[] classpathEntries) {
646         Util.verbose(
647             "CPContainer GET - missbehaving container (returning null classpath entry)\n" + //$NON-NLS-1$
648
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
649
" container path: " + containerPath + '\n' + //$NON-NLS-1$
650
" classpath entries: {\n" + //$NON-NLS-1$
651
org.eclipse.jdt.internal.compiler.util.Util.toString(
652                 classpathEntries,
653                 new org.eclipse.jdt.internal.compiler.util.Util.Displayable(){
654                     public String JavaDoc displayString(Object JavaDoc o) {
655                         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(" "); //$NON-NLS-1$
656
if (o == null) {
657                             buffer.append("<null>"); //$NON-NLS-1$
658
return buffer.toString();
659                         }
660                         buffer.append(o);
661                         return buffer.toString();
662                     }
663                 }) +
664             "\n }" //$NON-NLS-1$
665
);
666     }
667
668     private void containerRemoveInitializationInProgress(IJavaProject project, IPath containerPath) {
669         Map initializations = (Map)this.containerInitializationInProgress.get();
670         if (initializations == null)
671             return;
672         HashSet projectInitializations = (HashSet) initializations.get(project);
673         if (projectInitializations == null)
674             return;
675         projectInitializations.remove(containerPath);
676         if (projectInitializations.size() == 0)
677             initializations.remove(project);
678         if (initializations.size() == 0)
679             this.containerInitializationInProgress.set(null);
680     }
681     
682     private synchronized void containersReset(String JavaDoc[] containerIDs) {
683         for (int i = 0; i < containerIDs.length; i++) {
684             String JavaDoc containerID = containerIDs[i];
685             Iterator projectIterator = this.containers.values().iterator();
686             while (projectIterator.hasNext()){
687                 Map projectContainers = (Map) projectIterator.next();
688                 if (projectContainers != null){
689                     Iterator containerIterator = projectContainers.keySet().iterator();
690                     while (containerIterator.hasNext()){
691                         IPath containerPath = (IPath)containerIterator.next();
692                         if (containerPath.segment(0).equals(containerID)) { // registered container
693
projectContainers.put(containerPath, null); // reset container value, but leave entry in Map
694
}
695                     }
696                 }
697             }
698         }
699     }
700
701     /**
702      * Returns the Java element corresponding to the given resource, or
703      * <code>null</code> if unable to associate the given resource
704      * with a Java element.
705      * <p>
706      * The resource must be one of:<ul>
707      * <li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
708      * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
709      * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
710      * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
711      * <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
712      * or <code>IPackageFragment</code></li>
713      * <li>the workspace root resource - the element returned is the <code>IJavaModel</code></li>
714      * </ul>
715      * <p>
716      * Creating a Java element has the side effect of creating and opening all of the
717      * element's parents if they are not yet open.
718      */

719     public static IJavaElement create(IResource resource, IJavaProject project) {
720         if (resource == null) {
721             return null;
722         }
723         int type = resource.getType();
724         switch (type) {
725             case IResource.PROJECT :
726                 return JavaCore.create((IProject) resource);
727             case IResource.FILE :
728                 return create((IFile) resource, project);
729             case IResource.FOLDER :
730                 return create((IFolder) resource, project);
731             case IResource.ROOT :
732                 return JavaCore.create((IWorkspaceRoot) resource);
733             default :
734                 return null;
735         }
736     }
737
738     /**
739      * Returns the Java element corresponding to the given file, its project being the given
740      * project.
741      * Returns <code>null</code> if unable to associate the given file
742      * with a Java element.
743      *
744      * <p>The file must be one of:<ul>
745      * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
746      * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
747      * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
748      * </ul>
749      * <p>
750      * Creating a Java element has the side effect of creating and opening all of the
751      * element's parents if they are not yet open.
752      */

753     public static IJavaElement create(IFile file, IJavaProject project) {
754         if (file == null) {
755             return null;
756         }
757         if (project == null) {
758             project = JavaCore.create(file.getProject());
759         }
760     
761         if (file.getFileExtension() != null) {
762             String JavaDoc name = file.getName();
763             if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name))
764                 return createCompilationUnitFrom(file, project);
765             if (org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name))
766                 return createClassFileFrom(file, project);
767             if (org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(name))
768                 return createJarPackageFragmentRootFrom(file, project);
769         }
770         return null;
771     }
772
773     /**
774      * Returns the package fragment or package fragment root corresponding to the given folder,
775      * its parent or great parent being the given project.
776      * or <code>null</code> if unable to associate the given folder with a Java element.
777      * <p>
778      * Note that a package fragment root is returned rather than a default package.
779      * <p>
780      * Creating a Java element has the side effect of creating and opening all of the
781      * element's parents if they are not yet open.
782      */

783     public static IJavaElement create(IFolder folder, IJavaProject project) {
784         if (folder == null) {
785             return null;
786         }
787         IJavaElement element;
788         if (project == null) {
789             project = JavaCore.create(folder.getProject());
790             element = determineIfOnClasspath(folder, project);
791             if (element == null) {
792                 // walk all projects and find one that have the given folder on its classpath
793
IJavaProject[] projects;
794                 try {
795                     projects = JavaModelManager.getJavaModelManager().getJavaModel().getJavaProjects();
796                 } catch (JavaModelException e) {
797                     return null;
798                 }
799                 for (int i = 0, length = projects.length; i < length; i++) {
800                     project = projects[i];
801                     element = determineIfOnClasspath(folder, project);
802                     if (element != null)
803                         break;
804                 }
805             }
806         } else {
807             element = determineIfOnClasspath(folder, project);
808         }
809         return element;
810     }
811
812     /**
813      * Creates and returns a class file element for the given <code>.class</code> file,
814      * its project being the given project. Returns <code>null</code> if unable
815      * to recognize the class file.
816      */

817     public static IClassFile createClassFileFrom(IFile file, IJavaProject project ) {
818         if (file == null) {
819             return null;
820         }
821         if (project == null) {
822             project = JavaCore.create(file.getProject());
823         }
824         IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
825         if (pkg == null) {
826             // fix for 1FVS7WE
827
// not on classpath - make the root its folder, and a default package
828
PackageFragmentRoot root = (PackageFragmentRoot) project.getPackageFragmentRoot(file.getParent());
829             pkg = root.getPackageFragment(CharOperation.NO_STRINGS);
830         }
831         return pkg.getClassFile(file.getName());
832     }
833     
834     /**
835      * Creates and returns a compilation unit element for the given <code>.java</code>
836      * file, its project being the given project. Returns <code>null</code> if unable
837      * to recognize the compilation unit.
838      */

839     public static ICompilationUnit createCompilationUnitFrom(IFile file, IJavaProject project) {
840
841         if (file == null) return null;
842
843         if (project == null) {
844             project = JavaCore.create(file.getProject());
845         }
846         IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
847         if (pkg == null) {
848             // not on classpath - make the root its folder, and a default package
849
IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent());
850             pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
851             
852             if (VERBOSE){
853                 System.out.println("WARNING : creating unit element outside classpath ("+ Thread.currentThread()+"): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
854
}
855         }
856         return pkg.getCompilationUnit(file.getName());
857     }
858     
859     /**
860      * Creates and returns a handle for the given JAR file, its project being the given project.
861      * The Java model associated with the JAR's project may be
862      * created as a side effect.
863      * Returns <code>null</code> if unable to create a JAR package fragment root.
864      * (for example, if the JAR file represents a non-Java resource)
865      */

866     public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile file, IJavaProject project) {
867         if (file == null) {
868             return null;
869         }
870         if (project == null) {
871             project = JavaCore.create(file.getProject());
872         }
873     
874         // Create a jar package fragment root only if on the classpath
875
IPath resourcePath = file.getFullPath();
876         try {
877             IClasspathEntry entry = ((JavaProject)project).getClasspathEntryFor(resourcePath);
878             if (entry != null) {
879                 return project.getPackageFragmentRoot(file);
880             }
881         } catch (JavaModelException e) {
882             // project doesn't exist: return null
883
}
884         return null;
885     }
886     
887     /**
888      * Returns the package fragment root represented by the resource, or
889      * the package fragment the given resource is located in, or <code>null</code>
890      * if the given resource is not on the classpath of the given project.
891      */

892     public static IJavaElement determineIfOnClasspath(
893         IResource resource,
894         IJavaProject project) {
895             
896         IPath resourcePath = resource.getFullPath();
897         try {
898             JavaProjectElementInfo projectInfo = (JavaProjectElementInfo) getJavaModelManager().getInfo(project);
899             ProjectCache projectCache = projectInfo == null ? null : projectInfo.projectCache;
900             HashtableOfArrayToObject allPkgFragmentsCache = projectCache == null ? null : projectCache.allPkgFragmentsCache;
901             IClasspathEntry[] entries =
902                 org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resourcePath.lastSegment())
903                     ? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path)
904
: ((JavaProject)project).getResolvedClasspath();
905             
906             int length = entries.length;
907             if (length > 0) {
908                 String JavaDoc sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
909                 String JavaDoc complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
910                 for (int i = 0; i < length; i++) {
911                     IClasspathEntry entry = entries[i];
912                     if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
913                     IPath rootPath = entry.getPath();
914                     if (rootPath.equals(resourcePath)) {
915                         return project.getPackageFragmentRoot(resource);
916                     } else if (rootPath.isPrefixOf(resourcePath)) {
917                         // allow creation of package fragment if it contains a .java file that is included
918
if (!Util.isExcluded(resource, ((ClasspathEntry)entry).fullInclusionPatternChars(), ((ClasspathEntry)entry).fullExclusionPatternChars())) {
919                             // given we have a resource child of the root, it cannot be a JAR pkg root
920
PackageFragmentRoot root =(PackageFragmentRoot) ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
921                             if (root == null) return null;
922                             IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
923     
924                             if (resource.getType() == IResource.FILE) {
925                                 // if the resource is a file, then remove the last segment which
926
// is the file name in the package
927
pkgPath = pkgPath.removeLastSegments(1);
928                             }
929                             String JavaDoc[] pkgName = pkgPath.segments();
930                             
931                             // if package name is in the cache, then it has already been validated
932
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=133141)
933
if (allPkgFragmentsCache != null && allPkgFragmentsCache.containsKey(pkgName))
934                                 return root.getPackageFragment(pkgName);
935                             
936                             if (pkgName.length != 0 && JavaConventions.validatePackageName(Util.packageName(pkgPath, sourceLevel, complianceLevel), sourceLevel, complianceLevel).getSeverity() == IStatus.ERROR) {
937                                 return null;
938                             }
939                             return root.getPackageFragment(pkgName);
940                         }
941                     }
942                 }
943             }
944         } catch (JavaModelException npe) {
945             return null;
946         }
947         return null;
948     }
949     
950     /**
951      * The singleton manager
952      */

953     private static JavaModelManager MANAGER= new JavaModelManager();
954
955     /**
956      * Infos cache.
957      */

958     private JavaModelCache cache;
959     
960     /*
961      * Temporary cache of newly opened elements
962      */

963     private ThreadLocal JavaDoc temporaryCache = new ThreadLocal JavaDoc();
964
965     /**
966      * Set of elements which are out of sync with their buffers.
967      */

968     protected HashSet elementsOutOfSynchWithBuffers = new HashSet(11);
969     
970     /**
971      * Holds the state used for delta processing.
972      */

973     public DeltaProcessingState deltaState = new DeltaProcessingState();
974
975     public IndexManager indexManager = null;
976     
977     /**
978      * Table from IProject to PerProjectInfo.
979      * NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos
980      */

981     protected Map perProjectInfos = new HashMap(5);
982     
983     /**
984      * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo.
985      * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos
986      */

987     protected Map perWorkingCopyInfos = new HashMap(5);
988     
989     /**
990      * A weak set of the known search scopes.
991      */

992     protected WeakHashMap searchScopes = new WeakHashMap();
993
994     public static class PerProjectInfo {
995         private static final int JAVADOC_CACHE_INITIAL_SIZE = 10;
996         
997         public IProject project;
998         public Object JavaDoc savedState;
999         public boolean triedRead;
1000        public IClasspathEntry[] rawClasspath;
1001        public IJavaModelStatus rawClasspathStatus;
1002        public IClasspathEntry[] resolvedClasspath;
1003        public IJavaModelStatus unresolvedEntryStatus;
1004        public Map rootPathToRawEntries; // reverse map from a package fragment root's path to the raw entry
1005
public Map rootPathToResolvedEntries; // map from a package fragment root's path to the resolved entry
1006
public IPath outputLocation;
1007        
1008        public IEclipsePreferences preferences;
1009        public Hashtable options;
1010        public Hashtable secondaryTypes;
1011        public LRUCache javadocCache;
1012        
1013        public PerProjectInfo(IProject project) {
1014
1015            this.triedRead = false;
1016            this.savedState = null;
1017            this.project = project;
1018            this.javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
1019        }
1020        
1021        public void rememberExternalLibTimestamps() {
1022            IClasspathEntry[] classpath = this.resolvedClasspath;
1023            if (classpath == null) return;
1024            IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot();
1025            Map externalTimeStamps = JavaModelManager.getJavaModelManager().deltaState.getExternalLibTimeStamps();
1026            for (int i = 0, length = classpath.length; i < length; i++) {
1027                IClasspathEntry entry = classpath[i];
1028                if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
1029                    IPath path = entry.getPath();
1030                    if (externalTimeStamps.get(path) == null) {
1031                        Object JavaDoc target = JavaModel.getTarget(wRoot, path, true);
1032                        if (target instanceof java.io.File JavaDoc) {
1033                            long timestamp = DeltaProcessor.getTimeStamp((java.io.File JavaDoc)target);
1034                            externalTimeStamps.put(path, new Long JavaDoc(timestamp));
1035                        }
1036                    }
1037                }
1038            }
1039        }
1040        
1041        public synchronized void resetResolvedClasspath() {
1042            // null out resolved information
1043
setClasspath(this.rawClasspath, this.outputLocation, this.rawClasspathStatus, null, null, null, null);
1044        }
1045        
1046        public synchronized void setClasspath(IClasspathEntry[] newRawClasspath, IPath newOutputLocation, IJavaModelStatus newRawClasspathStatus, IClasspathEntry[] newResolvedClasspath, Map newRootPathToRawEntries, Map newRootPathToResolvedEntries, IJavaModelStatus newUnresolvedEntryStatus) {
1047            // remember old info
1048
JavaModelManager manager = JavaModelManager.getJavaModelManager();
1049            DeltaProcessor deltaProcessor = manager.deltaState.getDeltaProcessor();
1050            deltaProcessor.addClasspathChange(this.project, this.rawClasspath, this.outputLocation, this.resolvedClasspath);
1051            
1052            this.rawClasspath = newRawClasspath;
1053            this.outputLocation = newOutputLocation;
1054            this.rawClasspathStatus = newRawClasspathStatus;
1055            this.resolvedClasspath = newResolvedClasspath;
1056            this.rootPathToRawEntries = newRootPathToRawEntries;
1057            this.rootPathToResolvedEntries = newRootPathToResolvedEntries;
1058            this.unresolvedEntryStatus = newUnresolvedEntryStatus;
1059            this.javadocCache = new LRUCache(JAVADOC_CACHE_INITIAL_SIZE);
1060        }
1061        
1062        /*
1063         * Reads the raw classpath and output location from disk, and remember them.
1064         * Return the raw classpath, or JavaProject#INVALID_CLASSPATH if unable to read it.
1065         */

1066        public synchronized IClasspathEntry[] readAndCacheClasspath(JavaProject javaProject) {
1067            // read file entries and update status
1068
IClasspathEntry[] classpath;
1069            IJavaModelStatus status;
1070            try {
1071                classpath = javaProject.readFileEntriesWithException(null/*not interested in unknown elements*/);
1072                status = JavaModelStatus.VERIFIED_OK;
1073            } catch (CoreException e) {
1074                classpath = JavaProject.INVALID_CLASSPATH;
1075                status =
1076                    new JavaModelStatus(
1077                        IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1078                        Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
1079            } catch (IOException e) {
1080                classpath = JavaProject.INVALID_CLASSPATH;
1081                if (Messages.file_badFormat.equals(e.getMessage()))
1082                    status =
1083                        new JavaModelStatus(
1084                            IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1085                            Messages.bind(Messages.classpath_xmlFormatError, javaProject.getElementName(), Messages.file_badFormat));
1086                else
1087                    status =
1088                        new JavaModelStatus(
1089                            IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1090                            Messages.bind(Messages.classpath_cannotReadClasspathFile, javaProject.getElementName()));
1091            } catch (AssertionFailedException e) {
1092                classpath = JavaProject.INVALID_CLASSPATH;
1093                status =
1094                    new JavaModelStatus(
1095                        IJavaModelStatusConstants.INVALID_CLASSPATH_FILE_FORMAT,
1096                        Messages.bind(Messages.classpath_illegalEntryInClasspathFile, new String JavaDoc[] {javaProject.getElementName(), e.getMessage()}));
1097            }
1098        
1099            // extract out the output location
1100
IPath output = null;
1101            if (classpath.length > 0) {
1102                IClasspathEntry entry = classpath[classpath.length - 1];
1103                if (entry.getContentKind() == ClasspathEntry.K_OUTPUT) {
1104                    output = entry.getPath();
1105                    IClasspathEntry[] copy = new IClasspathEntry[classpath.length - 1];
1106                    System.arraycopy(classpath, 0, copy, 0, copy.length);
1107                    classpath = copy;
1108                }
1109            }
1110            
1111            // store new raw classpath, new output and new status, and null out resolved info
1112
setClasspath(classpath, output, status, null, null, null, null);
1113            
1114            return classpath;
1115        }
1116        
1117        public String JavaDoc toString() {
1118            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1119            buffer.append("Info for "); //$NON-NLS-1$
1120
buffer.append(this.project.getFullPath());
1121            buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
1122
if (this.rawClasspath == null) {
1123                buffer.append(" <null>\n"); //$NON-NLS-1$
1124
} else {
1125                for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
1126                    buffer.append(" "); //$NON-NLS-1$
1127
buffer.append(this.rawClasspath[i]);
1128                    buffer.append('\n');
1129                }
1130            }
1131            buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
1132
IClasspathEntry[] resolvedCP = this.resolvedClasspath;
1133            if (resolvedCP == null) {
1134                buffer.append(" <null>\n"); //$NON-NLS-1$
1135
} else {
1136                for (int i = 0, length = resolvedCP.length; i < length; i++) {
1137                    buffer.append(" "); //$NON-NLS-1$
1138
buffer.append(resolvedCP[i]);
1139                    buffer.append('\n');
1140                }
1141            }
1142            buffer.append("Output location:\n "); //$NON-NLS-1$
1143
if (this.outputLocation == null) {
1144                buffer.append("<null>"); //$NON-NLS-1$
1145
} else {
1146                buffer.append(this.outputLocation);
1147            }
1148            return buffer.toString();
1149        }
1150    }
1151    
1152    public static class PerWorkingCopyInfo implements IProblemRequestor {
1153        int useCount = 0;
1154        IProblemRequestor problemRequestor;
1155        CompilationUnit workingCopy;
1156        public PerWorkingCopyInfo(CompilationUnit workingCopy, IProblemRequestor problemRequestor) {
1157            this.workingCopy = workingCopy;
1158            this.problemRequestor = problemRequestor;
1159        }
1160        public void acceptProblem(IProblem problem) {
1161            IProblemRequestor requestor = getProblemRequestor();
1162            if (requestor == null) return;
1163            requestor.acceptProblem(problem);
1164        }
1165        public void beginReporting() {
1166            IProblemRequestor requestor = getProblemRequestor();
1167            if (requestor == null) return;
1168            requestor.beginReporting();
1169        }
1170        public void endReporting() {
1171            IProblemRequestor requestor = getProblemRequestor();
1172            if (requestor == null) return;
1173            requestor.endReporting();
1174        }
1175        public IProblemRequestor getProblemRequestor() {
1176            if (this.problemRequestor == null && this.workingCopy.owner != null) {
1177                return this.workingCopy.owner.getProblemRequestor(this.workingCopy);
1178            }
1179            return this.problemRequestor;
1180        }
1181        public ICompilationUnit getWorkingCopy() {
1182            return this.workingCopy;
1183        }
1184        public boolean isActive() {
1185            IProblemRequestor requestor = getProblemRequestor();
1186            return requestor != null && requestor.isActive();
1187        }
1188        public String JavaDoc toString() {
1189            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1190            buffer.append("Info for "); //$NON-NLS-1$
1191
buffer.append(((JavaElement)this.workingCopy).toStringWithAncestors());
1192            buffer.append("\nUse count = "); //$NON-NLS-1$
1193
buffer.append(this.useCount);
1194            buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$
1195
buffer.append(this.problemRequestor);
1196            if (this.problemRequestor == null) {
1197                IProblemRequestor requestor = getProblemRequestor();
1198                buffer.append("\nOwner problem requestor:\n "); //$NON-NLS-1$
1199
buffer.append(requestor);
1200            }
1201            return buffer.toString();
1202        }
1203    }
1204    
1205    public static boolean VERBOSE = false;
1206    public static boolean CP_RESOLVE_VERBOSE = false;
1207    public static boolean CP_RESOLVE_VERBOSE_ADVANCED = false;
1208    public static boolean ZIP_ACCESS_VERBOSE = false;
1209    
1210    /**
1211     * A cache of opened zip files per thread.
1212     * (for a given thread, the object value is a HashMap from IPath to java.io.ZipFile)
1213     */

1214    private ThreadLocal JavaDoc zipFiles = new ThreadLocal JavaDoc();
1215    
1216    private UserLibraryManager userLibraryManager;
1217    
1218    /**
1219     * Update the classpath variable cache
1220     */

1221    public class EclipsePreferencesListener implements IEclipsePreferences.IPreferenceChangeListener {
1222        /**
1223         * @see org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener#preferenceChange(org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent)
1224         */

1225        public void preferenceChange(IEclipsePreferences.PreferenceChangeEvent event) {
1226            String JavaDoc propertyName = event.getKey();
1227            if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
1228                String JavaDoc varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
1229                JavaModelManager manager = getJavaModelManager();
1230                if (manager.variablesWithInitializer.contains(varName)) {
1231                    // revert preference value as we will not apply it to JavaCore classpath variable
1232
String JavaDoc oldValue = (String JavaDoc) event.getOldValue();
1233                    if (oldValue == null) {
1234                        // unexpected old value => remove variable from set
1235
manager.variablesWithInitializer.remove(varName);
1236                    } else {
1237                        manager.getInstancePreferences().put(varName, oldValue);
1238                    }
1239                } else {
1240                    String JavaDoc newValue = (String JavaDoc)event.getNewValue();
1241                    IPath newPath;
1242                    if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) {
1243                        newPath = new Path(newValue);
1244                    } else {
1245                        newPath = null;
1246                    }
1247                    try {
1248                        SetVariablesOperation operation = new SetVariablesOperation(new String JavaDoc[] {varName}, new IPath[] {newPath}, false/*don't update preferences*/);
1249                        operation.runOperation(null/*no progress available*/);
1250                    } catch (JavaModelException e) {
1251                        Util.log(e, "Could not set classpath variable " + varName + " to " + newPath); //$NON-NLS-1$ //$NON-NLS-2$
1252
}
1253                }
1254            } else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
1255                recreatePersistedContainer(propertyName, (String JavaDoc)event.getNewValue(), false);
1256            } else if (propertyName.equals(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER) ||
1257                propertyName.equals(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER) ||
1258                propertyName.equals(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE) ||
1259                propertyName.equals(JavaCore.CORE_JAVA_BUILD_RECREATE_MODIFIED_CLASS_FILES_IN_OUTPUT_FOLDER) ||
1260                propertyName.equals(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH) ||
1261                propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS) ||
1262                propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) ||
1263                propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) ||
1264                propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) ||
1265                propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) {
1266                JavaModelManager manager = JavaModelManager.getJavaModelManager();
1267                IJavaModel model = manager.getJavaModel();
1268                IJavaProject[] projects;
1269                try {
1270                    projects = model.getJavaProjects();
1271                    for (int i = 0, pl = projects.length; i < pl; i++) {
1272                        JavaProject javaProject = (JavaProject) projects[i];
1273                        manager.deltaState.addClasspathValidation(javaProject);
1274                        try {
1275                            // need to touch the project to force validation by DeltaProcessor
1276
javaProject.getProject().touch(null);
1277                        } catch (CoreException e) {
1278                            // skip
1279
}
1280                    }
1281                } catch (JavaModelException e) {
1282                    // skip
1283
}
1284            }
1285        }
1286    }
1287
1288    /**
1289     * Constructs a new JavaModelManager
1290     */

1291    private JavaModelManager() {
1292        // singleton: prevent others from creating a new instance
1293
if (Platform.isRunning()) this.indexManager = new IndexManager();
1294    }
1295
1296    /**
1297     * @deprecated
1298     */

1299    private void addDeprecatedOptions(Hashtable options) {
1300        options.put(JavaCore.COMPILER_PB_INVALID_IMPORT, JavaCore.ERROR);
1301        options.put(JavaCore.COMPILER_PB_UNREACHABLE_CODE, JavaCore.ERROR);
1302    }
1303
1304    /**
1305     * Starts caching ZipFiles.
1306     * Ignores if there are already clients.
1307     */

1308    public void cacheZipFiles() {
1309        if (this.zipFiles.get() != null) return;
1310        this.zipFiles.set(new HashMap());
1311    }
1312    public void closeZipFile(ZipFile JavaDoc zipFile) {
1313        if (zipFile == null) return;
1314        if (this.zipFiles.get() != null) {
1315            return; // zip file will be closed by call to flushZipFiles
1316
}
1317        try {
1318            if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1319                System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$
1320
}
1321            zipFile.close();
1322        } catch (IOException e) {
1323            // problem occured closing zip file: cannot do much more
1324
}
1325    }
1326
1327    /**
1328     * Configure the plugin with respect to option settings defined in ".options" file
1329     */

1330    public void configurePluginDebugOptions(){
1331        if(JavaCore.getPlugin().isDebugging()){
1332            String JavaDoc option = Platform.getDebugOption(BUFFER_MANAGER_DEBUG);
1333            if(option != null) BufferManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1334            
1335            option = Platform.getDebugOption(BUILDER_DEBUG);
1336            if(option != null) JavaBuilder.DEBUG = option.equalsIgnoreCase(TRUE) ;
1337            
1338            option = Platform.getDebugOption(COMPILER_DEBUG);
1339            if(option != null) Compiler.DEBUG = option.equalsIgnoreCase(TRUE) ;
1340
1341            option = Platform.getDebugOption(COMPLETION_DEBUG);
1342            if(option != null) CompletionEngine.DEBUG = option.equalsIgnoreCase(TRUE) ;
1343            
1344            option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
1345            if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase(TRUE) ;
1346
1347            option = Platform.getDebugOption(CP_RESOLVE_ADVANCED_DEBUG);
1348            if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED = option.equalsIgnoreCase(TRUE) ;
1349
1350            option = Platform.getDebugOption(DELTA_DEBUG);
1351            if(option != null) DeltaProcessor.DEBUG = option.equalsIgnoreCase(TRUE) ;
1352
1353            option = Platform.getDebugOption(DELTA_DEBUG_VERBOSE);
1354            if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1355
1356            option = Platform.getDebugOption(HIERARCHY_DEBUG);
1357            if(option != null) TypeHierarchy.DEBUG = option.equalsIgnoreCase(TRUE) ;
1358
1359            option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
1360            if(option != null) JobManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1361            
1362            option = Platform.getDebugOption(JAVAMODEL_DEBUG);
1363            if(option != null) JavaModelManager.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1364
1365            option = Platform.getDebugOption(JAVAMODELCACHE_DEBUG);
1366            if(option != null) JavaModelCache.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1367
1368            option = Platform.getDebugOption(POST_ACTION_DEBUG);
1369            if(option != null) JavaModelOperation.POST_ACTION_VERBOSE = option.equalsIgnoreCase(TRUE) ;
1370
1371            option = Platform.getDebugOption(RESOLUTION_DEBUG);
1372            if(option != null) NameLookup.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1373
1374            option = Platform.getDebugOption(SEARCH_DEBUG);
1375            if(option != null) BasicSearchEngine.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1376
1377            option = Platform.getDebugOption(SELECTION_DEBUG);
1378            if(option != null) SelectionEngine.DEBUG = option.equalsIgnoreCase(TRUE) ;
1379
1380            option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
1381            if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase(TRUE) ;
1382            
1383            option = Platform.getDebugOption(SOURCE_MAPPER_DEBUG_VERBOSE);
1384            if(option != null) SourceMapper.VERBOSE = option.equalsIgnoreCase(TRUE) ;
1385        }
1386        
1387        // configure performance options
1388
if(PerformanceStats.ENABLED) {
1389            CompletionEngine.PERF = PerformanceStats.isEnabled(COMPLETION_PERF);
1390            SelectionEngine.PERF = PerformanceStats.isEnabled(SELECTION_PERF);
1391            DeltaProcessor.PERF = PerformanceStats.isEnabled(DELTA_LISTENER_PERF);
1392            JavaModelManager.PERF_VARIABLE_INITIALIZER = PerformanceStats.isEnabled(VARIABLE_INITIALIZER_PERF);
1393            JavaModelManager.PERF_CONTAINER_INITIALIZER = PerformanceStats.isEnabled(CONTAINER_INITIALIZER_PERF);
1394            ReconcileWorkingCopyOperation.PERF = PerformanceStats.isEnabled(RECONCILE_PERF);
1395        }
1396    }
1397    
1398    /*
1399     * Return a new Java 6 annotation processor manager. The manager will need to
1400     * be configured before it can be used. Returns null if a manager cannot be
1401     * created, ie if the current VM does not support Java 6 annotation processing.
1402     */

1403    public AbstractAnnotationProcessorManager createAnnotationProcessorManager() {
1404        synchronized(this) {
1405            if (this.annotationProcessorManagerFactory == null) {
1406                IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, ANNOTATION_PROCESSOR_MANAGER_EXTPOINT_ID);
1407                if (extension == null)
1408                    return null;
1409                IExtension[] extensions = extension.getExtensions();
1410                for(int i = 0; i < extensions.length; i++) {
1411                    if (i > 0) {
1412                        Util.log(null, "An annotation processor manager is already registered: ignoring " + extensions[i].getUniqueIdentifier()); //$NON-NLS-1$
1413
break;
1414                    }
1415                    IConfigurationElement[] configElements = extensions[i].getConfigurationElements();
1416                    for(int j = 0; j < configElements.length; j++) {
1417                        final IConfigurationElement configElement = configElements[j];
1418                        if ("annotationProcessorManager".equals(configElement.getName())) { //$NON-NLS-1$
1419
this.annotationProcessorManagerFactory = configElement;
1420                            break;
1421                        }
1422                    }
1423                }
1424            }
1425        }
1426        
1427        if (this.annotationProcessorManagerFactory == null) {
1428            return null;
1429        }
1430        final AbstractAnnotationProcessorManager[] apm = new AbstractAnnotationProcessorManager[1];
1431        apm[0] = null;
1432        final IConfigurationElement factory = this.annotationProcessorManagerFactory;
1433        SafeRunner.run(new ISafeRunnable() {
1434            public void handleException(Throwable JavaDoc exception) {
1435                Util.log(exception, "Exception occurred while loading annotation processor manager"); //$NON-NLS-1$
1436
}
1437            public void run() throws Exception JavaDoc {
1438                Object JavaDoc executableExtension = factory.createExecutableExtension("class"); //$NON-NLS-1$
1439
if (executableExtension instanceof AbstractAnnotationProcessorManager) {
1440                    apm[0] = (AbstractAnnotationProcessorManager) executableExtension;
1441                }
1442            }
1443        });
1444        return apm[0];
1445    }
1446    
1447    /*
1448     * Discards the per working copy info for the given working copy (making it a compilation unit)
1449     * if its use count was 1. Otherwise, just decrement the use count.
1450     * If the working copy is primary, computes the delta between its state and the original compilation unit
1451     * and register it.
1452     * Close the working copy, its buffer and remove it from the shared working copy table.
1453     * Ignore if no per-working copy info existed.
1454     * NOTE: it must NOT be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667.
1455     * Returns the new use count (or -1 if it didn't exist).
1456     */

1457    public int discardPerWorkingCopyInfo(CompilationUnit workingCopy) throws JavaModelException {
1458        
1459        // create the delta builder (this remembers the current content of the working copy)
1460
// outside the perWorkingCopyInfos lock (see bug 50667)
1461
JavaElementDeltaBuilder deltaBuilder = null;
1462        if (workingCopy.isPrimary() && workingCopy.hasUnsavedChanges()) {
1463            deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
1464        }
1465        PerWorkingCopyInfo info = null;
1466        synchronized(this.perWorkingCopyInfos) {
1467            WorkingCopyOwner owner = workingCopy.owner;
1468            Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
1469            if (workingCopyToInfos == null) return -1;
1470            
1471            info = (PerWorkingCopyInfo)workingCopyToInfos.get(workingCopy);
1472            if (info == null) return -1;
1473            
1474            if (--info.useCount == 0) {
1475                // remove per working copy info
1476
workingCopyToInfos.remove(workingCopy);
1477                if (workingCopyToInfos.isEmpty()) {
1478                    this.perWorkingCopyInfos.remove(owner);
1479                }
1480            }
1481        }
1482        if (info.useCount == 0) { // info cannot be null here (check was done above)
1483
// remove infos + close buffer (since no longer working copy)
1484
// outside the perWorkingCopyInfos lock (see bug 50667)
1485
removeInfoAndChildren(workingCopy);
1486            workingCopy.closeBuffer();
1487
1488            // compute the delta if needed and register it if there are changes
1489
if (deltaBuilder != null) {
1490                deltaBuilder.buildDeltas();
1491                if (deltaBuilder.delta != null) {
1492                    getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta);
1493                }
1494            }
1495        }
1496        return info.useCount;
1497    }
1498    
1499    /**
1500     * @see ISaveParticipant
1501     */

1502    public void doneSaving(ISaveContext context){
1503        // nothing to do for jdt.core
1504
}
1505
1506    /**
1507     * Flushes ZipFiles cache if there are no more clients.
1508     */

1509    public void flushZipFiles() {
1510        Thread JavaDoc currentThread = Thread.currentThread();
1511        HashMap map = (HashMap)this.zipFiles.get();
1512        if (map == null) return;
1513        this.zipFiles.set(null);
1514        Iterator iterator = map.values().iterator();
1515        while (iterator.hasNext()) {
1516            try {
1517                ZipFile JavaDoc zipFile = (ZipFile JavaDoc)iterator.next();
1518                if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1519                    System.out.println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$
1520
}
1521                zipFile.close();
1522            } catch (IOException e) {
1523                // problem occured closing zip file: cannot do much more
1524
}
1525        }
1526    }
1527    
1528    private synchronized boolean batchContainerInitializations() {
1529        if (this.batchContainerInitializations) {
1530            this.batchContainerInitializations = false;
1531            return true;
1532        }
1533        return false;
1534    }
1535    
1536    public IClasspathContainer getClasspathContainer(final IPath containerPath, final IJavaProject project) throws JavaModelException {
1537
1538        IClasspathContainer container = containerGet(project, containerPath);
1539
1540        if (container == null) {
1541            if (batchContainerInitializations()) {
1542                // avoid deep recursion while initializaing container on workspace restart
1543
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=60437)
1544
container = initializeAllContainers(project, containerPath);
1545            } else {
1546                container = initializeContainer(project, containerPath);
1547            }
1548        }
1549        return container;
1550    }
1551
1552    public DeltaProcessor getDeltaProcessor() {
1553        return this.deltaState.getDeltaProcessor();
1554    }
1555    
1556    /**
1557     * Returns the set of elements which are out of synch with their buffers.
1558     */

1559    protected HashSet getElementsOutOfSynchWithBuffers() {
1560        return this.elementsOutOfSynchWithBuffers;
1561    }
1562
1563    public IndexManager getIndexManager() {
1564        return this.indexManager;
1565    }
1566
1567    /**
1568     * Returns the info for the element.
1569     */

1570    public synchronized Object JavaDoc getInfo(IJavaElement element) {
1571        HashMap tempCache = (HashMap)this.temporaryCache.get();
1572        if (tempCache != null) {
1573            Object JavaDoc result = tempCache.get(element);
1574            if (result != null) {
1575                return result;
1576            }
1577        }
1578        return this.cache.getInfo(element);
1579    }
1580
1581    /**
1582     * Get workpsace eclipse preference for JavaCore plugin.
1583     */

1584    public IEclipsePreferences getInstancePreferences() {
1585        return preferencesLookup[PREF_INSTANCE];
1586    }
1587 
1588    // If modified, also modify the method getDefaultOptionsNoInitialization()
1589
public Hashtable getDefaultOptions(){
1590
1591        Hashtable defaultOptions = new Hashtable(10);
1592
1593        // see JavaCorePreferenceInitializer#initializeDefaultPluginPreferences() for changing default settings
1594
// If modified, also modify the method getDefaultOptionsNoInitialization()
1595
IEclipsePreferences defaultPreferences = getDefaultPreferences();
1596        
1597        // initialize preferences to their default
1598
Iterator iterator = this.optionNames.iterator();
1599        while (iterator.hasNext()) {
1600            String JavaDoc propertyName = (String JavaDoc) iterator.next();
1601            String JavaDoc value = defaultPreferences.get(propertyName, null);
1602            if (value != null) defaultOptions.put(propertyName, value);
1603        }
1604        // get encoding through resource plugin
1605
defaultOptions.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding());
1606        // backward compatibility
1607
addDeprecatedOptions(defaultOptions);
1608        
1609        return defaultOptions;
1610    }
1611    
1612    /**
1613     * Get default eclipse preference for JavaCore plugin.
1614     */

1615    public IEclipsePreferences getDefaultPreferences() {
1616        return preferencesLookup[PREF_DEFAULT];
1617    }
1618
1619    /**
1620     * Returns the handle to the active Java Model.
1621     */

1622    public final JavaModel getJavaModel() {
1623        return this.javaModel;
1624    }
1625
1626    /**
1627     * Returns the singleton JavaModelManager
1628     */

1629    public final static JavaModelManager getJavaModelManager() {
1630        return MANAGER;
1631    }
1632
1633    /**
1634     * Returns the last built state for the given project, or null if there is none.
1635     * Deserializes the state if necessary.
1636     *
1637     * For use by image builder and evaluation support only
1638     */

1639    public Object JavaDoc getLastBuiltState(IProject project, IProgressMonitor monitor) {
1640        if (!JavaProject.hasJavaNature(project)) {
1641            if (JavaBuilder.DEBUG)
1642                System.out.println(project + " is not a Java project"); //$NON-NLS-1$
1643
return null; // should never be requested on non-Java projects
1644
}
1645        PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/);
1646        if (!info.triedRead) {
1647            info.triedRead = true;
1648            try {
1649                if (monitor != null)
1650                    monitor.subTask(Messages.bind(Messages.build_readStateProgress, project.getName()));
1651                info.savedState = readState(project);
1652            } catch (CoreException e) {
1653                e.printStackTrace();
1654            }
1655        }
1656        return info.savedState;
1657    }
1658
1659    public String JavaDoc getOption(String JavaDoc optionName) {
1660        
1661        if (JavaCore.CORE_ENCODING.equals(optionName)){
1662            return JavaCore.getEncoding();
1663        }
1664        // backward compatibility
1665
if (isDeprecatedOption(optionName)) {
1666            return JavaCore.ERROR;
1667        }
1668        String JavaDoc propertyName = optionName;
1669        if (this.optionNames.contains(propertyName)){
1670            IPreferencesService service = Platform.getPreferencesService();
1671            String JavaDoc value = service.get(optionName, null, this.preferencesLookup);
1672            return value==null ? null : value.trim();
1673        }
1674        return null;
1675    }
1676    
1677    public Hashtable getOptions() {
1678
1679        // return cached options if already computed
1680
if (this.optionsCache != null) return new Hashtable(this.optionsCache);
1681
1682        if (!Platform.isRunning()) {
1683            return this.optionsCache = getDefaultOptionsNoInitialization();
1684        }
1685        // init
1686
Hashtable options = new Hashtable(10);
1687        IPreferencesService service = Platform.getPreferencesService();
1688
1689        // set options using preferences service lookup
1690
Iterator iterator = optionNames.iterator();
1691        while (iterator.hasNext()) {
1692            String JavaDoc propertyName = (String JavaDoc) iterator.next();
1693            String JavaDoc propertyValue = service.get(propertyName, null, this.preferencesLookup);
1694            if (propertyValue != null) {
1695                options.put(propertyName, propertyValue);
1696            }
1697        }
1698
1699        // get encoding through resource plugin
1700
options.put(JavaCore.CORE_ENCODING, JavaCore.getEncoding());
1701
1702        // backward compatibility
1703
addDeprecatedOptions(options);
1704
1705        // store built map in cache
1706
this.optionsCache = new Hashtable(options);
1707
1708        // return built map
1709
return options;
1710    }
1711
1712    // Do not modify without modifying getDefaultOptions()
1713
private Hashtable getDefaultOptionsNoInitialization() {
1714        Map defaultOptionsMap = new CompilerOptions().getMap(); // compiler defaults
1715

1716        // Override some compiler defaults
1717
defaultOptionsMap.put(JavaCore.COMPILER_LOCAL_VARIABLE_ATTR, JavaCore.GENERATE);
1718        defaultOptionsMap.put(JavaCore.COMPILER_CODEGEN_UNUSED_LOCAL, JavaCore.PRESERVE);
1719        defaultOptionsMap.put(JavaCore.COMPILER_TASK_TAGS, JavaCore.DEFAULT_TASK_TAGS);
1720        defaultOptionsMap.put(JavaCore.COMPILER_TASK_PRIORITIES, JavaCore.DEFAULT_TASK_PRIORITIES);
1721        defaultOptionsMap.put(JavaCore.COMPILER_TASK_CASE_SENSITIVE, JavaCore.ENABLED);
1722        defaultOptionsMap.put(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, JavaCore.ENABLED);
1723        defaultOptionsMap.put(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, JavaCore.ERROR);
1724        
1725        // Builder settings
1726
defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, ""); //$NON-NLS-1$
1727
defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, JavaCore.ABORT);
1728        defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_DUPLICATE_RESOURCE, JavaCore.WARNING);
1729        defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_CLEAN_OUTPUT_FOLDER, JavaCore.CLEAN);
1730
1731        // JavaCore settings
1732
defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE);
1733        defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR);
1734        defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR);
1735        defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE);
1736        defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED);
1737        defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED);
1738
1739        // Formatter settings
1740
defaultOptionsMap.putAll(DefaultCodeFormatterConstants.getEclipseDefaultSettings());
1741
1742        // CodeAssist settings
1743
defaultOptionsMap.put(JavaCore.CODEASSIST_VISIBILITY_CHECK, JavaCore.DISABLED);
1744        defaultOptionsMap.put(JavaCore.CODEASSIST_DEPRECATION_CHECK, JavaCore.DISABLED);
1745        defaultOptionsMap.put(JavaCore.CODEASSIST_IMPLICIT_QUALIFICATION, JavaCore.DISABLED);
1746        defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_PREFIXES, ""); //$NON-NLS-1$
1747
defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_PREFIXES, ""); //$NON-NLS-1$
1748
defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_PREFIXES, ""); //$NON-NLS-1$
1749
defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_PREFIXES, ""); //$NON-NLS-1$
1750
defaultOptionsMap.put(JavaCore.CODEASSIST_FIELD_SUFFIXES, ""); //$NON-NLS-1$
1751
defaultOptionsMap.put(JavaCore.CODEASSIST_STATIC_FIELD_SUFFIXES, ""); //$NON-NLS-1$
1752
defaultOptionsMap.put(JavaCore.CODEASSIST_LOCAL_SUFFIXES, ""); //$NON-NLS-1$
1753
defaultOptionsMap.put(JavaCore.CODEASSIST_ARGUMENT_SUFFIXES, ""); //$NON-NLS-1$
1754
defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
1755        defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
1756        defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
1757        defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
1758        
1759        // Time out for parameter names
1760
defaultOptionsMap.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, "50"); //$NON-NLS-1$
1761

1762        return new Hashtable(defaultOptionsMap);
1763    }
1764    
1765    /*
1766     * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist.
1767     */

1768    public PerProjectInfo getPerProjectInfo(IProject project, boolean create) {
1769        synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock
1770
PerProjectInfo info= (PerProjectInfo) this.perProjectInfos.get(project);
1771            if (info == null && create) {
1772                info= new PerProjectInfo(project);
1773                this.perProjectInfos.put(project, info);
1774            }
1775            return info;
1776        }
1777    }
1778    
1779    /*
1780     * Returns the per-project info for the given project.
1781     * If the info doesn't exist, check for the project existence and create the info.
1782     * @throws JavaModelException if the project doesn't exist.
1783     */

1784    public PerProjectInfo getPerProjectInfoCheckExistence(IProject project) throws JavaModelException {
1785        JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /* don't create info */);
1786        if (info == null) {
1787            if (!JavaProject.hasJavaNature(project)) {
1788                throw ((JavaProject)JavaCore.create(project)).newNotPresentException();
1789            }
1790            info = getPerProjectInfo(project, true /* create info */);
1791        }
1792        return info;
1793    }
1794    
1795    /*
1796     * Returns the per-working copy info for the given working copy at the given path.
1797     * If it doesn't exist and if create, add a new per-working copy info with the given problem requestor.
1798     * If recordUsage, increment the per-working copy info's use count.
1799     * Returns null if it doesn't exist and not create.
1800     */

1801    public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy,boolean create, boolean recordUsage, IProblemRequestor problemRequestor) {
1802        synchronized(this.perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock
1803
WorkingCopyOwner owner = workingCopy.owner;
1804            Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
1805            if (workingCopyToInfos == null && create) {
1806                workingCopyToInfos = new HashMap();
1807                this.perWorkingCopyInfos.put(owner, workingCopyToInfos);
1808            }
1809
1810            PerWorkingCopyInfo info = workingCopyToInfos == null ? null : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy);
1811            if (info == null && create) {
1812                info= new PerWorkingCopyInfo(workingCopy, problemRequestor);
1813                workingCopyToInfos.put(workingCopy, info);
1814            }
1815            if (info != null && recordUsage) info.useCount++;
1816            return info;
1817        }
1818    }
1819
1820    /**
1821     * Returns a persisted container from previous session if any. Note that it is not the original container from previous
1822     * session (i.e. it did not get serialized) but rather a summary of its entries recreated for CP initialization purpose.
1823     * As such it should not be stored into container caches.
1824     */

1825    public IClasspathContainer getPreviousSessionContainer(IPath containerPath, IJavaProject project) {
1826            Map previousContainerValues = (Map)this.previousSessionContainers.get(project);
1827            if (previousContainerValues != null){
1828                IClasspathContainer previousContainer = (IClasspathContainer)previousContainerValues.get(containerPath);
1829                if (previousContainer != null) {
1830                    if (JavaModelManager.CP_RESOLVE_VERBOSE_ADVANCED)
1831                        verbose_reentering_project_container_access(containerPath, project, previousContainer);
1832                    return previousContainer;
1833                }
1834            }
1835            return null; // break cycle if none found
1836
}
1837
1838    private void verbose_reentering_project_container_access( IPath containerPath, IJavaProject project, IClasspathContainer previousContainer) {
1839        StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
1840        buffer.append("CPContainer INIT - reentering access to project container during its initialization, will see previous value\n"); //$NON-NLS-1$
1841
buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$
1842
buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$
1843
buffer.append(" previous value: "); //$NON-NLS-1$
1844
buffer.append(previousContainer.getDescription());
1845        buffer.append(" {\n"); //$NON-NLS-1$
1846
IClasspathEntry[] entries = previousContainer.getClasspathEntries();
1847        if (entries != null){
1848            for (int j = 0; j < entries.length; j++){
1849                buffer.append(" "); //$NON-NLS-1$
1850
buffer.append(entries[j]);
1851                buffer.append('\n');
1852            }
1853        }
1854        buffer.append(" }"); //$NON-NLS-1$
1855
Util.verbose(buffer.toString());
1856        new Exception JavaDoc("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
1857
}
1858    
1859    /**
1860     * Returns a persisted container from previous session if any
1861     */

1862    public IPath getPreviousSessionVariable(String JavaDoc variableName) {
1863        IPath previousPath = (IPath)this.previousSessionVariables.get(variableName);
1864        if (previousPath != null){
1865            if (CP_RESOLVE_VERBOSE_ADVANCED)
1866                verbose_reentering_variable_access(variableName, previousPath);
1867            return previousPath;
1868        }
1869        return null; // break cycle
1870
}
1871
1872    private void verbose_reentering_variable_access(String JavaDoc variableName, IPath previousPath) {
1873        Util.verbose(
1874            "CPVariable INIT - reentering access to variable during its initialization, will see previous value\n" + //$NON-NLS-1$
1875
" variable: "+ variableName + '\n' + //$NON-NLS-1$
1876
" previous value: " + previousPath); //$NON-NLS-1$
1877
new Exception JavaDoc("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
1878
}
1879
1880    /**
1881     * Returns the temporary cache for newly opened elements for the current thread.
1882     * Creates it if not already created.
1883     */

1884    public HashMap getTemporaryCache() {
1885        HashMap result = (HashMap)this.temporaryCache.get();
1886        if (result == null) {
1887            result = new HashMap();
1888            this.temporaryCache.set(result);
1889        }
1890        return result;
1891    }
1892    
1893    private File JavaDoc getVariableAndContainersFile() {
1894        return JavaCore.getPlugin().getStateLocation().append("variablesAndContainers.dat").toFile(); //$NON-NLS-1$
1895
}
1896
1897    /**
1898     * Returns the name of the variables for which an CP variable initializer is registered through an extension point
1899     */

1900    public static String JavaDoc[] getRegisteredVariableNames(){
1901        
1902        Plugin jdtCorePlugin = JavaCore.getPlugin();
1903        if (jdtCorePlugin == null) return null;
1904
1905        ArrayList variableList = new ArrayList(5);
1906        IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
1907        if (extension != null) {
1908            IExtension[] extensions = extension.getExtensions();
1909            for(int i = 0; i < extensions.length; i++){
1910                IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
1911                for(int j = 0; j < configElements.length; j++){
1912                    String JavaDoc varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$
1913
if (varAttribute != null) variableList.add(varAttribute);
1914                }
1915            }
1916        }
1917        String JavaDoc[] variableNames = new String JavaDoc[variableList.size()];
1918        variableList.toArray(variableNames);
1919        return variableNames;
1920    }
1921
1922    /**
1923     * Returns the name of the container IDs for which an CP container initializer is registered through an extension point
1924     */

1925    public static String JavaDoc[] getRegisteredContainerIDs(){
1926        
1927        Plugin jdtCorePlugin = JavaCore.getPlugin();
1928        if (jdtCorePlugin == null) return null;
1929
1930        ArrayList containerIDList = new ArrayList(5);
1931        IExtensionPoint extension = Platform.getExtensionRegistry().getExtensionPoint(JavaCore.PLUGIN_ID, JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
1932        if (extension != null) {
1933            IExtension[] extensions = extension.getExtensions();
1934            for(int i = 0; i < extensions.length; i++){
1935                IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
1936                for(int j = 0; j < configElements.length; j++){
1937                    String JavaDoc idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$
1938
if (idAttribute != null) containerIDList.add(idAttribute);
1939                }
1940            }
1941        }
1942        String JavaDoc[] containerIDs = new String JavaDoc[containerIDList.size()];
1943        containerIDList.toArray(containerIDs);
1944        return containerIDs;
1945    }
1946
1947    /**
1948     * Returns the File to use for saving and restoring the last built state for the given project.
1949     */

1950    private File JavaDoc getSerializationFile(IProject project) {
1951        if (!project.exists()) return null;
1952        IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
1953        return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
1954
}
1955    
1956    public static UserLibraryManager getUserLibraryManager() {
1957        JavaModelManager modelManager = getJavaModelManager();
1958        if (modelManager.userLibraryManager == null) {
1959            UserLibraryManager libraryManager = new UserLibraryManager();
1960            synchronized(modelManager) {
1961                if (modelManager.userLibraryManager == null) { // ensure another library manager was not set while creating the instance above
1962
modelManager.userLibraryManager = libraryManager;
1963                    modelManager.getInstancePreferences().addPreferenceChangeListener(libraryManager);
1964                }
1965            }
1966        }
1967        return modelManager.userLibraryManager;
1968    }
1969    
1970    /*
1971     * Returns all the working copies which have the given owner.
1972     * Adds the working copies of the primary owner if specified.
1973     * Returns null if it has none.
1974     */

1975    public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner, boolean addPrimary) {
1976        synchronized(this.perWorkingCopyInfos) {
1977            ICompilationUnit[] primaryWCs = addPrimary && owner != DefaultWorkingCopyOwner.PRIMARY
1978                ? getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false)
1979                : null;
1980            Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
1981            if (workingCopyToInfos == null) return primaryWCs;
1982            int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
1983            int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
1984
ICompilationUnit[] result = new ICompilationUnit[primaryLength + size];
1985            int index = 0;
1986            if (primaryWCs != null) {
1987                for (int i = 0; i < primaryLength; i++) {
1988                    ICompilationUnit primaryWorkingCopy = primaryWCs[i];
1989                    ICompilationUnit workingCopy = new CompilationUnit((PackageFragment) primaryWorkingCopy.getParent(), primaryWorkingCopy.getElementName(), owner);
1990                    if (!workingCopyToInfos.containsKey(workingCopy))
1991                        result[index++] = primaryWorkingCopy;
1992                }
1993                if (index != primaryLength)
1994                    System.arraycopy(result, 0, result = new ICompilationUnit[index+size], 0, index);
1995            }
1996            Iterator iterator = workingCopyToInfos.values().iterator();
1997            while(iterator.hasNext()) {
1998                result[index++] = ((JavaModelManager.PerWorkingCopyInfo)iterator.next()).getWorkingCopy();
1999            }
2000            return result;
2001        }
2002    }
2003    
2004    public JavaWorkspaceScope getWorkspaceScope() {
2005        if (this.workspaceScope == null) {
2006            this.workspaceScope = new JavaWorkspaceScope();
2007        }
2008        return this.workspaceScope;
2009    }
2010    
2011    /**
2012     * Returns the open ZipFile at the given path. If the ZipFile
2013     * does not yet exist, it is created, opened, and added to the cache
2014     * of open ZipFiles.
2015     *
2016     * The path must be a file system path if representing an external
2017     * zip/jar, or it must be an absolute workspace relative path if
2018     * representing a zip/jar inside the workspace.
2019     *
2020     * @exception CoreException If unable to create/open the ZipFile
2021     */

2022    public ZipFile JavaDoc getZipFile(IPath path) throws CoreException {
2023            
2024        HashMap map;
2025        ZipFile JavaDoc zipFile;
2026        if ((map = (HashMap)this.zipFiles.get()) != null
2027                && (zipFile = (ZipFile JavaDoc)map.get(path)) != null) {
2028                
2029            return zipFile;
2030        }
2031        File JavaDoc localFile = null;
2032        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
2033        IResource file = root.findMember(path);
2034        if (file != null) {
2035            // internal resource
2036
URI JavaDoc location;
2037            if (file.getType() != IResource.FILE || (location = file.getLocationURI()) == null) {
2038                throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null));
2039            }
2040            localFile = Util.toLocalFile(location, null/*no progress availaible*/);
2041            if (localFile == null)
2042                throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.bind(Messages.file_notFound, path.toString()), null));
2043        } else {
2044            // external resource -> it is ok to use toFile()
2045
localFile= path.toFile();
2046        }
2047
2048        try {
2049            if (ZIP_ACCESS_VERBOSE) {
2050                System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + localFile ); //$NON-NLS-1$ //$NON-NLS-2$
2051
}
2052            zipFile = new ZipFile JavaDoc(localFile);
2053            if (map != null) {
2054                map.put(path, zipFile);
2055            }
2056            return zipFile;
2057        } catch (IOException e) {
2058            throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, e));
2059        }
2060    }
2061    
2062    /*
2063     * Returns whether there is a temporary cache for the current thread.
2064     */

2065    public boolean hasTemporaryCache() {
2066        return this.temporaryCache.get() != null;
2067    }
2068    
2069    /*
2070     * Initialize all container at the same time as the given container.
2071     * Return the container for the given path and project.
2072     */

2073    private IClasspathContainer initializeAllContainers(IJavaProject javaProjectToInit, IPath containerToInit) throws JavaModelException {
2074        if (CP_RESOLVE_VERBOSE_ADVANCED)
2075            verbose_batching_containers_initialization(javaProjectToInit, containerToInit);
2076
2077        // collect all container paths
2078
final HashMap allContainerPaths = new HashMap();
2079        IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
2080        for (int i = 0, length = projects.length; i < length; i++) {
2081            IProject project = projects[i];
2082            if (!JavaProject.hasJavaNature(project)) continue;
2083            IJavaProject javaProject = new JavaProject(project, getJavaModel());
2084            HashSet paths = (HashSet) allContainerPaths.get(javaProject);
2085            IClasspathEntry[] rawClasspath = javaProject.getRawClasspath();
2086            for (int j = 0, length2 = rawClasspath.length; j < length2; j++) {
2087                IClasspathEntry entry = rawClasspath[j];
2088                IPath path = entry.getPath();
2089                if (entry.getEntryKind() == IClasspathEntry.CPE_CONTAINER
2090                        && containerGet(javaProject, path) == null) {
2091                    if (paths == null) {
2092                        paths = new HashSet();
2093                        allContainerPaths.put(javaProject, paths);
2094                    }
2095                    paths.add(path);
2096                    // mark container as being initialized
2097
containerAddInitializationInProgress(javaProject, path);
2098                }
2099            }
2100            /* TODO (frederic) put back when JDT/UI dummy project will be thrown away...
2101             * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97524
2102             *
2103            if (javaProject.equals(javaProjectToInit)) {
2104                if (paths == null) {
2105                    paths = new HashSet();
2106                    allContainerPaths.put(javaProject, paths);
2107                }
2108                paths.add(containerToInit);
2109            }
2110            */

2111        }
2112        // TODO (frederic) remove following block when JDT/UI dummy project will be thrown away...
2113
HashSet containerPaths = (HashSet) allContainerPaths.get(javaProjectToInit);
2114        if (containerPaths == null) {
2115            containerPaths = new HashSet();
2116            allContainerPaths.put(javaProjectToInit, containerPaths);
2117        }
2118        containerPaths.add(containerToInit);
2119        // mark container as being initialized
2120
containerAddInitializationInProgress(javaProjectToInit, containerToInit);
2121        // end block
2122

2123        // initialize all containers
2124
boolean ok = false;
2125        try {
2126            // if possible run inside an IWokspaceRunnable with AVOID_UPATE to avoid unwanted builds
2127
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=118507)
2128
IWorkspaceRunnable runnable =
2129                new IWorkspaceRunnable() {
2130                    public void run(IProgressMonitor monitor) throws CoreException {
2131                        try {
2132                            Set entrySet = allContainerPaths.entrySet();
2133                            int length = entrySet.size();
2134                            if (monitor != null)
2135                                monitor.beginTask("", length); //$NON-NLS-1$
2136
Map.Entry[] entries = new Map.Entry[length]; // clone as the following will have a side effect
2137
entrySet.toArray(entries);
2138                            for (int i = 0; i < length; i++) {
2139                                Map.Entry entry = entries[i];
2140                                IJavaProject javaProject = (IJavaProject) entry.getKey();
2141                                HashSet pathSet = (HashSet) entry.getValue();
2142                                if (pathSet == null) continue;
2143                                int length2 = pathSet.size();
2144                                IPath[] paths = new IPath[length2];
2145                                pathSet.toArray(paths); // clone as the following will have a side effect
2146
for (int j = 0; j < length2; j++) {
2147                                    IPath path = paths[j];
2148                                    initializeContainer(javaProject, path);
2149                                }
2150                                if (monitor != null)
2151                                    monitor.worked(1);
2152                            }
2153                        } finally {
2154                            if (monitor != null)
2155                                monitor.done();
2156                        }
2157                    }
2158                };
2159            IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get();
2160            IWorkspace workspace = ResourcesPlugin.getWorkspace();
2161            if (workspace.isTreeLocked())
2162                runnable.run(monitor);
2163            else
2164                workspace.run(
2165                    runnable,
2166                    null/*don't take any lock*/,
2167                    IWorkspace.AVOID_UPDATE,
2168                    monitor);
2169            ok = true;
2170        } catch (CoreException e) {
2171            // ignore
2172
Util.log(e, "Exception while initializing all containers"); //$NON-NLS-1$
2173
} finally {
2174            if (!ok) {
2175                // if we're being traversed by an exception, ensure that that containers are
2176
// no longer marked as initialization in progress
2177
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=66437)
2178
this.containerInitializationInProgress.set(null);
2179            }
2180        }
2181        
2182        return containerGet(javaProjectToInit, containerToInit);
2183    }
2184
2185    private void verbose_batching_containers_initialization(IJavaProject javaProjectToInit, IPath containerToInit) {
2186        Util.verbose(
2187            "CPContainer INIT - batching containers initialization\n" + //$NON-NLS-1$
2188
" project to init: " + javaProjectToInit.getElementName() + '\n' + //$NON-NLS-1$
2189
" container path to init: " + containerToInit); //$NON-NLS-1$
2190
}
2191
2192    IClasspathContainer initializeContainer(IJavaProject project, IPath containerPath) throws JavaModelException {
2193
2194        IProgressMonitor monitor = (IProgressMonitor) this.batchContainerInitializationsProgress.get();
2195        if (monitor != null && monitor.isCanceled())
2196            throw new OperationCanceledException();
2197        
2198        IClasspathContainer container = null;
2199        final ClasspathContainerInitializer initializer = JavaCore.getClasspathContainerInitializer(containerPath.segment(0));
2200        if (initializer != null){
2201            if (CP_RESOLVE_VERBOSE)
2202                verbose_triggering_container_initialization(project, containerPath, initializer);
2203            if (CP_RESOLVE_VERBOSE_ADVANCED)
2204                verbose_triggering_container_initialization_invocation_trace();
2205            PerformanceStats stats = null;
2206            if(JavaModelManager.PERF_CONTAINER_INITIALIZER) {
2207                stats = PerformanceStats.getStats(JavaModelManager.CONTAINER_INITIALIZER_PERF, this);
2208                stats.startRun(containerPath + " of " + project.getPath()); //$NON-NLS-1$
2209
}
2210            containerPut(project, containerPath, CONTAINER_INITIALIZATION_IN_PROGRESS); // avoid initialization cycles
2211
boolean ok = false;
2212            try {
2213                if (monitor != null)
2214                    monitor.subTask(Messages.bind(Messages.javamodel_configuring, initializer.getDescription(containerPath, project)));
2215                
2216                // let OperationCanceledException go through
2217
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59363)
2218
initializer.initialize(containerPath, project);
2219                
2220                if (monitor != null)
2221                    monitor.subTask(""); //$NON-NLS-1$
2222

2223                // retrieve value (if initialization was successful)
2224
container = containerGet(project, containerPath);
2225                if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
2226                    // initializer failed to do its job: redirect to the failure container
2227
container = initializer.getFailureContainer(containerPath, project);
2228                    if (container == null) {
2229                        if (CP_RESOLVE_VERBOSE)
2230                            verbose_container_null_failure_container(project, containerPath, initializer);
2231                        return null; // break cycle
2232
}
2233                    if (CP_RESOLVE_VERBOSE)
2234                        verbose_container_using_failure_container(project, containerPath, initializer);
2235                    containerPut(project, containerPath, container);
2236                }
2237                ok = true;
2238            } catch (CoreException e) {
2239                if (e instanceof JavaModelException) {
2240                    throw (JavaModelException) e;
2241                } else {
2242                    throw new JavaModelException(e);
2243                }
2244            } catch (RuntimeException JavaDoc e) {
2245                if (JavaModelManager.CP_RESOLVE_VERBOSE)
2246                    e.printStackTrace();
2247                throw e;
2248            } catch (Error JavaDoc e) {
2249                if (JavaModelManager.CP_RESOLVE_VERBOSE)
2250                    e.printStackTrace();
2251                throw e;
2252            } finally {
2253                if(JavaModelManager.PERF_CONTAINER_INITIALIZER) {
2254                    stats.endRun();
2255                }
2256                if (!ok) {
2257                    // just remove initialization in progress and keep previous session container so as to avoid a full build
2258
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=92588
2259
containerRemoveInitializationInProgress(project, containerPath);
2260                    if (CP_RESOLVE_VERBOSE)
2261                        verbose_container_initialization_failed(project, containerPath, container, initializer);
2262                }
2263            }
2264            if (CP_RESOLVE_VERBOSE_ADVANCED)
2265                verbose_container_value_after_initialization(project, containerPath, container);
2266        } else {
2267            // create a dummy initializer and get the default failure container
2268
container = (new ClasspathContainerInitializer() {
2269                public void initialize(IPath path, IJavaProject javaProject) throws CoreException {
2270                    // not used
2271
}
2272            }).getFailureContainer(containerPath, project);
2273            if (CP_RESOLVE_VERBOSE_ADVANCED)
2274                verbose_no_container_initializer_found(project, containerPath);
2275        }
2276        return container;
2277    }
2278
2279    private void verbose_no_container_initializer_found(IJavaProject project, IPath containerPath) {
2280        Util.verbose(
2281            "CPContainer INIT - no initializer found\n" + //$NON-NLS-1$
2282
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2283
" container path: " + containerPath); //$NON-NLS-1$
2284
}
2285
2286    private void verbose_container_value_after_initialization(IJavaProject project, IPath containerPath, IClasspathContainer container) {
2287        StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
2288        buffer.append("CPContainer INIT - after resolution\n"); //$NON-NLS-1$
2289
buffer.append(" project: " + project.getElementName() + '\n'); //$NON-NLS-1$
2290
buffer.append(" container path: " + containerPath + '\n'); //$NON-NLS-1$
2291
if (container != null){
2292            buffer.append(" container: "+container.getDescription()+" {\n"); //$NON-NLS-2$//$NON-NLS-1$
2293
IClasspathEntry[] entries = container.getClasspathEntries();
2294            if (entries != null){
2295                for (int i = 0; i < entries.length; i++) {
2296                    buffer.append(" " + entries[i] + '\n'); //$NON-NLS-1$
2297
}
2298            }
2299            buffer.append(" }");//$NON-NLS-1$
2300
} else {
2301            buffer.append(" container: {unbound}");//$NON-NLS-1$
2302
}
2303        Util.verbose(buffer.toString());
2304    }
2305
2306    private void verbose_container_initialization_failed(IJavaProject project, IPath containerPath, IClasspathContainer container, ClasspathContainerInitializer initializer) {
2307        if (container == CONTAINER_INITIALIZATION_IN_PROGRESS) {
2308            Util.verbose(
2309                "CPContainer INIT - FAILED (initializer did not initialize container)\n" + //$NON-NLS-1$
2310
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2311
" container path: " + containerPath + '\n' + //$NON-NLS-1$
2312
" initializer: " + initializer); //$NON-NLS-1$
2313

2314        } else {
2315            Util.verbose(
2316                "CPContainer INIT - FAILED (see exception above)\n" + //$NON-NLS-1$
2317
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2318
" container path: " + containerPath + '\n' + //$NON-NLS-1$
2319
" initializer: " + initializer); //$NON-NLS-1$
2320
}
2321    }
2322
2323    private void verbose_container_null_failure_container(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) {
2324        Util.verbose(
2325            "CPContainer INIT - FAILED (and failure container is null)\n" + //$NON-NLS-1$
2326
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2327
" container path: " + containerPath + '\n' + //$NON-NLS-1$
2328
" initializer: " + initializer); //$NON-NLS-1$
2329
}
2330
2331    private void verbose_container_using_failure_container(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) {
2332        Util.verbose(
2333            "CPContainer INIT - FAILED (using failure container)\n" + //$NON-NLS-1$
2334
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2335
" container path: " + containerPath + '\n' + //$NON-NLS-1$
2336
" initializer: " + initializer); //$NON-NLS-1$
2337
}
2338
2339    private void verbose_triggering_container_initialization(IJavaProject project, IPath containerPath, ClasspathContainerInitializer initializer) {
2340        Util.verbose(
2341            "CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
2342
" project: " + project.getElementName() + '\n' + //$NON-NLS-1$
2343
" container path: " + containerPath + '\n' + //$NON-NLS-1$
2344
" initializer: " + initializer); //$NON-NLS-1$
2345
}
2346    
2347    private void verbose_triggering_container_initialization_invocation_trace() {
2348        Util.verbose(
2349            "CPContainer INIT - triggering initialization\n" + //$NON-NLS-1$
2350
" invocation trace:"); //$NON-NLS-1$
2351
new Exception JavaDoc("<Fake exception>").printStackTrace(System.out); //$NON-NLS-1$
2352
}
2353
2354    /**
2355     * Initialize preferences lookups for JavaCore plugin.
2356     */

2357    public void initializePreferences() {
2358        
2359        // Create lookups
2360
preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope()).getNode(JavaCore.PLUGIN_ID);
2361        preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope()).getNode(JavaCore.PLUGIN_ID);
2362
2363        // Listen to instance preferences node removal from parent in order to refresh stored one
2364
IEclipsePreferences.INodeChangeListener listener = new IEclipsePreferences.INodeChangeListener() {
2365            public void added(IEclipsePreferences.NodeChangeEvent event) {
2366                // do nothing
2367
}
2368            public void removed(IEclipsePreferences.NodeChangeEvent event) {
2369                if (event.getChild() == preferencesLookup[PREF_INSTANCE]) {
2370                    preferencesLookup[PREF_INSTANCE] = ((IScopeContext) new InstanceScope()).getNode(JavaCore.PLUGIN_ID);
2371                    preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener());
2372                }
2373            }
2374        };
2375        ((IEclipsePreferences) preferencesLookup[PREF_INSTANCE].parent()).addNodeChangeListener(listener);
2376        preferencesLookup[PREF_INSTANCE].addPreferenceChangeListener(new EclipsePreferencesListener());
2377
2378        // Listen to default preferences node removal from parent in order to refresh stored one
2379
listener = new IEclipsePreferences.INodeChangeListener() {
2380            public void added(IEclipsePreferences.NodeChangeEvent event) {
2381                // do nothing
2382
}
2383            public void removed(IEclipsePreferences.NodeChangeEvent event) {
2384                if (event.getChild() == preferencesLookup[PREF_DEFAULT]) {
2385                    preferencesLookup[PREF_DEFAULT] = ((IScopeContext) new DefaultScope()).getNode(JavaCore.PLUGIN_ID);
2386                }
2387            }
2388        };
2389        ((IEclipsePreferences) preferencesLookup[PREF_DEFAULT].parent()).addNodeChangeListener(listener);
2390    }
2391
2392    public synchronized char[] intern(char[] array) {
2393        return this.charArraySymbols.add(array);
2394    }
2395    
2396    public synchronized String JavaDoc intern(String JavaDoc s) {
2397        // make sure to copy the string (so that it doesn't hold on the underlying char[] that might be much bigger than necessary)
2398
return (String JavaDoc) this.stringSymbols.add(new String JavaDoc(s));
2399        
2400        // Note1: String#intern() cannot be used as on some VMs this prevents the string from being garbage collected
2401
// Note 2: Instead of using a WeakHashset, one could use a WeakHashMap with the following implementation
2402
// This would costs more per entry (one Entry object and one WeakReference more))
2403

2404        /*
2405        WeakReference reference = (WeakReference) this.symbols.get(s);
2406        String existing;
2407        if (reference != null && (existing = (String) reference.get()) != null)
2408            return existing;
2409        this.symbols.put(s, new WeakReference(s));
2410        return s;
2411        */

2412    }
2413    
2414    private HashSet getClasspathBeingResolved() {
2415        HashSet result = (HashSet) this.classpathsBeingResolved.get();
2416        if (result == null) {
2417            result = new HashSet();
2418            this.classpathsBeingResolved.set(result);
2419        }
2420        return result;
2421    }
2422    
2423    public boolean isClasspathBeingResolved(IJavaProject project) {
2424        return getClasspathBeingResolved().contains(project);
2425    }
2426    
2427    /**
2428     * @deprecated
2429     */

2430    private boolean isDeprecatedOption(String JavaDoc optionName) {
2431        return JavaCore.COMPILER_PB_INVALID_IMPORT.equals(optionName)
2432                || JavaCore.COMPILER_PB_UNREACHABLE_CODE.equals(optionName);
2433    }
2434    
2435    public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) {
2436        if (classpathIsResolved) {
2437            getClasspathBeingResolved().add(project);
2438        } else {
2439            getClasspathBeingResolved().remove(project);
2440        }
2441    }
2442
2443    public void loadVariablesAndContainers() throws CoreException {
2444        // backward compatibility, consider persistent property
2445
QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "variables"); //$NON-NLS-1$
2446
String JavaDoc xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
2447        
2448        try {
2449            if (xmlString != null){
2450                StringReader reader = new StringReader(xmlString);
2451                Element JavaDoc cpElement;
2452                try {
2453                    DocumentBuilder JavaDoc parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
2454                    cpElement = parser.parse(new InputSource JavaDoc(reader)).getDocumentElement();
2455                } catch(SAXException JavaDoc e) {
2456                    return;
2457                } catch(ParserConfigurationException JavaDoc e){
2458                    return;
2459                } finally {
2460                    reader.close();
2461                }
2462                if (cpElement == null) return;
2463                if (!cpElement.getNodeName().equalsIgnoreCase("variables")) { //$NON-NLS-1$
2464
return;
2465                }
2466                
2467                NodeList JavaDoc list= cpElement.getChildNodes();
2468                int length= list.getLength();
2469                for (int i= 0; i < length; ++i) {
2470                    Node JavaDoc node= list.item(i);
2471                    short type= node.getNodeType();
2472                    if (type == Node.ELEMENT_NODE) {
2473                        Element JavaDoc element= (Element JavaDoc) node;
2474                        if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$
2475
variablePut(
2476                                element.getAttribute("name"), //$NON-NLS-1$
2477
new Path(element.getAttribute("path"))); //$NON-NLS-1$
2478
}
2479                    }
2480                }
2481            }
2482        } catch(IOException e){
2483            // problem loading xml file: nothing we can do
2484
} finally {
2485            if (xmlString != null){
2486                ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, null); // flush old one
2487
}
2488        }
2489
2490        // backward compatibility, load variables and containers from preferences into cache
2491
loadVariablesAndContainers(getDefaultPreferences());
2492        loadVariablesAndContainers(getInstancePreferences());
2493
2494        // load variables and containers from saved file into cache
2495
File JavaDoc file = getVariableAndContainersFile();
2496        DataInputStream in = null;
2497        try {
2498            in = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
2499            switch (in.readInt()) {
2500                case 2 :
2501                    new VariablesAndContainersLoadHelper(in).load();
2502                    break;
2503                case 1 : // backward compatibility, load old format
2504
// variables
2505
int size = in.readInt();
2506                    while (size-- > 0) {
2507                        String JavaDoc varName = in.readUTF();
2508                        String JavaDoc pathString = in.readUTF();
2509                        if (CP_ENTRY_IGNORE.equals(pathString))
2510                            continue;
2511                        IPath varPath = Path.fromPortableString(pathString);
2512                        this.variables.put(varName, varPath);
2513                        this.previousSessionVariables.put(varName, varPath);
2514                    }
2515                    
2516                    // containers
2517
IJavaModel model = getJavaModel();
2518                    int projectSize = in.readInt();
2519                    while (projectSize-- > 0) {
2520                        String JavaDoc projectName = in.readUTF();
2521                        IJavaProject project = model.getJavaProject(projectName);
2522                        int containerSize = in.readInt();
2523                        while (containerSize-- > 0) {
2524                            IPath containerPath = Path.fromPortableString(in.readUTF());
2525                            int length = in.readInt();
2526                            byte[] containerString = new byte[length];
2527                            in.readFully(containerString);
2528                            recreatePersistedContainer(project, containerPath, new String JavaDoc(containerString), true/*add to container values*/);
2529                        }
2530                    }
2531                    break;
2532            }
2533        } catch (IOException e) {
2534            if (file.exists())
2535                Util.log(e, "Unable to read variable and containers file"); //$NON-NLS-1$
2536
} catch (RuntimeException JavaDoc e) {
2537            if (file.exists())
2538                Util.log(e, "Unable to read variable and containers file (file is corrupt)"); //$NON-NLS-1$
2539
} finally {
2540            if (in != null) {
2541                try {
2542                    in.close();
2543                } catch (IOException e) {
2544                    // nothing we can do: ignore
2545
}
2546            }
2547        }
2548
2549        // override persisted values for variables which have a registered initializer
2550
String JavaDoc[] registeredVariables = getRegisteredVariableNames();
2551        for (int i = 0; i < registeredVariables.length; i++) {
2552            String JavaDoc varName = registeredVariables[i];
2553            this.variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
2554
}
2555        // override persisted values for containers which have a registered initializer
2556
containersReset(getRegisteredContainerIDs());
2557    }
2558
2559    private void loadVariablesAndContainers(IEclipsePreferences preferences) {
2560        try {
2561            // only get variable from preferences not set to their default
2562
String JavaDoc[] propertyNames = preferences.keys();
2563            int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
2564            for (int i = 0; i < propertyNames.length; i++){
2565                String JavaDoc propertyName = propertyNames[i];
2566                if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){
2567                    String JavaDoc varName = propertyName.substring(variablePrefixLength);
2568                    String JavaDoc propertyValue = preferences.get(propertyName, null);
2569                    if (propertyValue != null) {
2570                        String JavaDoc pathString = propertyValue.trim();
2571                        
2572                        if (CP_ENTRY_IGNORE.equals(pathString)) {
2573                            // cleanup old preferences
2574
preferences.remove(propertyName);
2575                            continue;
2576                        }
2577                        
2578                        // add variable to table
2579
IPath varPath = new Path(pathString);
2580                        this.variables.put(varName, varPath);
2581                        this.previousSessionVariables.put(varName, varPath);
2582                    }
2583                } else if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
2584                    String JavaDoc propertyValue = preferences.get(propertyName, null);
2585                    if (propertyValue != null) {
2586                        // cleanup old preferences
2587
preferences.remove(propertyName);
2588                        
2589                        // recreate container
2590
recreatePersistedContainer(propertyName, propertyValue, true/*add to container values*/);
2591                    }
2592                }
2593            }
2594        } catch (BackingStoreException e1) {
2595            // TODO (frederic) see if it's necessary to report this failure...
2596
}
2597    }
2598
2599    private static final class PersistedClasspathContainer implements
2600            IClasspathContainer {
2601
2602        private final IPath containerPath;
2603
2604        private final IClasspathEntry[] entries;
2605
2606        private final IJavaProject project;
2607
2608        PersistedClasspathContainer(IJavaProject project, IPath containerPath,
2609                IClasspathEntry[] entries) {
2610            super();
2611            this.containerPath = containerPath;
2612            this.entries = entries;
2613            this.project = project;
2614        }
2615
2616        public IClasspathEntry[] getClasspathEntries() {
2617            return entries;
2618        }
2619
2620        public String JavaDoc getDescription() {
2621            return "Persisted container [" + containerPath //$NON-NLS-1$
2622
+ " for project [" + project.getElementName() //$NON-NLS-1$
2623
+ "]]"; //$NON-NLS-1$
2624
}
2625
2626        public int getKind() {
2627            return 0;
2628        }
2629
2630        public IPath getPath() {
2631            return containerPath;
2632        }
2633
2634        public String JavaDoc toString() {
2635            return getDescription();
2636        }
2637    }
2638
2639    private final class VariablesAndContainersLoadHelper {
2640
2641        private static final int ARRAY_INCREMENT = 200;
2642
2643        private IClasspathEntry[] allClasspathEntries;
2644        private int allClasspathEntryCount;
2645
2646        private final Map allPaths; // String -> IPath
2647

2648        private String JavaDoc[] allStrings;
2649        private int allStringsCount;
2650
2651        private final DataInputStream in;
2652
2653        VariablesAndContainersLoadHelper(DataInputStream in) {
2654            super();
2655            this.allClasspathEntries = null;
2656            this.allClasspathEntryCount = 0;
2657            this.allPaths = new HashMap();
2658            this.allStrings = null;
2659            this.allStringsCount = 0;
2660            this.in = in;
2661        }
2662
2663        void load() throws IOException {
2664            loadProjects(JavaModelManager.this.getJavaModel());
2665            loadVariables();
2666        }
2667
2668        private IAccessRule loadAccessRule() throws IOException {
2669            int problemId = loadInt();
2670            IPath pattern = loadPath();
2671            return new ClasspathAccessRule(pattern.toString().toCharArray(), problemId);
2672        }
2673
2674        private IAccessRule[] loadAccessRules() throws IOException {
2675            int count = loadInt();
2676
2677            if (count == 0)
2678                return ClasspathEntry.NO_ACCESS_RULES;
2679
2680            IAccessRule[] rules = new IAccessRule[count];
2681
2682            for (int i = 0; i < count; ++i)
2683                rules[i] = loadAccessRule();
2684
2685            return rules;
2686        }
2687
2688        private IClasspathAttribute loadAttribute() throws IOException {
2689            String JavaDoc name = loadString();
2690            String JavaDoc value = loadString();
2691
2692            return new ClasspathAttribute(name, value);
2693        }
2694
2695        private IClasspathAttribute[] loadAttributes() throws IOException {
2696            int count = loadInt();
2697
2698            if (count == 0)
2699                return ClasspathEntry.NO_EXTRA_ATTRIBUTES;
2700
2701            IClasspathAttribute[] attributes = new IClasspathAttribute[count];
2702
2703            for (int i = 0; i < count; ++i)
2704                attributes[i] = loadAttribute();
2705
2706            return attributes;
2707        }
2708
2709        private boolean loadBoolean() throws IOException {
2710            return this.in.readBoolean();
2711        }
2712
2713        private IClasspathEntry[] loadClasspathEntries() throws IOException {
2714            int count = loadInt();
2715            IClasspathEntry[] entries = new IClasspathEntry[count];
2716
2717            for (int i = 0; i < count; ++i)
2718                entries[i] = loadClasspathEntry();
2719
2720            return entries;
2721        }
2722
2723        private IClasspathEntry loadClasspathEntry() throws IOException {
2724            int id = loadInt();
2725
2726            if (id < 0 || id > this.allClasspathEntryCount)
2727                throw new IOException("Unexpected classpathentry id"); //$NON-NLS-1$
2728

2729            if (id < this.allClasspathEntryCount)
2730                return this.allClasspathEntries[id];
2731
2732            int contentKind = loadInt();
2733            int entryKind = loadInt();
2734            IPath path = loadPath();
2735            IPath[] inclusionPatterns = loadPaths();
2736            IPath[] exclusionPatterns = loadPaths();
2737            IPath sourceAttachmentPath = loadPath();
2738            IPath sourceAttachmentRootPath = loadPath();
2739            IPath specificOutputLocation = loadPath();
2740            boolean isExported = loadBoolean();
2741            IAccessRule[] accessRules = loadAccessRules();
2742            boolean combineAccessRules = loadBoolean();
2743            IClasspathAttribute[] extraAttributes = loadAttributes();
2744
2745            IClasspathEntry entry = new ClasspathEntry(contentKind, entryKind,
2746                    path, inclusionPatterns, exclusionPatterns,
2747                    sourceAttachmentPath, sourceAttachmentRootPath,
2748                    specificOutputLocation, isExported, accessRules,
2749                    combineAccessRules, extraAttributes);
2750
2751            IClasspathEntry[] array = this.allClasspathEntries;
2752
2753            if (array == null || id == array.length) {
2754                array = new IClasspathEntry[id + ARRAY_INCREMENT];
2755
2756                if (id != 0)
2757                    System.arraycopy(this.allClasspathEntries, 0, array, 0, id);
2758
2759                this.allClasspathEntries = array;
2760            }
2761
2762            array[id] = entry;
2763            this.allClasspathEntryCount = id + 1;
2764
2765            return entry;
2766        }
2767
2768        private void loadContainers(IJavaProject project) throws IOException {
2769            boolean projectIsAccessible = project.getProject().isAccessible();
2770            int count = loadInt();
2771            for (int i = 0; i < count; ++i) {
2772                IPath path = loadPath();
2773                IClasspathEntry[] entries = loadClasspathEntries();
2774                
2775                if (!projectIsAccessible)
2776                    // avoid leaking deleted project's persisted container,
2777
// but still read the container as it is is part of the file format
2778
continue;
2779
2780                IClasspathContainer container = new PersistedClasspathContainer(project, path, entries);
2781
2782                JavaModelManager.this.containerPut(project, path, container);
2783
2784                Map oldContainers = (Map) JavaModelManager.this.previousSessionContainers.get(project);
2785
2786                if (oldContainers == null) {
2787                    oldContainers = new HashMap();
2788                    JavaModelManager.this.previousSessionContainers.put(project, oldContainers);
2789                }
2790
2791                oldContainers.put(path, container);
2792            }
2793        }
2794
2795        private int loadInt() throws IOException {
2796            return this.in.readInt();
2797        }
2798
2799        private IPath loadPath() throws IOException {
2800            if (loadBoolean())
2801                return null;
2802
2803            String JavaDoc portableString = loadString();
2804            IPath path = (IPath) this.allPaths.get(portableString);
2805
2806            if (path == null) {
2807                path = Path.fromPortableString(portableString);
2808                this.allPaths.put(portableString, path);
2809            }
2810
2811            return path;
2812        }
2813
2814        private IPath[] loadPaths() throws IOException {
2815            int count = loadInt();
2816            IPath[] pathArray = new IPath[count];
2817
2818            for (int i = 0; i < count; ++i)
2819                pathArray[i] = loadPath();
2820
2821            return pathArray;
2822        }
2823
2824        private void loadProjects(IJavaModel model) throws IOException {
2825            int count = loadInt();
2826
2827            for (int i = 0; i < count; ++i) {
2828                String JavaDoc projectName = loadString();
2829
2830                loadContainers(model.getJavaProject(projectName));
2831            }
2832        }
2833
2834        private String JavaDoc loadString() throws IOException {
2835            int id = loadInt();
2836
2837            if (id < 0 || id > this.allStringsCount)
2838                throw new IOException("Unexpected string id"); //$NON-NLS-1$
2839

2840            if (id < this.allStringsCount)
2841                return this.allStrings[id];
2842
2843            String JavaDoc string = this.in.readUTF();
2844            String JavaDoc[] array = this.allStrings;
2845
2846            if (array == null || id == array.length) {
2847                array = new String JavaDoc[id + ARRAY_INCREMENT];
2848
2849                if (id != 0)
2850                    System.arraycopy(this.allStrings, 0, array, 0, id);
2851
2852                this.allStrings = array;
2853            }
2854
2855            array[id] = string;
2856            this.allStringsCount = id + 1;
2857
2858            return string;
2859        }
2860
2861        private void loadVariables() throws IOException {
2862            int size = loadInt();
2863            Map loadedVars = new HashMap(size);
2864
2865            for (int i = 0; i < size; ++i) {
2866                String JavaDoc varName = loadString();
2867                IPath varPath = loadPath();
2868
2869                if (varPath != null)
2870                    loadedVars.put(varName, varPath);
2871            }
2872
2873            JavaModelManager.this.previousSessionVariables.putAll(loadedVars);
2874            JavaModelManager.this.variables.putAll(loadedVars);
2875        }
2876    }
2877
2878    /**
2879     * Returns the info for this element without
2880     * disturbing the cache ordering.
2881     */

2882    protected synchronized Object JavaDoc peekAtInfo(IJavaElement element) {
2883        HashMap tempCache = (HashMap)this.temporaryCache.get();
2884        if (tempCache != null) {
2885            Object JavaDoc result = tempCache.get(element);
2886            if (result != null) {
2887                return result;
2888            }
2889        }
2890        return this.cache.peekAtInfo(element);
2891    }
2892
2893    /**
2894     * @see ISaveParticipant
2895     */

2896    public void prepareToSave(ISaveContext context) /*throws CoreException*/ {
2897        // nothing to do
2898
}
2899    /*
2900     * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos)
2901     * in the Java model cache in an atomic way.
2902     * First checks that the info for the opened element (or one of its ancestors) has not been
2903     * added to the cache. If it is the case, another thread has opened the element (or one of
2904     * its ancestors). So returns without updating the cache.
2905     */

2906    protected synchronized void putInfos(IJavaElement openedElement, Map newElements) {
2907        // remove children
2908
Object JavaDoc existingInfo = this.cache.peekAtInfo(openedElement);
2909        if (openedElement instanceof IParent && existingInfo instanceof JavaElementInfo) {
2910            IJavaElement[] children = ((JavaElementInfo)existingInfo).getChildren();
2911            for (int i = 0, size = children.length; i < size; ++i) {
2912                JavaElement child = (JavaElement) children[i];
2913                try {
2914                    child.close();
2915                } catch (JavaModelException e) {
2916                    // ignore
2917
}
2918            }
2919        }
2920        
2921        // Need to put any JarPackageFragmentRoot in first.
2922
// This is due to the way the LRU cache flushes entries.
2923
// When a JarPackageFragment is flused from the LRU cache, the entire
2924
// jar is flushed by removing the JarPackageFragmentRoot and all of its
2925
// children (see ElementCache.close()). If we flush the JarPackageFragment
2926
// when its JarPackageFragmentRoot is not in the cache and the root is about to be
2927
// added (during the 'while' loop), we will end up in an inconsist state.
2928
// Subsequent resolution against package in the jar would fail as a result.
2929
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422
2930
// (theodora)
2931
for(Iterator it = newElements.entrySet().iterator(); it.hasNext(); ) {
2932            Map.Entry entry = (Map.Entry)it.next();
2933            IJavaElement element = (IJavaElement)entry.getKey();
2934            if( element instanceof JarPackageFragmentRoot ){
2935                Object JavaDoc info = entry.getValue();
2936                it.remove();
2937                this.cache.putInfo(element, info);
2938            }
2939        }
2940    
2941        Iterator iterator = newElements.entrySet().iterator();
2942        while (iterator.hasNext()) {
2943            Map.Entry entry = (Map.Entry) iterator.next();
2944            this.cache.putInfo((IJavaElement) entry.getKey(), entry.getValue());
2945        }
2946    }
2947    
2948    /*
2949     * Remember the info for the jar binary type
2950     */

2951    protected synchronized void putJarTypeInfo(IJavaElement type, Object JavaDoc info) {
2952        this.cache.jarTypeCache.put(type, info);
2953    }
2954
2955    /**
2956     * Reads the build state for the relevant project.
2957     */

2958    protected Object JavaDoc readState(IProject project) throws CoreException {
2959        File JavaDoc file = getSerializationFile(project);
2960        if (file != null && file.exists()) {
2961            try {
2962                DataInputStream in= new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
2963                try {
2964                    String JavaDoc pluginID= in.readUTF();
2965                    if (!pluginID.equals(JavaCore.PLUGIN_ID))
2966                        throw new IOException(Messages.build_wrongFileFormat);
2967                    String JavaDoc kind= in.readUTF();
2968                    if (!kind.equals("STATE")) //$NON-NLS-1$
2969
throw new IOException(Messages.build_wrongFileFormat);
2970                    if (in.readBoolean())
2971                        return JavaBuilder.readState(project, in);
2972                    if (JavaBuilder.DEBUG)
2973                        System.out.println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$
2974
} finally {
2975                    in.close();
2976                }
2977            } catch (Exception JavaDoc e) {
2978                e.printStackTrace();
2979                throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error reading last build state for project "+ project.getName(), e)); //$NON-NLS-1$
2980
}
2981        } else if (JavaBuilder.DEBUG) {
2982            if (file == null)
2983                System.out.println("Project does not exist: " + project); //$NON-NLS-1$
2984
else
2985                System.out.println("Build state file " + file.getPath() + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
2986
}
2987        return null;
2988    }
2989
2990    public static void recreatePersistedContainer(String JavaDoc propertyName, String JavaDoc containerString, boolean addToContainerValues) {
2991        int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length();
2992        int index = propertyName.indexOf('|', containerPrefixLength);
2993        if (containerString != null) containerString = containerString.trim();
2994        if (index > 0) {
2995            String JavaDoc projectName = propertyName.substring(containerPrefixLength, index).trim();
2996            IJavaProject project = getJavaModelManager().getJavaModel().getJavaProject(projectName);
2997            IPath containerPath = new Path(propertyName.substring(index+1).trim());
2998            recreatePersistedContainer(project, containerPath, containerString, addToContainerValues);
2999        }
3000    }
3001    
3002    private static void recreatePersistedContainer(final IJavaProject project, final IPath containerPath, String JavaDoc containerString, boolean addToContainerValues) {
3003        if (!project.getProject().isAccessible()) return; // avoid leaking deleted project's persisted container
3004
if (containerString == null) {
3005            getJavaModelManager().containerPut(project, containerPath, null);
3006        } else {
3007            IClasspathEntry[] entries;
3008            try {
3009                entries = ((JavaProject) project).decodeClasspath(containerString, null/*not interested in unknown elements*/);
3010            } catch (IOException e) {
3011                Util.log(e, "Could not recreate persisted container: \n" + containerString); //$NON-NLS-1$
3012
entries = JavaProject.INVALID_CLASSPATH;
3013            }
3014            if (entries != JavaProject.INVALID_CLASSPATH) {
3015                final IClasspathEntry[] containerEntries = entries;
3016                IClasspathContainer container = new IClasspathContainer() {
3017                    public IClasspathEntry[] getClasspathEntries() {
3018                        return containerEntries;
3019                    }
3020                    public String JavaDoc getDescription() {
3021                        return "Persisted container ["+containerPath+" for project ["+ project.getElementName()+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
3022
}
3023                    public int getKind() {
3024                        return 0;
3025                    }
3026                    public IPath getPath() {
3027                        return containerPath;
3028                    }
3029                    public String JavaDoc toString() {
3030                        return getDescription();
3031                    }
3032
3033                };
3034                if (addToContainerValues) {
3035                    getJavaModelManager().containerPut(project, containerPath, container);
3036                }
3037                Map projectContainers = (Map)getJavaModelManager().previousSessionContainers.get(project);
3038                if (projectContainers == null){
3039                    projectContainers = new HashMap(1);
3040                    getJavaModelManager().previousSessionContainers.put(project, projectContainers);
3041                }
3042                projectContainers.put(containerPath, container);
3043            }
3044        }
3045    }
3046    
3047    /**
3048     * Remembers the given scope in a weak set
3049     * (so no need to remove it: it will be removed by the garbage collector)
3050     */

3051    public void rememberScope(AbstractSearchScope scope) {
3052        // NB: The value has to be null so as to not create a strong reference on the scope
3053
this.searchScopes.put(scope, null);
3054    }
3055    
3056    /*
3057     * Removes all cached info for the given element (including all children)
3058     * from the cache.
3059     * Returns the info for the given element, or null if it was closed.
3060     */

3061    public synchronized Object JavaDoc removeInfoAndChildren(JavaElement element) throws JavaModelException {
3062        Object JavaDoc info = this.cache.peekAtInfo(element);
3063        if (info != null) {
3064            boolean wasVerbose = false;
3065            try {
3066                if (JavaModelCache.VERBOSE) {
3067                    String JavaDoc elementType;
3068                    switch (element.getElementType()) {
3069                        case IJavaElement.JAVA_PROJECT:
3070                            elementType = "project"; //$NON-NLS-1$
3071
break;
3072                        case IJavaElement.PACKAGE_FRAGMENT_ROOT:
3073                            elementType = "root"; //$NON-NLS-1$
3074
break;
3075                        case IJavaElement.PACKAGE_FRAGMENT:
3076                            elementType = "package"; //$NON-NLS-1$
3077
break;
3078                        case IJavaElement.CLASS_FILE:
3079                            elementType = "class file"; //$NON-NLS-1$
3080
break;
3081                        case IJavaElement.COMPILATION_UNIT:
3082                            elementType = "compilation unit"; //$NON-NLS-1$
3083
break;
3084                        default:
3085                            elementType = "element"; //$NON-NLS-1$
3086
}
3087                    System.out.println(Thread.currentThread() + " CLOSING "+ elementType + " " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
3088
wasVerbose = true;
3089                    JavaModelCache.VERBOSE = false;
3090                }
3091                element.closing(info);
3092                if (element instanceof IParent && info instanceof JavaElementInfo) {
3093                    IJavaElement[] children = ((JavaElementInfo)info).getChildren();
3094                    for (int i = 0, size = children.length; i < size; ++i) {
3095                        JavaElement child = (JavaElement) children[i];
3096                        child.close();
3097                    }
3098                }
3099                this.cache.removeInfo(element);
3100                if (wasVerbose) {
3101                    System.out.println(this.cache.toStringFillingRation("-> ")); //$NON-NLS-1$
3102
}
3103            } finally {
3104                JavaModelCache.VERBOSE = wasVerbose;
3105            }
3106            return info;
3107        }
3108        return null;
3109    }
3110
3111    public void removePerProjectInfo(JavaProject javaProject) {
3112        synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock
3113
IProject project = javaProject.getProject();
3114            PerProjectInfo info= (PerProjectInfo) this.perProjectInfos.get(project);
3115            if (info != null) {
3116                this.perProjectInfos.remove(project);
3117            }
3118        }
3119    }
3120
3121    /*
3122     * Reset project options stored in info cache.
3123     */

3124    public void resetProjectOptions(JavaProject javaProject) {
3125        synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock
3126
IProject project = javaProject.getProject();
3127            PerProjectInfo info= (PerProjectInfo) this.perProjectInfos.get(project);
3128            if (info != null) {
3129                info.options = null;
3130            }
3131        }
3132    }
3133
3134    /*
3135     * Reset project preferences stored in info cache.
3136     */

3137    public void resetProjectPreferences(JavaProject javaProject) {
3138        synchronized(this.perProjectInfos) { // use the perProjectInfo collection as its own lock
3139
IProject project = javaProject.getProject();
3140            PerProjectInfo info= (PerProjectInfo) this.perProjectInfos.get(project);
3141            if (info != null) {
3142                info.preferences = null;
3143            }
3144        }
3145    }
3146    
3147    public static final void doNotUse() {
3148        // used by tests to simulate a startup
3149
MANAGER = new JavaModelManager();
3150    }
3151    
3152    /*
3153     * Resets the cache that holds on binary type in jar files
3154     */

3155    protected synchronized void resetJarTypeCache() {
3156        this.cache.resetJarTypeCache();
3157    }
3158
3159    /*
3160     * Resets the temporary cache for newly created elements to null.
3161     */

3162    public void resetTemporaryCache() {
3163        this.temporaryCache.set(null);
3164    }
3165
3166    /**
3167     * @see ISaveParticipant
3168     */

3169    public void rollback(ISaveContext context){
3170        // nothing to do
3171
}
3172
3173    private void saveState(PerProjectInfo info, ISaveContext context) throws CoreException {
3174
3175        // passed this point, save actions are non trivial
3176
if (context.getKind() == ISaveContext.SNAPSHOT) return;
3177        
3178        // save built state
3179
if (info.triedRead) saveBuiltState(info);
3180    }
3181    
3182    /**
3183     * Saves the built state for the project.
3184     */

3185    private void saveBuiltState(PerProjectInfo info) throws CoreException {
3186        if (JavaBuilder.DEBUG)
3187            System.out.println(Messages.bind(Messages.build_saveStateProgress, info.project.getName()));
3188        File JavaDoc file = getSerializationFile(info.project);
3189        if (file == null) return;
3190        long t = System.currentTimeMillis();
3191        try {
3192            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
3193            try {
3194                out.writeUTF(JavaCore.PLUGIN_ID);
3195                out.writeUTF("STATE"); //$NON-NLS-1$
3196
if (info.savedState == null) {
3197                    out.writeBoolean(false);
3198                } else {
3199                    out.writeBoolean(true);
3200                    JavaBuilder.writeState(info.savedState, out);
3201                }
3202            } finally {
3203                out.close();
3204            }
3205        } catch (RuntimeException JavaDoc e) {
3206            try {
3207                file.delete();
3208            } catch(SecurityException JavaDoc se) {
3209                // could not delete file: cannot do much more
3210
}
3211            throw new CoreException(
3212                new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR,
3213                    Messages.bind(Messages.build_cannotSaveState, info.project.getName()), e));
3214        } catch (IOException e) {
3215            try {
3216                file.delete();
3217            } catch(SecurityException JavaDoc se) {
3218                // could not delete file: cannot do much more
3219
}
3220            throw new CoreException(
3221                new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR,
3222                    Messages.bind(Messages.build_cannotSaveState, info.project.getName()), e));
3223        }
3224        if (JavaBuilder.DEBUG) {
3225            t = System.currentTimeMillis() - t;
3226            System.out.println(Messages.bind(Messages.build_saveStateComplete, String.valueOf(t)));
3227        }
3228    }
3229    
3230    private void saveVariablesAndContainers(ISaveContext context) throws CoreException {
3231        File JavaDoc file = getVariableAndContainersFile();
3232        DataOutputStream out = null;
3233        try {
3234            out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
3235            out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION);
3236            if (VARIABLES_AND_CONTAINERS_FILE_VERSION != 1)
3237                new VariablesAndContainersSaveHelper(out).save(context);
3238            else {
3239                // old code retained for performance comparisons
3240

3241                // variables
3242
out.writeInt(this.variables.size());
3243                Iterator iterator = this.variables.entrySet().iterator();
3244                while (iterator.hasNext()) {
3245                    Map.Entry entry = (Map.Entry) iterator.next();
3246                    String JavaDoc variableName = (String JavaDoc) entry.getKey();
3247                    out.writeUTF(variableName);
3248                    IPath path = (IPath) entry.getValue();
3249                    out.writeUTF(path == null ? CP_ENTRY_IGNORE : path.toPortableString());
3250                }
3251                
3252                // containers
3253
IJavaProject[] projects = getJavaModel().getJavaProjects();
3254                int length = projects.length;
3255                out.writeInt(length);
3256                for (int i = 0; i < length; i++) {
3257                    IJavaProject project = projects[i];
3258                    // clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
3259
Map projectContainers = containerClone(project);
3260                    out.writeUTF(project.getElementName());
3261                    if (projectContainers == null) {
3262                        out.writeInt(0);
3263                        continue;
3264                    }
3265                    HashMap containersToSave = new HashMap();
3266                    for (iterator = projectContainers.entrySet().iterator(); iterator.hasNext();) {
3267                        Map.Entry entry = (Map.Entry) iterator.next();
3268                        IPath containerPath = (IPath) entry.getKey();
3269                        IClasspathContainer container = (IClasspathContainer) entry.getValue();
3270                        String JavaDoc containerString = null;
3271                        try {
3272                            if (container == null) {
3273                                // container has not been initialized yet, use previous session value
3274
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
3275
container = getPreviousSessionContainer(containerPath, project);
3276                            }
3277                            if (container != null) {
3278                                IClasspathEntry[] entries = container.getClasspathEntries();
3279                                containerString = ((JavaProject)project).encodeClasspath(
3280                                        entries,
3281                                        null,
3282                                        false,
3283                                        null/*not interested in unknown elements*/);
3284                            }
3285                        } catch(JavaModelException e){
3286                            // could not encode entry: will not persist
3287
Util.log(e, "Could not persist container " + containerPath + " for project " + project.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
3288
}
3289                        if (containerString != null)
3290                            containersToSave.put(containerPath, containerString);
3291                    }
3292                    out.writeInt(containersToSave.size());
3293                    iterator = containersToSave.entrySet().iterator();
3294                    while (iterator.hasNext()) {
3295                        Map.Entry entry = (Map.Entry) iterator.next();
3296                        IPath containerPath = (IPath) entry.getKey();
3297                        out.writeUTF(containerPath.toPortableString());
3298                        String JavaDoc containerString = (String JavaDoc) entry.getValue();
3299                        out.writeInt(containerString.length());
3300                        out.writeBytes(containerString);
3301                    }
3302                }
3303            }
3304        } catch (IOException e) {
3305            IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving variables and containers", e); //$NON-NLS-1$
3306
throw new CoreException(status);
3307        } finally {
3308            if (out != null) {
3309                try {
3310                    out.close();
3311                } catch (IOException e) {
3312                    // nothing we can do: ignore
3313
}
3314            }
3315        }
3316    }
3317    
3318    private final class VariablesAndContainersSaveHelper {
3319
3320        private final HashtableOfObjectToInt classpathEntryIds; // IClasspathEntry -> int
3321
private final DataOutputStream out;
3322        private final HashtableOfObjectToInt stringIds; // Strings -> int
3323

3324        VariablesAndContainersSaveHelper(DataOutputStream out) {
3325            super();
3326            this.classpathEntryIds = new HashtableOfObjectToInt();
3327            this.out = out;
3328            this.stringIds = new HashtableOfObjectToInt();
3329        }
3330
3331        void save(ISaveContext context) throws IOException, JavaModelException {
3332            IProject project = context.getProject();
3333            if (project == null) { // save all projects if none specified (snapshot or full save)
3334
saveProjects(JavaModelManager.this.getJavaModel().getJavaProjects());
3335            }
3336            else {
3337                saveProjects(new IJavaProject[] {JavaCore.create(project)});
3338            }
3339            
3340            switch (context.getKind()) {
3341                case ISaveContext.FULL_SAVE :
3342                    // TODO (eric) - investigate after 3.3 if variables should be saved for a SNAPSHOT
3343
case ISaveContext.SNAPSHOT :
3344                    // remove variables that should not be saved
3345
HashMap varsToSave = null;
3346                    Iterator iterator = JavaModelManager.this.variables.entrySet().iterator();
3347                    IEclipsePreferences defaultPreferences = getDefaultPreferences();
3348                    while (iterator.hasNext()) {
3349                        Map.Entry entry = (Map.Entry) iterator.next();
3350                        String JavaDoc varName = (String JavaDoc) entry.getKey();
3351                        if (defaultPreferences.get(CP_VARIABLE_PREFERENCES_PREFIX + varName, null) != null // don't save classpath variables from the default preferences as there is no delta if they are removed
3352
|| CP_ENTRY_IGNORE_PATH.equals(entry.getValue())) {
3353                        
3354                            if (varsToSave == null)
3355                                varsToSave = new HashMap(JavaModelManager.this.variables);
3356                            varsToSave.remove(varName);
3357                        }
3358                    }
3359                    saveVariables(varsToSave != null ? varsToSave : JavaModelManager.this.variables);
3360                    break;
3361                default :
3362                    // do nothing
3363
}
3364        }
3365
3366        private void saveAccessRule(ClasspathAccessRule rule) throws IOException {
3367            saveInt(rule.problemId);
3368            savePath(rule.getPattern());
3369        }
3370
3371        private void saveAccessRules(IAccessRule[] rules) throws IOException {
3372            int count = rules == null ? 0 : rules.length;
3373
3374            saveInt(count);
3375            for (int i = 0; i < count; ++i)
3376                saveAccessRule((ClasspathAccessRule) rules[i]);
3377        }
3378
3379        private void saveAttribute(IClasspathAttribute attribute)
3380                throws IOException {
3381            saveString(attribute.getName());
3382            saveString(attribute.getValue());
3383        }
3384
3385        private void saveAttributes(IClasspathAttribute[] attributes)
3386                throws IOException {
3387            int count = attributes == null ? 0 : attributes.length;
3388
3389            saveInt(count);
3390            for (int i = 0; i < count; ++i)
3391                saveAttribute(attributes[i]);
3392        }
3393
3394        private void saveClasspathEntries(IClasspathEntry[] entries)
3395                throws IOException {
3396            int count = entries == null ? 0 : entries.length;
3397
3398            saveInt(count);
3399            for (int i = 0; i < count; ++i)
3400                saveClasspathEntry(entries[i]);
3401        }
3402
3403        private void saveClasspathEntry(IClasspathEntry entry)
3404                throws IOException {
3405            if (saveNewId(entry, this.classpathEntryIds)) {
3406                saveInt(entry.getContentKind());
3407                saveInt(entry.getEntryKind());
3408                savePath(entry.getPath());
3409                savePaths(entry.getInclusionPatterns());
3410                savePaths(entry.getExclusionPatterns());
3411                savePath(entry.getSourceAttachmentPath());
3412                savePath(entry.getSourceAttachmentRootPath());
3413                savePath(entry.getOutputLocation());
3414                this.out.writeBoolean(entry.isExported());
3415                saveAccessRules(entry.getAccessRules());
3416                this.out.writeBoolean(entry.combineAccessRules());
3417                saveAttributes(entry.getExtraAttributes());
3418            }
3419        }
3420
3421        private void saveContainers(IJavaProject project, Map containerMap)
3422                throws IOException {
3423            saveInt(containerMap.size());
3424
3425            for (Iterator i = containerMap.entrySet().iterator(); i.hasNext();) {
3426                Entry entry = (Entry) i.next();
3427                IPath path = (IPath) entry.getKey();
3428                IClasspathContainer container = (IClasspathContainer) entry.getValue();
3429                IClasspathEntry[] cpEntries = null;
3430
3431                if (container == null) {
3432                    // container has not been initialized yet, use previous
3433
// session value
3434
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969)
3435
container = JavaModelManager.this.getPreviousSessionContainer(path, project);
3436                }
3437
3438                if (container != null)
3439                    cpEntries = container.getClasspathEntries();
3440
3441                savePath(path);
3442                saveClasspathEntries(cpEntries);
3443            }
3444        }
3445
3446        private void saveInt(int value) throws IOException {
3447            this.out.writeInt(value);
3448        }
3449
3450        private boolean saveNewId(Object JavaDoc key, HashtableOfObjectToInt map) throws IOException {
3451            int id = map.get(key);
3452
3453            if (id == -1) {
3454                int newId = map.size();
3455
3456                map.put(key, newId);
3457
3458                saveInt(newId);
3459
3460                return true;
3461            } else {
3462                saveInt(id);
3463
3464                return false;
3465            }
3466        }
3467
3468        private void savePath(IPath path) throws IOException {
3469            if (path == null) {
3470                this.out.writeBoolean(true);
3471            } else {
3472                this.out.writeBoolean(false);
3473                saveString(path.toPortableString());
3474            }
3475        }
3476
3477        private void savePaths(IPath[] paths) throws IOException {
3478            int count = paths == null ? 0 : paths.length;
3479
3480            saveInt(count);
3481            for (int i = 0; i < count; ++i)
3482                savePath(paths[i]);
3483        }
3484
3485        private void saveProjects(IJavaProject[] projects) throws IOException,
3486                JavaModelException {
3487            int count = projects.length;
3488
3489            saveInt(count);
3490
3491            for (int i = 0; i < count; ++i) {
3492                IJavaProject project = projects[i];
3493
3494                saveString(project.getElementName());
3495
3496                Map containerMap = (Map) JavaModelManager.this.containers.get(project);
3497
3498                if (containerMap == null) {
3499                    containerMap = Collections.EMPTY_MAP;
3500                } else {
3501                    // clone while iterating
3502
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
3503
containerMap = new HashMap(containerMap);
3504                }
3505
3506                saveContainers(project, containerMap);
3507            }
3508        }
3509
3510        private void saveString(String JavaDoc string) throws IOException {
3511            if (saveNewId(string, this.stringIds))
3512                this.out.writeUTF(string);
3513        }
3514
3515        private void saveVariables(Map map) throws IOException {
3516            saveInt(map.size());
3517
3518            for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
3519                Entry entry = (Entry) i.next();
3520                String JavaDoc varName = (String JavaDoc) entry.getKey();
3521                IPath varPath = (IPath) entry.getValue();
3522
3523                saveString(varName);
3524                savePath(varPath);
3525            }
3526        }
3527    }
3528
3529    private void traceVariableAndContainers(String JavaDoc action, long start) {
3530
3531        Long JavaDoc delta = new Long JavaDoc(System.currentTimeMillis() - start);
3532        Long JavaDoc length = new Long JavaDoc(getVariableAndContainersFile().length());
3533        String JavaDoc pattern = "{0} {1} bytes in variablesAndContainers.dat in {2}ms"; //$NON-NLS-1$
3534
String JavaDoc message = MessageFormat.format(pattern, new Object JavaDoc[]{action, length, delta});
3535
3536        System.out.println(message);
3537    }
3538
3539    /**
3540     * @see ISaveParticipant
3541     */

3542    public void saving(ISaveContext context) throws CoreException {
3543        
3544        long start = -1;
3545        if (VERBOSE)
3546            start = System.currentTimeMillis();
3547
3548        // save variable and container values on snapshot/full save
3549
saveVariablesAndContainers(context);
3550
3551        if (VERBOSE)
3552            traceVariableAndContainers("Saved", start); //$NON-NLS-1$
3553

3554        if (context.getKind() == ISaveContext.FULL_SAVE) {
3555            // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
3556
context.needDelta();
3557            
3558            // clean up indexes on workspace full save
3559
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
3560
IndexManager manager = this.indexManager;
3561            if (manager != null
3562                    // don't force initialization of workspace scope as we could be shutting down
3563
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93941)
3564
&& this.workspaceScope != null) {
3565                manager.cleanUpIndexes();
3566            }
3567        }
3568    
3569        IProject savedProject = context.getProject();
3570        if (savedProject != null) {
3571            if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
3572
PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
3573            saveState(info, context);
3574            info.rememberExternalLibTimestamps();
3575            return;
3576        }
3577    
3578        ArrayList vStats= null; // lazy initialized
3579
ArrayList values = null;
3580        synchronized(this.perProjectInfos) {
3581            values = new ArrayList(this.perProjectInfos.values());
3582        }
3583        Iterator iterator = values.iterator();
3584        while (iterator.hasNext()) {
3585            try {
3586                PerProjectInfo info = (PerProjectInfo) iterator.next();
3587                saveState(info, context);
3588                info.rememberExternalLibTimestamps();
3589            } catch (CoreException e) {
3590                if (vStats == null)
3591                    vStats= new ArrayList();
3592                vStats.add(e.getStatus());
3593            }
3594        }
3595        if (vStats != null) {
3596            IStatus[] stats= new IStatus[vStats.size()];
3597            vStats.toArray(stats);
3598            throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Messages.build_cannotSaveStates, null));
3599        }
3600        
3601        // save external libs timestamps
3602
this.deltaState.saveExternalLibTimeStamps();
3603    }
3604
3605    /**
3606     * Add a secondary type in temporary indexing cache for a project got from given path.
3607     *
3608     * Current secondary types cache is not modified as we want to wait that indexing
3609     * was finished before taking new secondary types into account.
3610     *
3611     * Indexing cache is a specific entry in secondary types cache which key is
3612     * {@link #INDEXED_SECONDARY_TYPES } and value a map with same structure than
3613     * secondary types cache itself.
3614     *
3615     * @see #secondaryTypes(IJavaProject, boolean, IProgressMonitor)
3616     */

3617    public void secondaryTypeAdding(String JavaDoc path, char[] typeName, char[] packageName) {
3618        if (VERBOSE) {
3619            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("JavaModelManager.addSecondaryType("); //$NON-NLS-1$
3620
buffer.append(path);
3621            buffer.append(',');
3622            buffer.append('[');
3623            buffer.append(new String JavaDoc(packageName));
3624            buffer.append('.');
3625            buffer.append(new String JavaDoc(typeName));
3626            buffer.append(']');
3627            buffer.append(')');
3628            Util.verbose(buffer.toString());
3629        }
3630        IWorkspaceRoot wRoot = ResourcesPlugin.getWorkspace().getRoot();
3631        IResource resource = wRoot.findMember(path);
3632        if (resource != null) {
3633            if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path) && resource.getType() == IResource.FILE) {
3634                IProject project = resource.getProject();
3635                try {
3636                    PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project);
3637                    // Get or create map to cache secondary types while indexing (can be not synchronized as indexing insure a non-concurrent usage)
3638
HashMap indexedSecondaryTypes = null;
3639                    if (projectInfo.secondaryTypes == null) {
3640                        projectInfo.secondaryTypes = new Hashtable(3);
3641                        indexedSecondaryTypes = new HashMap(3);
3642                        projectInfo.secondaryTypes.put(INDEXED_SECONDARY_TYPES, indexedSecondaryTypes);
3643                    } else {
3644                        indexedSecondaryTypes = (HashMap) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
3645                        if (indexedSecondaryTypes == null) {
3646                            indexedSecondaryTypes = new HashMap(3);
3647                            projectInfo.secondaryTypes.put(INDEXED_SECONDARY_TYPES, indexedSecondaryTypes);
3648                        }
3649                    }
3650                    // Store the secondary type in temporary cache (these are just handles => no problem to create it now...)
3651
HashMap allTypes = (HashMap) indexedSecondaryTypes.get(resource);
3652                    if (allTypes == null) {
3653                        allTypes = new HashMap(3);
3654                        indexedSecondaryTypes.put(resource, allTypes);
3655                    }
3656                    ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom((IFile)resource, null);
3657                    if (unit != null) {
3658                        String JavaDoc typeString = new String JavaDoc(typeName);
3659                        String JavaDoc packageString = new String JavaDoc(packageName);
3660                        HashMap packageTypes = (HashMap) allTypes.get(packageString);
3661                        if (packageTypes == null) {
3662                            packageTypes = new HashMap(3);
3663                            allTypes.put(packageString, packageTypes);
3664                        }
3665                        packageTypes.put(typeString, unit.getType(typeString));
3666                    }
3667                    if (VERBOSE) {
3668                        Util.verbose(" - indexing cache:"); //$NON-NLS-1$
3669
Iterator entries = indexedSecondaryTypes.entrySet().iterator();
3670                        while (entries.hasNext()) {
3671                            Map.Entry entry = (Map.Entry) entries.next();
3672                            IFile file = (IFile) entry.getKey();
3673                            Util.verbose(" + "+file.getFullPath()+':'+ entry.getValue()); //$NON-NLS-1$
3674
}
3675                    }
3676                }
3677                catch (JavaModelException jme) {
3678                    // do nothing
3679
}
3680            }
3681        }
3682    }
3683
3684    /**
3685     * Get all secondary types for a project and store result in per project info cache.
3686     *
3687     * This cache is an Hashtable<String, HashMap<String, IType>>:
3688     * - key: package name
3689     * - value:
3690     * + key: type name
3691     * + value: java model handle for the secondary type
3692     * Hashtable was used to protect callers from possible concurrent access.
3693     *
3694     * Note that this map may have a specific entry which key is {@link #INDEXED_SECONDARY_TYPES }
3695     * and value is a map containing all secondary types created during indexing.
3696     * When this key is in cache and indexing is finished, returned map is merged
3697     * with the value of this special key. If indexing is not finished and caller does
3698     * not wait for the end of indexing, returned map is the current secondary
3699     * types cache content which may be invalid...
3700     *
3701     * @param project Project we want get secondary types from
3702     * @return HashMap Table of secondary type names->path for given project
3703     */

3704    public Map secondaryTypes(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor) throws JavaModelException {
3705        if (VERBOSE) {
3706            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("JavaModelManager.secondaryTypes("); //$NON-NLS-1$
3707
buffer.append(project.getElementName());
3708            buffer.append(',');
3709            buffer.append(waitForIndexes);
3710            buffer.append(')');
3711            Util.verbose(buffer.toString());
3712        }
3713
3714        // Return cache if not empty and there's no new secondary types created during indexing
3715
final PerProjectInfo projectInfo = getPerProjectInfoCheckExistence(project.getProject());
3716        Map indexingSecondaryCache = projectInfo.secondaryTypes == null ? null : (Map) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
3717        if (projectInfo.secondaryTypes != null && indexingSecondaryCache == null) {
3718            return projectInfo.secondaryTypes;
3719        }
3720
3721        // Perform search request only if secondary types cache is not initialized yet (this will happen only once!)
3722
if (projectInfo.secondaryTypes == null) {
3723            return secondaryTypesSearching(project, waitForIndexes, monitor, projectInfo);
3724        }
3725
3726        // New secondary types have been created while indexing secondary types cache
3727
// => need to know whether the indexing is finished or not
3728
boolean indexing = this.indexManager.awaitingJobsCount() > 0;
3729        if (indexing) {
3730            if (!waitForIndexes) {
3731                // Indexing is running but caller cannot wait => return current cache
3732
return projectInfo.secondaryTypes;
3733            }
3734
3735            // Wait for the end of indexing or a cancel
3736
while (this.indexManager.awaitingJobsCount() > 0) {
3737                if (monitor != null && monitor.isCanceled()) {
3738                    return projectInfo.secondaryTypes;
3739                }
3740                try {
3741                    Thread.sleep(10);
3742                } catch (InterruptedException JavaDoc e) {
3743                    return projectInfo.secondaryTypes;
3744                }
3745            }
3746        }
3747
3748        // Indexing is finished => merge caches and return result
3749
return secondaryTypesMerging(projectInfo.secondaryTypes);
3750    }
3751    
3752    /*
3753     * Return secondary types cache merged with new secondary types created while indexing
3754     * Note that merge result is directly stored in given parameter map.
3755     */

3756    private Hashtable secondaryTypesMerging(Hashtable secondaryTypes) {
3757        if (VERBOSE) {
3758            Util.verbose("JavaModelManager.getSecondaryTypesMerged()"); //$NON-NLS-1$
3759
Util.verbose(" - current cache to merge:"); //$NON-NLS-1$
3760
Iterator entries = secondaryTypes.entrySet().iterator();
3761            while (entries.hasNext()) {
3762                Map.Entry entry = (Map.Entry) entries.next();
3763                String JavaDoc packName = (String JavaDoc) entry.getKey();
3764                Util.verbose(" + "+packName+':'+ entry.getValue() ); //$NON-NLS-1$
3765
}
3766        }
3767
3768        // Return current cache if there's no indexing cache (double check, this should not happen)
3769
HashMap indexedSecondaryTypes = (HashMap) secondaryTypes.remove(INDEXED_SECONDARY_TYPES);
3770        if (indexedSecondaryTypes == null) {
3771            return secondaryTypes;
3772        }
3773
3774        // Merge indexing cache in secondary types one
3775
Iterator entries = indexedSecondaryTypes.entrySet().iterator();
3776        while (entries.hasNext()) {
3777            Map.Entry entry = (Map.Entry) entries.next();
3778            IFile file = (IFile) entry.getKey();
3779    
3780            // Remove all secondary types of indexed file from cache
3781
secondaryTypesRemoving(secondaryTypes, file);
3782            
3783            // Add all indexing file secondary types in given secondary types cache
3784
HashMap fileSecondaryTypes = (HashMap) entry.getValue();
3785            Iterator entries2 = fileSecondaryTypes.entrySet().iterator();
3786            while (entries2.hasNext()) {
3787                Map.Entry entry2 = (Map.Entry) entries2.next();
3788                String JavaDoc packageName = (String JavaDoc) entry2.getKey();
3789                HashMap cachedTypes = (HashMap) secondaryTypes.get(packageName);
3790                if (cachedTypes == null) {
3791                    secondaryTypes.put(packageName, entry2.getValue());
3792                } else {
3793                    HashMap types = (HashMap) entry2.getValue();
3794                    Iterator entries3 = types.entrySet().iterator();
3795                    while (entries3.hasNext()) {
3796                        Map.Entry entry3 = (Map.Entry) entries3.next();
3797                        String JavaDoc typeName = (String JavaDoc) entry3.getKey();
3798                        cachedTypes.put(typeName, entry3.getValue());
3799                    }
3800                }
3801            }
3802        }
3803        if (VERBOSE) {
3804            Util.verbose(" - secondary types cache merged:"); //$NON-NLS-1$
3805
entries = secondaryTypes.entrySet().iterator();
3806            while (entries.hasNext()) {
3807                Map.Entry entry = (Map.Entry) entries.next();
3808                String JavaDoc packName = (String JavaDoc) entry.getKey();
3809                Util.verbose(" + "+packName+':'+ entry.getValue()); //$NON-NLS-1$
3810
}
3811        }
3812        return secondaryTypes;
3813    }
3814
3815    /*
3816     * Perform search request to get all secondary types of a given project.
3817     * If not waiting for indexes and indexing is running, will return types found in current built indexes...
3818     */

3819    private Map secondaryTypesSearching(IJavaProject project, boolean waitForIndexes, IProgressMonitor monitor, final PerProjectInfo projectInfo) throws JavaModelException {
3820        if (VERBOSE || BasicSearchEngine.VERBOSE) {
3821            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("JavaModelManager.secondaryTypesSearch("); //$NON-NLS-1$
3822
buffer.append(project.getElementName());
3823            buffer.append(',');
3824            buffer.append(waitForIndexes);
3825            buffer.append(')');
3826            Util.verbose(buffer.toString());
3827        }
3828
3829        final Hashtable secondaryTypes = new Hashtable(3);
3830        IRestrictedAccessTypeRequestor nameRequestor = new IRestrictedAccessTypeRequestor() {
3831            public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String JavaDoc path, AccessRestriction access) {
3832                String JavaDoc key = packageName==null ? "" : new String JavaDoc(packageName); //$NON-NLS-1$
3833
HashMap types = (HashMap) secondaryTypes.get(key);
3834                if (types == null) types = new HashMap(3);
3835                types.put(new String JavaDoc(simpleTypeName), path);
3836                secondaryTypes.put(key, types);
3837            }
3838        };
3839
3840        // Build scope using prereq projects but only source folders
3841
IPackageFragmentRoot[] allRoots = project.getAllPackageFragmentRoots();
3842        int length = allRoots.length, size = 0;
3843        IPackageFragmentRoot[] allSourceFolders = new IPackageFragmentRoot[length];
3844        for (int i=0; i<length; i++) {
3845            if (allRoots[i].getKind() == IPackageFragmentRoot.K_SOURCE) {
3846                allSourceFolders[size++] = allRoots[i];
3847            }
3848        }
3849        if (size < length) {
3850            System.arraycopy(allSourceFolders, 0, allSourceFolders = new IPackageFragmentRoot[size], 0, size);
3851        }
3852
3853        // Search all secondary types on scope
3854
new BasicSearchEngine().searchAllSecondaryTypeNames(allSourceFolders, nameRequestor, waitForIndexes, monitor);
3855
3856        // Build types from paths
3857
Iterator packages = secondaryTypes.values().iterator();
3858        while (packages.hasNext()) {
3859            HashMap types = (HashMap) packages.next();
3860            Iterator names = types.entrySet().iterator();
3861            while (names.hasNext()) {
3862                Map.Entry entry = (Map.Entry) names.next();
3863                String JavaDoc typeName = (String JavaDoc) entry.getKey();
3864                String JavaDoc path = (String JavaDoc) entry.getValue();
3865                if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path)) {
3866                    IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(path));
3867                    ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom(file, null);
3868                    IType type = unit.getType(typeName);
3869                    types.put(typeName, type); // replace stored path with type itself
3870
}
3871            }
3872        }
3873
3874        // Store result in per project info cache if still null or there's still an indexing cache (may have been set by another thread...)
3875
if (projectInfo.secondaryTypes == null || projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES) != null) {
3876            projectInfo.secondaryTypes = secondaryTypes;
3877            if (VERBOSE || BasicSearchEngine.VERBOSE) {
3878                System.out.print(Thread.currentThread() + " -> secondary paths stored in cache: "); //$NON-NLS-1$
3879
System.out.println();
3880                Iterator entries = secondaryTypes.entrySet().iterator();
3881                while (entries.hasNext()) {
3882                    Map.Entry entry = (Map.Entry) entries.next();
3883                    String JavaDoc qualifiedName = (String JavaDoc) entry.getKey();
3884                    Util.verbose(" - "+qualifiedName+'-'+ entry.getValue()); //$NON-NLS-1$
3885
}
3886            }
3887        }
3888        return projectInfo.secondaryTypes;
3889    }
3890
3891    /**
3892     * Remove from secondary types cache all types belonging to a given file.
3893     * Clean secondary types cache built while indexing if requested.
3894     *
3895     * Project's secondary types cache is found using file location.
3896     *
3897     * @param file File to remove
3898     */

3899    public void secondaryTypesRemoving(IFile file, boolean cleanIndexCache) {
3900        if (VERBOSE) {
3901            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$
3902
buffer.append(file.getName());
3903            buffer.append(')');
3904            Util.verbose(buffer.toString());
3905        }
3906        if (file != null) {
3907            PerProjectInfo projectInfo = getPerProjectInfo(file.getProject(), false);
3908            if (projectInfo != null && projectInfo.secondaryTypes != null) {
3909                if (VERBOSE) {
3910                    Util.verbose("-> remove file from cache of project: "+file.getProject().getName()); //$NON-NLS-1$
3911
}
3912
3913                // Clean current cache
3914
secondaryTypesRemoving(projectInfo.secondaryTypes, file);
3915                
3916                // Clean indexing cache if necessary
3917
if (!cleanIndexCache) return;
3918                HashMap indexingCache = (HashMap) projectInfo.secondaryTypes.get(INDEXED_SECONDARY_TYPES);
3919                if (indexingCache != null) {
3920                    Set keys = indexingCache.keySet();
3921                    int filesSize = keys.size(), filesCount = 0;
3922                    IFile[] removed = null;
3923                    Iterator cachedFiles = keys.iterator();
3924                    while (cachedFiles.hasNext()) {
3925                        IFile cachedFile = (IFile) cachedFiles.next();
3926                        if (file.equals(cachedFile)) {
3927                            if (removed == null) removed = new IFile[filesSize];
3928                            filesSize--;
3929                            removed[filesCount++] = cachedFile;
3930                        }
3931                    }
3932                    if (removed != null) {
3933                        for (int i=0; i<filesCount; i++) {
3934                            indexingCache.remove(removed[i]);
3935                        }
3936                    }
3937                }
3938            }
3939        }
3940    }
3941
3942    /*
3943     * Remove from a given cache map all secondary types belonging to a given file.
3944     * Note that there can have several secondary types per file...
3945     */

3946    private void secondaryTypesRemoving(Hashtable secondaryTypesMap, IFile file) {
3947        if (VERBOSE) {
3948            StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("JavaModelManager.removeSecondaryTypesFromMap("); //$NON-NLS-1$
3949
Iterator entries = secondaryTypesMap.entrySet().iterator();
3950            while (entries.hasNext()) {
3951                Map.Entry entry = (Map.Entry) entries.next();
3952                String JavaDoc qualifiedName = (String JavaDoc) entry.getKey();
3953                buffer.append(qualifiedName+':'+ entry.getValue());
3954            }
3955            buffer.append(',');
3956            buffer.append(file.getFullPath());
3957            buffer.append(')');
3958            Util.verbose(buffer.toString());
3959        }
3960        Set packageEntries = secondaryTypesMap.entrySet();
3961        int packagesSize = packageEntries.size(), removedPackagesCount = 0;
3962        String JavaDoc[] removedPackages = null;
3963        Iterator packages = packageEntries.iterator();
3964        while (packages.hasNext()) {
3965            Map.Entry entry = (Map.Entry) packages.next();
3966            String JavaDoc packName = (String JavaDoc) entry.getKey();
3967            if (packName != INDEXED_SECONDARY_TYPES) { // skip indexing cache entry if present (!= is intentional)
3968
HashMap types = (HashMap) entry.getValue();
3969                Set nameEntries = types.entrySet();
3970                int namesSize = nameEntries.size(), removedNamesCount = 0;
3971                String JavaDoc[] removedNames = null;
3972                Iterator names = nameEntries.iterator();
3973                while (names.hasNext()) {
3974                    Map.Entry entry2 = (Map.Entry) names.next();
3975                    String JavaDoc typeName = (String JavaDoc) entry2.getKey();
3976                    IType type = (IType) entry2.getValue();
3977                    if (file.equals(type.getResource())) {
3978                        if (removedNames == null) removedNames = new String JavaDoc[namesSize];
3979                        namesSize--;
3980                        removedNames[removedNamesCount++] = typeName;
3981                    }
3982                }
3983                if (removedNames != null) {
3984                    for (int i=0; i<removedNamesCount; i++) {
3985                        types.remove(removedNames[i]);
3986                    }
3987                }
3988                if (types.size() == 0) {
3989                    if (removedPackages == null) removedPackages = new String JavaDoc[packagesSize];
3990                    packagesSize--;
3991                    removedPackages[removedPackagesCount++] = packName;
3992                }
3993            }
3994        }
3995        if (removedPackages != null) {
3996            for (int i=0; i<removedPackagesCount; i++) {
3997                secondaryTypesMap.remove(removedPackages[i]);
3998            }
3999        }
4000        if (VERBOSE) {
4001            Util.verbose(" - new secondary types map:"); //$NON-NLS-1$
4002
Iterator entries = secondaryTypesMap.entrySet().iterator();
4003            while (entries.hasNext()) {
4004                Map.Entry entry = (Map.Entry) entries.next();
4005                String JavaDoc qualifiedName = (String JavaDoc) entry.getKey();
4006                Util.verbose(" + "+qualifiedName+':'+ entry.getValue()); //$NON-NLS-1$
4007
}
4008        }
4009    }
4010
4011    /**
4012     * Record the order in which to build the java projects (batch build). This order is based
4013     * on the projects classpath settings.
4014     */

4015    protected void setBuildOrder(String JavaDoc[] javaBuildOrder) throws JavaModelException {
4016
4017        // optional behaviour
4018
// possible value of index 0 is Compute
4019
if (!JavaCore.COMPUTE.equals(JavaCore.getOption(JavaCore.CORE_JAVA_BUILD_ORDER))) return; // cannot be customized at project level
4020

4021        if (javaBuildOrder == null || javaBuildOrder.length <= 1) return;
4022        
4023        IWorkspace workspace = ResourcesPlugin.getWorkspace();
4024        IWorkspaceDescription description = workspace.getDescription();
4025        String JavaDoc[] wksBuildOrder = description.getBuildOrder();
4026
4027        String JavaDoc[] newOrder;
4028        if (wksBuildOrder == null){
4029            newOrder = javaBuildOrder;
4030        } else {
4031            // remove projects which are already mentionned in java builder order
4032
int javaCount = javaBuildOrder.length;
4033            HashMap newSet = new HashMap(javaCount); // create a set for fast check
4034
for (int i = 0; i < javaCount; i++){
4035                newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
4036            }
4037            int removed = 0;
4038            int oldCount = wksBuildOrder.length;
4039            for (int i = 0; i < oldCount; i++){
4040                if (newSet.containsKey(wksBuildOrder[i])){
4041                    wksBuildOrder[i] = null;
4042                    removed++;
4043                }
4044            }
4045            // add Java ones first
4046
newOrder = new String JavaDoc[oldCount - removed + javaCount];
4047            System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first
4048

4049            // copy previous items in their respective order
4050
int index = javaCount;
4051            for (int i = 0; i < oldCount; i++){
4052                if (wksBuildOrder[i] != null){
4053                    newOrder[index++] = wksBuildOrder[i];
4054                }
4055            }
4056        }
4057        // commit the new build order out
4058
description.setBuildOrder(newOrder);
4059        try {
4060            workspace.setDescription(description);
4061        } catch(CoreException e){
4062            throw new JavaModelException(e);
4063        }
4064    }
4065
4066    /**
4067     * Sets the last built state for the given project, or null to reset it.
4068     */

4069    public void setLastBuiltState(IProject project, Object JavaDoc state) {
4070        if (JavaProject.hasJavaNature(project)) {
4071            // should never be requested on non-Java projects
4072
PerProjectInfo info = getPerProjectInfo(project, true /*create if missing*/);
4073            info.triedRead = true; // no point trying to re-read once using setter
4074
info.savedState = state;
4075        }
4076        if (state == null) { // delete state file to ensure a full build happens if the workspace crashes
4077
try {
4078                File JavaDoc file = getSerializationFile(project);
4079                if (file != null && file.exists())
4080                    file.delete();
4081            } catch(SecurityException JavaDoc se) {
4082                // could not delete file: cannot do much more
4083
}
4084        }
4085    }
4086    
4087    public void setOptions(Hashtable newOptions) {
4088        
4089        try {
4090            IEclipsePreferences defaultPreferences = getDefaultPreferences();
4091            IEclipsePreferences instancePreferences = getInstancePreferences();
4092
4093            if (newOptions == null){
4094                instancePreferences.clear();
4095            } else {
4096                Enumeration keys = newOptions.keys();
4097                while (keys.hasMoreElements()){
4098                    String JavaDoc key = (String JavaDoc)keys.nextElement();
4099                    if (!this.optionNames.contains(key)) continue; // unrecognized option
4100
if (key.equals(JavaCore.CORE_ENCODING)) continue; // skipped, contributed by resource prefs
4101
String JavaDoc value = (String JavaDoc)newOptions.get(key);
4102                    String JavaDoc defaultValue = defaultPreferences.get(key, null);
4103                    if (defaultValue != null && defaultValue.equals(value)) {
4104                        instancePreferences.remove(key);
4105                    } else {
4106                        instancePreferences.put(key, value);
4107                    }
4108                }
4109            }
4110
4111            // persist options
4112
instancePreferences.flush();
4113            
4114            // update cache
4115
this.optionsCache = newOptions==null ? null : new Hashtable(newOptions);
4116        } catch (BackingStoreException e) {
4117            // ignore
4118
}
4119    }
4120        
4121    public void startup() throws CoreException {
4122        try {
4123            configurePluginDebugOptions();
4124            
4125            // initialize Java model cache
4126
this.cache = new JavaModelCache();
4127
4128            // request state folder creation (workaround 19885)
4129
JavaCore.getPlugin().getStateLocation();
4130
4131            // Initialize eclipse preferences
4132
initializePreferences();
4133
4134            // Listen to preference changes
4135
Preferences.IPropertyChangeListener propertyListener = new Preferences.IPropertyChangeListener() {
4136                public void propertyChange(Preferences.PropertyChangeEvent event) {
4137                    JavaModelManager.this.optionsCache = null;
4138                }
4139            };
4140            JavaCore.getPlugin().getPluginPreferences().addPropertyChangeListener(propertyListener);
4141            
4142            // Listen to content-type changes
4143
Platform.getContentTypeManager().addContentTypeChangeListener(this);
4144
4145            // retrieve variable values
4146
long start = -1;
4147            if (VERBOSE)
4148                start = System.currentTimeMillis();
4149            loadVariablesAndContainers();
4150            if (VERBOSE)
4151                traceVariableAndContainers("Loaded", start); //$NON-NLS-1$
4152

4153            final IWorkspace workspace = ResourcesPlugin.getWorkspace();
4154            workspace.addResourceChangeListener(
4155                this.deltaState,
4156                /* update spec in JavaCore#addPreProcessingResourceChangedListener(...) if adding more event types */
4157                IResourceChangeEvent.PRE_BUILD
4158                    | IResourceChangeEvent.POST_BUILD
4159                    | IResourceChangeEvent.POST_CHANGE
4160                    | IResourceChangeEvent.PRE_DELETE
4161                    | IResourceChangeEvent.PRE_CLOSE);
4162
4163            startIndexing();
4164            
4165            // process deltas since last activated in indexer thread so that indexes are up-to-date.
4166
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658
4167
Job processSavedState = new Job(Messages.savedState_jobName) {
4168                protected IStatus run(IProgressMonitor monitor) {
4169                    try {
4170                        // add save participant and process delta atomically
4171
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59937
4172
workspace.run(
4173                            new IWorkspaceRunnable() {
4174                                public void run(IProgressMonitor progress) throws CoreException {
4175                                    ISavedState savedState = workspace.addSaveParticipant(JavaCore.getJavaCore(), JavaModelManager.this);
4176                                    if (savedState != null) {
4177                                        // the event type coming from the saved state is always POST_AUTO_BUILD
4178
// force it to be POST_CHANGE so that the delta processor can handle it
4179
JavaModelManager.this.deltaState.getDeltaProcessor().overridenEventType = IResourceChangeEvent.POST_CHANGE;
4180                                        savedState.processResourceChangeEvents(JavaModelManager.this.deltaState);
4181                                    }
4182                                }
4183                            },
4184                            monitor);
4185                    } catch (CoreException e) {
4186                        return e.getStatus();
4187                    }
4188                    return Status.OK_STATUS;
4189                }
4190            };
4191            processSavedState.setSystem(true);
4192            processSavedState.setPriority(Job.SHORT); // process asap
4193
processSavedState.schedule();
4194        } catch (RuntimeException JavaDoc e) {
4195            shutdown();
4196            throw e;
4197        }
4198    }
4199
4200    /**
4201     * Initiate the background indexing process.
4202     * This should be deferred after the plugin activation.
4203     */

4204    private void startIndexing() {
4205        getIndexManager().reset();
4206    }
4207
4208    public void shutdown () {
4209        JavaCore javaCore = JavaCore.getJavaCore();
4210        javaCore.savePluginPreferences();
4211        IWorkspace workspace = ResourcesPlugin.getWorkspace();
4212        workspace.removeResourceChangeListener(this.deltaState);
4213        workspace.removeSaveParticipant(javaCore);
4214        
4215        // Stop listening to content-type changes
4216
Platform.getContentTypeManager().removeContentTypeChangeListener(this);
4217        
4218        // Stop listening to user library changes
4219
if (this.userLibraryManager != null)
4220            getInstancePreferences().removePreferenceChangeListener(this.userLibraryManager);
4221    
4222        if (this.indexManager != null){ // no more indexing
4223
this.indexManager.shutdown();
4224        }
4225        
4226        // wait for the initialization job to finish
4227
try {
4228            Job.getJobManager().join(JavaCore.PLUGIN_ID, null);
4229        } catch (InterruptedException JavaDoc e) {
4230            // ignore
4231
}
4232        
4233        // Note: no need to close the Java model as this just removes Java element infos from the Java model cache
4234
}
4235
4236    public synchronized IPath variableGet(String JavaDoc variableName){
4237        // check initialization in progress first
4238
HashSet initializations = variableInitializationInProgress();
4239        if (initializations.contains(variableName)) {
4240            return VARIABLE_INITIALIZATION_IN_PROGRESS;
4241        }
4242        return (IPath)this.variables.get(variableName);
4243    }
4244
4245    private synchronized IPath variableGetDefaultToPreviousSession(String JavaDoc variableName){
4246        IPath variablePath = (IPath)this.variables.get(variableName);
4247        if (variablePath == null)
4248            return getPreviousSessionVariable(variableName);
4249        return variablePath;
4250    }
4251
4252    /*
4253     * Returns the set of variable names that are being initialized in the current thread.
4254     */

4255    private HashSet variableInitializationInProgress() {
4256        HashSet initializations = (HashSet)this.variableInitializationInProgress.get();
4257        if (initializations == null) {
4258            initializations = new HashSet();
4259            this.variableInitializationInProgress.set(initializations);
4260        }
4261        return initializations;
4262    }
4263
4264    public synchronized String JavaDoc[] variableNames(){
4265        int length = this.variables.size();
4266        String JavaDoc[] result = new String JavaDoc[length];
4267        Iterator vars = this.variables.keySet().iterator();
4268        int index = 0;
4269        while (vars.hasNext()) {
4270            result[index++] = (String JavaDoc) vars.next();
4271        }
4272        return result;
4273    }
4274
4275    public synchronized void variablePut(String JavaDoc variableName, IPath variablePath){
4276
4277        // set/unset the initialization in progress
4278
HashSet initializations = variableInitializationInProgress();
4279        if (variablePath == VARIABLE_INITIALIZATION_IN_PROGRESS) {
4280            initializations.add(variableName);
4281            
4282            // do not write out intermediate initialization value
4283
return;
4284        } else {
4285            initializations.remove(variableName);
4286
4287            // update cache - do not only rely on listener refresh
4288
if (variablePath == null) {
4289                // if path is null, record that the variable was removed to avoid asking the initializer to initialize it again
4290
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=112609
4291
this.variables.put(variableName, CP_ENTRY_IGNORE_PATH);
4292            } else {
4293                this.variables.put(variableName, variablePath);
4294            }
4295            // discard obsoleted information about previous session
4296
this.previousSessionVariables.remove(variableName);
4297        }
4298    }
4299
4300    public void variablePreferencesPut(String JavaDoc variableName, IPath variablePath) {
4301        String JavaDoc variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName;
4302        if (variablePath == null) {
4303            this.variablesWithInitializer.remove(variableName);
4304            getInstancePreferences().remove(variableKey);
4305        } else {
4306            getInstancePreferences().put(variableKey, variablePath.toString());
4307        }
4308        try {
4309            getInstancePreferences().flush();
4310        } catch (BackingStoreException e) {
4311            // ignore exception
4312
}
4313    }
4314
4315    /*
4316     * Optimize startup case where 1 variable is initialized at a time with the same value as on shutdown.
4317     */

4318    public boolean variablePutIfInitializingWithSameValue(String JavaDoc[] variableNames, IPath[] variablePaths) {
4319        if (variableNames.length != 1)
4320            return false;
4321        String JavaDoc variableName = variableNames[0];
4322        IPath oldPath = variableGetDefaultToPreviousSession(variableName);
4323        if (oldPath == null)
4324            return false;
4325        IPath newPath = variablePaths[0];
4326        if (!oldPath.equals(newPath))
4327            return false;
4328        variablePut(variableName, newPath);
4329        return true;
4330    }
4331
4332    public void contentTypeChanged(ContentTypeChangeEvent event) {
4333        Util.resetJavaLikeExtensions();
4334        
4335    }
4336
4337    public synchronized String JavaDoc cacheToString(String JavaDoc prefix) {
4338        return this.cache.toStringFillingRation(prefix);
4339    }
4340}
4341
Popular Tags