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.Status;
75 import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
78 * The <code>JavaModelManager</code> manages instances of
79 * <code>IJavaModel</code>. <code>IElementChangedListener</code>s register
80 * with the <code>JavaModelManager</code>, and receive
81 * <code>ElementChangedEvent</code>s for all <code>IJavaModel</code>s.
83 * The single instance of <code>JavaModelManager</code> is available from the
84 * static method <code>JavaModelManager.getJavaModelManager()</code>.
86 public class JavaModelManager implements ISaveParticipant {
88 * Unique handle onto the JavaModel
90 final JavaModel javaModel = new JavaModel();
92 // public IndexManager indexManager = new IndexManager();
94 * Classpath variables pool
96 public static HashMap Variables = new HashMap(5);
98 public static HashMap PreviousSessionVariables = new HashMap(5);
100 public static HashSet OptionNames = new HashSet(20);
102 public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID
103 + ".classpathVariable."; //$NON-NLS-1$
105 public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID
106 + ".classpathContainer."; //$NON-NLS-1$
108 public final static String CP_ENTRY_IGNORE = "##<cp entry ignore>##"; //$NON-NLS-1$
111 * Classpath containers pool
113 public static HashMap containers = new HashMap(5);
115 public static HashMap PreviousSessionContainers = new HashMap(5);
118 * Name of the extension point for contributing classpath variable
121 // public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID =
122 // "classpathVariableInitializer" ; //$NON-NLS-1$
124 * Name of the extension point for contributing classpath container
127 // public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID =
128 // "classpathContainerInitializer" ; //$NON-NLS-1$
130 * Name of the extension point for contributing a source code formatter
132 public static final String FORMATTER_EXTPOINT_ID = "codeFormatter"; // $/**
135 * Value of the content-type for Java source files
137 public static final String JAVA_SOURCE_CONTENT_TYPE = PHPeclipsePlugin.PLUGIN_ID
138 + ".phpSource"; //$NON-NLS-1$NON-NLS-1$
141 * Special value used for recognizing ongoing initialization and breaking
142 * initialization cycles
144 public final static IPath VariableInitializationInProgress = new Path(
145 "Variable Initialization In Progress"); //$NON-NLS-1$
146 // public final static IClasspathContainer ContainerInitializationInProgress
147 // = new IClasspathContainer() {
148 // public IClasspathEntry[] getClasspathEntries() { return null; }
149 // public String getDescription() { return "Container Initialization In
150 // Progress"; } //$NON-NLS-1$
151 // public int getKind() { return 0; }
152 // public IPath getPath() { return null; }
153 // public String toString() { return getDescription(); }
156 private static final String INDEX_MANAGER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
157 + "/debug/indexmanager"; //$NON-NLS-1$
159 private static final String COMPILER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
160 + "/debug/compiler"; //$NON-NLS-1$
162 private static final String JAVAMODEL_DEBUG = PHPeclipsePlugin.PLUGIN_ID
163 + "/debug/javamodel"; //$NON-NLS-1$
165 private static final String CP_RESOLVE_DEBUG = PHPeclipsePlugin.PLUGIN_ID
166 + "/debug/cpresolution"; //$NON-NLS-1$
168 private static final String ZIP_ACCESS_DEBUG = PHPeclipsePlugin.PLUGIN_ID
169 + "/debug/zipaccess"; //$NON-NLS-1$
171 private static final String DELTA_DEBUG = PHPeclipsePlugin.PLUGIN_ID
172 + "/debug/javadelta"; //$NON-NLS-1$
174 private static final String HIERARCHY_DEBUG = PHPeclipsePlugin.PLUGIN_ID
175 + "/debug/hierarchy"; //$NON-NLS-1$
177 private static final String POST_ACTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
178 + "/debug/postaction"; //$NON-NLS-1$
180 private static final String BUILDER_DEBUG = PHPeclipsePlugin.PLUGIN_ID
181 + "/debug/builder"; //$NON-NLS-1$
183 private static final String COMPLETION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
184 + "/debug/completion"; //$NON-NLS-1$
186 private static final String SELECTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID
187 + "/debug/selection"; //$NON-NLS-1$
189 private static final String SHARED_WC_DEBUG = PHPeclipsePlugin.PLUGIN_ID
190 + "/debug/sharedworkingcopy"; //$NON-NLS-1$
192 private static final String SEARCH_DEBUG = PHPeclipsePlugin.PLUGIN_ID
193 + "/debug/search"; //$NON-NLS-1$
195 public final static IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0];
198 * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy
199 * handle) to PerWorkingCopyInfo. NOTE: this object itself is used as a lock
200 * to synchronize creation/removal of per working copy infos
202 protected Map perWorkingCopyInfos = new HashMap(5);
205 * Returns whether the given full path (for a package) conflicts with the
206 * output location of the given project.
208 public static boolean conflictsWithOutputLocation(IPath folderPath,
209 JavaProject project) {
211 IPath outputLocation = project.getOutputLocation();
212 if (outputLocation == null) {
213 // in doubt, there is a conflict
216 if (outputLocation.isPrefixOf(folderPath)) {
217 // only allow nesting in project's output if there is a
218 // corresponding source folder
219 // or if the project's output is not used (in other words, if
220 // all source folders have their custom output)
221 IClasspathEntry[] classpath = project
222 .getResolvedClasspath(true);
223 boolean isOutputUsed = false;
224 for (int i = 0, length = classpath.length; i < length; i++) {
225 IClasspathEntry entry = classpath[i];
226 if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
227 if (entry.getPath().equals(outputLocation)) {
230 if (entry.getOutputLocation() == null) {
238 } catch (JavaModelException e) {
239 // in doubt, there is a conflict
244 // public static IClasspathContainer containerGet(IJavaProject project,
245 // IPath containerPath) {
246 // Map projectContainers = (Map)Containers.get(project);
247 // if (projectContainers == null){
250 // IClasspathContainer container =
251 // (IClasspathContainer)projectContainers.get(containerPath);
255 // public static void containerPut(IJavaProject project, IPath
256 // containerPath, IClasspathContainer container){
258 // Map projectContainers = (Map)Containers.get(project);
259 // if (projectContainers == null){
260 // projectContainers = new HashMap(1);
261 // Containers.put(project, projectContainers);
264 // if (container == null) {
265 // projectContainers.remove(containerPath);
266 // Map previousContainers = (Map)PreviousSessionContainers.get(project);
267 // if (previousContainers != null){
268 // previousContainers.remove(containerPath);
271 // projectContainers.put(containerPath, container);
274 // // do not write out intermediate initialization value
275 // if (container == JavaModelManager.ContainerInitializationInProgress) {
278 // Preferences preferences =
279 // PHPeclipsePlugin.getPlugin().getPluginPreferences();
280 // String containerKey =
281 // CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName()
282 // +"|"+containerPath;//$NON-NLS-1$
283 // String containerString = CP_ENTRY_IGNORE;
285 // if (container != null) {
287 // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(),
290 // } catch(JavaModelException e){
292 // preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this
293 // default to get rid of removed ones
294 // preferences.setValue(containerKey, containerString);
295 // PHPeclipsePlugin.getPlugin().savePluginPreferences();
299 * Returns the Java element corresponding to the given resource, or
300 * <code>null</code> if unable to associate the given resource with a Java
303 * The resource must be one of:
305 * <li>a project - the element returned is the corresponding
306 * <code>IJavaProject</code></li>
307 * <li>a <code>.java</code> file - the element returned is the
308 * corresponding <code>ICompilationUnit</code></li>
309 * <li>a <code>.class</code> file - the element returned is the
310 * corresponding <code>IClassFile</code></li>
311 * <li>a <code>.jar</code> file - the element returned is the
312 * corresponding <code>IPackageFragmentRoot</code></li>
313 * <li>a folder - the element returned is the corresponding
314 * <code>IPackageFragmentRoot</code> or <code>IPackageFragment</code></li>
315 * <li>the workspace root resource - the element returned is the
316 * <code>IJavaModel</code></li>
319 * Creating a Java element has the side effect of creating and opening all
320 * of the element's parents if they are not yet open.
322 public static IJavaElement create(IResource resource, IJavaProject project) {
323 if (resource == null) {
326 int type = resource.getType();
328 case IResource.PROJECT:
329 return JavaCore.create((IProject) resource);
331 return create((IFile) resource, project);
332 case IResource.FOLDER:
333 return create((IFolder) resource, project);
335 return JavaCore.create((IWorkspaceRoot) resource);
342 * Returns the Java element corresponding to the given file, its project
343 * being the given project. Returns <code>null</code> if unable to
344 * associate the given file with a Java element.
347 * The file must be one of:
349 * <li>a <code>.java</code> file - the element returned is the
350 * corresponding <code>ICompilationUnit</code></li>
351 * <li>a <code>.class</code> file - the element returned is the
352 * corresponding <code>IClassFile</code></li>
353 * <li>a <code>.jar</code> file - the element returned is the
354 * corresponding <code>IPackageFragmentRoot</code></li>
357 * Creating a Java element has the side effect of creating and opening all
358 * of the element's parents if they are not yet open.
360 public static IJavaElement create(IFile file, IJavaProject project) {
364 if (project == null) {
365 project = JavaCore.create(file.getProject());
368 if (file.getFileExtension() != null) {
369 String name = file.getName();
370 if (PHPFileUtil.isValidPHPUnitName(name))
371 // if (PHPFileUtil.isPHPFile(file))
372 return createCompilationUnitFrom(file, project);
373 // if (ProjectPrefUtil.isValidClassFileName(name))
374 // return createClassFileFrom(file, project);
375 // if (ProjectPrefUtil.isArchiveFileName(name))
376 // return createJarPackageFragmentRootFrom(file, project);
382 * Returns the package fragment or package fragment root corresponding to
383 * the given folder, its parent or great parent being the given project. or
384 * <code>null</code> if unable to associate the given folder with a Java
387 * Note that a package fragment root is returned rather than a default
390 * Creating a Java element has the side effect of creating and opening all
391 * of the element's parents if they are not yet open.
393 public static IJavaElement create(IFolder folder, IJavaProject project) {
394 if (folder == null) {
397 if (project == null) {
398 project = JavaCore.create(folder.getProject());
400 IJavaElement element = determineIfOnClasspath(folder, project);
401 if (conflictsWithOutputLocation(folder.getFullPath(),
402 (JavaProject) project)
403 || (folder.getName().indexOf('.') >= 0 && !(element instanceof IPackageFragmentRoot))) {
404 return null; // only package fragment roots are allowed with dot
412 * Creates and returns a class file element for the given
413 * <code>.class</code> file, its project being the given project. Returns
414 * <code>null</code> if unable to recognize the class file.
416 // public static IClassFile createClassFileFrom(IFile file, IJavaProject
418 // if (file == null) {
421 // if (project == null) {
422 // project = PHPCore.create(file.getProject());
424 // IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file,
426 // if (pkg == null) {
427 // // fix for 1FVS7WE
428 // // not on classpath - make the root its folder, and a default package
429 // IPackageFragmentRoot root =
430 // project.getPackageFragmentRoot(file.getParent());
431 // pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
433 // return pkg.getClassFile(file.getName());
436 * Creates and returns a compilation unit element for the given
437 * <code>.java</code> file, its project being the given project. Returns
438 * <code>null</code> if unable to recognize the compilation unit.
440 public static ICompilationUnit createCompilationUnitFrom(IFile file,
441 IJavaProject project) {
446 if (project == null) {
447 project = JavaCore.create(file.getProject());
449 IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file,
452 // not on classpath - make the root its folder, and a default
454 IPackageFragmentRoot root = project.getPackageFragmentRoot(file
457 .getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
461 .println("WARNING : creating unit element outside classpath (" + Thread.currentThread() + "): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
464 return pkg.getCompilationUnit(file.getName());
468 * Creates and returns a handle for the given JAR file, its project being
469 * the given project. The Java model associated with the JAR's project may
470 * be created as a side effect. Returns <code>null</code> if unable to
471 * create a JAR package fragment root. (for example, if the JAR file
472 * represents a non-Java resource)
474 // public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile
475 // file, IJavaProject project) {
476 // if (file == null) {
479 // if (project == null) {
480 // project = PHPCore.create(file.getProject());
483 // // Create a jar package fragment root only if on the classpath
484 // IPath resourcePath = file.getFullPath();
486 // IClasspathEntry[] entries =
487 // ((JavaProject)project).getResolvedClasspath(true);
488 // for (int i = 0, length = entries.length; i < length; i++) {
489 // IClasspathEntry entry = entries[i];
490 // IPath rootPath = entry.getPath();
491 // if (rootPath.equals(resourcePath)) {
492 // return project.getPackageFragmentRoot(file);
495 // } catch (JavaModelException e) {
500 * Returns the package fragment root represented by the resource, or the
501 * package fragment the given resource is located in, or <code>null</code>
502 * if the given resource is not on the classpath of the given project.
504 public static IJavaElement determineIfOnClasspath(IResource resource,
505 IJavaProject project) {
507 IPath resourcePath = resource.getFullPath();
509 IClasspathEntry[] entries = net.sourceforge.phpdt.internal.compiler.util.Util
510 .isJavaFileName(resourcePath.lastSegment()) ? project
511 .getRawClasspath() // JAVA file can only live inside SRC
512 // folder (on the raw path)
513 : ((JavaProject) project).getResolvedClasspath(true);
515 for (int i = 0; i < entries.length; i++) {
516 IClasspathEntry entry = entries[i];
517 if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT)
519 IPath rootPath = entry.getPath();
520 if (rootPath.equals(resourcePath)) {
521 return project.getPackageFragmentRoot(resource);
522 } else if (rootPath.isPrefixOf(resourcePath)
523 && !Util.isExcluded(resource, null,
524 ((ClasspathEntry) entry)
525 .fullExclusionPatternChars())) {
526 // given we have a resource child of the root, it cannot be
528 IPackageFragmentRoot root = ((JavaProject) project)
529 .getFolderPackageFragmentRoot(rootPath);
532 IPath pkgPath = resourcePath.removeFirstSegments(rootPath
534 if (resource.getType() == IResource.FILE) {
535 // if the resource is a file, then remove the last
537 // is the file name in the package
538 pkgPath = pkgPath.removeLastSegments(1);
540 // don't check validity of package name (see
541 // http://bugs.eclipse.org/bugs/show_bug.cgi?id=26706)
542 // String pkgName = pkgPath.toString().replace('/',
544 String pkgName = pkgPath.toString();
545 return root.getPackageFragment(pkgName);
547 String pkgName = Util.packageName(pkgPath);
548 if (pkgName == null) {// ||
549 // JavaConventions.validatePackageName(pkgName).getSeverity()
550 // == IStatus.ERROR) {
553 return root.getPackageFragment(pkgName);
557 } catch (JavaModelException npe) {
564 * The singleton manager
566 private final static JavaModelManager Manager = new JavaModelManager();
571 protected JavaModelCache cache = new JavaModelCache();
574 * Temporary cache of newly opened elements
576 private ThreadLocal temporaryCache = new ThreadLocal();
579 * Set of elements which are out of sync with their buffers.
581 protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
584 * Holds the state used for delta processing.
586 public DeltaProcessingState deltaState = new DeltaProcessingState();
589 * Turns delta firing on/off. By default it is on.
591 private boolean isFiring = true;
594 * Queue of deltas created explicily by the Java Model that have yet to be
597 ArrayList javaModelDeltas = new ArrayList();
600 * Queue of reconcile deltas on working copies that have yet to be fired.
601 * This is a table form IWorkingCopy to IJavaElementDelta
603 HashMap reconcileDeltas = new HashMap();
606 * Collection of listeners for Java element deltas
608 private IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5];
610 private int[] elementChangedListenerMasks = new int[5];
612 private int elementChangedListenerCount = 0;
614 public int currentChangeEventType = ElementChangedEvent.PRE_AUTO_BUILD;
616 public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with
617 // ElementChangedEvent
621 * Used to convert <code>IResourceDelta</code>s into
622 * <code>IJavaElementDelta</code>s.
624 // public final DeltaProcessor deltaProcessor = new DeltaProcessor(this);
626 * Used to update the JavaModel for <code>IJavaElementDelta</code>s.
628 private final ModelUpdater modelUpdater = new ModelUpdater();
631 * Workaround for bug 15168 circular errors not reported This is a cache of
632 * the projects before any project addition/deletion has started.
634 public IJavaProject[] javaProjectsCache;
637 * Table from IProject to PerProjectInfo. NOTE: this object itself is used
638 * as a lock to synchronize creation/removal of per project infos
640 protected Map perProjectInfo = new HashMap(5);
643 * A map from ICompilationUnit to IWorkingCopy of the shared working copies.
645 public Map sharedWorkingCopies = new HashMap();
648 * A weak set of the known scopes.
650 protected WeakHashMap searchScopes = new WeakHashMap();
652 // public static class PerProjectInfo {
653 // public IProject project;
654 // public Object savedState;
655 // public boolean triedRead;
656 // public IClasspathEntry[] classpath;
657 // public IClasspathEntry[] lastResolvedClasspath;
658 // public Map resolvedPathToRawEntries; // reverse map from resolved path to
660 // public IPath outputLocation;
661 // public Preferences preferences;
662 // public PerProjectInfo(IProject project) {
664 // this.triedRead = false;
665 // this.savedState = null;
666 // this.project = project;
670 public static class PerProjectInfo {
672 public IProject project;
674 public Object savedState;
676 public boolean triedRead;
678 public IClasspathEntry[] rawClasspath;
680 public IClasspathEntry[] resolvedClasspath;
682 public Map resolvedPathToRawEntries; // reverse map from resolved
683 // path to raw entries
685 public IPath outputLocation;
687 public Preferences preferences;
689 public PerProjectInfo(IProject project) {
691 this.triedRead = false;
692 this.savedState = null;
693 this.project = project;
696 // updating raw classpath need to flush obsoleted cached information
697 // about resolved entries
698 public synchronized void updateClasspathInformation(
699 IClasspathEntry[] newRawClasspath) {
701 this.rawClasspath = newRawClasspath;
702 this.resolvedClasspath = null;
703 this.resolvedPathToRawEntries = null;
706 public String toString() {
707 StringBuffer buffer = new StringBuffer();
708 buffer.append("Info for "); //$NON-NLS-1$
709 buffer.append(this.project.getFullPath());
710 buffer.append("\nRaw classpath:\n"); //$NON-NLS-1$
711 if (this.rawClasspath == null) {
712 buffer.append(" <null>\n"); //$NON-NLS-1$
714 for (int i = 0, length = this.rawClasspath.length; i < length; i++) {
715 buffer.append(" "); //$NON-NLS-1$
716 buffer.append(this.rawClasspath[i]);
720 buffer.append("Resolved classpath:\n"); //$NON-NLS-1$
721 IClasspathEntry[] resolvedCP = this.resolvedClasspath;
722 if (resolvedCP == null) {
723 buffer.append(" <null>\n"); //$NON-NLS-1$
725 for (int i = 0, length = resolvedCP.length; i < length; i++) {
726 buffer.append(" "); //$NON-NLS-1$
727 buffer.append(resolvedCP[i]);
731 buffer.append("Output location:\n "); //$NON-NLS-1$
732 if (this.outputLocation == null) {
733 buffer.append("<null>"); //$NON-NLS-1$
735 buffer.append(this.outputLocation);
737 return buffer.toString();
741 public static class PerWorkingCopyInfo implements IProblemRequestor {
744 IProblemRequestor problemRequestor;
746 ICompilationUnit workingCopy;
748 public PerWorkingCopyInfo(ICompilationUnit workingCopy,
749 IProblemRequestor problemRequestor) {
750 this.workingCopy = workingCopy;
751 this.problemRequestor = problemRequestor;
754 public void acceptProblem(IProblem problem) {
755 if (this.problemRequestor == null)
757 this.problemRequestor.acceptProblem(problem);
760 public void beginReporting() {
761 if (this.problemRequestor == null)
763 this.problemRequestor.beginReporting();
766 public void endReporting() {
767 if (this.problemRequestor == null)
769 this.problemRequestor.endReporting();
772 public ICompilationUnit getWorkingCopy() {
773 return this.workingCopy;
776 public boolean isActive() {
777 return this.problemRequestor != null
778 && this.problemRequestor.isActive();
781 public String toString() {
782 StringBuffer buffer = new StringBuffer();
783 buffer.append("Info for "); //$NON-NLS-1$
784 buffer.append(((JavaElement) workingCopy).toStringWithAncestors());
785 buffer.append("\nUse count = "); //$NON-NLS-1$
786 buffer.append(this.useCount);
787 buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$
788 buffer.append(this.problemRequestor);
789 return buffer.toString();
793 public static boolean VERBOSE = false;
795 public static boolean CP_RESOLVE_VERBOSE = false;
797 public static boolean ZIP_ACCESS_VERBOSE = false;
800 * A cache of opened zip files per thread. (map from Thread to map of IPath
801 * to java.io.ZipFile) NOTE: this object itself is used as a lock to
802 * synchronize creation/removal of entries
804 private HashMap zipFiles = new HashMap();
807 * Update the classpath variable cache
809 public static class PluginPreferencesListener implements
810 Preferences.IPropertyChangeListener {
812 * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
814 public void propertyChange(Preferences.PropertyChangeEvent event) {
815 // TODO : jsurfer temp-del
816 // String propertyName = event.getProperty();
817 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) {
819 // propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length());
820 // String newValue = (String)event.getNewValue();
821 // if (newValue != null && !(newValue =
822 // newValue.trim()).equals(CP_ENTRY_IGNORE)) {
823 // Variables.put(varName, new Path(newValue));
825 // Variables.remove(varName);
828 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) {
829 // recreatePersistedContainer(propertyName,
830 // (String)event.getNewValue(), false);
836 * Line separator to use throughout the JavaModel for any source edit
839 public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$
842 * Constructs a new JavaModelManager
844 private JavaModelManager() {
848 * @deprecated - discard once debug has converted to not using it
850 public void addElementChangedListener(IElementChangedListener listener) {
851 this.addElementChangedListener(listener,
852 ElementChangedEvent.POST_CHANGE
853 | ElementChangedEvent.POST_RECONCILE);
857 * addElementChangedListener method comment. Need to clone defensively the
858 * listener information, in case some listener is reacting to some
859 * notification iteration by adding/changing/removing any of the other (for
860 * example, if it deregisters itself).
862 public void addElementChangedListener(IElementChangedListener listener,
864 for (int i = 0; i < this.elementChangedListenerCount; i++) {
865 if (this.elementChangedListeners[i].equals(listener)) {
867 // only clone the masks, since we could be in the middle of
868 // notifications and one listener decide to change
869 // any event mask of another listeners (yet not notified).
870 int cloneLength = this.elementChangedListenerMasks.length;
873 this.elementChangedListenerMasks,
875 this.elementChangedListenerMasks = new int[cloneLength],
877 this.elementChangedListenerMasks[i] = eventMask; // could be
882 // may need to grow, no need to clone, since iterators will have cached
883 // original arrays and max boundary and we only add to the end.
885 if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount) {
888 this.elementChangedListeners,
890 this.elementChangedListeners = new IElementChangedListener[length * 2],
892 System.arraycopy(this.elementChangedListenerMasks, 0,
893 this.elementChangedListenerMasks = new int[length * 2], 0,
896 this.elementChangedListeners[this.elementChangedListenerCount] = listener;
897 this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask;
898 this.elementChangedListenerCount++;
902 * Starts caching ZipFiles. Ignores if there are already clients.
904 public void cacheZipFiles() {
905 synchronized (this.zipFiles) {
906 Thread currentThread = Thread.currentThread();
907 if (this.zipFiles.get(currentThread) != null)
909 this.zipFiles.put(currentThread, new HashMap());
913 public void closeZipFile(ZipFile zipFile) {
916 synchronized (this.zipFiles) {
917 if (this.zipFiles.get(Thread.currentThread()) != null) {
918 return; // zip file will be closed by call to flushZipFiles
921 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
923 .println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$
926 } catch (IOException e) {
932 * Configure the plugin with respect to option settings defined in
935 public void configurePluginDebugOptions() {
936 if (JavaCore.getPlugin().isDebugging()) {
937 // TODO jsurfer temp-del
939 String option = Platform.getDebugOption(BUILDER_DEBUG);
940 // if(option != null) JavaBuilder.DEBUG =
941 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
943 // option = Platform.getDebugOption(COMPILER_DEBUG);
944 // if(option != null) Compiler.DEBUG =
945 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
947 // option = Platform.getDebugOption(COMPLETION_DEBUG);
948 // if(option != null) CompletionEngine.DEBUG =
949 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
951 option = Platform.getDebugOption(CP_RESOLVE_DEBUG);
953 JavaModelManager.CP_RESOLVE_VERBOSE = option
954 .equalsIgnoreCase("true"); //$NON-NLS-1$
956 option = Platform.getDebugOption(DELTA_DEBUG);
958 DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$
960 // option = Platform.getDebugOption(HIERARCHY_DEBUG);
961 // if(option != null) TypeHierarchy.DEBUG =
962 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
964 // option = Platform.getDebugOption(INDEX_MANAGER_DEBUG);
965 // if(option != null) IndexManager.VERBOSE =
966 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
968 option = Platform.getDebugOption(JAVAMODEL_DEBUG);
970 JavaModelManager.VERBOSE = option.equalsIgnoreCase("true"); //$NON-NLS-1$
972 option = Platform.getDebugOption(POST_ACTION_DEBUG);
974 JavaModelOperation.POST_ACTION_VERBOSE = option
975 .equalsIgnoreCase("true"); //$NON-NLS-1$
977 // option = Platform.getDebugOption(SEARCH_DEBUG);
978 // if(option != null) SearchEngine.VERBOSE =
979 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
981 // option = Platform.getDebugOption(SELECTION_DEBUG);
982 // if(option != null) SelectionEngine.DEBUG =
983 // option.equalsIgnoreCase("true") ; //$NON-NLS-1$
985 option = Platform.getDebugOption(ZIP_ACCESS_DEBUG);
987 JavaModelManager.ZIP_ACCESS_VERBOSE = option
988 .equalsIgnoreCase("true"); //$NON-NLS-1$
993 * Discards the per working copy info for the given working copy (making it
994 * a compilation unit) if its use count was 1. Otherwise, just decrement the
995 * use count. If the working copy is primary, computes the delta between its
996 * state and the original compilation unit and register it. Close the
997 * working copy, its buffer and remove it from the shared working copy
998 * table. Ignore if no per-working copy info existed. NOTE: it must be
999 * synchronized as it may interact with the element info cache (if useCount
1000 * is decremented to 0), see bug 50667. Returns the new use count (or -1 if
1003 public synchronized int discardPerWorkingCopyInfo(
1004 CompilationUnit workingCopy) throws JavaModelException {
1005 synchronized (perWorkingCopyInfos) {
1006 WorkingCopyOwner owner = workingCopy.owner;
1007 Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner);
1008 if (workingCopyToInfos == null)
1011 PerWorkingCopyInfo info = (PerWorkingCopyInfo) workingCopyToInfos
1016 if (--info.useCount == 0) {
1017 // create the delta builder (this remembers the current content
1018 // of the working copy)
1019 JavaElementDeltaBuilder deltaBuilder = null;
1020 if (workingCopy.isPrimary()) {
1021 deltaBuilder = new JavaElementDeltaBuilder(workingCopy);
1024 // remove per working copy info
1025 workingCopyToInfos.remove(workingCopy);
1026 if (workingCopyToInfos.isEmpty()) {
1027 this.perWorkingCopyInfos.remove(owner);
1030 // remove infos + close buffer (since no longer working copy)
1031 removeInfoAndChildren(workingCopy);
1032 workingCopy.closeBuffer();
1034 // compute the delta if needed and register it if there are
1036 if (deltaBuilder != null) {
1037 deltaBuilder.buildDeltas();
1038 if ((deltaBuilder.delta != null)
1039 && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
1040 getDeltaProcessor().registerJavaModelDelta(
1041 deltaBuilder.delta);
1046 return info.useCount;
1051 * @see ISaveParticipant
1053 public void doneSaving(ISaveContext context) {
1057 * Fire Java Model delta, flushing them after the fact after post_change
1058 * notification. If the firing mode has been turned off, this has no effect.
1060 public void fire(IJavaElementDelta customDelta, int eventType) {
1065 if (DeltaProcessor.VERBOSE
1066 && (eventType == DEFAULT_CHANGE_EVENT || eventType == ElementChangedEvent.PRE_AUTO_BUILD)) {
1068 .println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$
1071 IJavaElementDelta deltaToNotify;
1072 if (customDelta == null) {
1073 deltaToNotify = this.mergeDeltas(this.javaModelDeltas);
1075 deltaToNotify = customDelta;
1078 // Refresh internal scopes
1079 if (deltaToNotify != null) {
1081 // Iterator scopes = this.scopes.keySet().iterator();
1082 // while (scopes.hasNext()) {
1083 // AbstractSearchScope scope = (AbstractSearchScope)scopes.next();
1084 // scope.processDelta(deltaToNotify);
1090 // Important: if any listener reacts to notification by updating the
1091 // listeners list or mask, these lists will
1092 // be duplicated, so it is necessary to remember original lists in a
1093 // variable (since field values may change under us)
1094 IElementChangedListener[] listeners = this.elementChangedListeners;
1095 int[] listenerMask = this.elementChangedListenerMasks;
1096 int listenerCount = this.elementChangedListenerCount;
1098 switch (eventType) {
1099 case DEFAULT_CHANGE_EVENT:
1100 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask,
1102 firePostChangeDelta(deltaToNotify, listeners, listenerMask,
1104 fireReconcileDelta(listeners, listenerMask, listenerCount);
1106 case ElementChangedEvent.PRE_AUTO_BUILD:
1107 firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask,
1110 case ElementChangedEvent.POST_CHANGE:
1111 firePostChangeDelta(deltaToNotify, listeners, listenerMask,
1113 fireReconcileDelta(listeners, listenerMask, listenerCount);
1119 private void firePreAutoBuildDelta(IJavaElementDelta deltaToNotify,
1120 IElementChangedListener[] listeners, int[] listenerMask,
1121 int listenerCount) {
1123 if (DeltaProcessor.VERBOSE) {
1125 .println("FIRING PRE_AUTO_BUILD Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1127 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1129 if (deltaToNotify != null) {
1130 notifyListeners(deltaToNotify, ElementChangedEvent.PRE_AUTO_BUILD,
1131 listeners, listenerMask, listenerCount);
1135 private void firePostChangeDelta(IJavaElementDelta deltaToNotify,
1136 IElementChangedListener[] listeners, int[] listenerMask,
1137 int listenerCount) {
1139 // post change deltas
1140 if (DeltaProcessor.VERBOSE) {
1142 .println("FIRING POST_CHANGE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1144 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1146 if (deltaToNotify != null) {
1147 // flush now so as to keep listener reactions to post their own
1148 // deltas for subsequent iteration
1151 notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE,
1152 listeners, listenerMask, listenerCount);
1156 private void fireReconcileDelta(IElementChangedListener[] listeners,
1157 int[] listenerMask, int listenerCount) {
1159 IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas
1161 if (DeltaProcessor.VERBOSE) {
1163 .println("FIRING POST_RECONCILE Delta [" + Thread.currentThread() + "]:"); //$NON-NLS-1$//$NON-NLS-2$
1165 .println(deltaToNotify == null ? "<NONE>" : deltaToNotify.toString()); //$NON-NLS-1$
1167 if (deltaToNotify != null) {
1168 // flush now so as to keep listener reactions to post their own
1169 // deltas for subsequent iteration
1170 this.reconcileDeltas = new HashMap();
1172 notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE,
1173 listeners, listenerMask, listenerCount);
1177 public void notifyListeners(IJavaElementDelta deltaToNotify, int eventType,
1178 IElementChangedListener[] listeners, int[] listenerMask,
1179 int listenerCount) {
1180 final ElementChangedEvent extraEvent = new ElementChangedEvent(
1181 deltaToNotify, eventType);
1182 for (int i = 0; i < listenerCount; i++) {
1183 if ((listenerMask[i] & eventType) != 0) {
1184 final IElementChangedListener listener = listeners[i];
1186 if (DeltaProcessor.VERBOSE) {
1188 .print("Listener #" + (i + 1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$
1189 start = System.currentTimeMillis();
1191 // wrap callbacks with Safe runnable for subsequent listeners to
1192 // be called when some are causing grief
1193 Platform.run(new ISafeRunnable() {
1194 public void handleException(Throwable exception) {
1197 "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$
1200 public void run() throws Exception {
1201 listener.elementChanged(extraEvent);
1204 if (DeltaProcessor.VERBOSE) {
1206 .println(" -> " + (System.currentTimeMillis() - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
1213 * Flushes all deltas without firing them.
1215 protected void flush() {
1216 this.javaModelDeltas = new ArrayList();
1220 * Flushes ZipFiles cache if there are no more clients.
1222 public void flushZipFiles() {
1223 synchronized (this.zipFiles) {
1224 Thread currentThread = Thread.currentThread();
1225 HashMap map = (HashMap) this.zipFiles.remove(currentThread);
1228 Iterator iterator = map.values().iterator();
1229 while (iterator.hasNext()) {
1231 ZipFile zipFile = (ZipFile) iterator.next();
1232 if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
1234 .println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " + zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$
1237 } catch (IOException e) {
1243 public DeltaProcessor getDeltaProcessor() {
1244 return this.deltaState.getDeltaProcessor();
1248 * Returns the set of elements which are out of synch with their buffers.
1250 protected Map getElementsOutOfSynchWithBuffers() {
1251 return this.elementsOutOfSynchWithBuffers;
1254 // public IndexManager getIndexManager() {
1255 // return this.indexManager;
1258 * Returns the <code>IJavaElement</code> represented by the
1259 * <code>String</code> memento.
1261 public IJavaElement getHandleFromMemento(String memento)
1262 throws JavaModelException {
1263 if (memento == null) {
1266 JavaModel model = (JavaModel) getJavaModel();
1267 if (memento.equals("")) { // workspace memento //$NON-NLS-1$
1270 int modelEnd = memento.indexOf(JavaElement.JEM_JAVAPROJECT);
1271 if (modelEnd == -1) {
1274 boolean returnProject = false;
1275 int projectEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT,
1277 if (projectEnd == -1) {
1278 projectEnd = memento.length();
1279 returnProject = true;
1281 String projectName = memento.substring(modelEnd + 1, projectEnd);
1282 JavaProject proj = (JavaProject) model.getJavaProject(projectName);
1283 if (returnProject) {
1286 int rootEnd = memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT,
1289 // if (rootEnd == -1) {
1290 // return model.getHandleFromMementoForRoot(memento, proj, projectEnd,
1291 // memento.length());
1293 // IPackageFragmentRoot root =
1294 // model.getHandleFromMementoForRoot(memento, proj, projectEnd,
1296 // if (root == null)
1299 // int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd);
1301 // end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd);
1303 // if (rootEnd + 1 == memento.length()) {
1305 // root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME);
1307 // return root.getPackageFragment(memento.substring(rootEnd + 1));
1310 // //deal with class file and binary members
1311 // return model.getHandleFromMementoForBinaryMembers(memento, root,
1315 // //deal with compilation units and source members
1316 // return model.getHandleFromMementoForSourceMembers(memento, root,
1321 // public IndexManager getIndexManager() {
1322 // return this.deltaProcessor.indexManager;
1326 * Returns the info for the element.
1328 public Object getInfo(IJavaElement element) {
1329 return this.cache.getInfo(element);
1333 * Returns the handle to the active Java Model.
1335 public final JavaModel getJavaModel() {
1340 * Returns the singleton JavaModelManager
1342 public final static JavaModelManager getJavaModelManager() {
1347 * Returns the last built state for the given project, or null if there is
1348 * none. Deserializes the state if necessary.
1350 * For use by image builder and evaluation support only
1352 public Object getLastBuiltState(IProject project, IProgressMonitor monitor) {
1353 if (!JavaProject.hasJavaNature(project))
1354 return null; // should never be requested on non-Java projects
1355 PerProjectInfo info = getPerProjectInfo(project, true/*
1359 if (!info.triedRead) {
1360 info.triedRead = true;
1362 if (monitor != null)
1363 monitor.subTask(Util.bind(
1364 "build.readStateProgress", project.getName())); //$NON-NLS-1$
1365 info.savedState = readState(project);
1366 } catch (CoreException e) {
1367 e.printStackTrace();
1370 return info.savedState;
1374 * Returns the per-project info for the given project. If specified, create
1375 * the info if the info doesn't exist.
1377 public PerProjectInfo getPerProjectInfo(IProject project, boolean create) {
1378 synchronized (perProjectInfo) { // use the perProjectInfo collection as
1380 PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project);
1381 if (info == null && create) {
1382 info = new PerProjectInfo(project);
1383 perProjectInfo.put(project, info);
1390 * Returns the per-project info for the given project. If the info doesn't
1391 * exist, check for the project existence and create the info. @throws
1392 * JavaModelException if the project doesn't exist.
1394 public PerProjectInfo getPerProjectInfoCheckExistence(IProject project)
1395 throws JavaModelException {
1396 JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /*
1402 if (!JavaProject.hasJavaNature(project)) {
1403 throw ((JavaProject) JavaCore.create(project))
1404 .newNotPresentException();
1406 info = getPerProjectInfo(project, true /* create info */);
1412 * Returns the per-working copy info for the given working copy at the given
1413 * path. If it doesn't exist and if create, add a new per-working copy info
1414 * with the given problem requestor. If recordUsage, increment the
1415 * per-working copy info's use count. Returns null if it doesn't exist and
1418 public PerWorkingCopyInfo getPerWorkingCopyInfo(
1419 CompilationUnit workingCopy, boolean create, boolean recordUsage,
1420 IProblemRequestor problemRequestor) {
1421 synchronized (perWorkingCopyInfos) { // use the perWorkingCopyInfo
1422 // collection as its own lock
1423 WorkingCopyOwner owner = workingCopy.owner;
1424 Map workingCopyToInfos = (Map) this.perWorkingCopyInfos.get(owner);
1425 if (workingCopyToInfos == null && create) {
1426 workingCopyToInfos = new HashMap();
1427 this.perWorkingCopyInfos.put(owner, workingCopyToInfos);
1430 PerWorkingCopyInfo info = workingCopyToInfos == null ? null
1431 : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy);
1432 if (info == null && create) {
1433 info = new PerWorkingCopyInfo(workingCopy, problemRequestor);
1434 workingCopyToInfos.put(workingCopy, info);
1436 if (info != null && recordUsage)
1443 * Returns the name of the variables for which an CP variable initializer is
1444 * registered through an extension point
1446 public static String[] getRegisteredVariableNames() {
1448 Plugin jdtCorePlugin = JavaCore.getPlugin();
1449 if (jdtCorePlugin == null)
1452 ArrayList variableList = new ArrayList(5);
1453 // IExtensionPoint extension =
1454 // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID);
1455 // if (extension != null) {
1456 // IExtension[] extensions = extension.getExtensions();
1457 // for(int i = 0; i < extensions.length; i++){
1458 // IConfigurationElement [] configElements =
1459 // extensions[i].getConfigurationElements();
1460 // for(int j = 0; j < configElements.length; j++){
1461 // String varAttribute = configElements[j].getAttribute("variable");
1463 // if (varAttribute != null) variableList.add(varAttribute);
1467 String[] variableNames = new String[variableList.size()];
1468 variableList.toArray(variableNames);
1469 return variableNames;
1473 * Returns the name of the container IDs for which an CP container
1474 * initializer is registered through an extension point
1476 // public static String[] getRegisteredContainerIDs(){
1478 // Plugin jdtCorePlugin = PHPCore.getPlugin();
1479 // if (jdtCorePlugin == null) return null;
1481 // ArrayList containerIDList = new ArrayList(5);
1482 // IExtensionPoint extension =
1483 // jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID);
1484 // if (extension != null) {
1485 // IExtension[] extensions = extension.getExtensions();
1486 // for(int i = 0; i < extensions.length; i++){
1487 // IConfigurationElement [] configElements =
1488 // extensions[i].getConfigurationElements();
1489 // for(int j = 0; j < configElements.length; j++){
1490 // String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$
1491 // if (idAttribute != null) containerIDList.add(idAttribute);
1495 // String[] containerIDs = new String[containerIDList.size()];
1496 // containerIDList.toArray(containerIDs);
1497 // return containerIDs;
1500 * Returns the File to use for saving and restoring the last built state for
1501 * the given project.
1503 private File getSerializationFile(IProject project) {
1504 if (!project.exists())
1506 IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID);
1507 return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$
1511 * Returns the temporary cache for newly opened elements for the current
1512 * thread. Creates it if not already created.
1514 public HashMap getTemporaryCache() {
1515 HashMap result = (HashMap) this.temporaryCache.get();
1516 if (result == null) {
1517 result = new HashMap();
1518 this.temporaryCache.set(result);
1524 * Returns the open ZipFile at the given location. If the ZipFile does not
1525 * yet exist, it is created, opened, and added to the cache of open
1526 * ZipFiles. The location must be a absolute path.
1528 * @exception CoreException
1529 * If unable to create/open the ZipFile
1531 public ZipFile getZipFile(IPath path) throws CoreException {
1533 synchronized (this.zipFiles) { // TODO: use PeThreadObject which does
1535 Thread currentThread = Thread.currentThread();
1538 if ((map = (HashMap) this.zipFiles.get(currentThread)) != null
1539 && (zipFile = (ZipFile) map.get(path)) != null) {
1543 String fileSystemPath = null;
1544 IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
1545 IResource file = root.findMember(path);
1546 if (path.isAbsolute() && file != null) {
1547 if (file == null) { // external file
1548 fileSystemPath = path.toOSString();
1549 } else { // internal resource (not an IFile or not existing)
1551 if (file.getType() != IResource.FILE
1552 || (location = file.getFullPath()) == null) {
1553 throw new CoreException(
1560 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1562 fileSystemPath = location.toOSString();
1564 } else if (!path.isAbsolute()) {
1565 file = root.getFile(path);
1566 if (file == null || file.getType() != IResource.FILE) {
1567 throw new CoreException(new Status(IStatus.ERROR,
1568 JavaCore.PLUGIN_ID, -1, Util.bind(
1569 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1571 IPath location = file.getFullPath();
1572 if (location == null) {
1573 throw new CoreException(new Status(IStatus.ERROR,
1574 JavaCore.PLUGIN_ID, -1, Util.bind(
1575 "file.notFound", path.toString()), null)); //$NON-NLS-1$
1577 fileSystemPath = location.toOSString();
1579 fileSystemPath = path.toOSString();
1583 if (ZIP_ACCESS_VERBOSE) {
1585 .println("(" + currentThread + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath); //$NON-NLS-1$ //$NON-NLS-2$
1587 zipFile = new ZipFile(fileSystemPath);
1589 map.put(path, zipFile);
1592 } catch (IOException e) {
1593 throw new CoreException(new Status(Status.ERROR,
1594 JavaCore.PLUGIN_ID, -1,
1595 Util.bind("status.IOException"), e)); //$NON-NLS-1$
1601 * Returns whether there is a temporary cache for the current thread.
1603 public boolean hasTemporaryCache() {
1604 return this.temporaryCache.get() != null;
1607 // public void loadVariablesAndContainers() throws CoreException {
1609 // // backward compatibility, consider persistent property
1610 // QualifiedName qName = new QualifiedName(PHPCore.PLUGIN_ID, "variables");
1612 // String xmlString =
1613 // ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName);
1616 // if (xmlString != null){
1617 // StringReader reader = new StringReader(xmlString);
1618 // Element cpElement;
1620 // DocumentBuilder parser =
1621 // DocumentBuilderFactory.newInstance().newDocumentBuilder();
1622 // cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
1623 // } catch(SAXException e) {
1625 // } catch(ParserConfigurationException e){
1630 // if (cpElement == null) return;
1631 // if (!cpElement.getNodeName().equalsIgnoreCase("variables")) {
1636 // NodeList list= cpElement.getChildNodes();
1637 // int length= list.getLength();
1638 // for (int i= 0; i < length; ++i) {
1639 // Node node= list.item(i);
1640 // short type= node.getNodeType();
1641 // if (type == Node.ELEMENT_NODE) {
1642 // Element element= (Element) node;
1643 // if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$
1645 // element.getAttribute("name"), //$NON-NLS-1$
1646 // new Path(element.getAttribute("path"))); //$NON-NLS-1$
1651 // } catch(IOException e){
1653 // if (xmlString != null){
1654 // ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName,
1655 // null); // flush old one
1660 // // load variables and containers from preferences into cache
1661 // Preferences preferences =
1662 // PHPeclipsePlugin.getDefault().getPluginPreferences();
1664 // // only get variable from preferences not set to their default
1665 // String[] propertyNames = preferences.propertyNames();
1666 // int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length();
1667 // for (int i = 0; i < propertyNames.length; i++){
1668 // String propertyName = propertyNames[i];
1669 // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){
1670 // String varName = propertyName.substring(variablePrefixLength);
1671 // IPath varPath = new Path(preferences.getString(propertyName).trim());
1673 // Variables.put(varName, varPath);
1674 // PreviousSessionVariables.put(varName, varPath);
1676 // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){
1677 // recreatePersistedContainer(propertyName,
1678 // preferences.getString(propertyName), true/*add to container values*/);
1681 // // override persisted values for variables which have a registered
1683 // String[] registeredVariables = getRegisteredVariableNames();
1684 // for (int i = 0; i < registeredVariables.length; i++) {
1685 // String varName = registeredVariables[i];
1686 // Variables.put(varName, null); // reset variable, but leave its entry in
1687 // the Map, so it will be part of variable names.
1689 // // override persisted values for containers which have a registered
1691 // String[] registeredContainerIDs = getRegisteredContainerIDs();
1692 // for (int i = 0; i < registeredContainerIDs.length; i++) {
1693 // String containerID = registeredContainerIDs[i];
1694 // Iterator projectIterator = Containers.keySet().iterator();
1695 // while (projectIterator.hasNext()){
1696 // IJavaProject project = (IJavaProject)projectIterator.next();
1697 // Map projectContainers = (Map)Containers.get(project);
1698 // if (projectContainers != null){
1699 // Iterator containerIterator = projectContainers.keySet().iterator();
1700 // while (containerIterator.hasNext()){
1701 // IPath containerPath = (IPath)containerIterator.next();
1702 // if (containerPath.segment(0).equals(containerID)) { // registered
1704 // projectContainers.put(containerPath, null); // reset container value, but
1705 // leave entry in Map
1714 * Merged all awaiting deltas.
1716 public IJavaElementDelta mergeDeltas(Collection deltas) {
1717 if (deltas.size() == 0)
1719 if (deltas.size() == 1)
1720 return (IJavaElementDelta) deltas.iterator().next();
1722 if (DeltaProcessor.VERBOSE) {
1724 .println("MERGING " + deltas.size() + " DELTAS [" + Thread.currentThread() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1727 Iterator iterator = deltas.iterator();
1728 IJavaElement javaModel = this.getJavaModel();
1729 JavaElementDelta rootDelta = new JavaElementDelta(javaModel);
1730 boolean insertedTree = false;
1731 while (iterator.hasNext()) {
1732 JavaElementDelta delta = (JavaElementDelta) iterator.next();
1733 if (DeltaProcessor.VERBOSE) {
1734 System.out.println(delta.toString());
1736 IJavaElement element = delta.getElement();
1737 if (javaModel.equals(element)) {
1738 IJavaElementDelta[] children = delta.getAffectedChildren();
1739 for (int j = 0; j < children.length; j++) {
1740 JavaElementDelta projectDelta = (JavaElementDelta) children[j];
1741 rootDelta.insertDeltaTree(projectDelta.getElement(),
1743 insertedTree = true;
1745 IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
1746 if (resourceDeltas != null) {
1747 for (int i = 0, length = resourceDeltas.length; i < length; i++) {
1748 rootDelta.addResourceDelta(resourceDeltas[i]);
1749 insertedTree = true;
1753 rootDelta.insertDeltaTree(element, delta);
1754 insertedTree = true;
1765 * Returns the info for this element without disturbing the cache ordering.
1767 // TODO: should be synchronized, could answer unitialized info or if cache
1768 // is in middle of rehash, could even answer distinct element info
1769 protected Object peekAtInfo(IJavaElement element) {
1770 return this.cache.peekAtInfo(element);
1774 * @see ISaveParticipant
1776 public void prepareToSave(ISaveContext context) throws CoreException {
1779 protected void putInfo(IJavaElement element, Object info) {
1780 this.cache.putInfo(element, info);
1784 * Puts the infos in the given map (keys are IJavaElements and values are
1785 * JavaElementInfos) in the Java model cache in an atomic way. First checks
1786 * that the info for the opened element (or one of its ancestors) has not
1787 * been added to the cache. If it is the case, another thread has opened the
1788 * element (or one of its ancestors). So returns without updating the cache.
1790 protected synchronized void putInfos(IJavaElement openedElement,
1793 Object existingInfo = this.cache.peekAtInfo(openedElement);
1794 if (openedElement instanceof IParent
1795 && existingInfo instanceof JavaElementInfo) {
1796 IJavaElement[] children = ((JavaElementInfo) existingInfo)
1798 for (int i = 0, size = children.length; i < size; ++i) {
1799 JavaElement child = (JavaElement) children[i];
1802 } catch (JavaModelException e) {
1808 Iterator iterator = newElements.keySet().iterator();
1809 while (iterator.hasNext()) {
1810 IJavaElement element = (IJavaElement) iterator.next();
1811 Object info = newElements.get(element);
1812 this.cache.putInfo(element, info);
1817 * Reads the build state for the relevant project.
1819 protected Object readState(IProject project) throws CoreException {
1820 File file = getSerializationFile(project);
1821 if (file != null && file.exists()) {
1823 DataInputStream in = new DataInputStream(
1824 new BufferedInputStream(new FileInputStream(file)));
1826 String pluginID = in.readUTF();
1827 if (!pluginID.equals(JavaCore.PLUGIN_ID))
1828 throw new IOException(Util
1829 .bind("build.wrongFileFormat")); //$NON-NLS-1$
1830 String kind = in.readUTF();
1831 if (!kind.equals("STATE")) //$NON-NLS-1$
1832 throw new IOException(Util
1833 .bind("build.wrongFileFormat")); //$NON-NLS-1$
1834 if (in.readBoolean())
1835 return PHPBuilder.readState(project, in);
1836 if (PHPBuilder.DEBUG)
1838 .println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$
1842 } catch (Exception e) {
1843 e.printStackTrace();
1844 throw new CoreException(
1848 Platform.PLUGIN_ERROR,
1849 "Error reading last build state for project " + project.getName(), e)); //$NON-NLS-1$
1855 // public static void recreatePersistedContainer(String propertyName, String
1856 // containerString, boolean addToContainerValues) {
1857 // int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length();
1858 // int index = propertyName.indexOf('|', containerPrefixLength);
1859 // if (containerString != null) containerString = containerString.trim();
1861 // final String projectName = propertyName.substring(containerPrefixLength,
1863 // JavaProject project =
1864 // (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName);
1865 // final IPath containerPath = new
1866 // Path(propertyName.substring(index+1).trim());
1868 // if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) {
1869 // containerPut(project, containerPath, null);
1871 // final IClasspathEntry[] containerEntries =
1872 // project.decodeClasspath(containerString, false, false);
1873 // if (containerEntries != null && containerEntries !=
1874 // JavaProject.INVALID_CLASSPATH) {
1875 // IClasspathContainer container = new IClasspathContainer() {
1876 // public IClasspathEntry[] getClasspathEntries() {
1877 // return containerEntries;
1879 // public String getDescription() {
1880 // return "Persisted container ["+containerPath+" for project ["+
1881 // projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
1883 // public int getKind() {
1886 // public IPath getPath() {
1887 // return containerPath;
1889 // public String toString() {
1890 // return getDescription();
1894 // if (addToContainerValues) {
1895 // containerPut(project, containerPath, container);
1897 // Map projectContainers = (Map)PreviousSessionContainers.get(project);
1898 // if (projectContainers == null){
1899 // projectContainers = new HashMap(1);
1900 // PreviousSessionContainers.put(project, projectContainers);
1902 // projectContainers.put(containerPath, container);
1909 * Registers the given delta with this manager.
1911 protected void registerJavaModelDelta(IJavaElementDelta delta) {
1912 this.javaModelDeltas.add(delta);
1916 * Remembers the given scope in a weak set (so no need to remove it: it will
1917 * be removed by the garbage collector)
1919 // public void rememberScope(AbstractSearchScope scope) {
1920 // // NB: The value has to be null so as to not create a strong reference on
1922 // this.scopes.put(scope, null);
1925 * removeElementChangedListener method comment.
1927 public void removeElementChangedListener(IElementChangedListener listener) {
1929 for (int i = 0; i < this.elementChangedListenerCount; i++) {
1931 if (this.elementChangedListeners[i].equals(listener)) {
1933 // need to clone defensively since we might be in the middle of
1934 // listener notifications (#fire)
1935 int length = this.elementChangedListeners.length;
1936 IElementChangedListener[] newListeners = new IElementChangedListener[length];
1937 System.arraycopy(this.elementChangedListeners, 0, newListeners,
1939 int[] newMasks = new int[length];
1940 System.arraycopy(this.elementChangedListenerMasks, 0, newMasks,
1943 // copy trailing listeners
1944 int trailingLength = this.elementChangedListenerCount - i - 1;
1945 if (trailingLength > 0) {
1946 System.arraycopy(this.elementChangedListeners, i + 1,
1947 newListeners, i, trailingLength);
1948 System.arraycopy(this.elementChangedListenerMasks, i + 1,
1949 newMasks, i, trailingLength);
1952 // update manager listener state (#fire need to iterate over
1953 // original listeners through a local variable to hold onto
1954 // the original ones)
1955 this.elementChangedListeners = newListeners;
1956 this.elementChangedListenerMasks = newMasks;
1957 this.elementChangedListenerCount--;
1964 * Remembers the given scope in a weak set (so no need to remove it: it will
1965 * be removed by the garbage collector)
1967 // public void rememberScope(AbstractSearchScope scope) {
1968 // // NB: The value has to be null so as to not create a strong reference on
1970 // this.searchScopes.put(scope, null);
1973 * Removes all cached info for the given element (including all children)
1974 * from the cache. Returns the info for the given element, or null if it was
1977 public synchronized Object removeInfoAndChildren(JavaElement element)
1978 throws JavaModelException {
1979 Object info = this.cache.peekAtInfo(element);
1981 boolean wasVerbose = false;
1985 .println("CLOSING Element (" + Thread.currentThread() + "): " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$
1989 element.closing(info);
1990 if (element instanceof IParent
1991 && info instanceof JavaElementInfo) {
1992 IJavaElement[] children = ((JavaElementInfo) info)
1994 for (int i = 0, size = children.length; i < size; ++i) {
1995 JavaElement child = (JavaElement) children[i];
1999 this.cache.removeInfo(element);
2002 .println("-> Package cache size = " + this.cache.pkgSize()); //$NON-NLS-1$
2004 .println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(this.cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$
2007 JavaModelManager.VERBOSE = wasVerbose;
2014 public void removePerProjectInfo(JavaProject javaProject) {
2015 synchronized (perProjectInfo) { // use the perProjectInfo collection as
2017 IProject project = javaProject.getProject();
2018 PerProjectInfo info = (PerProjectInfo) perProjectInfo.get(project);
2020 perProjectInfo.remove(project);
2026 * Resets the temporary cache for newly created elements to null.
2028 public void resetTemporaryCache() {
2029 this.temporaryCache.set(null);
2033 * @see ISaveParticipant
2035 public void rollback(ISaveContext context) {
2038 private void saveState(PerProjectInfo info, ISaveContext context)
2039 throws CoreException {
2041 // passed this point, save actions are non trivial
2042 if (context.getKind() == ISaveContext.SNAPSHOT)
2047 saveBuiltState(info);
2051 * Saves the built state for the project.
2053 private void saveBuiltState(PerProjectInfo info) throws CoreException {
2054 if (PHPBuilder.DEBUG)
2055 System.out.println(Util.bind(
2056 "build.saveStateProgress", info.project.getName())); //$NON-NLS-1$
2057 File file = getSerializationFile(info.project);
2060 long t = System.currentTimeMillis();
2062 DataOutputStream out = new DataOutputStream(
2063 new BufferedOutputStream(new FileOutputStream(file)));
2065 out.writeUTF(JavaCore.PLUGIN_ID);
2066 out.writeUTF("STATE"); //$NON-NLS-1$
2067 if (info.savedState == null) {
2068 out.writeBoolean(false);
2070 out.writeBoolean(true);
2071 PHPBuilder.writeState(info.savedState, out);
2076 } catch (RuntimeException e) {
2079 } catch (SecurityException se) {
2081 throw new CoreException(
2085 Platform.PLUGIN_ERROR,
2088 "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
2089 } catch (IOException e) {
2092 } catch (SecurityException se) {
2094 throw new CoreException(
2098 Platform.PLUGIN_ERROR,
2101 "build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$
2103 if (PHPBuilder.DEBUG) {
2104 t = System.currentTimeMillis() - t;
2105 System.out.println(Util.bind(
2106 "build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$
2110 private synchronized Map containerClone(IJavaProject project) {
2111 Map originalProjectContainers = (Map) JavaModelManager.containers.get(project);
2112 if (originalProjectContainers == null)
2114 Map projectContainers = new HashMap(originalProjectContainers.size());
2115 projectContainers.putAll(originalProjectContainers);
2116 return projectContainers;
2120 * @see ISaveParticipant
2122 public void saving(ISaveContext context) throws CoreException {
2124 // save container values on snapshot/full save
2125 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
2126 IJavaProject[] projects = getJavaModel().getJavaProjects();
2127 for (int i = 0, length = projects.length; i < length; i++) {
2128 IJavaProject project = projects[i];
2129 // clone while iterating (see
2130 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638)
2131 Map projectContainers = containerClone(project);
2132 if (projectContainers == null)
2134 for (Iterator keys = projectContainers.keySet().iterator(); keys
2136 IPath containerPath = (IPath) keys.next();
2137 // IClasspathContainer container = (IClasspathContainer)
2138 // projectContainers.get(containerPath);
2139 String containerKey = CP_CONTAINER_PREFERENCES_PREFIX
2140 + project.getElementName() + "|" + containerPath;//$NON-NLS-1$
2141 String containerString = CP_ENTRY_IGNORE;
2143 // if (container != null) {
2144 // containerString =
2145 // ((JavaProject)project).encodeClasspath(container.getClasspathEntries(),
2148 // } catch(JavaModelException e){
2149 // // could not encode entry: leave it as CP_ENTRY_IGNORE
2151 preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use
2160 preferences.setValue(containerKey, containerString);
2163 JavaCore.getPlugin().savePluginPreferences();
2165 // if (context.getKind() == ISaveContext.FULL_SAVE) {
2166 // // will need delta since this save (see
2167 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658)
2168 // context.needDelta();
2170 // // clean up indexes on workspace full save
2171 // // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=52347)
2172 // IndexManager manager = this.indexManager;
2173 // if (manager != null) {
2174 // manager.cleanUpIndexes();
2178 IProject savedProject = context.getProject();
2179 if (savedProject != null) {
2180 if (!JavaProject.hasJavaNature(savedProject))
2182 PerProjectInfo info = getPerProjectInfo(savedProject, true /*
2186 saveState(info, context);
2190 ArrayList vStats = null; // lazy initialized
2191 for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) {
2193 PerProjectInfo info = (PerProjectInfo) iter.next();
2194 saveState(info, context);
2195 } catch (CoreException e) {
2197 vStats = new ArrayList();
2198 vStats.add(e.getStatus());
2201 if (vStats != null) {
2202 IStatus[] stats = new IStatus[vStats.size()];
2203 vStats.toArray(stats);
2204 throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID,
2205 IStatus.ERROR, stats,
2206 Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$
2211 * @see ISaveParticipant
2213 // public void saving(ISaveContext context) throws CoreException {
2215 // IProject savedProject = context.getProject();
2216 // if (savedProject != null) {
2217 // if (!JavaProject.hasJavaNature(savedProject)) return; // ignore
2218 // PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info
2220 // saveState(info, context);
2224 // ArrayList vStats= null; // lazy initialized
2225 // for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();)
2228 // PerProjectInfo info = (PerProjectInfo) iter.next();
2229 // saveState(info, context);
2230 // } catch (CoreException e) {
2231 // if (vStats == null)
2232 // vStats= new ArrayList();
2233 // vStats.add(e.getStatus());
2236 // if (vStats != null) {
2237 // IStatus[] stats= new IStatus[vStats.size()];
2238 // vStats.toArray(stats);
2239 // throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID,
2240 // IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null));
2245 * Record the order in which to build the java projects (batch build). This
2246 * order is based on the projects classpath settings.
2248 protected void setBuildOrder(String[] javaBuildOrder)
2249 throws JavaModelException {
2251 // optional behaviour
2252 // possible value of index 0 is Compute
2253 if (!JavaCore.COMPUTE.equals(JavaCore
2254 .getOption(JavaCore.CORE_JAVA_BUILD_ORDER)))
2255 return; // cannot be customized at project level
2257 if (javaBuildOrder == null || javaBuildOrder.length <= 1)
2260 IWorkspace workspace = ResourcesPlugin.getWorkspace();
2261 IWorkspaceDescription description = workspace.getDescription();
2262 String[] wksBuildOrder = description.getBuildOrder();
2265 if (wksBuildOrder == null) {
2266 newOrder = javaBuildOrder;
2268 // remove projects which are already mentionned in java builder
2270 int javaCount = javaBuildOrder.length;
2271 HashMap newSet = new HashMap(javaCount); // create a set for fast
2273 for (int i = 0; i < javaCount; i++) {
2274 newSet.put(javaBuildOrder[i], javaBuildOrder[i]);
2277 int oldCount = wksBuildOrder.length;
2278 for (int i = 0; i < oldCount; i++) {
2279 if (newSet.containsKey(wksBuildOrder[i])) {
2280 wksBuildOrder[i] = null;
2284 // add Java ones first
2285 newOrder = new String[oldCount - removed + javaCount];
2286 System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java
2292 // copy previous items in their respective order
2293 int index = javaCount;
2294 for (int i = 0; i < oldCount; i++) {
2295 if (wksBuildOrder[i] != null) {
2296 newOrder[index++] = wksBuildOrder[i];
2300 // commit the new build order out
2301 description.setBuildOrder(newOrder);
2303 workspace.setDescription(description);
2304 } catch (CoreException e) {
2305 throw new JavaModelException(e);
2310 * Sets the last built state for the given project, or null to reset it.
2312 public void setLastBuiltState(IProject project, Object state) {
2313 if (!JavaProject.hasJavaNature(project))
2314 return; // should never be requested on non-Java projects
2315 PerProjectInfo info = getPerProjectInfo(project, true /*
2319 info.triedRead = true; // no point trying to re-read once using setter
2320 info.savedState = state;
2321 if (state == null) { // delete state file to ensure a full build
2322 // happens if the workspace crashes
2324 File file = getSerializationFile(project);
2325 if (file != null && file.exists())
2327 } catch (SecurityException se) {
2332 public void shutdown() {
2334 // if (this.deltaProcessor.indexManager != null){ // no more indexing
2335 // this.deltaProcessor.indexManager.shutdown();
2338 IJavaModel model = this.getJavaModel();
2339 if (model != null) {
2343 } catch (JavaModelException e) {
2348 * Turns the firing mode to on. That is, deltas that are/have been
2349 * registered will be fired.
2351 public void startDeltas() {
2352 this.isFiring = true;
2356 * Turns the firing mode to off. That is, deltas that are/have been
2357 * registered will not be fired until deltas are started again.
2359 public void stopDeltas() {
2360 this.isFiring = false;
2364 * Update Java Model given some delta
2366 public void updateJavaModel(IJavaElementDelta customDelta) {
2368 if (customDelta == null) {
2369 for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++) {
2370 IJavaElementDelta delta = (IJavaElementDelta) this.javaModelDeltas
2372 this.modelUpdater.processJavaDelta(delta);
2375 this.modelUpdater.processJavaDelta(customDelta);
2379 public static IPath variableGet(String variableName) {
2380 return (IPath) Variables.get(variableName);
2383 public static String[] variableNames() {
2384 int length = Variables.size();
2385 String[] result = new String[length];
2386 Iterator vars = Variables.keySet().iterator();
2388 while (vars.hasNext()) {
2389 result[index++] = (String) vars.next();
2394 public static void variablePut(String variableName, IPath variablePath) {
2396 // update cache - do not only rely on listener refresh
2397 if (variablePath == null) {
2398 Variables.remove(variableName);
2399 PreviousSessionVariables.remove(variableName);
2401 Variables.put(variableName, variablePath);
2404 // do not write out intermediate initialization value
2405 if (variablePath == JavaModelManager.VariableInitializationInProgress) {
2408 Preferences preferences = JavaCore.getPlugin().getPluginPreferences();
2409 String variableKey = CP_VARIABLE_PREFERENCES_PREFIX + variableName;
2410 String variableString = variablePath == null ? CP_ENTRY_IGNORE
2411 : variablePath.toString();
2412 preferences.setDefault(variableKey, CP_ENTRY_IGNORE); // use this
2416 preferences.setValue(variableKey, variableString);
2417 JavaCore.getPlugin().savePluginPreferences();
2421 * Returns all the working copies which have the given owner. Adds the
2422 * working copies of the primary owner if specified. Returns null if it has
2425 public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner,
2426 boolean addPrimary) {
2427 synchronized (perWorkingCopyInfos) {
2428 ICompilationUnit[] primaryWCs = addPrimary
2429 && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies(
2430 DefaultWorkingCopyOwner.PRIMARY, false)
2432 Map workingCopyToInfos = (Map) perWorkingCopyInfos.get(owner);
2433 if (workingCopyToInfos == null)
2435 int primaryLength = primaryWCs == null ? 0 : primaryWCs.length;
2436 int size = workingCopyToInfos.size(); // note size is > 0
2438 // pathToPerWorkingCopyInfos
2440 ICompilationUnit[] result = new ICompilationUnit[primaryLength
2442 if (primaryWCs != null) {
2443 System.arraycopy(primaryWCs, 0, result, 0, primaryLength);
2445 Iterator iterator = workingCopyToInfos.values().iterator();
2446 int index = primaryLength;
2447 while (iterator.hasNext()) {
2448 result[index++] = ((JavaModelManager.PerWorkingCopyInfo) iterator
2449 .next()).getWorkingCopy();
2456 * A HashSet that contains the IJavaProject whose classpath is being
2459 private ThreadLocal classpathsBeingResolved = new ThreadLocal();
2461 private HashSet getClasspathBeingResolved() {
2462 HashSet result = (HashSet) this.classpathsBeingResolved.get();
2463 if (result == null) {
2464 result = new HashSet();
2465 this.classpathsBeingResolved.set(result);
2470 public boolean isClasspathBeingResolved(IJavaProject project) {
2471 return getClasspathBeingResolved().contains(project);
2474 public void setClasspathBeingResolved(IJavaProject project,
2475 boolean classpathIsResolved) {
2476 if (classpathIsResolved) {
2477 getClasspathBeingResolved().add(project);
2479 getClasspathBeingResolved().remove(project);