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.core.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.SafeRunner;
75 import org.eclipse.core.runtime.Status;
76 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
79 * The <code>JavaModelManager</code> manages instances of
80 * <code>IJavaModel</code>. <code>IElementChangedListener</code>s register
81 * with the <code>JavaModelManager</code>, and receive
82 * <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
84 * The single instance of <code>JavaModelManager</code> is available from the
85 * static method <code>JavaModelManager.getJavaModelManager()</code>.
87 public class JavaModelManager implements ISaveParticipant {
89 * Unique handle onto the JavaModel
91 final JavaModel javaModel = new JavaModel();
93 // public IndexManager indexManager = new IndexManager();
95 * Classpath variables pool
97 public static HashMap Variables = new HashMap(5);
99 public static HashMap PreviousSessionVariables = new HashMap(5);
101 public static HashSet OptionNames = new HashSet(20);
103 public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID
104 + ".classpathVariable."; //$NON-NLS-1$
106 public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID
107 + ".classpathContainer."; //$NON-NLS-1$
109 public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
112 * Classpath containers pool
114 public static HashMap containers = new HashMap(5);
116 public static HashMap PreviousSessionContainers = new HashMap(5);
119 * Name of the extension point for contributing classpath variable
122 // public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID =
123 // "classpathVariableInitializer" ; //$NON-NLS-1$
125 * Name of the extension point for contributing classpath container
128 // public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID =
129 // "classpathContainerInitializer" ; //$NON-NLS-1$
131 * Name of the extension point for contributing a source code formatter
133 public static final String FORMATTER_EXTPOINT_ID = "codeFormatter"; // $/**
136 * Value of the content-type for Java source files
138 public static final String JAVA_SOURCE_CONTENT_TYPE = PHPeclipsePlugin.PLUGIN_ID
139 + ".phpSource"; //$NON-NLS-1$NON-NLS-1$
142 * Special value used for recognizing ongoing initialization and breaking
143 * initialization cycles
145 public final static IPath VariableInitializationInProgress = new Path(
146 "Variable Initialization In Progress"); //$NON-NLS-1$
147 // public final static IClasspathContainer ContainerInitializationInProgress
148 // = new IClasspathContainer() {
149 // public IClasspathEntry[] getClasspathEntries() { return null; }
150 // public String getDescription() { return "Container Initialization In
151 // Progress"; } //$NON-NLS-1$
152 // public int getKind() { return 0; }
153 // public IPath getPath() { return null; }
154 // public String toString() { return getDescription(); }
157 private static final String INDEX_MANAGER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
158 + "/debug/indexmanager"; //$NON-NLS-1$
160 private static final String COMPILER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
161 + "/debug/compiler"; //$NON-NLS-1$
163 private static final String JAVAMODEL_DEBUG = PHPeclipsePlugin.PLUGIN_ID
164 + "/debug/javamodel"; //$NON-NLS-1$
166 private static final String CP_RESOLVE_DEBUG = PHPeclipsePlugin.PLUGIN_ID
167 + "/debug/cpresolution"; //$NON-NLS-1$
169 private static final String ZIP_ACCESS_DEBUG = PHPeclipsePlugin.PLUGIN_ID
170 + "/debug/zipaccess"; //$NON-NLS-1$
172 private static final String DELTA_DEBUG = PHPeclipsePlugin.PLUGIN_ID
173 + "/debug/javadelta"; //$NON-NLS-1$
175 private static final String HIERARCHY_DEBUG = PHPeclipsePlugin.PLUGIN_ID
176 + "/debug/hierarchy"; //$NON-NLS-1$
178 private static final String POST_ACTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
179 + "/debug/postaction"; //$NON-NLS-1$
181 private static final String BUILDER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
182 + "/debug/builder"; //$NON-NLS-1$
184 private static final String COMPLETION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
185 + "/debug/completion"; //$NON-NLS-1$
187 private static final String SELECTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
188 + "/debug/selection"; //$NON-NLS-1$
190 private static final String SHARED_WC_DEBUG = PHPeclipsePlugin.PLUGIN_ID
191 + "/debug/sharedworkingcopy"; //$NON-NLS-1$
193 private static final String SEARCH_DEBUG = PHPeclipsePlugin.PLUGIN_ID
194 + "/debug/search"; //$NON-NLS-1$
196 public final static IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0];
199 * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy
200 * handle) to PerWorkingCopyInfo. NOTE: this object itself is used as a lock
201 * to synchronize creation/removal of per working copy infos
203 protected Map perWorkingCopyInfos = new HashMap(5);
206 * Returns whether the given full path (for a package) conflicts with the
207 * output location of the given project.
209 public static boolean conflictsWithOutputLocation(IPath folderPath,
210 JavaProject project) {
212 IPath outputLocation = project.getOutputLocation();
213 if (outputLocation == null) {
214 // in doubt, there is a conflict
217 if (outputLocation.isPrefixOf(folderPath)) {
218 // only allow nesting in project's output if there is a
219 // corresponding source folder
220 // or if the project's output is not used (in other words, if
221 // all source folders have their custom output)
222 IClasspathEntry[] classpath = project
223 .getResolvedClasspath(true);
224 boolean isOutputUsed = false;
225 for (int i = 0, length = classpath.length; i < length; i++) {
226 IClasspathEntry entry = classpath[i];
227 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
228 if (entry.getPath().equals(outputLocation)) {
231 if (entry.getOutputLocation() == null) {
239 } catch (JavaModelException e) {
240 // in doubt, there is a conflict
245 // public static IClasspathContainer containerGet(IJavaProject project,
246 // IPath containerPath) {
247 // Map projectContainers = (Map)Containers.get(project);
248 // if (projectContainers == null){
251 // IClasspathContainer container =
252 // (IClasspathContainer)projectContainers.get(containerPath);
256 // public static void containerPut(IJavaProject project, IPath
257 // containerPath, IClasspathContainer container){
259 // Map projectContainers = (Map)Containers.get(project);
260 // if (projectContainers == null){
261 // projectContainers = new HashMap(1);
262 // Containers.put(project, projectContainers);
265 // if (container == null) {
266 // projectContainers.remove(containerPath);
267 // Map previousContainers = (Map)PreviousSessionContainers.get(project);
268 // if (previousContainers != null){
269 // previousContainers.remove(containerPath);
272 // projectContainers.put(containerPath, container);
275 // // do not write out intermediate initialization value
276 // if (container == JavaModelManager.ContainerInitializationInProgress) {
279 // Preferences preferences =
280 // PHPeclipsePlugin.getPlugin().getPluginPreferences();
281 // String containerKey =
282 // CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName()
283 // +"|"+containerPath;//$NON-NLS-1$
284 // String containerString = CP_ENTRY_IGNORE;
286 // if (container != null) {
288 // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(),
291 // } catch(JavaModelException e){
293 // preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this
294 // default to get rid of removed ones
295 // preferences.setValue(containerKey, containerString);
296 // PHPeclipsePlugin.getPlugin().savePluginPreferences();
300 * Returns the Java element corresponding to the given resource, or
301 * <code>null</code> if unable to associate the given resource with a Java
304 * The resource must be one of:
306 * <li>a project - the element returned is the corresponding
307 * <code>IJavaProject</code></li>
308 * <li>a <code>.java</code> file - the element returned is the
309 * corresponding <code>ICompilationUnit</code></li>
310 * <li>a <code>.class</code> file - the element returned is the
311 * corresponding <code>IClassFile</code></li>
312 * <li>a <code>.jar</code> file - the element returned is the
313 * corresponding <code>IPackageFragmentRoot</code></li>
314 * <li>a folder - the element returned is the corresponding
315 * <code>IPackageFragmentRoot</code> or <code>IPackageFragment</code></li>
316 * <li>the workspace root resource - the element returned is the
317 * <code>IJavaModel</code></li>
320 * Creating a Java element has the side effect of creating and opening all
321 * of the element's parents if they are not yet open.
323 public static IJavaElement create(IResource resource, IJavaProject project) {
324 if (resource == null) {
327 int type = resource.getType();
329 case IResource.PROJECT:
330 return JavaCore.create((IProject) resource);
332 return create((IFile) resource, project);
333 case IResource.FOLDER:
334 return create((IFolder) resource, project);
336 return JavaCore.create((IWorkspaceRoot) resource);
343 * Returns the Java element corresponding to the given file, its project
344 * being the given project. Returns <code>null</code> if unable to
345 * associate the given file with a Java element.
348 * The file must be one of:
350 * <li>a <code>.java</code> file - the element returned is the
351 * corresponding <code>ICompilationUnit</code></li>
352 * <li>a <code>.class</code> file - the element returned is the
353 * corresponding <code>IClassFile</code></li>
354 * <li>a <code>.jar</code> file - the element returned is the
355 * corresponding <code>IPackageFragmentRoot</code></li>
358 * Creating a Java element has the side effect of creating and opening all
359 * of the element's parents if they are not yet open.
361 public static IJavaElement create(IFile file, IJavaProject project) {
365 if (project == null) {
366 project = JavaCore.create(file.getProject());
369 if (file.getFileExtension() != null) {
370 String name = file.getName();
371 if (PHPFileUtil.isValidPHPUnitName(name))
372 // if (PHPFileUtil.isPHPFile(file))
373 return createCompilationUnitFrom(file, project);
374 // if (ProjectPrefUtil.isValidClassFileName(name))
375 // return createClassFileFrom(file, project);
376 // if (ProjectPrefUtil.isArchiveFileName(name))
377 // return createJarPackageFragmentRootFrom(file, project);
383 * Returns the package fragment or package fragment root corresponding to
384 * the given folder, its parent or great parent being the given project. or
385 * <code>null</code> if unable to associate the given folder with a Java
388 * Note that a package fragment root is returned rather than a default
391 * Creating a Java element has the side effect of creating and opening all
392 * of the element's parents if they are not yet open.
394 public static IJavaElement create(IFolder folder, IJavaProject project) {
395 if (folder == null) {
398 if (project == null) {
399 project = JavaCore.create(folder.getProject());
401 IJavaElement element = determineIfOnClasspath(folder, project);
402 if (conflictsWithOutputLocation(folder.getFullPath(),
403 (JavaProject) project)
404 || (folder.getName().indexOf('.') >= 0 && !(element instanceof IPackageFragmentRoot))) {
405 return null; // only package fragment roots are allowed with dot
413 * Creates and returns a class file element for the given
414 * <code>.class</code> file, its project being the given project. Returns
415 * <code>null</code> if unable to recognize the class file.
417 // public static IClassFile createClassFileFrom(IFile file, IJavaProject
419 // if (file == null) {
422 // if (project == null) {
423 // project = PHPCore.create(file.getProject());
425 // IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file,
427 // if (pkg == null) {
428 // // fix for 1FVS7WE
429 // // not on classpath - make the root its folder, and a default package
430 // IPackageFragmentRoot root =
431 // project.getPackageFragmentRoot(file.getParent());
432 // pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
434 // return pkg.getClassFile(file.getName());
437 * Creates and returns a compilation unit element for the given
438 * <code>.java</code> file, its project being the given project. Returns
439 * <code>null</code> if unable to recognize the compilation unit.
441 public static ICompilationUnit createCompilationUnitFrom(IFile file,
442 IJavaProject project) {
447 if (project == null) {
448 project = JavaCore.create(file.getProject());
450 IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file,
453 // not on classpath - make the root its folder, and a default
455 IPackageFragmentRoot root = project.getPackageFragmentRoot(file
458 .getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
462 .println("WARNING : creating unit element outside classpath (" + Thread.currentThread() + "): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
465 return pkg.getCompilationUnit(file.getName());
469 * Creates and returns a handle for the given JAR file, its project being
470 * the given project. The Java model associated with the JAR's project may
471 * be created as a side effect. Returns <code>null</code> if unable to
472 * create a JAR package fragment root. (for example, if the JAR file
473 * represents a non-Java resource)
475 // public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile
476 // file, IJavaProject project) {
477 // if (file == null) {
480 // if (project == null) {
481 // project = PHPCore.create(file.getProject());
484 // // Create a jar package fragment root only if on the classpath
485 // IPath resourcePath = file.getFullPath();
487 // IClasspathEntry[] entries =
488 // ((JavaProject)project).getResolvedClasspath(true);
489 // for (int i = 0, length = entries.length; i < length; i++) {
490 // IClasspathEntry entry = entries[i];
491 // IPath rootPath = entry.getPath();
492 // if (rootPath.equals(resourcePath)) {
493 // return project.getPackageFragmentRoot(file);
496 // } catch (JavaModelException e) {
501 * Returns the package fragment root represented by the resource, or the
502 * package fragment the given resource is located in, or <code>null</code>
503 * if the given resource is not on the classpath of the given project.
505 public static IJavaElement determineIfOnClasspath(IResource resource,
506 IJavaProject project) {
508 IPath resourcePath = resource.getFullPath();
510 IClasspathEntry[] entries = net.sourceforge.phpdt.internal.compiler.util.Util
511 .isJavaFileName(resourcePath.lastSegment()) ? project
512 .getRawClasspath() // JAVA file can only live inside SRC
513 // folder (on the raw path)
514 : ((JavaProject) project).getResolvedClasspath(true);
516 for (int i = 0; i < entries.length; i++) {
517 IClasspathEntry entry = entries[i];
518 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
520 IPath rootPath = entry.getPath();
521 if (rootPath.equals(resourcePath)) {
522 return project.getPackageFragmentRoot(resource);
523 } else if (rootPath.isPrefixOf(resourcePath)
524 && !Util.isExcluded(resource, null,
525 ((ClasspathEntry) entry)
526 .fullExclusionPatternChars())) {
527 // given we have a resource child of the root, it cannot be
529 IPackageFragmentRoot root = ((JavaProject) project)
530 .getFolderPackageFragmentRoot(rootPath);
533 IPath pkgPath = resourcePath.removeFirstSegments(rootPath
535 if (resource.getType() == IResource.FILE) {
536 // if the resource is a file, then remove the last
538 // is the file name in the package
539 pkgPath = pkgPath.removeLastSegments(1);
541 // don't check validity of package name (see
542 // http://bugs.eclipse.org/bugs/show_bug.cgi?id=26706)
543 // String pkgName = pkgPath.toString().replace('/',
545 String pkgName = pkgPath.toString();
546 return root.getPackageFragment(pkgName);
548 String pkgName = Util.packageName(pkgPath);
549 if (pkgName == null) {// ||
550 // JavaConventions.validatePackageName(pkgName).getSeverity()
551 // == IStatus.ERROR) {
554 return root.getPackageFragment(pkgName);
558 } catch (JavaModelException npe) {
565 * The singleton manager
567 private final static JavaModelManager Manager = new JavaModelManager();
572 protected JavaModelCache cache = new JavaModelCache();
575 * Temporary cache of newly opened elements
577 private ThreadLocal temporaryCache = new ThreadLocal();
580 * Set of elements which are out of sync with their buffers.
582 protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
585 * Holds the state used for delta processing.
587 public DeltaProcessingState deltaState = new DeltaProcessingState();
590 * Turns delta firing on/off. By default it is on.
592 private boolean isFiring = true;
595 * Queue of deltas created explicily by the Java Model that have yet to be
598 ArrayList javaModelDeltas = new ArrayList();
601 * Queue of reconcile deltas on working copies that have yet to be fired.
602 * This is a table form IWorkingCopy to IJavaElementDelta
604 HashMap reconcileDeltas = new HashMap();
607 * Collection of listeners for Java element deltas
609 private IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5];
611 private int[] elementChangedListenerMasks = new int[5];
613 private int elementChangedListenerCount = 0;
615 public int currentChangeEventType = ElementChangedEvent.PRE_AUTO_BUILD;
617 public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with
618 // ElementChangedEvent
622 * Used to convert <code>IResourceDelta</code>s into
623 * <code>IJavaElementDelta</code>s.
625 // public final DeltaProcessor deltaProcessor = new DeltaProcessor(this);
627 * Used to update the JavaModel for <code>IJavaElementDelta</code>s.
629 private final ModelUpdater modelUpdater = new ModelUpdater();
632 * Workaround for bug 15168 circular errors not reported This is a cache of
633 * the projects before any project addition/deletion has started.
635 public IJavaProject[] javaProjectsCache;
638 * Table from IProject to PerProjectInfo. NOTE: this object itself is used
639 * as a lock to synchronize creation/removal of per project infos
641 protected Map perProjectInfo = new HashMap(5);
644 * A map from ICompilationUnit to IWorkingCopy of the shared working copies.
646 public Map sharedWorkingCopies = new HashMap();
649 * A weak set of the known scopes.
651 protected WeakHashMap searchScopes = new WeakHashMap();
653 // public static class PerProjectInfo {
654 // public IProject project;
655 // public Object savedState;
656 // public boolean triedRead;
657 // public IClasspathEntry[] classpath;
658 // public IClasspathEntry[] lastResolvedClasspath;
659 // public Map resolvedPathToRawEntries; // reverse map from resolved path to
661 // public IPath outputLocation;
662 // public Preferences preferences;
663 // public PerProjectInfo(IProject project) {
665 // this.triedRead = false;
666 // this.savedState = null;
667 // this.project = project;
671 public static class PerProjectInfo {
673 public IProject project;
675 public Object savedState;
677 public boolean triedRead;
679 public IClasspathEntry[] rawClasspath;
681 public IClasspathEntry[] resolvedClasspath;
683 public Map resolvedPathToRawEntries; // reverse map from resolved
684 // path to raw entries
686 public IPath outputLocation;
688 public Preferences preferences;
690 public PerProjectInfo(IProject project) {
692 this.triedRead = false;
693 this.savedState = null;
694 this.project = project;
697 // updating raw classpath need to flush obsoleted cached information
698 // about resolved entries
699 public synchronized void updateClasspathInformation(
700 IClasspathEntry[] newRawClasspath) {
702 this.rawClasspath = newRawClasspath;
703 this.resolvedClasspath = null;
704 this.resolvedPathToRawEntries = null;
707 public String toString() {
708 StringBuffer buffer = new StringBuffer();
709 buffer.append("Info for "); //$NON-NLS-1$
710 buffer.append(this.project.getFullPath());
711 buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
712 if (this.rawClasspath == null) {
713 buffer.append(" <null>\n"); //$NON-NLS-1$
715 for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
716 buffer.append(" "); //$NON-NLS-1$
717 buffer.append(this.rawClasspath[i]);
721 buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
722 IClasspathEntry[] resolvedCP = this.resolvedClasspath;
723 if (resolvedCP == null) {
724 buffer.append(" <null>\n"); //$NON-NLS-1$
726 for (int i = 0, length = resolvedCP.length; i < length; i++) {
727 buffer.append(" "); //$NON-NLS-1$
728 buffer.append(resolvedCP[i]);
732 buffer.append("Output location:\n "); //$NON-NLS-1$
733 if (this.outputLocation == null) {
734 buffer.append("<null>"); //$NON-NLS-1$
736 buffer.append(this.outputLocation);
738 return buffer.toString();
742 public static class PerWorkingCopyInfo implements IProblemRequestor {
745 IProblemRequestor problemRequestor;
747 ICompilationUnit workingCopy;
749 public PerWorkingCopyInfo(ICompilationUnit workingCopy,
750 IProblemRequestor problemRequestor) {
751 this.workingCopy = workingCopy;
752 this.problemRequestor = problemRequestor;
755 public void acceptProblem(IProblem problem) {
756 if (this.problemRequestor == null)
758 this.problemRequestor.acceptProblem(problem);
761 public void beginReporting() {
762 if (this.problemRequestor == null)
764 this.problemRequestor.beginReporting();
767 public void endReporting() {
768 if (this.problemRequestor == null)
770 this.problemRequestor.endReporting();
773 public ICompilationUnit getWorkingCopy() {
774 return this.workingCopy;
777 public boolean isActive() {
778 return this.problemRequestor != null
779 && this.problemRequestor.isActive();
782 public String toString() {
783 StringBuffer buffer = new StringBuffer();
784 buffer.append("Info for "); //$NON-NLS-1$
785 buffer.append(((JavaElement) workingCopy).toStringWithAncestors());
786 buffer.append("\nUse count = "); //$NON-NLS-1$
787 buffer.append(this.useCount);
788 buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$
789 buffer.append(this.problemRequestor);
790 return buffer.toString();
794 public static boolean VERBOSE = false;
796 public static boolean CP_RESOLVE_VERBOSE = false;
798 public static boolean ZIP_ACCESS_VERBOSE = false;
801 * A cache of opened zip files per thread. (map from Thread to map of IPath
802 * to java.io.ZipFile) NOTE: this object itself is used as a lock to
803 * synchronize creation/removal of entries
805 private HashMap zipFiles = new HashMap();
808 * Update the classpath variable cache
810 public static class PluginPreferencesListener implements
811 Preferences.IPropertyChangeListener {
813 * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
815 public void propertyChange(Preferences.PropertyChangeEvent event) {
816 // TODO : jsurfer temp-del
817 // String propertyName = event.getProperty();
818 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
820 // propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
821 // String newValue = (String)event.getNewValue();
822 // if (newValue != null && !(newValue =
823 // newValue.trim()).equals(CP_ENTRY_IGNORE)) {
824 // Variables.put(varName, new Path(newValue));
826 // Variables.remove(varName);
829 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
830 // recreatePersistedContainer(propertyName,
831 // (String)event.getNewValue(), false);
837 * Line separator to use throughout the JavaModel for any source edit
840 public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
843 * Constructs a new JavaModelManager
845 private JavaModelManager() {
849 * @deprecated - discard once debug has converted to not using it
851 public void addElementChangedListener(IElementChangedListener listener) {
852 this.addElementChangedListener(listener,
853 ElementChangedEvent.POST_CHANGE
854 | ElementChangedEvent.POST_RECONCILE);
858 * addElementChangedListener method comment. Need to clone defensively the
859 * listener information, in case some listener is reacting to some
860 * notification iteration by adding/changing/removing any of the other (for
861 * example, if it deregisters itself).
863 public void addElementChangedListener(IElementChangedListener listener,
865 for (int i = 0; i < this.elementChangedListenerCount; i++) {
866 if (this.elementChangedListeners[i].equals(listener)) {
868 // only clone the masks, since we could be in the middle of
869 // notifications and one listener decide to change
870 // any event mask of another listeners (yet not notified).
871 int cloneLength = this.elementChangedListenerMasks.length;
874 this.elementChangedListenerMasks,
876 this.elementChangedListenerMasks = new int[cloneLength],
878 this.elementChangedListenerMasks[i] = eventMask; // could be
883 // may need to grow, no need to clone, since iterators will have cached
884 // original arrays and max boundary and we only add to the end.
886 if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount) {
889 this.elementChangedListeners,
891 this.elementChangedListeners = new IElementChangedListener[length * 2],
893 System.arraycopy(this.elementChangedListenerMasks, 0,
894 this.elementChangedListenerMasks = new int[length * 2], 0,
897 this.elementChangedListeners[this.elementChangedListenerCount] = listener;
898 this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask;
899 this.elementChangedListenerCount++;
903 * Starts caching ZipFiles. Ignores if there are already clients.
905 public void cacheZipFiles() {
906 synchronized (this.zipFiles) {
907 Thread currentThread = Thread.currentThread();
908 if (this.zipFiles.get(currentThread) != null)
910 this.zipFiles.put(currentThread, new HashMap());
914 public void closeZipFile(ZipFile zipFile) {
917 synchronized (this.zipFiles) {
918 if (this.zipFiles.get(Thread.currentThread()) != null) {
919 return; // zip file will be closed by call to flushZipFiles
922 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
924 .println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$
927 } catch (IOException e) {
933 * Configure the plugin with respect to option settings defined in
936 public void configurePluginDebugOptions() {
937 if (JavaCore.getPlugin().isDebugging()) {
938 // TODO jsurfer temp-del
940 String option = Platform.getDebugOption(BUILDER_DEBUG);
941 // if(option != null) JavaBuilder.DEBUG =
942 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
944 // option = Platform.getDebugOption(COMPILER_DEBUG);
945 // if(option != null) Compiler.DEBUG =
946 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
948 // option = Platform.getDebugOption(COMPLETION_DEBUG);
949 // if(option != null) CompletionEngine.DEBUG =
950 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
952 option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
954 JavaModelManager.CP_RESOLVE_VERBOSE = option
955 .equalsIgnoreCase("true"); //$NON-NLS-1$
957 option = Platform.getDebugOption(DELTA_DEBUG);
959 DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$
961 // option = Platform.getDebugOption(HIERARCHY_DEBUG);
962 // if(option != null) TypeHierarchy.DEBUG =
963 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
965 // option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
966 // if(option != null) IndexManager.VERBOSE =
967 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
969 option = Platform.getDebugOption(JAVAMODEL_DEBUG);
971 JavaModelManager.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$
973 option = Platform.getDebugOption(POST_ACTION_DEBUG);
975 JavaModelOperation.POST_ACTION_VERBOSE = option
976 .equalsIgnoreCase("true"); //$NON-NLS-1$
978 // option = Platform.getDebugOption(SEARCH_DEBUG);
979 // if(option != null) SearchEngine.VERBOSE =
980 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
982 // option = Platform.getDebugOption(SELECTION_DEBUG);
983 // if(option != null) SelectionEngine.DEBUG =
984 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
986 option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
988 JavaModelManager.ZIP_ACCESS_VERBOSE = option
989 .equalsIgnoreCase("true"); //$NON-NLS-1$
994 * Discards the per working copy info for the given working copy (making it
995 * a compilation unit) if its use count was 1. Otherwise, just decrement the
996 * use count. If the working copy is primary, computes the delta between its
997 * state and the original compilation unit and register it. Close the
998 * working copy, its buffer and remove it from the shared working copy
999 * table. Ignore if no per-working copy info existed. NOTE: it must be
1000 * synchronized as it may interact with the element info cache (if useCount
1001 * is decremented to 0), see bug 50667. Returns the new use count (or -1 if
1004 public synchronized int discardPerWorkingCopyInfo(
1005 CompilationUnit workingCopy) throws JavaModelException {
1006 synchronized (perWorkingCopyInfos) {
1007 WorkingCopyOwner owner = workingCopy.owner;
1008 Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner);
1009 if (workingCopyToInfos == null)
1012 PerWorkingCopyInfo info = (PerWorkingCopyInfo) workingCopyToInfos
1017 if (--info.useCount == 0) {
1018 // create the delta builder (this remembers the current content
1019 // of the working copy)
1020 JavaElementDeltaBuilder deltaBuilder = null;
1021 if (workingCopy.isPrimary()) {
1022 deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
1025 // remove per working copy info
1026 workingCopyToInfos.remove(workingCopy);
1027 if (workingCopyToInfos.isEmpty()) {
1028 this.perWorkingCopyInfos.remove(owner);
1031 // remove infos + close buffer (since no longer working copy)
1032 removeInfoAndChildren(workingCopy);
1033 workingCopy.closeBuffer();
1035 // compute the delta if needed and register it if there are
1037 if (deltaBuilder != null) {
1038 deltaBuilder.buildDeltas();
1039 if ((deltaBuilder.delta != null)
1040 && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
1041 getDeltaProcessor().registerJavaModelDelta(
1042 deltaBuilder.delta);
1047 return info.useCount;
1052 * @see ISaveParticipant
1054 public void doneSaving(ISaveContext context) {
1058 * Fire Java Model delta, flushing them after the fact after post_change
1059 * notification. If the firing mode has been turned off, this has no effect.
1061 public void fire(IJavaElementDelta customDelta, int eventType) {
1066 if (DeltaProcessor.VERBOSE
1067 && (eventType == DEFAULT_CHANGE_EVENT || eventType == ElementChangedEvent.PRE_AUTO_BUILD)) {
1069 .println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
1072 IJavaElementDelta deltaToNotify;
1073 if (customDelta == null) {
1074 deltaToNotify = this.mergeDeltas(this.javaModelDeltas);
1076 deltaToNotify = customDelta;
1079 // Refresh internal scopes
1080 if (deltaToNotify != null) {
1082 // Iterator scopes = this.scopes.keySet().iterator();
1083 // while (scopes.hasNext()) {
1084 // AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
1085 // scope.processDelta(deltaToNotify);
1091 // Important: if any listener reacts to notification by updating the
1092 // listeners list or mask, these lists will
1093 // be duplicated, so it is necessary to remember original lists in a
1094 // variable (since field values may change under us)
1095 IElementChangedListener[] listeners = this.elementChangedListeners;
1096 int[] listenerMask = this.elementChangedListenerMasks;
1097 int listenerCount = this.elementChangedListenerCount;
1099 switch (eventType) {
1100 case DEFAULT_CHANGE_EVENT:
1101 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask,
1103 firePostChangeDelta(deltaToNotify, listeners, listenerMask,
1105 fireReconcileDelta(listeners, listenerMask, listenerCount);
1107 case ElementChangedEvent.PRE_AUTO_BUILD:
1108 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask,
1111 case ElementChangedEvent.POST_CHANGE:
1112 firePostChangeDelta(deltaToNotify, listeners, listenerMask,
1114 fireReconcileDelta(listeners, listenerMask, listenerCount);
1120 private void firePreAutoBuildDelta(IJavaElementDelta deltaToNotify,
1121 IElementChangedListener[] listeners, int[] listenerMask,
1122 int listenerCount) {
1124 if (DeltaProcessor.VERBOSE) {
1126 .println("FIRING PRE_AUTO_BUILD Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1128 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1130 if (deltaToNotify != null) {
1131 notifyListeners(deltaToNotify, ElementChangedEvent.PRE_AUTO_BUILD,
1132 listeners, listenerMask, listenerCount);
1136 private void firePostChangeDelta(IJavaElementDelta deltaToNotify,
1137 IElementChangedListener[] listeners, int[] listenerMask,
1138 int listenerCount) {
1140 // post change deltas
1141 if (DeltaProcessor.VERBOSE) {
1143 .println("FIRING POST_CHANGE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1145 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1147 if (deltaToNotify != null) {
1148 // flush now so as to keep listener reactions to post their own
1149 // deltas for subsequent iteration
1152 notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE,
1153 listeners, listenerMask, listenerCount);
1157 private void fireReconcileDelta(IElementChangedListener[] listeners,
1158 int[] listenerMask, int listenerCount) {
1160 IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas
1162 if (DeltaProcessor.VERBOSE) {
1164 .println("FIRING POST_RECONCILE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1166 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1168 if (deltaToNotify != null) {
1169 // flush now so as to keep listener reactions to post their own
1170 // deltas for subsequent iteration
1171 this.reconcileDeltas = new HashMap();
1173 notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE,
1174 listeners, listenerMask, listenerCount);
1178 public void notifyListeners(IJavaElementDelta deltaToNotify, int eventType,
1179 IElementChangedListener[] listeners, int[] listenerMask,
1180 int listenerCount) {
1181 final ElementChangedEvent extraEvent = new ElementChangedEvent(
1182 deltaToNotify, eventType);
1183 for (int i = 0; i < listenerCount; i++) {
1184 if ((listenerMask[i] & eventType) != 0) {
1185 final IElementChangedListener listener = listeners[i];
1187 if (DeltaProcessor.VERBOSE) {
1189 .print("Listener #" + (i + 1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$
1190 start = System.currentTimeMillis();
1192 // wrap callbacks with Safe runnable for subsequent listeners to
1193 // be called when some are causing grief
1195 SafeRunner.run(new ISafeRunnable() {
1196 public void handleException(Throwable exception) {
1199 "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
1202 public void run() throws Exception {
1203 listener.elementChanged(extraEvent);
1206 if (DeltaProcessor.VERBOSE) {
1208 .println(" -> " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1215 * Flushes all deltas without firing them.
1217 protected void flush() {
1218 this.javaModelDeltas = new ArrayList();
1222 * Flushes ZipFiles cache if there are no more clients.
1224 public void flushZipFiles() {
1225 synchronized (this.zipFiles) {
1226 Thread currentThread = Thread.currentThread();
1227 HashMap map = (HashMap) this.zipFiles.remove(currentThread);
1230 Iterator iterator = map.values().iterator();
1231 while (iterator.hasNext()) {
1233 ZipFile zipFile = (ZipFile) iterator.next();
1234 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1236 .println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$
1239 } catch (IOException e) {
1245 public DeltaProcessor getDeltaProcessor() {
1246 return this.deltaState.getDeltaProcessor();
1250 * Returns the set of elements which are out of synch with their buffers.
1252 protected Map getElementsOutOfSynchWithBuffers() {
1253 return this.elementsOutOfSynchWithBuffers;
1256 // public IndexManager getIndexManager() {
1257 // return this.indexManager;
1260 * Returns the <code>IJavaElement</code> represented by the
1261 * <code>String</code> memento.
1263 public IJavaElement getHandleFromMemento(String memento)
1264 throws JavaModelException {
1265 if (memento == null) {
1268 JavaModel model = (JavaModel) getJavaModel();
1269 if (memento.equals("")) { // workspace memento //$NON-NLS-1$
1272 int modelEnd = memento.indexOf(JavaElement.JEM_JAVAPROJECT);
1273 if (modelEnd == -1) {
1276 boolean returnProject = false;
1277 int projectEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT,
1279 if (projectEnd == -1) {
1280 projectEnd = memento.length();
1281 returnProject = true;
1283 String projectName = memento.substring(modelEnd + 1, projectEnd);
1284 JavaProject proj = (JavaProject) model.getJavaProject(projectName);
1285 if (returnProject) {
1288 int rootEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT,
1291 // if (rootEnd == -1) {
1292 // return model.getHandleFromMementoForRoot(memento, proj, projectEnd,
1293 // memento.length());
1295 // IPackageFragmentRoot root =
1296 // model.getHandleFromMementoForRoot(memento, proj, projectEnd,
1298 // if (root == null)
1301 // int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd);
1303 // end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd);
1305 // if (rootEnd + 1 == memento.length()) {
1307 // root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
1309 // return root.getPackageFragment(memento.substring(rootEnd + 1));
1312 // //deal with class file and binary members
1313 // return model.getHandleFromMementoForBinaryMembers(memento, root,
1317 // //deal with compilation units and source members
1318 // return model.getHandleFromMementoForSourceMembers(memento, root,
1323 // public IndexManager getIndexManager() {
1324 // return this.deltaProcessor.indexManager;
1328 * Returns the info for the element.
1330 public Object getInfo(IJavaElement element) {
1331 return this.cache.getInfo(element);
1335 * Returns the handle to the active Java Model.
1337 public final JavaModel getJavaModel() {
1342 * Returns the singleton JavaModelManager
1344 public final static JavaModelManager getJavaModelManager() {
1349 * Returns the last built state for the given project, or null if there is
1350 * none. Deserializes the state if necessary.
1352 * For use by image builder and evaluation support only
1354 public Object getLastBuiltState(IProject project, IProgressMonitor monitor) {
1355 if (!JavaProject.hasJavaNature(project))
1356 return null; // should never be requested on non-Java projects
1357 PerProjectInfo info = getPerProjectInfo(project, true/*
1361 if (!info.triedRead) {
1362 info.triedRead = true;
1364 if (monitor != null)
1365 monitor.subTask(Util.bind(
1366 "build.readStateProgress", project.getName())); //$NON-NLS-1$
1367 info.savedState = readState(project);
1368 } catch (CoreException e) {
1369 e.printStackTrace();
1372 return info.savedState;
1376 * Returns the per-project info for the given project. If specified, create
1377 * the info if the info doesn't exist.
1379 public PerProjectInfo getPerProjectInfo(IProject project, boolean create) {
1380 synchronized (perProjectInfo) { // use the perProjectInfo collection as
1382 PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project);
1383 if (info == null && create) {
1384 info = new PerProjectInfo(project);
1385 perProjectInfo.put(project, info);
1392 * Returns the per-project info for the given project. If the info doesn't
1393 * exist, check for the project existence and create the info. @throws
1394 * JavaModelException if the project doesn't exist.
1396 public PerProjectInfo getPerProjectInfoCheckExistence(IProject project)
1397 throws JavaModelException {
1398 JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /*
1404 if (!JavaProject.hasJavaNature(project)) {
1405 throw ((JavaProject) JavaCore.create(project))
1406 .newNotPresentException();
1408 info = getPerProjectInfo(project, true /* create info */);
1414 * Returns the per-working copy info for the given working copy at the given
1415 * path. If it doesn't exist and if create, add a new per-working copy info
1416 * with the given problem requestor. If recordUsage, increment the
1417 * per-working copy info's use count. Returns null if it doesn't exist and
1420 public PerWorkingCopyInfo getPerWorkingCopyInfo(
1421 CompilationUnit workingCopy, boolean create, boolean recordUsage,
1422 IProblemRequestor problemRequestor) {
1423 synchronized (perWorkingCopyInfos) { // use the perWorkingCopyInfo
1424 // collection as its own lock
1425 WorkingCopyOwner owner = workingCopy.owner;
1426 Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner);
1427 if (workingCopyToInfos == null && create) {
1428 workingCopyToInfos = new HashMap();
1429 this.perWorkingCopyInfos.put(owner, workingCopyToInfos);
1432 PerWorkingCopyInfo info = workingCopyToInfos == null ? null
1433 : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy);
1434 if (info == null && create) {
1435 info = new PerWorkingCopyInfo(workingCopy, problemRequestor);
1436 workingCopyToInfos.put(workingCopy, info);
1438 if (info != null && recordUsage)
1445 * Returns the name of the variables for which an CP variable initializer is
1446 * registered through an extension point
1448 public static String[] getRegisteredVariableNames() {
1450 Plugin jdtCorePlugin = JavaCore.getPlugin();
1451 if (jdtCorePlugin == null)
1454 ArrayList variableList = new ArrayList(5);
1455 // IExtensionPoint extension =
1456 // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
1457 // if (extension != null) {
1458 // IExtension[] extensions = extension.getExtensions();
1459 // for(int i = 0; i < extensions.length; i++){
1460 // IConfigurationElement [] configElements =
1461 // extensions[i].getConfigurationElements();
1462 // for(int j = 0; j < configElements.length; j++){
1463 // String varAttribute = configElements[j].getAttribute("variable");
1465 // if (varAttribute != null) variableList.add(varAttribute);
1469 String[] variableNames = new String[variableList.size()];
1470 variableList.toArray(variableNames);
1471 return variableNames;
1475 * Returns the name of the container IDs for which an CP container
1476 * initializer is registered through an extension point
1478 // public static String[] getRegisteredContainerIDs(){
1480 // Plugin jdtCorePlugin = PHPCore.getPlugin();
1481 // if (jdtCorePlugin == null) return null;
1483 // ArrayList containerIDList = new ArrayList(5);
1484 // IExtensionPoint extension =
1485 // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
1486 // if (extension != null) {
1487 // IExtension[] extensions = extension.getExtensions();
1488 // for(int i = 0; i < extensions.length; i++){
1489 // IConfigurationElement [] configElements =
1490 // extensions[i].getConfigurationElements();
1491 // for(int j = 0; j < configElements.length; j++){
1492 // String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$
1493 // if (idAttribute != null) containerIDList.add(idAttribute);
1497 // String[] containerIDs = new String[containerIDList.size()];
1498 // containerIDList.toArray(containerIDs);
1499 // return containerIDs;
1502 * Returns the File to use for saving and restoring the last built state for
1503 * the given project.
1505 private File getSerializationFile(IProject project) {
1506 if (!project.exists())
1508 IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
1509 return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
1513 * Returns the temporary cache for newly opened elements for the current
1514 * thread. Creates it if not already created.
1516 public HashMap getTemporaryCache() {
1517 HashMap result = (HashMap) this.temporaryCache.get();
1518 if (result == null) {
1519 result = new HashMap();
1520 this.temporaryCache.set(result);
1526 * Returns the open ZipFile at the given location. If the ZipFile does not
1527 * yet exist, it is created, opened, and added to the cache of open
1528 * ZipFiles. The location must be a absolute path.
1530 * @exception CoreException
1531 * If unable to create/open the ZipFile
1533 public ZipFile getZipFile(IPath path) throws CoreException {
1535 synchronized (this.zipFiles) { // TODO: use PeThreadObject which does
1537 Thread currentThread = Thread.currentThread();
1540 if ((map = (HashMap) this.zipFiles.get(currentThread)) != null
1541 && (zipFile = (ZipFile) map.get(path)) != null) {
1545 String fileSystemPath = null;
1546 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
1547 IResource file = root.findMember(path);
1548 if (path.isAbsolute() && file != null) {
1549 if (file == null) { // external file
1550 fileSystemPath = path.toOSString();
1551 } else { // internal resource (not an IFile or not existing)
1553 if (file.getType() != IResource.FILE
1554 || (location = file.getFullPath()) == null) {
1555 throw new CoreException(
1562 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1564 fileSystemPath = location.toOSString();
1566 } else if (!path.isAbsolute()) {
1567 file = root.getFile(path);
1568 if (file == null || file.getType() != IResource.FILE) {
1569 throw new CoreException(new Status(IStatus.ERROR,
1570 JavaCore.PLUGIN_ID, -1, Util.bind(
1571 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1573 IPath location = file.getFullPath();
1574 if (location == null) {
1575 throw new CoreException(new Status(IStatus.ERROR,
1576 JavaCore.PLUGIN_ID, -1, Util.bind(
1577 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1579 fileSystemPath = location.toOSString();
1581 fileSystemPath = path.toOSString();
1585 if (ZIP_ACCESS_VERBOSE) {
1587 .println("(" + currentThread + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath); //$NON-NLS-1$ //$NON-NLS-2$
1589 zipFile = new ZipFile(fileSystemPath);
1591 map.put(path, zipFile);
1594 } catch (IOException e) {
1595 throw new CoreException(new Status(Status.ERROR,
1596 JavaCore.PLUGIN_ID, -1,
1597 Util.bind("status.IOException"), e)); //$NON-NLS-1$
1603 * Returns whether there is a temporary cache for the current thread.
1605 public boolean hasTemporaryCache() {
1606 return this.temporaryCache.get() != null;
1609 // public void loadVariablesAndContainers() throws CoreException {
1611 // // backward compatibility, consider persistent property
1612 // QualifiedName qName = new QualifiedName(PHPCore.PLUGIN_ID, "variables");
1614 // String xmlString =
1615 // ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
1618 // if (xmlString != null){
1619 // StringReader reader = new StringReader(xmlString);
1620 // Element cpElement;
1622 // DocumentBuilder parser =
1623 // DocumentBuilderFactory.newInstance().newDocumentBuilder();
1624 // cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
1625 // } catch(SAXException e) {
1627 // } catch(ParserConfigurationException e){
1632 // if (cpElement == null) return;
1633 // if (!cpElement.getNodeName().equalsIgnoreCase("variables")) {
1638 // NodeList list= cpElement.getChildNodes();
1639 // int length= list.getLength();
1640 // for (int i= 0; i < length; ++i) {
1641 // Node node= list.item(i);
1642 // short type= node.getNodeType();
1643 // if (type == Node.ELEMENT_NODE) {
1644 // Element element= (Element) node;
1645 // if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$
1647 // element.getAttribute("name"), //$NON-NLS-1$
1648 // new Path(element.getAttribute("path"))); //$NON-NLS-1$
1653 // } catch(IOException e){
1655 // if (xmlString != null){
1656 // ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName,
1657 // null); // flush old one
1662 // // load variables and containers from preferences into cache
1663 // Preferences preferences =
1664 // PHPeclipsePlugin.getDefault().getPluginPreferences();
1666 // // only get variable from preferences not set to their default
1667 // String[] propertyNames = preferences.propertyNames();
1668 // int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
1669 // for (int i = 0; i < propertyNames.length; i++){
1670 // String propertyName = propertyNames[i];
1671 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){
1672 // String varName = propertyName.substring(variablePrefixLength);
1673 // IPath varPath = new Path(preferences.getString(propertyName).trim());
1675 // Variables.put(varName, varPath);
1676 // PreviousSessionVariables.put(varName, varPath);
1678 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
1679 // recreatePersistedContainer(propertyName,
1680 // preferences.getString(propertyName), true/*add to container values*/);
1683 // // override persisted values for variables which have a registered
1685 // String[] registeredVariables = getRegisteredVariableNames();
1686 // for (int i = 0; i < registeredVariables.length; i++) {
1687 // String varName = registeredVariables[i];
1688 // Variables.put(varName, null); // reset variable, but leave its entry in
1689 // the Map, so it will be part of variable names.
1691 // // override persisted values for containers which have a registered
1693 // String[] registeredContainerIDs = getRegisteredContainerIDs();
1694 // for (int i = 0; i < registeredContainerIDs.length; i++) {
1695 // String containerID = registeredContainerIDs[i];
1696 // Iterator projectIterator = Containers.keySet().iterator();
1697 // while (projectIterator.hasNext()){
1698 // IJavaProject project = (IJavaProject)projectIterator.next();
1699 // Map projectContainers = (Map)Containers.get(project);
1700 // if (projectContainers != null){
1701 // Iterator containerIterator = projectContainers.keySet().iterator();
1702 // while (containerIterator.hasNext()){
1703 // IPath containerPath = (IPath)containerIterator.next();
1704 // if (containerPath.segment(0).equals(containerID)) { // registered
1706 // projectContainers.put(containerPath, null); // reset container value, but
1707 // leave entry in Map
1716 * Merged all awaiting deltas.
1718 public IJavaElementDelta mergeDeltas(Collection deltas) {
1719 if (deltas.size() == 0)
1721 if (deltas.size() == 1)
1722 return (IJavaElementDelta) deltas.iterator().next();
1724 if (DeltaProcessor.VERBOSE) {
1726 .println("MERGING " + deltas.size() + " DELTAS [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1729 Iterator iterator = deltas.iterator();
1730 IJavaElement javaModel = this.getJavaModel();
1731 JavaElementDelta rootDelta = new JavaElementDelta(javaModel);
1732 boolean insertedTree = false;
1733 while (iterator.hasNext()) {
1734 JavaElementDelta delta = (JavaElementDelta) iterator.next();
1735 if (DeltaProcessor.VERBOSE) {
1736 System.out.println(delta.toString());
1738 IJavaElement element = delta.getElement();
1739 if (javaModel.equals(element)) {
1740 IJavaElementDelta[] children = delta.getAffectedChildren();
1741 for (int j = 0; j < children.length; j++) {
1742 JavaElementDelta projectDelta = (JavaElementDelta) children[j];
1743 rootDelta.insertDeltaTree(projectDelta.getElement(),
1745 insertedTree = true;
1747 IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
1748 if (resourceDeltas != null) {
1749 for (int i = 0, length = resourceDeltas.length; i < length; i++) {
1750 rootDelta.addResourceDelta(resourceDeltas[i]);
1751 insertedTree = true;
1755 rootDelta.insertDeltaTree(element, delta);
1756 insertedTree = true;
1767 * Returns the info for this element without disturbing the cache ordering.
1769 // TODO: should be synchronized, could answer unitialized info or if cache
1770 // is in middle of rehash, could even answer distinct element info
1771 protected Object peekAtInfo(IJavaElement element) {
1772 return this.cache.peekAtInfo(element);
1776 * @see ISaveParticipant
1778 public void prepareToSave(ISaveContext context) throws CoreException {
1781 protected void putInfo(IJavaElement element, Object info) {
1782 this.cache.putInfo(element, info);
1786 * Puts the infos in the given map (keys are IJavaElements and values are
1787 * JavaElementInfos) in the Java model cache in an atomic way. First checks
1788 * that the info for the opened element (or one of its ancestors) has not
1789 * been added to the cache. If it is the case, another thread has opened the
1790 * element (or one of its ancestors). So returns without updating the cache.
1792 protected synchronized void putInfos(IJavaElement openedElement,
1795 Object existingInfo = this.cache.peekAtInfo(openedElement);
1796 if (openedElement instanceof IParent
1797 && existingInfo instanceof JavaElementInfo) {
1798 IJavaElement[] children = ((JavaElementInfo) existingInfo)
1800 for (int i = 0, size = children.length; i < size; ++i) {
1801 JavaElement child = (JavaElement) children[i];
1804 } catch (JavaModelException e) {
1810 Iterator iterator = newElements.keySet().iterator();
1811 while (iterator.hasNext()) {
1812 IJavaElement element = (IJavaElement) iterator.next();
1813 Object info = newElements.get(element);
1814 this.cache.putInfo(element, info);
1819 * Reads the build state for the relevant project.
1821 protected Object readState(IProject project) throws CoreException {
1822 File file = getSerializationFile(project);
1823 if (file != null && file.exists()) {
1825 DataInputStream in = new DataInputStream(
1826 new BufferedInputStream(new FileInputStream(file)));
1828 String pluginID = in.readUTF();
1829 if (!pluginID.equals(JavaCore.PLUGIN_ID))
1830 throw new IOException(Util
1831 .bind("build.wrongFileFormat")); //$NON-NLS-1$
1832 String kind = in.readUTF();
1833 if (!kind.equals("STATE")) //$NON-NLS-1$
1834 throw new IOException(Util
1835 .bind("build.wrongFileFormat")); //$NON-NLS-1$
1836 if (in.readBoolean())
1837 return PHPBuilder.readState(project, in);
1838 if (PHPBuilder.DEBUG)
1840 .println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$
1844 } catch (Exception e) {
1845 e.printStackTrace();
1846 throw new CoreException(
1850 Platform.PLUGIN_ERROR,
1851 "Error reading last build state for project " + project.getName(), e)); //$NON-NLS-1$
1857 // public static void recreatePersistedContainer(String propertyName, String
1858 // containerString, boolean addToContainerValues) {
1859 // int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length();
1860 // int index = propertyName.indexOf('|', containerPrefixLength);
1861 // if (containerString != null) containerString = containerString.trim();
1863 // final String projectName = propertyName.substring(containerPrefixLength,
1865 // JavaProject project =
1866 // (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName);
1867 // final IPath containerPath = new
1868 // Path(propertyName.substring(index+1).trim());
1870 // if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) {
1871 // containerPut(project, containerPath, null);
1873 // final IClasspathEntry[] containerEntries =
1874 // project.decodeClasspath(containerString, false, false);
1875 // if (containerEntries != null && containerEntries !=
1876 // JavaProject.INVALID_CLASSPATH) {
1877 // IClasspathContainer container = new IClasspathContainer() {
1878 // public IClasspathEntry[] getClasspathEntries() {
1879 // return containerEntries;
1881 // public String getDescription() {
1882 // return "Persisted container ["+containerPath+" for project ["+
1883 // projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
1885 // public int getKind() {
1888 // public IPath getPath() {
1889 // return containerPath;
1891 // public String toString() {
1892 // return getDescription();
1896 // if (addToContainerValues) {
1897 // containerPut(project, containerPath, container);
1899 // Map projectContainers = (Map)PreviousSessionContainers.get(project);
1900 // if (projectContainers == null){
1901 // projectContainers = new HashMap(1);
1902 // PreviousSessionContainers.put(project, projectContainers);
1904 // projectContainers.put(containerPath, container);
1911 * Registers the given delta with this manager.
1913 protected void registerJavaModelDelta(IJavaElementDelta delta) {
1914 this.javaModelDeltas.add(delta);
1918 * Remembers the given scope in a weak set (so no need to remove it: it will
1919 * be removed by the garbage collector)
1921 // public void rememberScope(AbstractSearchScope scope) {
1922 // // NB: The value has to be null so as to not create a strong reference on
1924 // this.scopes.put(scope, null);
1927 * removeElementChangedListener method comment.
1929 public void removeElementChangedListener(IElementChangedListener listener) {
1931 for (int i = 0; i < this.elementChangedListenerCount; i++) {
1933 if (this.elementChangedListeners[i].equals(listener)) {
1935 // need to clone defensively since we might be in the middle of
1936 // listener notifications (#fire)
1937 int length = this.elementChangedListeners.length;
1938 IElementChangedListener[] newListeners = new IElementChangedListener[length];
1939 System.arraycopy(this.elementChangedListeners, 0, newListeners,
1941 int[] newMasks = new int[length];
1942 System.arraycopy(this.elementChangedListenerMasks, 0, newMasks,
1945 // copy trailing listeners
1946 int trailingLength = this.elementChangedListenerCount - i - 1;
1947 if (trailingLength > 0) {
1948 System.arraycopy(this.elementChangedListeners, i + 1,
1949 newListeners, i, trailingLength);
1950 System.arraycopy(this.elementChangedListenerMasks, i + 1,
1951 newMasks, i, trailingLength);
1954 // update manager listener state (#fire need to iterate over
1955 // original listeners through a local variable to hold onto
1956 // the original ones)
1957 this.elementChangedListeners = newListeners;
1958 this.elementChangedListenerMasks = newMasks;
1959 this.elementChangedListenerCount--;
1966 * Remembers the given scope in a weak set (so no need to remove it: it will
1967 * be removed by the garbage collector)
1969 // public void rememberScope(AbstractSearchScope scope) {
1970 // // NB: The value has to be null so as to not create a strong reference on
1972 // this.searchScopes.put(scope, null);
1975 * Removes all cached info for the given element (including all children)
1976 * from the cache. Returns the info for the given element, or null if it was
1979 public synchronized Object removeInfoAndChildren(JavaElement element)
1980 throws JavaModelException {
1981 Object info = this.cache.peekAtInfo(element);
1983 boolean wasVerbose = false;
1987 .println("CLOSING Element (" + Thread.currentThread() + "): " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
1991 element.closing(info);
1992 if (element instanceof IParent
1993 && info instanceof JavaElementInfo) {
1994 IJavaElement[] children = ((JavaElementInfo) info)
1996 for (int i = 0, size = children.length; i < size; ++i) {
1997 JavaElement child = (JavaElement) children[i];
2001 this.cache.removeInfo(element);
2004 .println("-> Package cache size = " + this.cache.pkgSize()); //$NON-NLS-1$
2006 .println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(this.cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
2009 JavaModelManager.VERBOSE = wasVerbose;
2016 public void removePerProjectInfo(JavaProject javaProject) {
2017 synchronized (perProjectInfo) { // use the perProjectInfo collection as
2019 IProject project = javaProject.getProject();
2020 PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project);
2022 perProjectInfo.remove(project);
2028 * Resets the temporary cache for newly created elements to null.
2030 public void resetTemporaryCache() {
2031 this.temporaryCache.set(null);
2035 * @see ISaveParticipant
2037 public void rollback(ISaveContext context) {
2040 private void saveState(PerProjectInfo info, ISaveContext context)
2041 throws CoreException {
2043 // passed this point, save actions are non trivial
2044 if (context.getKind() == ISaveContext.SNAPSHOT)
2049 saveBuiltState(info);
2053 * Saves the built state for the project.
2055 private void saveBuiltState(PerProjectInfo info) throws CoreException {
2056 if (PHPBuilder.DEBUG)
2057 System.out.println(Util.bind(
2058 "build.saveStateProgress", info.project.getName())); //$NON-NLS-1$
2059 File file = getSerializationFile(info.project);
2062 long t = System.currentTimeMillis();
2064 DataOutputStream out = new DataOutputStream(
2065 new BufferedOutputStream(new FileOutputStream(file)));
2067 out.writeUTF(JavaCore.PLUGIN_ID);
2068 out.writeUTF("STATE"); //$NON-NLS-1$
2069 if (info.savedState == null) {
2070 out.writeBoolean(false);
2072 out.writeBoolean(true);
2073 PHPBuilder.writeState(info.savedState, out);
2078 } catch (RuntimeException e) {
2081 } catch (SecurityException se) {
2083 throw new CoreException(
2087 Platform.PLUGIN_ERROR,
2090 "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
2091 } catch (IOException e) {
2094 } catch (SecurityException se) {
2096 throw new CoreException(
2100 Platform.PLUGIN_ERROR,
2103 "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
2105 if (PHPBuilder.DEBUG) {
2106 t = System.currentTimeMillis() - t;
2107 System.out.println(Util.bind(
2108 "build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$
2112 private synchronized Map containerClone(IJavaProject project) {
2113 Map originalProjectContainers = (Map) JavaModelManager.containers.get(project);
2114 if (originalProjectContainers == null)
2116 Map projectContainers = new HashMap(originalProjectContainers.size());
2117 projectContainers.putAll(originalProjectContainers);
2118 return projectContainers;
2122 * @see ISaveParticipant
2124 public void saving(ISaveContext context) throws CoreException {
2126 // save container values on snapshot/full save
2127 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
2128 IJavaProject[] projects = getJavaModel().getJavaProjects();
2129 for (int i = 0, length = projects.length; i < length; i++) {
2130 IJavaProject project = projects[i];
2131 // clone while iterating (see
2132 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
2133 Map projectContainers = containerClone(project);
2134 if (projectContainers == null)
2136 for (Iterator keys = projectContainers.keySet().iterator(); keys
2138 IPath containerPath = (IPath) keys.next();
2139 // IClasspathContainer container = (IClasspathContainer)
2140 // projectContainers.get(containerPath);
2141 String containerKey = CP_CONTAINER_PREFERENCES_PREFIX
2142 + project.getElementName() + "|" + containerPath;//$NON-NLS-1$
2143 String containerString = CP_ENTRY_IGNORE;
2145 // if (container != null) {
2146 // containerString =
2147 // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(),
2150 // } catch(JavaModelException e){
2151 // // could not encode entry: leave it as CP_ENTRY_IGNORE
2153 preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use
2162 preferences.setValue(containerKey, containerString);
2165 JavaCore.getPlugin().savePluginPreferences();
2167 // if (context.getKind() == ISaveContext.FULL_SAVE) {
2168 // // will need delta since this save (see
2169 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
2170 // context.needDelta();
2172 // // clean up indexes on workspace full save
2173 // // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
2174 // IndexManager manager = this.indexManager;
2175 // if (manager != null) {
2176 // manager.cleanUpIndexes();
2180 IProject savedProject = context.getProject();
2181 if (savedProject != null) {
2182 if (!JavaProject.hasJavaNature(savedProject))
2184 PerProjectInfo info = getPerProjectInfo(savedProject, true /*
2188 saveState(info, context);
2192 ArrayList vStats = null; // lazy initialized
2193 for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) {
2195 PerProjectInfo info = (PerProjectInfo) iter.next();
2196 saveState(info, context);
2197 } catch (CoreException e) {
2199 vStats = new ArrayList();
2200 vStats.add(e.getStatus());
2203 if (vStats != null) {
2204 IStatus[] stats = new IStatus[vStats.size()];
2205 vStats.toArray(stats);
2206 throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID,
2207 IStatus.ERROR, stats,
2208 Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
2213 * @see ISaveParticipant
2215 // public void saving(ISaveContext context) throws CoreException {
2217 // IProject savedProject = context.getProject();
2218 // if (savedProject != null) {
2219 // if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
2220 // PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info
2222 // saveState(info, context);
2226 // ArrayList vStats= null; // lazy initialized
2227 // for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();)
2230 // PerProjectInfo info = (PerProjectInfo) iter.next();
2231 // saveState(info, context);
2232 // } catch (CoreException e) {
2233 // if (vStats == null)
2234 // vStats= new ArrayList();
2235 // vStats.add(e.getStatus());
2238 // if (vStats != null) {
2239 // IStatus[] stats= new IStatus[vStats.size()];
2240 // vStats.toArray(stats);
2241 // throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID,
2242 // IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null));
2247 * Record the order in which to build the java projects (batch build). This
2248 * order is based on the projects classpath settings.
2250 protected void setBuildOrder(String[] javaBuildOrder)
2251 throws JavaModelException {
2253 // optional behaviour
2254 // possible value of index 0 is Compute
2255 if (!JavaCore.COMPUTE.equals(JavaCore
2256 .getOption(JavaCore.CORE_JAVA_BUILD_ORDER)))
2257 return; // cannot be customized at project level
2259 if (javaBuildOrder == null || javaBuildOrder.length <= 1)
2262 IWorkspace workspace = ResourcesPlugin.getWorkspace();
2263 IWorkspaceDescription description = workspace.getDescription();
2264 String[] wksBuildOrder = description.getBuildOrder();
2267 if (wksBuildOrder == null) {
2268 newOrder = javaBuildOrder;
2270 // remove projects which are already mentionned in java builder
2272 int javaCount = javaBuildOrder.length;
2273 HashMap newSet = new HashMap(javaCount); // create a set for fast
2275 for (int i = 0; i < javaCount; i++) {
2276 newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
2279 int oldCount = wksBuildOrder.length;
2280 for (int i = 0; i < oldCount; i++) {
2281 if (newSet.containsKey(wksBuildOrder[i])) {
2282 wksBuildOrder[i] = null;
2286 // add Java ones first
2287 newOrder = new String[oldCount - removed + javaCount];
2288 System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java
2294 // copy previous items in their respective order
2295 int index = javaCount;
2296 for (int i = 0; i < oldCount; i++) {
2297 if (wksBuildOrder[i] != null) {
2298 newOrder[index++] = wksBuildOrder[i];
2302 // commit the new build order out
2303 description.setBuildOrder(newOrder);
2305 workspace.setDescription(description);
2306 } catch (CoreException e) {
2307 throw new JavaModelException(e);
2312 * Sets the last built state for the given project, or null to reset it.
2314 public void setLastBuiltState(IProject project, Object state) {
2315 if (!JavaProject.hasJavaNature(project))
2316 return; // should never be requested on non-Java projects
2317 PerProjectInfo info = getPerProjectInfo(project, true /*
2321 info.triedRead = true; // no point trying to re-read once using setter
2322 info.savedState = state;
2323 if (state == null) { // delete state file to ensure a full build
2324 // happens if the workspace crashes
2326 File file = getSerializationFile(project);
2327 if (file != null && file.exists())
2329 } catch (SecurityException se) {
2334 public void shutdown() {
2336 // if (this.deltaProcessor.indexManager != null){ // no more indexing
2337 // this.deltaProcessor.indexManager.shutdown();
2340 IJavaModel model = this.getJavaModel();
2341 if (model != null) {
2345 } catch (JavaModelException e) {
2350 * Turns the firing mode to on. That is, deltas that are/have been
2351 * registered will be fired.
2353 public void startDeltas() {
2354 this.isFiring = true;
2358 * Turns the firing mode to off. That is, deltas that are/have been
2359 * registered will not be fired until deltas are started again.
2361 public void stopDeltas() {
2362 this.isFiring = false;
2366 * Update Java Model given some delta
2368 public void updateJavaModel(IJavaElementDelta customDelta) {
2370 if (customDelta == null) {
2371 for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++) {
2372 IJavaElementDelta delta = (IJavaElementDelta) this.javaModelDeltas
2374 this.modelUpdater.processJavaDelta(delta);
2377 this.modelUpdater.processJavaDelta(customDelta);
2381 public static IPath variableGet(String variableName) {
2382 return (IPath) Variables.get(variableName);
2385 public static String[] variableNames() {
2386 int length = Variables.size();
2387 String[] result = new String[length];
2388 Iterator vars = Variables.keySet().iterator();
2390 while (vars.hasNext()) {
2391 result[index++] = (String) vars.next();
2396 public static void variablePut(String variableName, IPath variablePath) {
2398 // update cache - do not only rely on listener refresh
2399 if (variablePath == null) {
2400 Variables.remove(variableName);
2401 PreviousSessionVariables.remove(variableName);
2403 Variables.put(variableName, variablePath);
2406 // do not write out intermediate initialization value
2407 if (variablePath == JavaModelManager.VariableInitializationInProgress) {
2410 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
2411 String variableKey = CP_VARIABLE_PREFERENCES_PREFIX + variableName;
2412 String variableString = variablePath == null ? CP_ENTRY_IGNORE
2413 : variablePath.toString();
2414 preferences.setDefault(variableKey, CP_ENTRY_IGNORE); // use this
2418 preferences.setValue(variableKey, variableString);
2419 JavaCore.getPlugin().savePluginPreferences();
2423 * Returns all the working copies which have the given owner. Adds the
2424 * working copies of the primary owner if specified. Returns null if it has
2427 public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner,
2428 boolean addPrimary) {
2429 synchronized (perWorkingCopyInfos) {
2430 ICompilationUnit[] primaryWCs = addPrimary
2431 && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies(
2432 DefaultWorkingCopyOwner.PRIMARY, false)
2434 Map workingCopyToInfos = (Map) perWorkingCopyInfos.get(owner);
2435 if (workingCopyToInfos == null)
2437 int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
2438 int size = workingCopyToInfos.size(); // note size is > 0
2440 // pathToPerWorkingCopyInfos
2442 ICompilationUnit[] result = new ICompilationUnit[primaryLength
2444 if (primaryWCs != null) {
2445 System.arraycopy(primaryWCs, 0, result, 0, primaryLength);
2447 Iterator iterator = workingCopyToInfos.values().iterator();
2448 int index = primaryLength;
2449 while (iterator.hasNext()) {
2450 result[index++] = ((JavaModelManager.PerWorkingCopyInfo) iterator
2451 .next()).getWorkingCopy();
2458 * A HashSet that contains the IJavaProject whose classpath is being
2461 private ThreadLocal classpathsBeingResolved = new ThreadLocal();
2463 private HashSet getClasspathBeingResolved() {
2464 HashSet result = (HashSet) this.classpathsBeingResolved.get();
2465 if (result == null) {
2466 result = new HashSet();
2467 this.classpathsBeingResolved.set(result);
2472 public boolean isClasspathBeingResolved(IJavaProject project) {
2473 return getClasspathBeingResolved().contains(project);
2476 public void setClasspathBeingResolved(IJavaProject project,
2477 boolean classpathIsResolved) {
2478 if (classpathIsResolved) {
2479 getClasspathBeingResolved().add(project);
2481 getClasspathBeingResolved().remove(project);