/*******************************************************************************
* 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.IPluginDescriptor;
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.BufferManager;
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
.
* IElementChangedListener
s register with the JavaModelManager
,
* and receive ElementChangedEvent
s for all IJavaModel
s.
*
* The single instance of
* 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 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
* 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 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 = "##null
if unable to associate the given resource
* with a Java element.
*
*
* IJavaProject
.java
file - the element returned is the corresponding ICompilationUnit
.class
file - the element returned is the corresponding IClassFile
.jar
file - the element returned is the corresponding IPackageFragmentRoot
IPackageFragmentRoot
* or IPackageFragment
IJavaModel
null
if unable to associate the given file
* with a Java element.
*
*
*
* .java
file - the element returned is the corresponding ICompilationUnit
.class
file - the element returned is the corresponding IClassFile
.jar
file - the element returned is the corresponding IPackageFragmentRoot
null
if unable to associate the given folder with a Java element.
* .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('/', '.');
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 IResourceDelta
s into IJavaElementDelta
s.
*/
// public final DeltaProcessor deltaProcessor = new DeltaProcessor(this);
/**
* Used to update the JavaModel for IJavaElementDelta
s.
*/
// 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 = true;
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 ? "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;
IPluginDescriptor descr= JavaCore.getJavaCore().getDescriptor();
IPath workingLocation= project.getPluginWorkingLocation(descr);
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;
}
}
}