/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap; import java.util.zip.ZipFile; import net.sourceforge.phpdt.core.ElementChangedEvent; import net.sourceforge.phpdt.core.IClasspathEntry; import net.sourceforge.phpdt.core.ICompilationUnit; import net.sourceforge.phpdt.core.IElementChangedListener; import net.sourceforge.phpdt.core.IJavaElement; import net.sourceforge.phpdt.core.IJavaElementDelta; import net.sourceforge.phpdt.core.IJavaModel; import net.sourceforge.phpdt.core.IJavaProject; import net.sourceforge.phpdt.core.IPackageFragment; import net.sourceforge.phpdt.core.IPackageFragmentRoot; import net.sourceforge.phpdt.core.IWorkingCopy; import net.sourceforge.phpdt.core.JavaModelException; import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpdt.internal.core.builder.PHPBuilder; import net.sourceforge.phpdt.internal.core.util.Util; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.ISaveContext; import org.eclipse.core.resources.ISaveParticipant; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Preferences; import org.eclipse.core.runtime.Status; import net.sourceforge.phpdt.internal.core.DefaultWorkingCopyOwner; import net.sourceforge.phpdt.internal.core.DeltaProcessingState; import net.sourceforge.phpdt.internal.core.DeltaProcessor; import net.sourceforge.phpdt.core.IParent; import net.sourceforge.phpdt.internal.core.JavaElementInfo; import net.sourceforge.phpdt.core.IProblemRequestor; import net.sourceforge.phpdt.core.WorkingCopyOwner; import net.sourceforge.phpdt.core.compiler.IProblem; import net.sourceforge.phpdt.internal.core.CompilationUnit; import net.sourceforge.phpdt.internal.core.JavaElement; import net.sourceforge.phpdt.internal.core.JavaElementDeltaBuilder; import net.sourceforge.phpdt.internal.core.JavaModelManager.PerWorkingCopyInfo; /** * The JavaModelManager manages instances of IJavaModel. * IElementChangedListeners register with the JavaModelManager, * and receive ElementChangedEvents for all IJavaModels. *

* The single instance of JavaModelManager is available from * the static method JavaModelManager.getJavaModelManager(). */ public class JavaModelManager implements ISaveParticipant { /** * Unique handle onto the JavaModel */ final JavaModel javaModel = new JavaModel(); /** * Classpath variables pool */ public static HashMap Variables = new HashMap(5); public static HashMap PreviousSessionVariables = new HashMap(5); public static HashSet OptionNames = new HashSet(20); public final static String CP_VARIABLE_PREFERENCES_PREFIX = PHPeclipsePlugin.PLUGIN_ID+".classpathVariable."; //$NON-NLS-1$ // public final static String CP_CONTAINER_PREFERENCES_PREFIX = PHPCore.PLUGIN_ID+".classpathContainer."; //$NON-NLS-1$ public final static String CP_ENTRY_IGNORE = "####"; //$NON-NLS-1$ /** * Classpath containers pool */ public static HashMap Containers = new HashMap(5); public static HashMap PreviousSessionContainers = new HashMap(5); /** * Name of the extension point for contributing classpath variable initializers */ // public static final String CPVARIABLE_INITIALIZER_EXTPOINT_ID = "classpathVariableInitializer" ; //$NON-NLS-1$ /** * Name of the extension point for contributing classpath container initializers */ // public static final String CPCONTAINER_INITIALIZER_EXTPOINT_ID = "classpathContainerInitializer" ; //$NON-NLS-1$ /** * Name of the extension point for contributing a source code formatter */ public static final String FORMATTER_EXTPOINT_ID = "codeFormatter" ; //$NON-NLS-1$ /** * Special value used for recognizing ongoing initialization and breaking initialization cycles */ public final static IPath VariableInitializationInProgress = new Path("Variable Initialization In Progress"); //$NON-NLS-1$ // public final static IClasspathContainer ContainerInitializationInProgress = new IClasspathContainer() { // public IClasspathEntry[] getClasspathEntries() { return null; } // public String getDescription() { return "Container Initialization In Progress"; } //$NON-NLS-1$ // public int getKind() { return 0; } // public IPath getPath() { return null; } // public String toString() { return getDescription(); } // }; private static final String INDEX_MANAGER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/indexmanager" ; //$NON-NLS-1$ private static final String COMPILER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/compiler" ; //$NON-NLS-1$ private static final String JAVAMODEL_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/javamodel" ; //$NON-NLS-1$ private static final String CP_RESOLVE_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/cpresolution" ; //$NON-NLS-1$ private static final String ZIP_ACCESS_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/zipaccess" ; //$NON-NLS-1$ private static final String DELTA_DEBUG =PHPeclipsePlugin.PLUGIN_ID + "/debug/javadelta" ; //$NON-NLS-1$ private static final String HIERARCHY_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/hierarchy" ; //$NON-NLS-1$ private static final String POST_ACTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/postaction" ; //$NON-NLS-1$ private static final String BUILDER_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/builder" ; //$NON-NLS-1$ private static final String COMPLETION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/completion" ; //$NON-NLS-1$ private static final String SELECTION_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/selection" ; //$NON-NLS-1$ private static final String SHARED_WC_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/sharedworkingcopy" ; //$NON-NLS-1$ private static final String SEARCH_DEBUG = PHPeclipsePlugin.PLUGIN_ID + "/debug/search" ; //$NON-NLS-1$ public final static IWorkingCopy[] NoWorkingCopy = new IWorkingCopy[0]; /** * Table from WorkingCopyOwner to a table of ICompilationUnit (working copy handle) to PerWorkingCopyInfo. * NOTE: this object itself is used as a lock to synchronize creation/removal of per working copy infos */ protected Map perWorkingCopyInfos = new HashMap(5); /** * Returns whether the given full path (for a package) conflicts with the output location * of the given project. */ public static boolean conflictsWithOutputLocation(IPath folderPath, JavaProject project) { try { IPath outputLocation = project.getOutputLocation(); if (outputLocation == null) { // in doubt, there is a conflict return true; } if (outputLocation.isPrefixOf(folderPath)) { // only allow nesting in project's output if there is a corresponding source folder // or if the project's output is not used (in other words, if all source folders have their custom output) IClasspathEntry[] classpath = project.getResolvedClasspath(true); boolean isOutputUsed = false; for (int i = 0, length = classpath.length; i < length; i++) { IClasspathEntry entry = classpath[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (entry.getPath().equals(outputLocation)) { return false; } if (entry.getOutputLocation() == null) { isOutputUsed = true; } } } return isOutputUsed; } return false; } catch (JavaModelException e) { // in doubt, there is a conflict return true; } } // public static IClasspathContainer containerGet(IJavaProject project, IPath containerPath) { // Map projectContainers = (Map)Containers.get(project); // if (projectContainers == null){ // return null; // } // IClasspathContainer container = (IClasspathContainer)projectContainers.get(containerPath); // return container; // } // public static void containerPut(IJavaProject project, IPath containerPath, IClasspathContainer container){ // // Map projectContainers = (Map)Containers.get(project); // if (projectContainers == null){ // projectContainers = new HashMap(1); // Containers.put(project, projectContainers); // } // // if (container == null) { // projectContainers.remove(containerPath); // Map previousContainers = (Map)PreviousSessionContainers.get(project); // if (previousContainers != null){ // previousContainers.remove(containerPath); // } // } else { // projectContainers.put(containerPath, container); // } // // // do not write out intermediate initialization value // if (container == JavaModelManager.ContainerInitializationInProgress) { // return; // } // Preferences preferences = PHPeclipsePlugin.getPlugin().getPluginPreferences(); // String containerKey = CP_CONTAINER_PREFERENCES_PREFIX+project.getElementName() +"|"+containerPath;//$NON-NLS-1$ // String containerString = CP_ENTRY_IGNORE; // try { // if (container != null) { // containerString = ((JavaProject)project).encodeClasspath(container.getClasspathEntries(), null, false); // } // } catch(JavaModelException e){ // } // preferences.setDefault(containerKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones // preferences.setValue(containerKey, containerString); // PHPeclipsePlugin.getPlugin().savePluginPreferences(); // } /** * Returns the Java element corresponding to the given resource, or * null if unable to associate the given resource * with a Java element. *

* The resource must be one of:

*

* Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */ public static IJavaElement create(IResource resource, IJavaProject project) { if (resource == null) { return null; } int type = resource.getType(); switch (type) { case IResource.PROJECT : return JavaCore.create((IProject) resource); case IResource.FILE : return create((IFile) resource, project); case IResource.FOLDER : return create((IFolder) resource, project); case IResource.ROOT : return JavaCore.create((IWorkspaceRoot) resource); default : return null; } } /** * Returns the Java element corresponding to the given file, its project being the given * project. * Returns null if unable to associate the given file * with a Java element. * *

The file must be one of:

*

* Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */ public static IJavaElement create(IFile file, IJavaProject project) { if (file == null) { return null; } if (project == null) { project = JavaCore.create(file.getProject()); } if (file.getFileExtension() != null) { String name = file.getName(); if (PHPFileUtil.isValidPHPUnitName(name)) //if (PHPFileUtil.isPHPFile(file)) return createCompilationUnitFrom(file, project); // if (Util.isValidClassFileName(name)) // return createClassFileFrom(file, project); // if (Util.isArchiveFileName(name)) // return createJarPackageFragmentRootFrom(file, project); } return null; } /** * Returns the package fragment or package fragment root corresponding to the given folder, * its parent or great parent being the given project. * or null if unable to associate the given folder with a Java element. *

* Note that a package fragment root is returned rather than a default package. *

* Creating a Java element has the side effect of creating and opening all of the * element's parents if they are not yet open. */ public static IJavaElement create(IFolder folder, IJavaProject project) { if (folder == null) { return null; } if (project == null) { project = JavaCore.create(folder.getProject()); } IJavaElement element = determineIfOnClasspath(folder, project); if (conflictsWithOutputLocation(folder.getFullPath(), (JavaProject)project) || (folder.getName().indexOf('.') >= 0 && !(element instanceof IPackageFragmentRoot))) { return null; // only package fragment roots are allowed with dot names } else { return element; } } /** * Creates and returns a class file element for the given .class file, * its project being the given project. Returns null if unable * to recognize the class file. */ // public static IClassFile createClassFileFrom(IFile file, IJavaProject project ) { // if (file == null) { // return null; // } // if (project == null) { // project = PHPCore.create(file.getProject()); // } // IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project); // if (pkg == null) { // // fix for 1FVS7WE // // not on classpath - make the root its folder, and a default package // IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent()); // pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); // } // return pkg.getClassFile(file.getName()); // } /** * Creates and returns a compilation unit element for the given .java * file, its project being the given project. Returns null if unable * to recognize the compilation unit. */ public static ICompilationUnit createCompilationUnitFrom(IFile file, IJavaProject project) { if (file == null) return null; if (project == null) { project = JavaCore.create(file.getProject()); } IPackageFragment pkg = (IPackageFragment) determineIfOnClasspath(file, project); if (pkg == null) { // not on classpath - make the root its folder, and a default package IPackageFragmentRoot root = project.getPackageFragmentRoot(file.getParent()); pkg = root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); if (VERBOSE){ System.out.println("WARNING : creating unit element outside classpath ("+ Thread.currentThread()+"): " + file.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$ } } return pkg.getCompilationUnit(file.getName()); } /** * Creates and returns a handle for the given JAR file, its project being the given project. * The Java model associated with the JAR's project may be * created as a side effect. * Returns null if unable to create a JAR package fragment root. * (for example, if the JAR file represents a non-Java resource) */ // public static IPackageFragmentRoot createJarPackageFragmentRootFrom(IFile file, IJavaProject project) { // if (file == null) { // return null; // } // if (project == null) { // project = PHPCore.create(file.getProject()); // } // // // Create a jar package fragment root only if on the classpath // IPath resourcePath = file.getFullPath(); // try { // IClasspathEntry[] entries = ((JavaProject)project).getResolvedClasspath(true); // for (int i = 0, length = entries.length; i < length; i++) { // IClasspathEntry entry = entries[i]; // IPath rootPath = entry.getPath(); // if (rootPath.equals(resourcePath)) { // return project.getPackageFragmentRoot(file); // } // } // } catch (JavaModelException e) { // } // return null; // } /** * Returns the package fragment root represented by the resource, or * the package fragment the given resource is located in, or null * if the given resource is not on the classpath of the given project. */ public static IJavaElement determineIfOnClasspath( IResource resource, IJavaProject project) { IPath resourcePath = resource.getFullPath(); try { IClasspathEntry[] entries = net.sourceforge.phpdt.internal.compiler.util.Util.isJavaFileName(resourcePath.lastSegment()) ? project.getRawClasspath() // JAVA file can only live inside SRC folder (on the raw path) : ((JavaProject)project).getResolvedClasspath(true); for (int i = 0; i < entries.length; i++) { IClasspathEntry entry = entries[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) continue; IPath rootPath = entry.getPath(); if (rootPath.equals(resourcePath)) { return project.getPackageFragmentRoot(resource); } else if (rootPath.isPrefixOf(resourcePath) && !Util.isExcluded(resource, ((ClasspathEntry)entry).fullExclusionPatternChars())) { // given we have a resource child of the root, it cannot be a JAR pkg root IPackageFragmentRoot root = ((JavaProject) project).getFolderPackageFragmentRoot(rootPath); if (root == null) return null; IPath pkgPath = resourcePath.removeFirstSegments(rootPath.segmentCount()); if (resource.getType() == IResource.FILE) { // if the resource is a file, then remove the last segment which // is the file name in the package pkgPath = pkgPath.removeLastSegments(1); // don't check validity of package name (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=26706) // String pkgName = pkgPath.toString().replace('/', '.'); String pkgName = pkgPath.toString(); return root.getPackageFragment(pkgName); } else { String pkgName = Util.packageName(pkgPath); if (pkgName == null){// || JavaConventions.validatePackageName(pkgName).getSeverity() == IStatus.ERROR) { return null; } return root.getPackageFragment(pkgName); } } } } catch (JavaModelException npe) { return null; } return null; } /** * The singleton manager */ private final static JavaModelManager Manager= new JavaModelManager(); /** * Infos cache. */ protected JavaModelCache cache = new JavaModelCache(); /* * Temporary cache of newly opened elements */ private ThreadLocal temporaryCache = new ThreadLocal(); /** * Set of elements which are out of sync with their buffers. */ protected Map elementsOutOfSynchWithBuffers = new HashMap(11); /** * Holds the state used for delta processing. */ public DeltaProcessingState deltaState = new DeltaProcessingState(); /** * Turns delta firing on/off. By default it is on. */ private boolean isFiring= true; /** * Queue of deltas created explicily by the Java Model that * have yet to be fired. */ ArrayList javaModelDeltas= new ArrayList(); /** * Queue of reconcile deltas on working copies that have yet to be fired. * This is a table form IWorkingCopy to IJavaElementDelta */ HashMap reconcileDeltas = new HashMap(); /** * Collection of listeners for Java element deltas */ private IElementChangedListener[] elementChangedListeners = new IElementChangedListener[5]; private int[] elementChangedListenerMasks = new int[5]; private int elementChangedListenerCount = 0; public int currentChangeEventType = ElementChangedEvent.PRE_AUTO_BUILD; public static final int DEFAULT_CHANGE_EVENT = 0; // must not collide with ElementChangedEvent event masks /** * Used to convert IResourceDeltas into IJavaElementDeltas. */ // public final DeltaProcessor deltaProcessor = new DeltaProcessor(this); /** * Used to update the JavaModel for IJavaElementDeltas. */ // private final ModelUpdater modelUpdater =new ModelUpdater(); /** * Workaround for bug 15168 circular errors not reported * This is a cache of the projects before any project addition/deletion has started. */ public IJavaProject[] javaProjectsCache; /** * Table from IProject to PerProjectInfo. * NOTE: this object itself is used as a lock to synchronize creation/removal of per project infos */ protected Map perProjectInfo = new HashMap(5); /** * A map from ICompilationUnit to IWorkingCopy * of the shared working copies. */ public Map sharedWorkingCopies = new HashMap(); /** * A weak set of the known scopes. */ protected WeakHashMap scopes = new WeakHashMap(); public static class PerProjectInfo { public IProject project; public Object savedState; public boolean triedRead; public IClasspathEntry[] classpath; public IClasspathEntry[] lastResolvedClasspath; public Map resolvedPathToRawEntries; // reverse map from resolved path to raw entries public IPath outputLocation; public Preferences preferences; public PerProjectInfo(IProject project) { this.triedRead = false; this.savedState = null; this.project = project; } } public static class PerWorkingCopyInfo implements IProblemRequestor { int useCount = 0; IProblemRequestor problemRequestor; ICompilationUnit workingCopy; public PerWorkingCopyInfo(ICompilationUnit workingCopy, IProblemRequestor problemRequestor) { this.workingCopy = workingCopy; this.problemRequestor = problemRequestor; } public void acceptProblem(IProblem problem) { if (this.problemRequestor == null) return; this.problemRequestor.acceptProblem(problem); } public void beginReporting() { if (this.problemRequestor == null) return; this.problemRequestor.beginReporting(); } public void endReporting() { if (this.problemRequestor == null) return; this.problemRequestor.endReporting(); } public ICompilationUnit getWorkingCopy() { return this.workingCopy; } public boolean isActive() { return this.problemRequestor != null && this.problemRequestor.isActive(); } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append("Info for "); //$NON-NLS-1$ buffer.append(((JavaElement)workingCopy).toStringWithAncestors()); buffer.append("\nUse count = "); //$NON-NLS-1$ buffer.append(this.useCount); buffer.append("\nProblem requestor:\n "); //$NON-NLS-1$ buffer.append(this.problemRequestor); return buffer.toString(); } } public static boolean VERBOSE = false; public static boolean CP_RESOLVE_VERBOSE = false; public static boolean ZIP_ACCESS_VERBOSE = false; /** * A cache of opened zip files per thread. * (map from Thread to map of IPath to java.io.ZipFile) * NOTE: this object itself is used as a lock to synchronize creation/removal of entries */ private HashMap zipFiles = new HashMap(); /** * Update the classpath variable cache */ public static class PluginPreferencesListener implements Preferences.IPropertyChangeListener { /** * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(PropertyChangeEvent) */ public void propertyChange(Preferences.PropertyChangeEvent event) { // TODO : jsurfer temp-del // String propertyName = event.getProperty(); // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)) { // String varName = propertyName.substring(CP_VARIABLE_PREFERENCES_PREFIX.length()); // String newValue = (String)event.getNewValue(); // if (newValue != null && !(newValue = newValue.trim()).equals(CP_ENTRY_IGNORE)) { // Variables.put(varName, new Path(newValue)); // } else { // Variables.remove(varName); // } // } // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)) { // recreatePersistedContainer(propertyName, (String)event.getNewValue(), false); // } } } /** * Line separator to use throughout the JavaModel for any source edit operation */ public static String LINE_SEPARATOR = System.getProperty("line.separator"); //$NON-NLS-1$ /** * Constructs a new JavaModelManager */ private JavaModelManager() { } /** * @deprecated - discard once debug has converted to not using it */ public void addElementChangedListener(IElementChangedListener listener) { this.addElementChangedListener(listener, ElementChangedEvent.POST_CHANGE | ElementChangedEvent.POST_RECONCILE); } /** * addElementChangedListener method comment. * Need to clone defensively the listener information, in case some listener is reacting to some notification iteration by adding/changing/removing * any of the other (for example, if it deregisters itself). */ public void addElementChangedListener(IElementChangedListener listener, int eventMask) { for (int i = 0; i < this.elementChangedListenerCount; i++){ if (this.elementChangedListeners[i].equals(listener)){ // only clone the masks, since we could be in the middle of notifications and one listener decide to change // any event mask of another listeners (yet not notified). int cloneLength = this.elementChangedListenerMasks.length; System.arraycopy(this.elementChangedListenerMasks, 0, this.elementChangedListenerMasks = new int[cloneLength], 0, cloneLength); this.elementChangedListenerMasks[i] = eventMask; // could be different return; } } // may need to grow, no need to clone, since iterators will have cached original arrays and max boundary and we only add to the end. int length; if ((length = this.elementChangedListeners.length) == this.elementChangedListenerCount){ System.arraycopy(this.elementChangedListeners, 0, this.elementChangedListeners = new IElementChangedListener[length*2], 0, length); System.arraycopy(this.elementChangedListenerMasks, 0, this.elementChangedListenerMasks = new int[length*2], 0, length); } this.elementChangedListeners[this.elementChangedListenerCount] = listener; this.elementChangedListenerMasks[this.elementChangedListenerCount] = eventMask; this.elementChangedListenerCount++; } /** * Starts caching ZipFiles. * Ignores if there are already clients. */ public void cacheZipFiles() { synchronized(this.zipFiles) { Thread currentThread = Thread.currentThread(); if (this.zipFiles.get(currentThread) != null) return; this.zipFiles.put(currentThread, new HashMap()); } } public void closeZipFile(ZipFile zipFile) { if (zipFile == null) return; synchronized(this.zipFiles) { if (this.zipFiles.get(Thread.currentThread()) != null) { return; // zip file will be closed by call to flushZipFiles } try { if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelManager.closeZipFile(ZipFile)] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } zipFile.close(); } catch (IOException e) { } } } /** * Configure the plugin with respect to option settings defined in ".options" file */ public void configurePluginDebugOptions(){ if(JavaCore.getPlugin().isDebugging()){ // TODO jsurfer temp-del String option = Platform.getDebugOption(BUILDER_DEBUG); // if(option != null) JavaBuilder.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // // option = Platform.getDebugOption(COMPILER_DEBUG); // if(option != null) Compiler.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // // option = Platform.getDebugOption(COMPLETION_DEBUG); // if(option != null) CompletionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // option = Platform.getDebugOption(CP_RESOLVE_DEBUG); if(option != null) JavaModelManager.CP_RESOLVE_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ option = Platform.getDebugOption(DELTA_DEBUG); if(option != null) DeltaProcessor.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // option = Platform.getDebugOption(HIERARCHY_DEBUG); // if(option != null) TypeHierarchy.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // // option = Platform.getDebugOption(INDEX_MANAGER_DEBUG); // if(option != null) IndexManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ option = Platform.getDebugOption(JAVAMODEL_DEBUG); if(option != null) JavaModelManager.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ option = Platform.getDebugOption(POST_ACTION_DEBUG); if(option != null) JavaModelOperation.POST_ACTION_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // option = Platform.getDebugOption(SEARCH_DEBUG); // if(option != null) SearchEngine.VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ // // option = Platform.getDebugOption(SELECTION_DEBUG); // if(option != null) SelectionEngine.DEBUG = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ option = Platform.getDebugOption(ZIP_ACCESS_DEBUG); if(option != null) JavaModelManager.ZIP_ACCESS_VERBOSE = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ } } /* * Discards the per working copy info for the given working copy (making it a compilation unit) * if its use count was 1. Otherwise, just decrement the use count. * If the working copy is primary, computes the delta between its state and the original compilation unit * and register it. * Close the working copy, its buffer and remove it from the shared working copy table. * Ignore if no per-working copy info existed. * NOTE: it must be synchronized as it may interact with the element info cache (if useCount is decremented to 0), see bug 50667. * Returns the new use count (or -1 if it didn't exist). */ public synchronized int discardPerWorkingCopyInfo(CompilationUnit workingCopy) throws JavaModelException { synchronized(perWorkingCopyInfos) { WorkingCopyOwner owner = workingCopy.owner; Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null) return -1; PerWorkingCopyInfo info = (PerWorkingCopyInfo)workingCopyToInfos.get(workingCopy); if (info == null) return -1; if (--info.useCount == 0) { // create the delta builder (this remembers the current content of the working copy) JavaElementDeltaBuilder deltaBuilder = null; if (workingCopy.isPrimary()) { deltaBuilder = new JavaElementDeltaBuilder(workingCopy); } // remove per working copy info workingCopyToInfos.remove(workingCopy); if (workingCopyToInfos.isEmpty()) { this.perWorkingCopyInfos.remove(owner); } // remove infos + close buffer (since no longer working copy) removeInfoAndChildren(workingCopy); workingCopy.closeBuffer(); // compute the delta if needed and register it if there are changes if (deltaBuilder != null) { deltaBuilder.buildDeltas(); if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) { getDeltaProcessor().registerJavaModelDelta(deltaBuilder.delta); } } } return info.useCount; } } /** * @see ISaveParticipant */ public void doneSaving(ISaveContext context){ } /** * Fire Java Model delta, flushing them after the fact after post_change notification. * If the firing mode has been turned off, this has no effect. */ public void fire(IJavaElementDelta customDelta, int eventType) { if (!this.isFiring) return; if (DeltaProcessor.VERBOSE && (eventType == DEFAULT_CHANGE_EVENT || eventType == ElementChangedEvent.PRE_AUTO_BUILD)) { System.out.println("-----------------------------------------------------------------------------------------------------------------------");//$NON-NLS-1$ } IJavaElementDelta deltaToNotify; if (customDelta == null){ deltaToNotify = this.mergeDeltas(this.javaModelDeltas); } else { deltaToNotify = customDelta; } // Refresh internal scopes if (deltaToNotify != null) { // TODO khartlage temp-del // Iterator scopes = this.scopes.keySet().iterator(); // while (scopes.hasNext()) { // AbstractSearchScope scope = (AbstractSearchScope)scopes.next(); // scope.processDelta(deltaToNotify); // } } // Notification // Important: if any listener reacts to notification by updating the listeners list or mask, these lists will // be duplicated, so it is necessary to remember original lists in a variable (since field values may change under us) IElementChangedListener[] listeners = this.elementChangedListeners; int[] listenerMask = this.elementChangedListenerMasks; int listenerCount = this.elementChangedListenerCount; switch (eventType) { case DEFAULT_CHANGE_EVENT: firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, listenerCount); firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount); fireReconcileDelta(listeners, listenerMask, listenerCount); break; case ElementChangedEvent.PRE_AUTO_BUILD: firePreAutoBuildDelta(deltaToNotify, listeners, listenerMask, listenerCount); break; case ElementChangedEvent.POST_CHANGE: firePostChangeDelta(deltaToNotify, listeners, listenerMask, listenerCount); fireReconcileDelta(listeners, listenerMask, listenerCount); break; } } private void firePreAutoBuildDelta( IJavaElementDelta deltaToNotify, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { if (DeltaProcessor.VERBOSE){ System.out.println("FIRING PRE_AUTO_BUILD Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$ System.out.println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ } if (deltaToNotify != null) { notifyListeners(deltaToNotify, ElementChangedEvent.PRE_AUTO_BUILD, listeners, listenerMask, listenerCount); } } private void firePostChangeDelta( IJavaElementDelta deltaToNotify, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { // post change deltas if (DeltaProcessor.VERBOSE){ System.out.println("FIRING POST_CHANGE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$ System.out.println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ } if (deltaToNotify != null) { // flush now so as to keep listener reactions to post their own deltas for subsequent iteration this.flush(); notifyListeners(deltaToNotify, ElementChangedEvent.POST_CHANGE, listeners, listenerMask, listenerCount); } } private void fireReconcileDelta( IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { IJavaElementDelta deltaToNotify = mergeDeltas(this.reconcileDeltas.values()); if (DeltaProcessor.VERBOSE){ System.out.println("FIRING POST_RECONCILE Delta ["+Thread.currentThread()+"]:"); //$NON-NLS-1$//$NON-NLS-2$ System.out.println(deltaToNotify == null ? "" : deltaToNotify.toString()); //$NON-NLS-1$ } if (deltaToNotify != null) { // flush now so as to keep listener reactions to post their own deltas for subsequent iteration this.reconcileDeltas = new HashMap(); notifyListeners(deltaToNotify, ElementChangedEvent.POST_RECONCILE, listeners, listenerMask, listenerCount); } } public void notifyListeners(IJavaElementDelta deltaToNotify, int eventType, IElementChangedListener[] listeners, int[] listenerMask, int listenerCount) { final ElementChangedEvent extraEvent = new ElementChangedEvent(deltaToNotify, eventType); for (int i= 0; i < listenerCount; i++) { if ((listenerMask[i] & eventType) != 0){ final IElementChangedListener listener = listeners[i]; long start = -1; if (DeltaProcessor.VERBOSE) { System.out.print("Listener #" + (i+1) + "=" + listener.toString());//$NON-NLS-1$//$NON-NLS-2$ start = System.currentTimeMillis(); } // wrap callbacks with Safe runnable for subsequent listeners to be called when some are causing grief Platform.run(new ISafeRunnable() { public void handleException(Throwable exception) { Util.log(exception, "Exception occurred in listener of Java element change notification"); //$NON-NLS-1$ } public void run() throws Exception { listener.elementChanged(extraEvent); } }); if (DeltaProcessor.VERBOSE) { System.out.println(" -> " + (System.currentTimeMillis()-start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ } } } } /** * Flushes all deltas without firing them. */ protected void flush() { this.javaModelDeltas = new ArrayList(); } /** * Flushes ZipFiles cache if there are no more clients. */ public void flushZipFiles() { synchronized(this.zipFiles) { Thread currentThread = Thread.currentThread(); HashMap map = (HashMap)this.zipFiles.remove(currentThread); if (map == null) return; Iterator iterator = map.values().iterator(); while (iterator.hasNext()) { try { ZipFile zipFile = (ZipFile)iterator.next(); if (JavaModelManager.ZIP_ACCESS_VERBOSE) { System.out.println("(" + currentThread + ") [JavaModelManager.flushZipFiles()] Closing ZipFile on " +zipFile.getName()); //$NON-NLS-1$//$NON-NLS-2$ } zipFile.close(); } catch (IOException e) { } } } } public DeltaProcessor getDeltaProcessor() { return this.deltaState.getDeltaProcessor(); } /** * Returns the set of elements which are out of synch with their buffers. */ protected Map getElementsOutOfSynchWithBuffers() { return this.elementsOutOfSynchWithBuffers; } /** * Returns the IJavaElement represented by the * String memento. */ public IJavaElement getHandleFromMemento(String memento) throws JavaModelException { if (memento == null) { return null; } JavaModel model= (JavaModel) getJavaModel(); if (memento.equals("")){ // workspace memento //$NON-NLS-1$ return model; } int modelEnd= memento.indexOf(JavaElement.JEM_JAVAPROJECT); if (modelEnd == -1) { return null; } boolean returnProject= false; int projectEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENTROOT, modelEnd); if (projectEnd == -1) { projectEnd= memento.length(); returnProject= true; } String projectName= memento.substring(modelEnd + 1, projectEnd); JavaProject proj= (JavaProject) model.getJavaProject(projectName); if (returnProject) { return proj; } int rootEnd= memento.indexOf(JavaElement.JEM_PACKAGEFRAGMENT, projectEnd + 1); // TODO khartlage temp-del // if (rootEnd == -1) { // return model.getHandleFromMementoForRoot(memento, proj, projectEnd, memento.length()); // } // IPackageFragmentRoot root = model.getHandleFromMementoForRoot(memento, proj, projectEnd, rootEnd); // if (root == null) // return null; // // int end= memento.indexOf(JavaElement.JEM_COMPILATIONUNIT, rootEnd); // if (end == -1) { // end= memento.indexOf(JavaElement.JEM_CLASSFILE, rootEnd); // if (end == -1) { // if (rootEnd + 1 == memento.length()) { // return root.getPackageFragment(IPackageFragment.DEFAULT_PACKAGE_NAME); // } else { // return root.getPackageFragment(memento.substring(rootEnd + 1)); // } // } // //deal with class file and binary members // return model.getHandleFromMementoForBinaryMembers(memento, root, rootEnd, end); // } // // //deal with compilation units and source members // return model.getHandleFromMementoForSourceMembers(memento, root, rootEnd, end); return null; } // public IndexManager getIndexManager() { // return this.deltaProcessor.indexManager; // } /** * Returns the info for the element. */ public Object getInfo(IJavaElement element) { return this.cache.getInfo(element); } /** * Returns the handle to the active Java Model. */ public final JavaModel getJavaModel() { return javaModel; } /** * Returns the singleton JavaModelManager */ public final static JavaModelManager getJavaModelManager() { return Manager; } /** * Returns the last built state for the given project, or null if there is none. * Deserializes the state if necessary. * * For use by image builder and evaluation support only */ public Object getLastBuiltState(IProject project, IProgressMonitor monitor) { if (!JavaProject.hasJavaNature(project)) return null; // should never be requested on non-Java projects PerProjectInfo info = getPerProjectInfo(project, true/*create if missing*/); if (!info.triedRead) { info.triedRead = true; try { if (monitor != null) monitor.subTask(Util.bind("build.readStateProgress", project.getName())); //$NON-NLS-1$ info.savedState = readState(project); } catch (CoreException e) { e.printStackTrace(); } } return info.savedState; } /* * Returns the per-project info for the given project. If specified, create the info if the info doesn't exist. */ public PerProjectInfo getPerProjectInfo(IProject project, boolean create) { synchronized(perProjectInfo) { // use the perProjectInfo collection as its own lock PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project); if (info == null && create) { info= new PerProjectInfo(project); perProjectInfo.put(project, info); } return info; } } /* * Returns the per-project info for the given project. * If the info doesn't exist, check for the project existence and create the info. * @throws JavaModelException if the project doesn't exist. */ public PerProjectInfo getPerProjectInfoCheckExistence(IProject project) throws JavaModelException { JavaModelManager.PerProjectInfo info = getPerProjectInfo(project, false /* don't create info */); if (info == null) { if (!JavaProject.hasJavaNature(project)) { throw ((JavaProject)JavaCore.create(project)).newNotPresentException(); } info = getPerProjectInfo(project, true /* create info */); } return info; } /* * Returns the per-working copy info for the given working copy at the given path. * If it doesn't exist and if create, add a new per-working copy info with the given problem requestor. * If recordUsage, increment the per-working copy info's use count. * Returns null if it doesn't exist and not create. */ public PerWorkingCopyInfo getPerWorkingCopyInfo(CompilationUnit workingCopy,boolean create, boolean recordUsage, IProblemRequestor problemRequestor) { synchronized(perWorkingCopyInfos) { // use the perWorkingCopyInfo collection as its own lock WorkingCopyOwner owner = workingCopy.owner; Map workingCopyToInfos = (Map)this.perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null && create) { workingCopyToInfos = new HashMap(); this.perWorkingCopyInfos.put(owner, workingCopyToInfos); } PerWorkingCopyInfo info = workingCopyToInfos == null ? null : (PerWorkingCopyInfo) workingCopyToInfos.get(workingCopy); if (info == null && create) { info= new PerWorkingCopyInfo(workingCopy, problemRequestor); workingCopyToInfos.put(workingCopy, info); } if (info != null && recordUsage) info.useCount++; return info; } } /** * Returns the name of the variables for which an CP variable initializer is registered through an extension point */ public static String[] getRegisteredVariableNames(){ Plugin jdtCorePlugin = JavaCore.getPlugin(); if (jdtCorePlugin == null) return null; ArrayList variableList = new ArrayList(5); // IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPVARIABLE_INITIALIZER_EXTPOINT_ID); // if (extension != null) { // IExtension[] extensions = extension.getExtensions(); // for(int i = 0; i < extensions.length; i++){ // IConfigurationElement [] configElements = extensions[i].getConfigurationElements(); // for(int j = 0; j < configElements.length; j++){ // String varAttribute = configElements[j].getAttribute("variable"); //$NON-NLS-1$ // if (varAttribute != null) variableList.add(varAttribute); // } // } // } String[] variableNames = new String[variableList.size()]; variableList.toArray(variableNames); return variableNames; } /** * Returns the name of the container IDs for which an CP container initializer is registered through an extension point */ // public static String[] getRegisteredContainerIDs(){ // // Plugin jdtCorePlugin = PHPCore.getPlugin(); // if (jdtCorePlugin == null) return null; // // ArrayList containerIDList = new ArrayList(5); // IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.CPCONTAINER_INITIALIZER_EXTPOINT_ID); // if (extension != null) { // IExtension[] extensions = extension.getExtensions(); // for(int i = 0; i < extensions.length; i++){ // IConfigurationElement [] configElements = extensions[i].getConfigurationElements(); // for(int j = 0; j < configElements.length; j++){ // String idAttribute = configElements[j].getAttribute("id"); //$NON-NLS-1$ // if (idAttribute != null) containerIDList.add(idAttribute); // } // } // } // String[] containerIDs = new String[containerIDList.size()]; // containerIDList.toArray(containerIDs); // return containerIDs; // } /** * Returns the File to use for saving and restoring the last built state for the given project. */ private File getSerializationFile(IProject project) { if (!project.exists()) return null; IPath workingLocation = project.getWorkingLocation(JavaCore.PLUGIN_ID); return workingLocation.append("state.dat").toFile(); //$NON-NLS-1$ } /* * Returns the temporary cache for newly opened elements for the current thread. * Creates it if not already created. */ public HashMap getTemporaryCache() { HashMap result = (HashMap)this.temporaryCache.get(); if (result == null) { result = new HashMap(); this.temporaryCache.set(result); } return result; } /** * Returns the open ZipFile at the given location. If the ZipFile * does not yet exist, it is created, opened, and added to the cache * of open ZipFiles. The location must be a absolute path. * * @exception CoreException If unable to create/open the ZipFile */ public ZipFile getZipFile(IPath path) throws CoreException { synchronized(this.zipFiles) { // TODO: use PeThreadObject which does synchronization Thread currentThread = Thread.currentThread(); HashMap map = null; ZipFile zipFile; if ((map = (HashMap)this.zipFiles.get(currentThread)) != null && (zipFile = (ZipFile)map.get(path)) != null) { return zipFile; } String fileSystemPath= null; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IResource file = root.findMember(path); if (path.isAbsolute() && file != null) { if (file == null) { // external file fileSystemPath= path.toOSString(); } else { // internal resource (not an IFile or not existing) IPath location; if (file.getType() != IResource.FILE || (location = file.getLocation()) == null) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$ } fileSystemPath= location.toOSString(); } } else if (!path.isAbsolute()) { file= root.getFile(path); if (file == null || file.getType() != IResource.FILE) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$ } IPath location = file.getLocation(); if (location == null) { throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("file.notFound", path.toString()), null)); //$NON-NLS-1$ } fileSystemPath= location.toOSString(); } else { fileSystemPath= path.toOSString(); } try { if (ZIP_ACCESS_VERBOSE) { System.out.println("(" + currentThread + ") [JavaModelManager.getZipFile(IPath)] Creating ZipFile on " + fileSystemPath ); //$NON-NLS-1$ //$NON-NLS-2$ } zipFile = new ZipFile(fileSystemPath); if (map != null) { map.put(path, zipFile); } return zipFile; } catch (IOException e) { throw new CoreException(new Status(Status.ERROR, JavaCore.PLUGIN_ID, -1, Util.bind("status.IOException"), e)); //$NON-NLS-1$ } } } /* * Returns whether there is a temporary cache for the current thread. */ public boolean hasTemporaryCache() { return this.temporaryCache.get() != null; } // public void loadVariablesAndContainers() throws CoreException { // // // backward compatibility, consider persistent property // QualifiedName qName = new QualifiedName(PHPCore.PLUGIN_ID, "variables"); //$NON-NLS-1$ // String xmlString = ResourcesPlugin.getWorkspace().getRoot().getPersistentProperty(qName); // // try { // if (xmlString != null){ // StringReader reader = new StringReader(xmlString); // Element cpElement; // try { // DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); // cpElement = parser.parse(new InputSource(reader)).getDocumentElement(); // } catch(SAXException e) { // return; // } catch(ParserConfigurationException e){ // return; // } finally { // reader.close(); // } // if (cpElement == null) return; // if (!cpElement.getNodeName().equalsIgnoreCase("variables")) { //$NON-NLS-1$ // return; // } // // NodeList list= cpElement.getChildNodes(); // int length= list.getLength(); // for (int i= 0; i < length; ++i) { // Node node= list.item(i); // short type= node.getNodeType(); // if (type == Node.ELEMENT_NODE) { // Element element= (Element) node; // if (element.getNodeName().equalsIgnoreCase("variable")) { //$NON-NLS-1$ // variablePut( // element.getAttribute("name"), //$NON-NLS-1$ // new Path(element.getAttribute("path"))); //$NON-NLS-1$ // } // } // } // } // } catch(IOException e){ // } finally { // if (xmlString != null){ // ResourcesPlugin.getWorkspace().getRoot().setPersistentProperty(qName, null); // flush old one // } // // } // // // load variables and containers from preferences into cache // Preferences preferences = PHPCore.getPlugin().getPluginPreferences(); // // // only get variable from preferences not set to their default // String[] propertyNames = preferences.propertyNames(); // int variablePrefixLength = CP_VARIABLE_PREFERENCES_PREFIX.length(); // for (int i = 0; i < propertyNames.length; i++){ // String propertyName = propertyNames[i]; // if (propertyName.startsWith(CP_VARIABLE_PREFERENCES_PREFIX)){ // String varName = propertyName.substring(variablePrefixLength); // IPath varPath = new Path(preferences.getString(propertyName).trim()); // // Variables.put(varName, varPath); // PreviousSessionVariables.put(varName, varPath); // } // if (propertyName.startsWith(CP_CONTAINER_PREFERENCES_PREFIX)){ // recreatePersistedContainer(propertyName, preferences.getString(propertyName), true/*add to container values*/); // } // } // // override persisted values for variables which have a registered initializer // String[] registeredVariables = getRegisteredVariableNames(); // for (int i = 0; i < registeredVariables.length; i++) { // String varName = registeredVariables[i]; // Variables.put(varName, null); // reset variable, but leave its entry in the Map, so it will be part of variable names. // } // // override persisted values for containers which have a registered initializer // String[] registeredContainerIDs = getRegisteredContainerIDs(); // for (int i = 0; i < registeredContainerIDs.length; i++) { // String containerID = registeredContainerIDs[i]; // Iterator projectIterator = Containers.keySet().iterator(); // while (projectIterator.hasNext()){ // IJavaProject project = (IJavaProject)projectIterator.next(); // Map projectContainers = (Map)Containers.get(project); // if (projectContainers != null){ // Iterator containerIterator = projectContainers.keySet().iterator(); // while (containerIterator.hasNext()){ // IPath containerPath = (IPath)containerIterator.next(); // if (containerPath.segment(0).equals(containerID)) { // registered container // projectContainers.put(containerPath, null); // reset container value, but leave entry in Map // } // } // } // } // } // } /** * Merged all awaiting deltas. */ public IJavaElementDelta mergeDeltas(Collection deltas) { if (deltas.size() == 0) return null; if (deltas.size() == 1) return (IJavaElementDelta)deltas.iterator().next(); if (DeltaProcessor.VERBOSE) { System.out.println("MERGING " + deltas.size() + " DELTAS ["+Thread.currentThread()+"]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } Iterator iterator = deltas.iterator(); IJavaElement javaModel = this.getJavaModel(); JavaElementDelta rootDelta = new JavaElementDelta(javaModel); boolean insertedTree = false; while (iterator.hasNext()) { JavaElementDelta delta = (JavaElementDelta)iterator.next(); if (DeltaProcessor.VERBOSE) { System.out.println(delta.toString()); } IJavaElement element = delta.getElement(); if (javaModel.equals(element)) { IJavaElementDelta[] children = delta.getAffectedChildren(); for (int j = 0; j < children.length; j++) { JavaElementDelta projectDelta = (JavaElementDelta) children[j]; rootDelta.insertDeltaTree(projectDelta.getElement(), projectDelta); insertedTree = true; } IResourceDelta[] resourceDeltas = delta.getResourceDeltas(); if (resourceDeltas != null) { for (int i = 0, length = resourceDeltas.length; i < length; i++) { rootDelta.addResourceDelta(resourceDeltas[i]); insertedTree = true; } } } else { rootDelta.insertDeltaTree(element, delta); insertedTree = true; } } if (insertedTree) { return rootDelta; } else { return null; } } /** * Returns the info for this element without * disturbing the cache ordering. */ // TODO: should be synchronized, could answer unitialized info or if cache is in middle of rehash, could even answer distinct element info protected Object peekAtInfo(IJavaElement element) { return this.cache.peekAtInfo(element); } /** * @see ISaveParticipant */ public void prepareToSave(ISaveContext context) throws CoreException { } protected void putInfo(IJavaElement element, Object info) { this.cache.putInfo(element, info); } /* * Puts the infos in the given map (keys are IJavaElements and values are JavaElementInfos) * in the Java model cache in an atomic way. * First checks that the info for the opened element (or one of its ancestors) has not been * added to the cache. If it is the case, another thread has opened the element (or one of * its ancestors). So returns without updating the cache. */ protected synchronized void putInfos(IJavaElement openedElement, Map newElements) { // remove children Object existingInfo = this.cache.peekAtInfo(openedElement); if (openedElement instanceof IParent && existingInfo instanceof JavaElementInfo) { IJavaElement[] children = ((JavaElementInfo)existingInfo).getChildren(); for (int i = 0, size = children.length; i < size; ++i) { JavaElement child = (JavaElement) children[i]; try { child.close(); } catch (JavaModelException e) { // ignore } } } Iterator iterator = newElements.keySet().iterator(); while (iterator.hasNext()) { IJavaElement element = (IJavaElement)iterator.next(); Object info = newElements.get(element); this.cache.putInfo(element, info); } } /** * Reads the build state for the relevant project. */ protected Object readState(IProject project) throws CoreException { File file = getSerializationFile(project); if (file != null && file.exists()) { try { DataInputStream in= new DataInputStream(new BufferedInputStream(new FileInputStream(file))); try { String pluginID= in.readUTF(); if (!pluginID.equals(JavaCore.PLUGIN_ID)) throw new IOException(Util.bind("build.wrongFileFormat")); //$NON-NLS-1$ String kind= in.readUTF(); if (!kind.equals("STATE")) //$NON-NLS-1$ throw new IOException(Util.bind("build.wrongFileFormat")); //$NON-NLS-1$ if (in.readBoolean()) return PHPBuilder.readState(project, in); if (PHPBuilder.DEBUG) System.out.println("Saved state thinks last build failed for " + project.getName()); //$NON-NLS-1$ } finally { in.close(); } } catch (Exception e) { e.printStackTrace(); throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, "Error reading last build state for project "+ project.getName(), e)); //$NON-NLS-1$ } } return null; } // public static void recreatePersistedContainer(String propertyName, String containerString, boolean addToContainerValues) { // int containerPrefixLength = CP_CONTAINER_PREFERENCES_PREFIX.length(); // int index = propertyName.indexOf('|', containerPrefixLength); // if (containerString != null) containerString = containerString.trim(); // if (index > 0) { // final String projectName = propertyName.substring(containerPrefixLength, index).trim(); // JavaProject project = (JavaProject)getJavaModelManager().getJavaModel().getJavaProject(projectName); // final IPath containerPath = new Path(propertyName.substring(index+1).trim()); // // if (containerString == null || containerString.equals(CP_ENTRY_IGNORE)) { // containerPut(project, containerPath, null); // } else { // final IClasspathEntry[] containerEntries = project.decodeClasspath(containerString, false, false); // if (containerEntries != null && containerEntries != JavaProject.INVALID_CLASSPATH) { // IClasspathContainer container = new IClasspathContainer() { // public IClasspathEntry[] getClasspathEntries() { // return containerEntries; // } // public String getDescription() { // return "Persisted container ["+containerPath+" for project ["+ projectName+"]"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ // } // public int getKind() { // return 0; // } // public IPath getPath() { // return containerPath; // } // public String toString() { // return getDescription(); // } // // }; // if (addToContainerValues) { // containerPut(project, containerPath, container); // } // Map projectContainers = (Map)PreviousSessionContainers.get(project); // if (projectContainers == null){ // projectContainers = new HashMap(1); // PreviousSessionContainers.put(project, projectContainers); // } // projectContainers.put(containerPath, container); // } // } // } // } /** * Registers the given delta with this manager. */ protected void registerJavaModelDelta(IJavaElementDelta delta) { this.javaModelDeltas.add(delta); } /** * Remembers the given scope in a weak set * (so no need to remove it: it will be removed by the garbage collector) */ // public void rememberScope(AbstractSearchScope scope) { // // NB: The value has to be null so as to not create a strong reference on the scope // this.scopes.put(scope, null); // } /** * removeElementChangedListener method comment. */ public void removeElementChangedListener(IElementChangedListener listener) { for (int i = 0; i < this.elementChangedListenerCount; i++){ if (this.elementChangedListeners[i].equals(listener)){ // need to clone defensively since we might be in the middle of listener notifications (#fire) int length = this.elementChangedListeners.length; IElementChangedListener[] newListeners = new IElementChangedListener[length]; System.arraycopy(this.elementChangedListeners, 0, newListeners, 0, i); int[] newMasks = new int[length]; System.arraycopy(this.elementChangedListenerMasks, 0, newMasks, 0, i); // copy trailing listeners int trailingLength = this.elementChangedListenerCount - i - 1; if (trailingLength > 0){ System.arraycopy(this.elementChangedListeners, i+1, newListeners, i, trailingLength); System.arraycopy(this.elementChangedListenerMasks, i+1, newMasks, i, trailingLength); } // update manager listener state (#fire need to iterate over original listeners through a local variable to hold onto // the original ones) this.elementChangedListeners = newListeners; this.elementChangedListenerMasks = newMasks; this.elementChangedListenerCount--; return; } } } // PROTECTED VOID REMOVEINFO(IJAVAELEMENT ELEMENT) { // THIS.CACHE.REMOVEINFO(ELEMENT); // } /* * Removes all cached info for the given element (including all children) * from the cache. * Returns the info for the given element, or null if it was closed. */ public synchronized Object removeInfoAndChildren(JavaElement element) throws JavaModelException { Object info = this.cache.peekAtInfo(element); if (info != null) { boolean wasVerbose = false; try { if (VERBOSE) { System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + element.toStringWithAncestors()); //$NON-NLS-1$//$NON-NLS-2$ wasVerbose = true; VERBOSE = false; } element.closing(info); if (element instanceof IParent && info instanceof JavaElementInfo) { IJavaElement[] children = ((JavaElementInfo)info).getChildren(); for (int i = 0, size = children.length; i < size; ++i) { JavaElement child = (JavaElement) children[i]; child.close(); } } this.cache.removeInfo(element); if (wasVerbose) { System.out.println("-> Package cache size = " + this.cache.pkgSize()); //$NON-NLS-1$ System.out.println("-> Openable cache filling ratio = " + NumberFormat.getInstance().format(this.cache.openableFillingRatio()) + "%"); //$NON-NLS-1$//$NON-NLS-2$ } } finally { JavaModelManager.VERBOSE = wasVerbose; } return info; } return null; } public void removePerProjectInfo(JavaProject javaProject) { synchronized(perProjectInfo) { // use the perProjectInfo collection as its own lock IProject project = javaProject.getProject(); PerProjectInfo info= (PerProjectInfo) perProjectInfo.get(project); if (info != null) { perProjectInfo.remove(project); } } } /* * Resets the temporary cache for newly created elements to null. */ public void resetTemporaryCache() { this.temporaryCache.set(null); } /** * @see ISaveParticipant */ public void rollback(ISaveContext context){ } private void saveState(PerProjectInfo info, ISaveContext context) throws CoreException { // passed this point, save actions are non trivial if (context.getKind() == ISaveContext.SNAPSHOT) return; // save built state if (info.triedRead) saveBuiltState(info); } /** * Saves the built state for the project. */ private void saveBuiltState(PerProjectInfo info) throws CoreException { if (PHPBuilder.DEBUG) System.out.println(Util.bind("build.saveStateProgress", info.project.getName())); //$NON-NLS-1$ File file = getSerializationFile(info.project); if (file == null) return; long t = System.currentTimeMillis(); try { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); try { out.writeUTF(JavaCore.PLUGIN_ID); out.writeUTF("STATE"); //$NON-NLS-1$ if (info.savedState == null) { out.writeBoolean(false); } else { out.writeBoolean(true); PHPBuilder.writeState(info.savedState, out); } } finally { out.close(); } } catch (RuntimeException e) { try {file.delete();} catch(SecurityException se) {} throw new CoreException( new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, Util.bind("build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$ } catch (IOException e) { try {file.delete();} catch(SecurityException se) {} throw new CoreException( new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, Platform.PLUGIN_ERROR, Util.bind("build.cannotSaveState", info.project.getName()), e)); //$NON-NLS-1$ } if (PHPBuilder.DEBUG) { t = System.currentTimeMillis() - t; System.out.println(Util.bind("build.saveStateComplete", String.valueOf(t))); //$NON-NLS-1$ } } /** * @see ISaveParticipant */ public void saving(ISaveContext context) throws CoreException { IProject savedProject = context.getProject(); if (savedProject != null) { if (!JavaProject.hasJavaNature(savedProject)) return; // ignore PerProjectInfo info = getPerProjectInfo(savedProject, true /* create info */); saveState(info, context); return; } ArrayList vStats= null; // lazy initialized for (Iterator iter = perProjectInfo.values().iterator(); iter.hasNext();) { try { PerProjectInfo info = (PerProjectInfo) iter.next(); saveState(info, context); } catch (CoreException e) { if (vStats == null) vStats= new ArrayList(); vStats.add(e.getStatus()); } } if (vStats != null) { IStatus[] stats= new IStatus[vStats.size()]; vStats.toArray(stats); throw new CoreException(new MultiStatus(JavaCore.PLUGIN_ID, IStatus.ERROR, stats, Util.bind("build.cannotSaveStates"), null)); //$NON-NLS-1$ } } /** * Record the order in which to build the java projects (batch build). This order is based * on the projects classpath settings. */ protected void setBuildOrder(String[] javaBuildOrder) throws JavaModelException { // optional behaviour // possible value of index 0 is Compute if (!JavaCore.COMPUTE.equals(JavaCore.getOption(JavaCore.CORE_JAVA_BUILD_ORDER))) return; // cannot be customized at project level if (javaBuildOrder == null || javaBuildOrder.length <= 1) return; IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceDescription description = workspace.getDescription(); String[] wksBuildOrder = description.getBuildOrder(); String[] newOrder; if (wksBuildOrder == null){ newOrder = javaBuildOrder; } else { // remove projects which are already mentionned in java builder order int javaCount = javaBuildOrder.length; HashMap newSet = new HashMap(javaCount); // create a set for fast check for (int i = 0; i < javaCount; i++){ newSet.put(javaBuildOrder[i], javaBuildOrder[i]); } int removed = 0; int oldCount = wksBuildOrder.length; for (int i = 0; i < oldCount; i++){ if (newSet.containsKey(wksBuildOrder[i])){ wksBuildOrder[i] = null; removed++; } } // add Java ones first newOrder = new String[oldCount - removed + javaCount]; System.arraycopy(javaBuildOrder, 0, newOrder, 0, javaCount); // java projects are built first // copy previous items in their respective order int index = javaCount; for (int i = 0; i < oldCount; i++){ if (wksBuildOrder[i] != null){ newOrder[index++] = wksBuildOrder[i]; } } } // commit the new build order out description.setBuildOrder(newOrder); try { workspace.setDescription(description); } catch(CoreException e){ throw new JavaModelException(e); } } /** * Sets the last built state for the given project, or null to reset it. */ public void setLastBuiltState(IProject project, Object state) { if (!JavaProject.hasJavaNature(project)) return; // should never be requested on non-Java projects PerProjectInfo info = getPerProjectInfo(project, true /*create if missing*/); info.triedRead = true; // no point trying to re-read once using setter info.savedState = state; if (state == null) { // delete state file to ensure a full build happens if the workspace crashes try { File file = getSerializationFile(project); if (file != null && file.exists()) file.delete(); } catch(SecurityException se) {} } } public void shutdown () { // TODO khartlage temp-del // if (this.deltaProcessor.indexManager != null){ // no more indexing // this.deltaProcessor.indexManager.shutdown(); // } try { IJavaModel model = this.getJavaModel(); if (model != null) { model.close(); } } catch (JavaModelException e) { } } /** * Turns the firing mode to on. That is, deltas that are/have been * registered will be fired. */ public void startDeltas() { this.isFiring= true; } /** * Turns the firing mode to off. That is, deltas that are/have been * registered will not be fired until deltas are started again. */ public void stopDeltas() { this.isFiring= false; } /** * Update Java Model given some delta */ // public void updateJavaModel(IJavaElementDelta customDelta) { // // if (customDelta == null){ // for (int i = 0, length = this.javaModelDeltas.size(); i < length; i++){ // IJavaElementDelta delta = (IJavaElementDelta)this.javaModelDeltas.get(i); // this.modelUpdater.processJavaDelta(delta); // } // } else { // this.modelUpdater.processJavaDelta(customDelta); // } // } public static IPath variableGet(String variableName){ return (IPath)Variables.get(variableName); } public static String[] variableNames(){ int length = Variables.size(); String[] result = new String[length]; Iterator vars = Variables.keySet().iterator(); int index = 0; while (vars.hasNext()) { result[index++] = (String) vars.next(); } return result; } public static void variablePut(String variableName, IPath variablePath){ // update cache - do not only rely on listener refresh if (variablePath == null) { Variables.remove(variableName); PreviousSessionVariables.remove(variableName); } else { Variables.put(variableName, variablePath); } // do not write out intermediate initialization value if (variablePath == JavaModelManager.VariableInitializationInProgress){ return; } Preferences preferences = JavaCore.getPlugin().getPluginPreferences(); String variableKey = CP_VARIABLE_PREFERENCES_PREFIX+variableName; String variableString = variablePath == null ? CP_ENTRY_IGNORE : variablePath.toString(); preferences.setDefault(variableKey, CP_ENTRY_IGNORE); // use this default to get rid of removed ones preferences.setValue(variableKey, variableString); JavaCore.getPlugin().savePluginPreferences(); } /* * Returns all the working copies which have the given owner. * Adds the working copies of the primary owner if specified. * Returns null if it has none. */ public ICompilationUnit[] getWorkingCopies(WorkingCopyOwner owner, boolean addPrimary) { synchronized(perWorkingCopyInfos) { ICompilationUnit[] primaryWCs = addPrimary && owner != DefaultWorkingCopyOwner.PRIMARY ? getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false) : null; Map workingCopyToInfos = (Map)perWorkingCopyInfos.get(owner); if (workingCopyToInfos == null) return primaryWCs; int primaryLength = primaryWCs == null ? 0 : primaryWCs.length; int size = workingCopyToInfos.size(); // note size is > 0 otherwise pathToPerWorkingCopyInfos would be null ICompilationUnit[] result = new ICompilationUnit[primaryLength + size]; if (primaryWCs != null) { System.arraycopy(primaryWCs, 0, result, 0, primaryLength); } Iterator iterator = workingCopyToInfos.values().iterator(); int index = primaryLength; while(iterator.hasNext()) { result[index++] = ((JavaModelManager.PerWorkingCopyInfo)iterator.next()).getWorkingCopy(); } return result; } } }