1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
13 import java.io.BufferedInputStream;
14 import java.io.BufferedOutputStream;
15 import java.io.DataInputStream;
16 import java.io.DataOutputStream;
18 import java.io.FileInputStream;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.text.NumberFormat;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Iterator;
28 import java.util.WeakHashMap;
29 import java.util.zip.ZipFile;
31 import net.sourceforge.phpdt.core.ElementChangedEvent;
32 import net.sourceforge.phpdt.core.IClasspathEntry;
33 import net.sourceforge.phpdt.core.ICompilationUnit;
34 import net.sourceforge.phpdt.core.IElementChangedListener;
35 import net.sourceforge.phpdt.core.IJavaElement;
36 import net.sourceforge.phpdt.core.IJavaElementDelta;
37 import net.sourceforge.phpdt.core.IJavaModel;
38 import net.sourceforge.phpdt.core.IJavaProject;
39 import net.sourceforge.phpdt.core.IPackageFragment;
40 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
41 import net.sourceforge.phpdt.core.IParent;
42 import net.sourceforge.phpdt.core.IProblemRequestor;
43 import net.sourceforge.phpdt.core.IWorkingCopy;
44 import net.sourceforge.phpdt.core.JavaCore;
45 import net.sourceforge.phpdt.core.JavaModelException;
46 import net.sourceforge.phpdt.core.WorkingCopyOwner;
47 import net.sourceforge.phpdt.core.compiler.IProblem;
48 import net.sourceforge.phpdt.internal.core.builder.PHPBuilder;
49 import net.sourceforge.phpdt.internal.core.util.Util;
50 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
51 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
53 import org.eclipse.core.resources.IFile;
54 import org.eclipse.core.resources.IFolder;
55 import org.eclipse.core.resources.IProject;
56 import org.eclipse.core.resources.IResource;
57 import org.eclipse.core.resources.IResourceDelta;
58 import org.eclipse.core.resources.ISaveContext;
59 import org.eclipse.core.resources.ISaveParticipant;
60 import org.eclipse.core.resources.IWorkspace;
61 import org.eclipse.core.resources.IWorkspaceDescription;
62 import org.eclipse.core.resources.IWorkspaceRoot;
63 import org.eclipse.core.resources.ResourcesPlugin;
64 import org.eclipse.core.runtime.CoreException;
65 import org.eclipse.core.runtime.IPath;
66 import org.eclipse.core.runtime.IProgressMonitor;
67 import org.eclipse.core.runtime.ISafeRunnable;
68 import org.eclipse.core.runtime.IStatus;
69 import org.eclipse.core.runtime.MultiStatus;
70 import org.eclipse.core.runtime.Path;
71 import org.eclipse.core.runtime.Platform;
72 import org.eclipse.core.runtime.Plugin;
73 import org.eclipse.core.runtime.Preferences;
74 import org.eclipse.core.runtime.Status;
75 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
78 * The <code>JavaModelManager</code> manages instances of <code>IJavaModel</code>.
79 * <code>IElementChangedListener</code>s register with the <code>JavaModelManager</code>,
80 * and receive <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
82 * The single instance of <code>JavaModelManager</code> is available from
83 * the static method <code>JavaModelManager.getJavaModelManager()</code>.
85 public class JavaModelManager implements ISaveParticipant {
87 * Unique handle onto the JavaModel
89 final JavaModel javaModel = new JavaModel();
90 // public IndexManager indexManager = new IndexManager();
92 * Classpath variables pool
94 public static HashMap Variables = new HashMap(5);
95 public static HashMap PreviousSessionVariables = new HashMap(5);
96 public static HashSet OptionNames = new HashSet(20);
97 public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$
98 public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$
99 public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
102 * Classpath containers pool
104 public static HashMap containers = new HashMap(5);
105 public static HashMap PreviousSessionContainers = new HashMap(5);
108 * Name of the extension point for contributing classpath variable initializers
110 // public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID = "classpathVariableInitializer" ; //$NON-NLS-1$
113 * Name of the extension point for contributing classpath container initializers
115 // public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID = "classpathContainerInitializer" ; //$NON-NLS-1$
118 * Name of the extension point for contributing a source code formatter
120 public static final String FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$/**
123 * Value of the content-type for Java source files
125 public static final String JAVA_SOURCE_CONTENT_TYPE = PHPeclipsePlugin.PLUGIN_ID+".phpSource" ; //$NON-NLS-1$NON-NLS-1$
128 * Special value used for recognizing ongoing initialization and breaking initialization cycles
130 public final static IPath VariableInitializationInProgress = new Path("Variable Initialization In Progress"); //$NON-NLS-1$
131 // public final static IClasspathContainer ContainerInitializationInProgress = new IClasspathContainer() {
132 // public IClasspathEntry[] getClasspathEntries() { return null; }
133 // public String getDescription() { return "Container Initialization In Progress"; } //$NON-NLS-1$
134 // public int getKind() { return 0; }
135 // public IPath getPath() { return null; }
136 // public String toString() { return getDescription(); }
139 private static final String INDEX_MANAGER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$
140 private static final String COMPILER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$
141 private static final String JAVAMODEL_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$
142 private static final String CP_RESOLVE_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$
143 private static final String ZIP_ACCESS_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/zipaccess" ; //$NON-NLS-1$
144 private static final String DELTA_DEBUG =PHPeclipsePlugin.PLUGIN_ID + "/debug/javadelta" ; //$NON-NLS-1$
145 private static final String HIERARCHY_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/hierarchy" ; //$NON-NLS-1$
146 private static final String POST_ACTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/postaction" ; //$NON-NLS-1$
147 private static final String BUILDER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$
148 private static final String COMPLETION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/completion" ; //$NON-NLS-1$
149 private static final String SELECTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$
150 private static final String SHARED_WC_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/sharedworkingcopy" ; //$NON-NLS-1$
151 private static final String SEARCH_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$
153 public final static IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0];
156 * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo.
157 * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos
159 protected Map perWorkingCopyInfos = new HashMap(5);
161 * Returns whether the given full path (for a package) conflicts with the output location
162 * of the given project.
164 public static boolean conflictsWithOutputLocation(IPath folderPath, JavaProject project) {
166 IPath outputLocation = project.getOutputLocation();
167 if (outputLocation == null) {
168 // in doubt, there is a conflict
171 if (outputLocation.isPrefixOf(folderPath)) {
172 // only allow nesting in project's output if there is a corresponding source folder
173 // or if the project's output is not used (in other words, if all source folders have their custom output)
174 IClasspathEntry[] classpath = project.getResolvedClasspath(true);
175 boolean isOutputUsed = false;
176 for (int i = 0, length = classpath.length; i < length; i++) {
177 IClasspathEntry entry = classpath[i];
178 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
179 if (entry.getPath().equals(outputLocation)) {
182 if (entry.getOutputLocation() == null) {
190 } catch (JavaModelException e) {
191 // in doubt, there is a conflict
196 // public static IClasspathContainer containerGet(IJavaProject project, IPath containerPath) {
197 // Map projectContainers = (Map)Containers.get(project);
198 // if (projectContainers == null){
201 // IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath);
205 // public static void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){
207 // Map projectContainers = (Map)Containers.get(project);
208 // if (projectContainers == null){
209 // projectContainers = new HashMap(1);
210 // Containers.put(project, projectContainers);
213 // if (container == null) {
214 // projectContainers.remove(containerPath);
215 // Map previousContainers = (Map)PreviousSessionContainers.get(project);
216 // if (previousContainers != null){
217 // previousContainers.remove(containerPath);
220 // projectContainers.put(containerPath, container);
223 // // do not write out intermediate initialization value
224 // if (container == JavaModelManager.ContainerInitializationInProgress) {
227 // Preferences preferences = PHPeclipsePlugin.getPlugin().getPluginPreferences();
228 // String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
229 // String containerString = CP_ENTRY_IGNORE;
231 // if (container != null) {
232 // containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false);
234 // } catch(JavaModelException e){
236 // preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
237 // preferences.setValue(containerKey, containerString);
238 // PHPeclipsePlugin.getPlugin().savePluginPreferences();
242 * Returns the Java element corresponding to the given resource, or
243 * <code>null</code> if unable to associate the given resource
244 * with a Java element.
246 * The resource must be one of:<ul>
247 * <li>a project - the element returned is the corresponding <code>IJavaProject</code></li>
248 * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
249 * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
250 * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
251 * <li>a folder - the element returned is the corresponding <code>IPackageFragmentRoot</code>
252 * or <code>IPackageFragment</code></li>
253 * <li>the workspace root resource - the element returned is the <code>IJavaModel</code></li>
256 * Creating a Java element has the side effect of creating and opening all of the
257 * element's parents if they are not yet open.
259 public static IJavaElement create(IResource resource, IJavaProject project) {
260 if (resource == null) {
263 int type = resource.getType();
265 case IResource.PROJECT :
266 return JavaCore.create((IProject) resource);
267 case IResource.FILE :
268 return create((IFile) resource, project);
269 case IResource.FOLDER :
270 return create((IFolder) resource, project);
271 case IResource.ROOT :
272 return JavaCore.create((IWorkspaceRoot) resource);
279 * Returns the Java element corresponding to the given file, its project being the given
281 * Returns <code>null</code> if unable to associate the given file
282 * with a Java element.
284 * <p>The file must be one of:<ul>
285 * <li>a <code>.java</code> file - the element returned is the corresponding <code>ICompilationUnit</code></li>
286 * <li>a <code>.class</code> file - the element returned is the corresponding <code>IClassFile</code></li>
287 * <li>a <code>.jar</code> file - the element returned is the corresponding <code>IPackageFragmentRoot</code></li>
290 * Creating a Java element has the side effect of creating and opening all of the
291 * element's parents if they are not yet open.
293 public static IJavaElement create(IFile file, IJavaProject project) {
297 if (project == null) {
298 project = JavaCore.create(file.getProject());
301 if (file.getFileExtension() != null) {
302 String name = file.getName();
303 if (PHPFileUtil.isValidPHPUnitName(name))
304 //if (PHPFileUtil.isPHPFile(file))
305 return createCompilationUnitFrom(file, project);
306 // if (ProjectPrefUtil.isValidClassFileName(name))
307 // return createClassFileFrom(file, project);
308 // if (ProjectPrefUtil.isArchiveFileName(name))
309 // return createJarPackageFragmentRootFrom(file, project);
315 * Returns the package fragment or package fragment root corresponding to the given folder,
316 * its parent or great parent being the given project.
317 * or <code>null</code> if unable to associate the given folder with a Java element.
319 * Note that a package fragment root is returned rather than a default package.
321 * Creating a Java element has the side effect of creating and opening all of the
322 * element's parents if they are not yet open.
324 public static IJavaElement create(IFolder folder, IJavaProject project) {
325 if (folder == null) {
328 if (project == null) {
329 project = JavaCore.create(folder.getProject());
331 IJavaElement element = determineIfOnClasspath(folder, project);
332 if (conflictsWithOutputLocation(folder.getFullPath(), (JavaProject)project)
333 || (folder.getName().indexOf('.') >= 0
334 && !(element instanceof IPackageFragmentRoot))) {
335 return null; // only package fragment roots are allowed with dot names
342 * Creates and returns a class file element for the given <code>.class</code> file,
343 * its project being the given project. Returns <code>null</code> if unable
344 * to recognize the class file.
346 // public static IClassFile createClassFileFrom(IFile file, IJavaProject project ) {
347 // if (file == null) {
350 // if (project == null) {
351 // project = PHPCore.create(file.getProject());
353 // IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
354 // if (pkg == null) {
355 // // fix for 1FVS7WE
356 // // not on classpath - make the root its folder, and a default package
357 // IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent());
358 // pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
360 // return pkg.getClassFile(file.getName());
364 * Creates and returns a compilation unit element for the given <code>.java</code>
365 * file, its project being the given project. Returns <code>null</code> if unable
366 * to recognize the compilation unit.
368 public static ICompilationUnit createCompilationUnitFrom(IFile file, IJavaProject project) {
370 if (file == null) return null;
372 if (project == null) {
373 project = JavaCore.create(file.getProject());
375 IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project);
377 // not on classpath - make the root its folder, and a default package
378 IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent());
379 pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
382 System.out.println("WARNING : creating unit element outside classpath ("+ Thread.currentThread()+"): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
385 return pkg.getCompilationUnit(file.getName());
388 * Creates and returns a handle for the given JAR file, its project being the given project.
389 * The Java model associated with the JAR's project may be
390 * created as a side effect.
391 * Returns <code>null</code> if unable to create a JAR package fragment root.
392 * (for example, if the JAR file represents a non-Java resource)
394 // public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile file, IJavaProject project) {
395 // if (file == null) {
398 // if (project == null) {
399 // project = PHPCore.create(file.getProject());
402 // // Create a jar package fragment root only if on the classpath
403 // IPath resourcePath = file.getFullPath();
405 // IClasspathEntry[] entries = ((JavaProject)project).getResolvedClasspath(true);
406 // for (int i = 0, length = entries.length; i < length; i++) {
407 // IClasspathEntry entry = entries[i];
408 // IPath rootPath = entry.getPath();
409 // if (rootPath.equals(resourcePath)) {
410 // return project.getPackageFragmentRoot(file);
413 // } catch (JavaModelException e) {
419 * Returns the package fragment root represented by the resource, or
420 * the package fragment the given resource is located in, or <code>null</code>
421 * if the given resource is not on the classpath of the given project.
423 public static IJavaElement determineIfOnClasspath(
425 IJavaProject project) {
427 IPath resourcePath = resource.getFullPath();
429 IClasspathEntry[] entries =
430 net.sourceforge.phpdt.internal.compiler.util.Util.isJavaFileName(resourcePath.lastSegment())
431 ? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path)
432 : ((JavaProject)project).getResolvedClasspath(true);
434 for (int i = 0; i < entries.length; i++) {
435 IClasspathEntry entry = entries[i];
436 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue;
437 IPath rootPath = entry.getPath();
438 if (rootPath.equals(resourcePath)) {
439 return project.getPackageFragmentRoot(resource);
440 } else if (rootPath.isPrefixOf(resourcePath) && !Util.isExcluded(resource, null, ((ClasspathEntry)entry).fullExclusionPatternChars())) {
441 // given we have a resource child of the root, it cannot be a JAR pkg root
442 IPackageFragmentRoot root = ((JavaProject) project).getFolderPackageFragmentRoot(rootPath);
443 if (root == null) return null;
444 IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount());
445 if (resource.getType() == IResource.FILE) {
446 // if the resource is a file, then remove the last segment which
447 // is the file name in the package
448 pkgPath = pkgPath.removeLastSegments(1);
450 // don't check validity of package name (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=26706)
451 // String pkgName = pkgPath.toString().replace('/', '.');
452 String pkgName = pkgPath.toString();
453 return root.getPackageFragment(pkgName);
455 String pkgName = Util.packageName(pkgPath);
456 if (pkgName == null){// || JavaConventions.validatePackageName(pkgName).getSeverity() == IStatus.ERROR) {
459 return root.getPackageFragment(pkgName);
463 } catch (JavaModelException npe) {
470 * The singleton manager
472 private final static JavaModelManager Manager= new JavaModelManager();
477 protected JavaModelCache cache = new JavaModelCache();
480 * Temporary cache of newly opened elements
482 private ThreadLocal temporaryCache = new ThreadLocal();
484 * Set of elements which are out of sync with their buffers.
486 protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
488 * Holds the state used for delta processing.
490 public DeltaProcessingState deltaState = new DeltaProcessingState();
492 * Turns delta firing on/off. By default it is on.
494 private boolean isFiring= true;
497 * Queue of deltas created explicily by the Java Model that
498 * have yet to be fired.
500 ArrayList javaModelDeltas= new ArrayList();
502 * Queue of reconcile deltas on working copies that have yet to be fired.
503 * This is a table form IWorkingCopy to IJavaElementDelta
505 HashMap reconcileDeltas = new HashMap();
509 * Collection of listeners for Java element deltas
511 private IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5];
512 private int[] elementChangedListenerMasks = new int[5];
513 private int elementChangedListenerCount = 0;
514 public int currentChangeEventType = ElementChangedEvent.PRE_AUTO_BUILD;
515 public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with ElementChangedEvent event masks
520 * Used to convert <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
522 // public final DeltaProcessor deltaProcessor = new DeltaProcessor(this);
524 * Used to update the JavaModel for <code>IJavaElementDelta</code>s.
526 private final ModelUpdater modelUpdater =new ModelUpdater();
528 * Workaround for bug 15168 circular errors not reported
529 * This is a cache of the projects before any project addition/deletion has started.
531 public IJavaProject[] javaProjectsCache;
534 * Table from IProject to PerProjectInfo.
535 * NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos
537 protected Map perProjectInfo = new HashMap(5);
540 * A map from ICompilationUnit to IWorkingCopy
541 * of the shared working copies.
543 public Map sharedWorkingCopies = new HashMap();
546 * A weak set of the known scopes.
548 protected WeakHashMap searchScopes = new WeakHashMap();
550 // public static class PerProjectInfo {
551 // public IProject project;
552 // public Object savedState;
553 // public boolean triedRead;
554 // public IClasspathEntry[] classpath;
555 // public IClasspathEntry[] lastResolvedClasspath;
556 // public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries
557 // public IPath outputLocation;
558 // public Preferences preferences;
559 // public PerProjectInfo(IProject project) {
561 // this.triedRead = false;
562 // this.savedState = null;
563 // this.project = project;
567 public static class PerProjectInfo {
569 public IProject project;
570 public Object savedState;
571 public boolean triedRead;
572 public IClasspathEntry[] rawClasspath;
573 public IClasspathEntry[] resolvedClasspath;
574 public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries
575 public IPath outputLocation;
576 public Preferences preferences;
578 public PerProjectInfo(IProject project) {
580 this.triedRead = false;
581 this.savedState = null;
582 this.project = project;
585 // updating raw classpath need to flush obsoleted cached information about resolved entries
586 public synchronized void updateClasspathInformation(IClasspathEntry[] newRawClasspath) {
588 this.rawClasspath = newRawClasspath;
589 this.resolvedClasspath = null;
590 this.resolvedPathToRawEntries = null;
592 public String toString() {
593 StringBuffer buffer = new StringBuffer();
594 buffer.append("Info for "); //$NON-NLS-1$
595 buffer.append(this.project.getFullPath());
596 buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
597 if (this.rawClasspath == null) {
598 buffer.append(" <null>\n"); //$NON-NLS-1$
600 for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
601 buffer.append(" "); //$NON-NLS-1$
602 buffer.append(this.rawClasspath[i]);
606 buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
607 IClasspathEntry[] resolvedCP = this.resolvedClasspath;
608 if (resolvedCP == null) {
609 buffer.append(" <null>\n"); //$NON-NLS-1$
611 for (int i = 0, length = resolvedCP.length; i < length; i++) {
612 buffer.append(" "); //$NON-NLS-1$
613 buffer.append(resolvedCP[i]);
617 buffer.append("Output location:\n "); //$NON-NLS-1$
618 if (this.outputLocation == null) {
619 buffer.append("<null>"); //$NON-NLS-1$
621 buffer.append(this.outputLocation);
623 return buffer.toString();
627 public static class PerWorkingCopyInfo implements IProblemRequestor {
629 IProblemRequestor problemRequestor;
630 ICompilationUnit workingCopy;
631 public PerWorkingCopyInfo(ICompilationUnit workingCopy, IProblemRequestor problemRequestor) {
632 this.workingCopy = workingCopy;
633 this.problemRequestor = problemRequestor;
635 public void acceptProblem(IProblem problem) {
636 if (this.problemRequestor == null) return;
637 this.problemRequestor.acceptProblem(problem);
639 public void beginReporting() {
640 if (this.problemRequestor == null) return;
641 this.problemRequestor.beginReporting();
643 public void endReporting() {
644 if (this.problemRequestor == null) return;
645 this.problemRequestor.endReporting();
647 public ICompilationUnit getWorkingCopy() {
648 return this.workingCopy;
650 public boolean isActive() {
651 return this.problemRequestor != null && this.problemRequestor.isActive();
653 public String toString() {
654 StringBuffer buffer = new StringBuffer();
655 buffer.append("Info for "); //$NON-NLS-1$
656 buffer.append(((JavaElement)workingCopy).toStringWithAncestors());
657 buffer.append("\nUse count = "); //$NON-NLS-1$
658 buffer.append(this.useCount);
659 buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$
660 buffer.append(this.problemRequestor);
661 return buffer.toString();
664 public static boolean VERBOSE = false;
665 public static boolean CP_RESOLVE_VERBOSE = false;
666 public static boolean ZIP_ACCESS_VERBOSE = false;
669 * A cache of opened zip files per thread.
670 * (map from Thread to map of IPath to java.io.ZipFile)
671 * NOTE: this object itself is used as a lock to synchronize creation/removal of entries
673 private HashMap zipFiles = new HashMap();
677 * Update the classpath variable cache
679 public static class PluginPreferencesListener implements Preferences.IPropertyChangeListener {
681 * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
683 public void propertyChange(Preferences.PropertyChangeEvent event) {
684 // TODO : jsurfer temp-del
685 // String propertyName = event.getProperty();
686 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
687 // String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
688 // String newValue = (String)event.getNewValue();
689 // if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) {
690 // Variables.put(varName, new Path(newValue));
692 // Variables.remove(varName);
695 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
696 // recreatePersistedContainer(propertyName, (String)event.getNewValue(), false);
702 * Line separator to use throughout the JavaModel for any source edit operation
704 public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
706 * Constructs a new JavaModelManager
708 private JavaModelManager() {
712 * @deprecated - discard once debug has converted to not using it
714 public void addElementChangedListener(IElementChangedListener listener) {
715 this.addElementChangedListener(listener, ElementChangedEvent.POST_CHANGE | ElementChangedEvent.POST_RECONCILE);
718 * addElementChangedListener method comment.
719 * Need to clone defensively the listener information, in case some listener is reacting to some notification iteration by adding/changing/removing
720 * any of the other (for example, if it deregisters itself).
722 public void addElementChangedListener(IElementChangedListener listener, int eventMask) {
723 for (int i = 0; i < this.elementChangedListenerCount; i++){
724 if (this.elementChangedListeners[i].equals(listener)){
726 // only clone the masks, since we could be in the middle of notifications and one listener decide to change
727 // any event mask of another listeners (yet not notified).
728 int cloneLength = this.elementChangedListenerMasks.length;
729 System.arraycopy(this.elementChangedListenerMasks, 0, this.elementChangedListenerMasks = new int[cloneLength], 0, cloneLength);
730 this.elementChangedListenerMasks[i] = eventMask; // could be different
734 // may need to grow, no need to clone, since iterators will have cached original arrays and max boundary and we only add to the end.
736 if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount){
737 System.arraycopy(this.elementChangedListeners, 0, this.elementChangedListeners = new IElementChangedListener[length*2], 0, length);
738 System.arraycopy(this.elementChangedListenerMasks, 0, this.elementChangedListenerMasks = new int[length*2], 0, length);
740 this.elementChangedListeners[this.elementChangedListenerCount] = listener;
741 this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask;
742 this.elementChangedListenerCount++;
746 * Starts caching ZipFiles.
747 * Ignores if there are already clients.
749 public void cacheZipFiles() {
750 synchronized(this.zipFiles) {
751 Thread currentThread = Thread.currentThread();
752 if (this.zipFiles.get(currentThread) != null) return;
753 this.zipFiles.put(currentThread, new HashMap());
756 public void closeZipFile(ZipFile zipFile) {
757 if (zipFile == null) return;
758 synchronized(this.zipFiles) {
759 if (this.zipFiles.get(Thread.currentThread()) != null) {
760 return; // zip file will be closed by call to flushZipFiles
763 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
764 System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$
767 } catch (IOException e) {
775 * Configure the plugin with respect to option settings defined in ".options" file
777 public void configurePluginDebugOptions(){
778 if(JavaCore.getPlugin().isDebugging()){
779 // TODO jsurfer temp-del
781 String option = Platform.getDebugOption(BUILDER_DEBUG);
782 // if(option != null) JavaBuilder.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
784 // option = Platform.getDebugOption(COMPILER_DEBUG);
785 // if(option != null) Compiler.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
787 // option = Platform.getDebugOption(COMPLETION_DEBUG);
788 // if(option != null) CompletionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
790 option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
791 if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
793 option = Platform.getDebugOption(DELTA_DEBUG);
794 if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
796 // option = Platform.getDebugOption(HIERARCHY_DEBUG);
797 // if(option != null) TypeHierarchy.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
799 // option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
800 // if(option != null) IndexManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
802 option = Platform.getDebugOption(JAVAMODEL_DEBUG);
803 if(option != null) JavaModelManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
805 option = Platform.getDebugOption(POST_ACTION_DEBUG);
806 if(option != null) JavaModelOperation.POST_ACTION_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
808 // option = Platform.getDebugOption(SEARCH_DEBUG);
809 // if(option != null) SearchEngine.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
811 // option = Platform.getDebugOption(SELECTION_DEBUG);
812 // if(option != null) SelectionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
814 option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
815 if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$
821 * Discards the per working copy info for the given working copy (making it a compilation unit)
822 * if its use count was 1. Otherwise, just decrement the use count.
823 * If the working copy is primary, computes the delta between its state and the original compilation unit
825 * Close the working copy, its buffer and remove it from the shared working copy table.
826 * Ignore if no per-working copy info existed.
827 * NOTE: it must be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667.
828 * Returns the new use count (or -1 if it didn't exist).
830 public synchronized int discardPerWorkingCopyInfo(CompilationUnit workingCopy) throws JavaModelException {
831 synchronized(perWorkingCopyInfos) {
832 WorkingCopyOwner owner = workingCopy.owner;
833 Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
834 if (workingCopyToInfos == null) return -1;
836 PerWorkingCopyInfo info = (PerWorkingCopyInfo)workingCopyToInfos.get(workingCopy);
837 if (info == null) return -1;
839 if (--info.useCount == 0) {
840 // create the delta builder (this remembers the current content of the working copy)
841 JavaElementDeltaBuilder deltaBuilder = null;
842 if (workingCopy.isPrimary()) {
843 deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
846 // remove per working copy info
847 workingCopyToInfos.remove(workingCopy);
848 if (workingCopyToInfos.isEmpty()) {
849 this.perWorkingCopyInfos.remove(owner);
852 // remove infos + close buffer (since no longer working copy)
853 removeInfoAndChildren(workingCopy);
854 workingCopy.closeBuffer();
856 // compute the delta if needed and register it if there are changes
857 if (deltaBuilder != null) {
858 deltaBuilder.buildDeltas();
859 if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
860 getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta);
865 return info.useCount;
870 * @see ISaveParticipant
872 public void doneSaving(ISaveContext context){
876 * Fire Java Model delta, flushing them after the fact after post_change notification.
877 * If the firing mode has been turned off, this has no effect.
879 public void fire(IJavaElementDelta customDelta, int eventType) {
881 if (!this.isFiring) return;
883 if (DeltaProcessor.VERBOSE && (eventType == DEFAULT_CHANGE_EVENT || eventType == ElementChangedEvent.PRE_AUTO_BUILD)) {
884 System.out.println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
887 IJavaElementDelta deltaToNotify;
888 if (customDelta == null){
889 deltaToNotify = this.mergeDeltas(this.javaModelDeltas);
891 deltaToNotify = customDelta;
894 // Refresh internal scopes
895 if (deltaToNotify != null) {
897 // Iterator scopes = this.scopes.keySet().iterator();
898 // while (scopes.hasNext()) {
899 // AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
900 // scope.processDelta(deltaToNotify);
906 // Important: if any listener reacts to notification by updating the listeners list or mask, these lists will
907 // be duplicated, so it is necessary to remember original lists in a variable (since field values may change under us)
908 IElementChangedListener[] listeners = this.elementChangedListeners;
909 int[] listenerMask = this.elementChangedListenerMasks;
910 int listenerCount = this.elementChangedListenerCount;
913 case DEFAULT_CHANGE_EVENT:
914 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, listenerCount);
915 firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount);
916 fireReconcileDelta(listeners, listenerMask, listenerCount);
918 case ElementChangedEvent.PRE_AUTO_BUILD:
919 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, listenerCount);
921 case ElementChangedEvent.POST_CHANGE:
922 firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount);
923 fireReconcileDelta(listeners, listenerMask, listenerCount);
929 private void firePreAutoBuildDelta(
930 IJavaElementDelta deltaToNotify,
931 IElementChangedListener[] listeners,
935 if (DeltaProcessor.VERBOSE){
936 System.out.println("FIRING PRE_AUTO_BUILD Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
937 System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
939 if (deltaToNotify != null) {
940 notifyListeners(deltaToNotify, ElementChangedEvent.PRE_AUTO_BUILD, listeners, listenerMask, listenerCount);
944 private void firePostChangeDelta(
945 IJavaElementDelta deltaToNotify,
946 IElementChangedListener[] listeners,
950 // post change deltas
951 if (DeltaProcessor.VERBOSE){
952 System.out.println("FIRING POST_CHANGE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
953 System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
955 if (deltaToNotify != null) {
956 // flush now so as to keep listener reactions to post their own deltas for subsequent iteration
959 notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE, listeners, listenerMask, listenerCount);
962 private void fireReconcileDelta(
963 IElementChangedListener[] listeners,
968 IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas.values());
969 if (DeltaProcessor.VERBOSE){
970 System.out.println("FIRING POST_RECONCILE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$
971 System.out.println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
973 if (deltaToNotify != null) {
974 // flush now so as to keep listener reactions to post their own deltas for subsequent iteration
975 this.reconcileDeltas = new HashMap();
977 notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE, listeners, listenerMask, listenerCount);
981 public void notifyListeners(IJavaElementDelta deltaToNotify, int eventType, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) {
982 final ElementChangedEvent extraEvent = new ElementChangedEvent(deltaToNotify, eventType);
983 for (int i= 0; i < listenerCount; i++) {
984 if ((listenerMask[i] & eventType) != 0){
985 final IElementChangedListener listener = listeners[i];
987 if (DeltaProcessor.VERBOSE) {
988 System.out.print("Listener #" + (i+1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$
989 start = System.currentTimeMillis();
991 // wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief
992 Platform.run(new ISafeRunnable() {
993 public void handleException(Throwable exception) {
994 Util.log(exception, "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
996 public void run() throws Exception {
997 listener.elementChanged(extraEvent);
1000 if (DeltaProcessor.VERBOSE) {
1001 System.out.println(" -> " + (System.currentTimeMillis()-start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1008 * Flushes all deltas without firing them.
1010 protected void flush() {
1011 this.javaModelDeltas = new ArrayList();
1015 * Flushes ZipFiles cache if there are no more clients.
1017 public void flushZipFiles() {
1018 synchronized(this.zipFiles) {
1019 Thread currentThread = Thread.currentThread();
1020 HashMap map = (HashMap)this.zipFiles.remove(currentThread);
1021 if (map == null) return;
1022 Iterator iterator = map.values().iterator();
1023 while (iterator.hasNext()) {
1025 ZipFile zipFile = (ZipFile)iterator.next();
1026 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1027 System.out.println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$
1030 } catch (IOException e) {
1037 public DeltaProcessor getDeltaProcessor() {
1038 return this.deltaState.getDeltaProcessor();
1041 * Returns the set of elements which are out of synch with their buffers.
1043 protected Map getElementsOutOfSynchWithBuffers() {
1044 return this.elementsOutOfSynchWithBuffers;
1047 // public IndexManager getIndexManager() {
1048 // return this.indexManager;
1051 * Returns the <code>IJavaElement</code> represented by the
1052 * <code>String</code> memento.
1054 public IJavaElement getHandleFromMemento(String memento) throws JavaModelException {
1055 if (memento == null) {
1058 JavaModel model= (JavaModel) getJavaModel();
1059 if (memento.equals("")){ // workspace memento //$NON-NLS-1$
1062 int modelEnd= memento.indexOf(JavaElement.JEM_JAVAPROJECT);
1063 if (modelEnd == -1) {
1066 boolean returnProject= false;
1067 int projectEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT, modelEnd);
1068 if (projectEnd == -1) {
1069 projectEnd= memento.length();
1070 returnProject= true;
1072 String projectName= memento.substring(modelEnd + 1, projectEnd);
1073 JavaProject proj= (JavaProject) model.getJavaProject(projectName);
1074 if (returnProject) {
1077 int rootEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT, projectEnd + 1);
1079 // if (rootEnd == -1) {
1080 // return model.getHandleFromMementoForRoot(memento, proj, projectEnd, memento.length());
1082 // IPackageFragmentRoot root = model.getHandleFromMementoForRoot(memento, proj, projectEnd, rootEnd);
1083 // if (root == null)
1086 // int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd);
1088 // end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd);
1090 // if (rootEnd + 1 == memento.length()) {
1091 // return root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
1093 // return root.getPackageFragment(memento.substring(rootEnd + 1));
1096 // //deal with class file and binary members
1097 // return model.getHandleFromMementoForBinaryMembers(memento, root, rootEnd, end);
1100 // //deal with compilation units and source members
1101 // return model.getHandleFromMementoForSourceMembers(memento, root, rootEnd, end);
1104 // public IndexManager getIndexManager() {
1105 // return this.deltaProcessor.indexManager;
1109 * Returns the info for the element.
1111 public Object getInfo(IJavaElement element) {
1112 return this.cache.getInfo(element);
1116 * Returns the handle to the active Java Model.
1118 public final JavaModel getJavaModel() {
1123 * Returns the singleton JavaModelManager
1125 public final static JavaModelManager getJavaModelManager() {
1130 * Returns the last built state for the given project, or null if there is none.
1131 * Deserializes the state if necessary.
1133 * For use by image builder and evaluation support only
1135 public Object getLastBuiltState(IProject project, IProgressMonitor monitor) {
1136 if (!JavaProject.hasJavaNature(project)) return null; // should never be requested on non-Java projects
1137 PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/);
1138 if (!info.triedRead) {
1139 info.triedRead = true;
1141 if (monitor != null)
1142 monitor.subTask(Util.bind("build.readStateProgress", project.getName())); //$NON-NLS-1$
1143 info.savedState = readState(project);
1144 } catch (CoreException e) {
1145 e.printStackTrace();
1148 return info.savedState;
1152 * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist.
1154 public PerProjectInfo getPerProjectInfo(IProject project, boolean create) {
1155 synchronized(perProjectInfo) { // use the perProjectInfo collection as its own lock
1156 PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project);
1157 if (info == null && create) {
1158 info= new PerProjectInfo(project);
1159 perProjectInfo.put(project, info);
1166 * Returns the per-project info for the given project.
1167 * If the info doesn't exist, check for the project existence and create the info.
1168 * @throws JavaModelException if the project doesn't exist.
1170 public PerProjectInfo getPerProjectInfoCheckExistence(IProject project) throws JavaModelException {
1171 JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /* don't create info */);
1173 if (!JavaProject.hasJavaNature(project)) {
1174 throw ((JavaProject)JavaCore.create(project)).newNotPresentException();
1176 info = getPerProjectInfo(project, true /* create info */);
1181 * Returns the per-working copy info for the given working copy at the given path.
1182 * If it doesn't exist and if create, add a new per-working copy info with the given problem requestor.
1183 * If recordUsage, increment the per-working copy info's use count.
1184 * Returns null if it doesn't exist and not create.
1186 public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy,boolean create, boolean recordUsage, IProblemRequestor problemRequestor) {
1187 synchronized(perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock
1188 WorkingCopyOwner owner = workingCopy.owner;
1189 Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner);
1190 if (workingCopyToInfos == null && create) {
1191 workingCopyToInfos = new HashMap();
1192 this.perWorkingCopyInfos.put(owner, workingCopyToInfos);
1195 PerWorkingCopyInfo info = workingCopyToInfos == null ? null : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy);
1196 if (info == null && create) {
1197 info= new PerWorkingCopyInfo(workingCopy, problemRequestor);
1198 workingCopyToInfos.put(workingCopy, info);
1200 if (info != null && recordUsage) info.useCount++;
1205 * Returns the name of the variables for which an CP variable initializer is registered through an extension point
1207 public static String[] getRegisteredVariableNames(){
1209 Plugin jdtCorePlugin = JavaCore.getPlugin();
1210 if (jdtCorePlugin == null) return null;
1212 ArrayList variableList = new ArrayList(5);
1213 // IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
1214 // if (extension != null) {
1215 // IExtension[] extensions = extension.getExtensions();
1216 // for(int i = 0; i < extensions.length; i++){
1217 // IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
1218 // for(int j = 0; j < configElements.length; j++){
1219 // String varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$
1220 // if (varAttribute != null) variableList.add(varAttribute);
1224 String[] variableNames = new String[variableList.size()];
1225 variableList.toArray(variableNames);
1226 return variableNames;
1230 * Returns the name of the container IDs for which an CP container initializer is registered through an extension point
1232 // public static String[] getRegisteredContainerIDs(){
1234 // Plugin jdtCorePlugin = PHPCore.getPlugin();
1235 // if (jdtCorePlugin == null) return null;
1237 // ArrayList containerIDList = new ArrayList(5);
1238 // IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
1239 // if (extension != null) {
1240 // IExtension[] extensions = extension.getExtensions();
1241 // for(int i = 0; i < extensions.length; i++){
1242 // IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
1243 // for(int j = 0; j < configElements.length; j++){
1244 // String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$
1245 // if (idAttribute != null) containerIDList.add(idAttribute);
1249 // String[] containerIDs = new String[containerIDList.size()];
1250 // containerIDList.toArray(containerIDs);
1251 // return containerIDs;
1255 * Returns the File to use for saving and restoring the last built state for the given project.
1257 private File getSerializationFile(IProject project) {
1258 if (!project.exists()) return null;
1259 IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
1260 return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
1264 * Returns the temporary cache for newly opened elements for the current thread.
1265 * Creates it if not already created.
1267 public HashMap getTemporaryCache() {
1268 HashMap result = (HashMap)this.temporaryCache.get();
1269 if (result == null) {
1270 result = new HashMap();
1271 this.temporaryCache.set(result);
1276 * Returns the open ZipFile at the given location. If the ZipFile
1277 * does not yet exist, it is created, opened, and added to the cache
1278 * of open ZipFiles. The location must be a absolute path.
1280 * @exception CoreException If unable to create/open the ZipFile
1282 public ZipFile getZipFile(IPath path) throws CoreException {
1284 synchronized(this.zipFiles) { // TODO: use PeThreadObject which does synchronization
1285 Thread currentThread = Thread.currentThread();
1288 if ((map = (HashMap)this.zipFiles.get(currentThread)) != null
1289 && (zipFile = (ZipFile)map.get(path)) != null) {
1293 String fileSystemPath= null;
1294 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
1295 IResource file = root.findMember(path);
1296 if (path.isAbsolute() && file != null) {
1297 if (file == null) { // external file
1298 fileSystemPath= path.toOSString();
1299 } else { // internal resource (not an IFile or not existing)
1301 if (file.getType() != IResource.FILE || (location = file.getLocation()) == null) {
1302 throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$
1304 fileSystemPath= location.toOSString();
1306 } else if (!path.isAbsolute()) {
1307 file= root.getFile(path);
1308 if (file == null || file.getType() != IResource.FILE) {
1309 throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$
1311 IPath location = file.getLocation();
1312 if (location == null) {
1313 throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$
1315 fileSystemPath= location.toOSString();
1317 fileSystemPath= path.toOSString();
1321 if (ZIP_ACCESS_VERBOSE) {
1322 System.out.println("(" + currentThread + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath ); //$NON-NLS-1$ //$NON-NLS-2$
1324 zipFile = new ZipFile(fileSystemPath);
1326 map.put(path, zipFile);
1329 } catch (IOException e) {
1330 throw new CoreException(new Status(Status.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("status.IOException"), e)); //$NON-NLS-1$
1335 * Returns whether there is a temporary cache for the current thread.
1337 public boolean hasTemporaryCache() {
1338 return this.temporaryCache.get() != null;
1340 // public void loadVariablesAndContainers() throws CoreException {
1342 // // backward compatibility, consider persistent property
1343 // QualifiedName qName = new QualifiedName(PHPCore.PLUGIN_ID, "variables"); //$NON-NLS-1$
1344 // String xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
1347 // if (xmlString != null){
1348 // StringReader reader = new StringReader(xmlString);
1349 // Element cpElement;
1351 // DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
1352 // cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
1353 // } catch(SAXException e) {
1355 // } catch(ParserConfigurationException e){
1360 // if (cpElement == null) return;
1361 // if (!cpElement.getNodeName().equalsIgnoreCase("variables")) { //$NON-NLS-1$
1365 // NodeList list= cpElement.getChildNodes();
1366 // int length= list.getLength();
1367 // for (int i= 0; i < length; ++i) {
1368 // Node node= list.item(i);
1369 // short type= node.getNodeType();
1370 // if (type == Node.ELEMENT_NODE) {
1371 // Element element= (Element) node;
1372 // if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$
1374 // element.getAttribute("name"), //$NON-NLS-1$
1375 // new Path(element.getAttribute("path"))); //$NON-NLS-1$
1380 // } catch(IOException e){
1382 // if (xmlString != null){
1383 // ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, null); // flush old one
1388 // // load variables and containers from preferences into cache
1389 // Preferences preferences = PHPeclipsePlugin.getDefault().getPluginPreferences();
1391 // // only get variable from preferences not set to their default
1392 // String[] propertyNames = preferences.propertyNames();
1393 // int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
1394 // for (int i = 0; i < propertyNames.length; i++){
1395 // String propertyName = propertyNames[i];
1396 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){
1397 // String varName = propertyName.substring(variablePrefixLength);
1398 // IPath varPath = new Path(preferences.getString(propertyName).trim());
1400 // Variables.put(varName, varPath);
1401 // PreviousSessionVariables.put(varName, varPath);
1403 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
1404 // recreatePersistedContainer(propertyName, preferences.getString(propertyName), true/*add to container values*/);
1407 // // override persisted values for variables which have a registered initializer
1408 // String[] registeredVariables = getRegisteredVariableNames();
1409 // for (int i = 0; i < registeredVariables.length; i++) {
1410 // String varName = registeredVariables[i];
1411 // Variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names.
1413 // // override persisted values for containers which have a registered initializer
1414 // String[] registeredContainerIDs = getRegisteredContainerIDs();
1415 // for (int i = 0; i < registeredContainerIDs.length; i++) {
1416 // String containerID = registeredContainerIDs[i];
1417 // Iterator projectIterator = Containers.keySet().iterator();
1418 // while (projectIterator.hasNext()){
1419 // IJavaProject project = (IJavaProject)projectIterator.next();
1420 // Map projectContainers = (Map)Containers.get(project);
1421 // if (projectContainers != null){
1422 // Iterator containerIterator = projectContainers.keySet().iterator();
1423 // while (containerIterator.hasNext()){
1424 // IPath containerPath = (IPath)containerIterator.next();
1425 // if (containerPath.segment(0).equals(containerID)) { // registered container
1426 // projectContainers.put(containerPath, null); // reset container value, but leave entry in Map
1435 * Merged all awaiting deltas.
1437 public IJavaElementDelta mergeDeltas(Collection deltas) {
1438 if (deltas.size() == 0) return null;
1439 if (deltas.size() == 1) return (IJavaElementDelta)deltas.iterator().next();
1441 if (DeltaProcessor.VERBOSE) {
1442 System.out.println("MERGING " + deltas.size() + " DELTAS ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1445 Iterator iterator = deltas.iterator();
1446 IJavaElement javaModel = this.getJavaModel();
1447 JavaElementDelta rootDelta = new JavaElementDelta(javaModel);
1448 boolean insertedTree = false;
1449 while (iterator.hasNext()) {
1450 JavaElementDelta delta = (JavaElementDelta)iterator.next();
1451 if (DeltaProcessor.VERBOSE) {
1452 System.out.println(delta.toString());
1454 IJavaElement element = delta.getElement();
1455 if (javaModel.equals(element)) {
1456 IJavaElementDelta[] children = delta.getAffectedChildren();
1457 for (int j = 0; j < children.length; j++) {
1458 JavaElementDelta projectDelta = (JavaElementDelta) children[j];
1459 rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta);
1460 insertedTree = true;
1462 IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
1463 if (resourceDeltas != null) {
1464 for (int i = 0, length = resourceDeltas.length; i < length; i++) {
1465 rootDelta.addResourceDelta(resourceDeltas[i]);
1466 insertedTree = true;
1470 rootDelta.insertDeltaTree(element, delta);
1471 insertedTree = true;
1483 * Returns the info for this element without
1484 * disturbing the cache ordering.
1485 */ // TODO: should be synchronized, could answer unitialized info or if cache is in middle of rehash, could even answer distinct element info
1486 protected Object peekAtInfo(IJavaElement element) {
1487 return this.cache.peekAtInfo(element);
1491 * @see ISaveParticipant
1493 public void prepareToSave(ISaveContext context) throws CoreException {
1496 protected void putInfo(IJavaElement element, Object info) {
1497 this.cache.putInfo(element, info);
1500 * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos)
1501 * in the Java model cache in an atomic way.
1502 * First checks that the info for the opened element (or one of its ancestors) has not been
1503 * added to the cache. If it is the case, another thread has opened the element (or one of
1504 * its ancestors). So returns without updating the cache.
1506 protected synchronized void putInfos(IJavaElement openedElement, Map newElements) {
1508 Object existingInfo = this.cache.peekAtInfo(openedElement);
1509 if (openedElement instanceof IParent && existingInfo instanceof JavaElementInfo) {
1510 IJavaElement[] children = ((JavaElementInfo)existingInfo).getChildren();
1511 for (int i = 0, size = children.length; i < size; ++i) {
1512 JavaElement child = (JavaElement) children[i];
1515 } catch (JavaModelException e) {
1521 Iterator iterator = newElements.keySet().iterator();
1522 while (iterator.hasNext()) {
1523 IJavaElement element = (IJavaElement)iterator.next();
1524 Object info = newElements.get(element);
1525 this.cache.putInfo(element, info);
1529 * Reads the build state for the relevant project.
1531 protected Object readState(IProject project) throws CoreException {
1532 File file = getSerializationFile(project);
1533 if (file != null && file.exists()) {
1535 DataInputStream in= new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
1537 String pluginID= in.readUTF();
1538 if (!pluginID.equals(JavaCore.PLUGIN_ID))
1539 throw new IOException(Util.bind("build.wrongFileFormat")); //$NON-NLS-1$
1540 String kind= in.readUTF();
1541 if (!kind.equals("STATE")) //$NON-NLS-1$
1542 throw new IOException(Util.bind("build.wrongFileFormat")); //$NON-NLS-1$
1543 if (in.readBoolean())
1544 return PHPBuilder.readState(project, in);
1545 if (PHPBuilder.DEBUG)
1546 System.out.println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$
1550 } catch (Exception e) {
1551 e.printStackTrace();
1552 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$
1558 // public static void recreatePersistedContainer(String propertyName, String containerString, boolean addToContainerValues) {
1559 // int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length();
1560 // int index = propertyName.indexOf('|', containerPrefixLength);
1561 // if (containerString != null) containerString = containerString.trim();
1563 // final String projectName = propertyName.substring(containerPrefixLength, index).trim();
1564 // JavaProject project = (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName);
1565 // final IPath containerPath = new Path(propertyName.substring(index+1).trim());
1567 // if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) {
1568 // containerPut(project, containerPath, null);
1570 // final IClasspathEntry[] containerEntries = project.decodeClasspath(containerString, false, false);
1571 // if (containerEntries != null && containerEntries != JavaProject.INVALID_CLASSPATH) {
1572 // IClasspathContainer container = new IClasspathContainer() {
1573 // public IClasspathEntry[] getClasspathEntries() {
1574 // return containerEntries;
1576 // public String getDescription() {
1577 // return "Persisted container ["+containerPath+" for project ["+ projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
1579 // public int getKind() {
1582 // public IPath getPath() {
1583 // return containerPath;
1585 // public String toString() {
1586 // return getDescription();
1590 // if (addToContainerValues) {
1591 // containerPut(project, containerPath, container);
1593 // Map projectContainers = (Map)PreviousSessionContainers.get(project);
1594 // if (projectContainers == null){
1595 // projectContainers = new HashMap(1);
1596 // PreviousSessionContainers.put(project, projectContainers);
1598 // projectContainers.put(containerPath, container);
1605 * Registers the given delta with this manager.
1607 protected void registerJavaModelDelta(IJavaElementDelta delta) {
1608 this.javaModelDeltas.add(delta);
1612 * Remembers the given scope in a weak set
1613 * (so no need to remove it: it will be removed by the garbage collector)
1615 // public void rememberScope(AbstractSearchScope scope) {
1616 // // NB: The value has to be null so as to not create a strong reference on the scope
1617 // this.scopes.put(scope, null);
1621 * removeElementChangedListener method comment.
1623 public void removeElementChangedListener(IElementChangedListener listener) {
1625 for (int i = 0; i < this.elementChangedListenerCount; i++){
1627 if (this.elementChangedListeners[i].equals(listener)){
1629 // need to clone defensively since we might be in the middle of listener notifications (#fire)
1630 int length = this.elementChangedListeners.length;
1631 IElementChangedListener[] newListeners = new IElementChangedListener[length];
1632 System.arraycopy(this.elementChangedListeners, 0, newListeners, 0, i);
1633 int[] newMasks = new int[length];
1634 System.arraycopy(this.elementChangedListenerMasks, 0, newMasks, 0, i);
1636 // copy trailing listeners
1637 int trailingLength = this.elementChangedListenerCount - i - 1;
1638 if (trailingLength > 0){
1639 System.arraycopy(this.elementChangedListeners, i+1, newListeners, i, trailingLength);
1640 System.arraycopy(this.elementChangedListenerMasks, i+1, newMasks, i, trailingLength);
1643 // update manager listener state (#fire need to iterate over original listeners through a local variable to hold onto
1644 // the original ones)
1645 this.elementChangedListeners = newListeners;
1646 this.elementChangedListenerMasks = newMasks;
1647 this.elementChangedListenerCount--;
1654 * Remembers the given scope in a weak set
1655 * (so no need to remove it: it will be removed by the garbage collector)
1657 // public void rememberScope(AbstractSearchScope scope) {
1658 // // NB: The value has to be null so as to not create a strong reference on the scope
1659 // this.searchScopes.put(scope, null);
1662 * Removes all cached info for the given element (including all children)
1664 * Returns the info for the given element, or null if it was closed.
1666 public synchronized Object removeInfoAndChildren(JavaElement element) throws JavaModelException {
1667 Object info = this.cache.peekAtInfo(element);
1669 boolean wasVerbose = false;
1672 System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
1676 element.closing(info);
1677 if (element instanceof IParent && info instanceof JavaElementInfo) {
1678 IJavaElement[] children = ((JavaElementInfo)info).getChildren();
1679 for (int i = 0, size = children.length; i < size; ++i) {
1680 JavaElement child = (JavaElement) children[i];
1684 this.cache.removeInfo(element);
1686 System.out.println("-> Package cache size = " + this.cache.pkgSize()); //$NON-NLS-1$
1687 System.out.println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(this.cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
1690 JavaModelManager.VERBOSE = wasVerbose;
1696 public void removePerProjectInfo(JavaProject javaProject) {
1697 synchronized(perProjectInfo) { // use the perProjectInfo collection as its own lock
1698 IProject project = javaProject.getProject();
1699 PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project);
1701 perProjectInfo.remove(project);
1706 * Resets the temporary cache for newly created elements to null.
1708 public void resetTemporaryCache() {
1709 this.temporaryCache.set(null);
1712 * @see ISaveParticipant
1714 public void rollback(ISaveContext context){
1717 private void saveState(PerProjectInfo info, ISaveContext context) throws CoreException {
1719 // passed this point, save actions are non trivial
1720 if (context.getKind() == ISaveContext.SNAPSHOT) return;
1723 if (info.triedRead) saveBuiltState(info);
1727 * Saves the built state for the project.
1729 private void saveBuiltState(PerProjectInfo info) throws CoreException {
1730 if (PHPBuilder.DEBUG)
1731 System.out.println(Util.bind("build.saveStateProgress", info.project.getName())); //$NON-NLS-1$
1732 File file = getSerializationFile(info.project);
1733 if (file == null) return;
1734 long t = System.currentTimeMillis();
1736 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
1738 out.writeUTF(JavaCore.PLUGIN_ID);
1739 out.writeUTF("STATE"); //$NON-NLS-1$
1740 if (info.savedState == null) {
1741 out.writeBoolean(false);
1743 out.writeBoolean(true);
1744 PHPBuilder.writeState(info.savedState, out);
1749 } catch (RuntimeException e) {
1750 try {file.delete();} catch(SecurityException se) {}
1751 throw new CoreException(
1752 new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR,
1753 Util.bind("build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
1754 } catch (IOException e) {
1755 try {file.delete();} catch(SecurityException se) {}
1756 throw new CoreException(
1757 new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR,
1758 Util.bind("build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
1760 if (PHPBuilder.DEBUG) {
1761 t = System.currentTimeMillis() - t;
1762 System.out.println(Util.bind("build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$
1765 private synchronized Map containerClone(IJavaProject project) {
1766 Map originalProjectContainers = (Map)this.containers.get(project);
1767 if (originalProjectContainers == null) return null;
1768 Map projectContainers = new HashMap(originalProjectContainers.size());
1769 projectContainers.putAll(originalProjectContainers);
1770 return projectContainers;
1773 * @see ISaveParticipant
1775 public void saving(ISaveContext context) throws CoreException {
1777 // save container values on snapshot/full save
1778 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
1779 IJavaProject[] projects = getJavaModel().getJavaProjects();
1780 for (int i = 0, length = projects.length; i < length; i++) {
1781 IJavaProject project = projects[i];
1782 // clone while iterating (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
1783 Map projectContainers = containerClone(project);
1784 if (projectContainers == null) continue;
1785 for (Iterator keys = projectContainers.keySet().iterator(); keys.hasNext();) {
1786 IPath containerPath = (IPath) keys.next();
1787 // IClasspathContainer container = (IClasspathContainer) projectContainers.get(containerPath);
1788 String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$
1789 String containerString = CP_ENTRY_IGNORE;
1791 // if (container != null) {
1792 // containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false);
1794 // } catch(JavaModelException e){
1795 // // could not encode entry: leave it as CP_ENTRY_IGNORE
1797 preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
1798 preferences.setValue(containerKey, containerString);
1801 JavaCore.getPlugin().savePluginPreferences();
1803 // if (context.getKind() == ISaveContext.FULL_SAVE) {
1804 // // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
1805 // context.needDelta();
1807 // // clean up indexes on workspace full save
1808 // // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
1809 // IndexManager manager = this.indexManager;
1810 // if (manager != null) {
1811 // manager.cleanUpIndexes();
1815 IProject savedProject = context.getProject();
1816 if (savedProject != null) {
1817 if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
1818 PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
1819 saveState(info, context);
1823 ArrayList vStats= null; // lazy initialized
1824 for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) {
1826 PerProjectInfo info = (PerProjectInfo) iter.next();
1827 saveState(info, context);
1828 } catch (CoreException e) {
1830 vStats= new ArrayList();
1831 vStats.add(e.getStatus());
1834 if (vStats != null) {
1835 IStatus[] stats= new IStatus[vStats.size()];
1836 vStats.toArray(stats);
1837 throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
1841 * @see ISaveParticipant
1843 // public void saving(ISaveContext context) throws CoreException {
1845 // IProject savedProject = context.getProject();
1846 // if (savedProject != null) {
1847 // if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
1848 // PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */);
1849 // saveState(info, context);
1853 // ArrayList vStats= null; // lazy initialized
1854 // for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) {
1856 // PerProjectInfo info = (PerProjectInfo) iter.next();
1857 // saveState(info, context);
1858 // } catch (CoreException e) {
1859 // if (vStats == null)
1860 // vStats= new ArrayList();
1861 // vStats.add(e.getStatus());
1864 // if (vStats != null) {
1865 // IStatus[] stats= new IStatus[vStats.size()];
1866 // vStats.toArray(stats);
1867 // throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
1872 * Record the order in which to build the java projects (batch build). This order is based
1873 * on the projects classpath settings.
1875 protected void setBuildOrder(String[] javaBuildOrder) throws JavaModelException {
1877 // optional behaviour
1878 // possible value of index 0 is Compute
1879 if (!JavaCore.COMPUTE.equals(JavaCore.getOption(JavaCore.CORE_JAVA_BUILD_ORDER))) return; // cannot be customized at project level
1881 if (javaBuildOrder == null || javaBuildOrder.length <= 1) return;
1883 IWorkspace workspace = ResourcesPlugin.getWorkspace();
1884 IWorkspaceDescription description = workspace.getDescription();
1885 String[] wksBuildOrder = description.getBuildOrder();
1888 if (wksBuildOrder == null){
1889 newOrder = javaBuildOrder;
1891 // remove projects which are already mentionned in java builder order
1892 int javaCount = javaBuildOrder.length;
1893 HashMap newSet = new HashMap(javaCount); // create a set for fast check
1894 for (int i = 0; i < javaCount; i++){
1895 newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
1898 int oldCount = wksBuildOrder.length;
1899 for (int i = 0; i < oldCount; i++){
1900 if (newSet.containsKey(wksBuildOrder[i])){
1901 wksBuildOrder[i] = null;
1905 // add Java ones first
1906 newOrder = new String[oldCount - removed + javaCount];
1907 System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first
1909 // copy previous items in their respective order
1910 int index = javaCount;
1911 for (int i = 0; i < oldCount; i++){
1912 if (wksBuildOrder[i] != null){
1913 newOrder[index++] = wksBuildOrder[i];
1917 // commit the new build order out
1918 description.setBuildOrder(newOrder);
1920 workspace.setDescription(description);
1921 } catch(CoreException e){
1922 throw new JavaModelException(e);
1927 * Sets the last built state for the given project, or null to reset it.
1929 public void setLastBuiltState(IProject project, Object state) {
1930 if (!JavaProject.hasJavaNature(project)) return; // should never be requested on non-Java projects
1931 PerProjectInfo info = getPerProjectInfo(project, true /*create if missing*/);
1932 info.triedRead = true; // no point trying to re-read once using setter
1933 info.savedState = state;
1934 if (state == null) { // delete state file to ensure a full build happens if the workspace crashes
1936 File file = getSerializationFile(project);
1937 if (file != null && file.exists())
1939 } catch(SecurityException se) {}
1943 public void shutdown () {
1945 // if (this.deltaProcessor.indexManager != null){ // no more indexing
1946 // this.deltaProcessor.indexManager.shutdown();
1949 IJavaModel model = this.getJavaModel();
1950 if (model != null) {
1954 } catch (JavaModelException e) {
1959 * Turns the firing mode to on. That is, deltas that are/have been
1960 * registered will be fired.
1962 public void startDeltas() {
1963 this.isFiring= true;
1967 * Turns the firing mode to off. That is, deltas that are/have been
1968 * registered will not be fired until deltas are started again.
1970 public void stopDeltas() {
1971 this.isFiring= false;
1975 * Update Java Model given some delta
1977 public void updateJavaModel(IJavaElementDelta customDelta) {
1979 if (customDelta == null){
1980 for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++){
1981 IJavaElementDelta delta = (IJavaElementDelta)this.javaModelDeltas.get(i);
1982 this.modelUpdater.processJavaDelta(delta);
1985 this.modelUpdater.processJavaDelta(customDelta);
1991 public static IPath variableGet(String variableName){
1992 return (IPath)Variables.get(variableName);
1995 public static String[] variableNames(){
1996 int length = Variables.size();
1997 String[] result = new String[length];
1998 Iterator vars = Variables.keySet().iterator();
2000 while (vars.hasNext()) {
2001 result[index++] = (String) vars.next();
2006 public static void variablePut(String variableName, IPath variablePath){
2008 // update cache - do not only rely on listener refresh
2009 if (variablePath == null) {
2010 Variables.remove(variableName);
2011 PreviousSessionVariables.remove(variableName);
2013 Variables.put(variableName, variablePath);
2016 // do not write out intermediate initialization value
2017 if (variablePath == JavaModelManager.VariableInitializationInProgress){
2020 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
2021 String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName;
2022 String variableString = variablePath == null ? CP_ENTRY_IGNORE : variablePath.toString();
2023 preferences.setDefault(variableKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones
2024 preferences.setValue(variableKey, variableString);
2025 JavaCore.getPlugin().savePluginPreferences();
2028 * Returns all the working copies which have the given owner.
2029 * Adds the working copies of the primary owner if specified.
2030 * Returns null if it has none.
2032 public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner, boolean addPrimary) {
2033 synchronized(perWorkingCopyInfos) {
2034 ICompilationUnit[] primaryWCs = addPrimary && owner != DefaultWorkingCopyOwner.PRIMARY
2035 ? getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false)
2037 Map workingCopyToInfos = (Map)perWorkingCopyInfos.get(owner);
2038 if (workingCopyToInfos == null) return primaryWCs;
2039 int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
2040 int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null
2041 ICompilationUnit[] result = new ICompilationUnit[primaryLength + size];
2042 if (primaryWCs != null) {
2043 System.arraycopy(primaryWCs, 0, result, 0, primaryLength);
2045 Iterator iterator = workingCopyToInfos.values().iterator();
2046 int index = primaryLength;
2047 while(iterator.hasNext()) {
2048 result[index++] = ((JavaModelManager.PerWorkingCopyInfo)iterator.next()).getWorkingCopy();
2055 * A HashSet that contains the IJavaProject whose classpath is being resolved.
2057 private ThreadLocal classpathsBeingResolved = new ThreadLocal();
2059 private HashSet getClasspathBeingResolved() {
2060 HashSet result = (HashSet) this.classpathsBeingResolved.get();
2061 if (result == null) {
2062 result = new HashSet();
2063 this.classpathsBeingResolved.set(result);
2067 public boolean isClasspathBeingResolved(IJavaProject project) {
2068 return getClasspathBeingResolved().contains(project);
2071 public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) {
2072 if (classpathIsResolved) {
2073 getClasspathBeingResolved().add(project);
2075 getClasspathBeingResolved().remove(project);