Index: model/org/eclipse/jdt/internal/core/JavaModelManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java,v retrieving revision 1.298 diff -u -r1.298 JavaModelManager.java --- model/org/eclipse/jdt/internal/core/JavaModelManager.java 14 Nov 2005 08:59:32 -0000 1.298 +++ model/org/eclipse/jdt/internal/core/JavaModelManager.java 14 Nov 2005 18:22:09 -0000 @@ -11,7 +11,9 @@ package org.eclipse.jdt.internal.core; import java.io.*; +import java.text.MessageFormat; import java.util.*; +import java.util.Map.Entry; import java.util.zip.ZipFile; import javax.xml.parsers.DocumentBuilder; @@ -104,7 +106,7 @@ public final static String CP_ENTRY_IGNORE = "####"; //$NON-NLS-1$ public final static IPath CP_ENTRY_IGNORE_PATH = new Path(CP_ENTRY_IGNORE); - private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 1; + private final static int VARIABLES_AND_CONTAINERS_FILE_VERSION = 2; /** * Name of the extension point for contributing classpath variable initializers @@ -1930,8 +1932,12 @@ DataInputStream in = null; try { in = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); - if (VARIABLES_AND_CONTAINERS_FILE_VERSION == in.readInt()) { - + switch (in.readInt()) + { + case 2 : + new VariablesAndContainersLoadHelper(in).load(); + break; + case 1 : // backward compatibility, load old format // variables int size = in.readInt(); while (size-- > 0) { @@ -1986,6 +1992,283 @@ containersReset(getRegisteredContainerIDs()); } + private static final class PersistedClasspathContainer implements + IClasspathContainer { + + private final IPath containerPath; + + private final IClasspathEntry[] entries; + + private final IJavaProject project; + + PersistedClasspathContainer(IJavaProject project, IPath containerPath, + IClasspathEntry[] entries) { + super(); + this.containerPath = containerPath; + this.entries = entries; + this.project = project; + } + + public IClasspathEntry[] getClasspathEntries() { + return entries; + } + + public String getDescription() { + return "Persisted container [" + containerPath //$NON-NLS-1$ + + " for project [" + project.getElementName() //$NON-NLS-1$ + + "]]"; //$NON-NLS-1$ + } + + public int getKind() { + return 0; + } + + public IPath getPath() { + return containerPath; + } + + public String toString() { + return getDescription(); + } + } + + private final class VariablesAndContainersLoadHelper { + + private static final int ArrayIncrement = 200; + + private IClasspathEntry[] allClasspathEntries; + private int allClasspathEntryCount; + + private final Map allPaths; // String -> IPath + + private String[] allStrings; + private int allStringsCount; + + private final DataInputStream in; + + VariablesAndContainersLoadHelper(DataInputStream in) { + super(); + this.allClasspathEntries = null; + this.allClasspathEntryCount = 0; + this.allPaths = new HashMap(); + this.allStrings = null; + this.allStringsCount = 0; + this.in = in; + } + + void load() throws IOException { + loadProjects(JavaModelManager.this.getJavaModel()); + loadVariables(); + } + + private IAccessRule loadAccessRule() throws IOException { + int kind = loadInt(); + IPath pattern = loadPath(); + + return new ClasspathAccessRule(pattern, kind); + } + + private IAccessRule[] loadAccessRules() throws IOException { + int count = loadInt(); + + if (count == 0) + return ClasspathEntry.NO_ACCESS_RULES; + + IAccessRule[] rules = new IAccessRule[count]; + + for (int i = 0; i < count; ++i) + rules[i] = loadAccessRule(); + + return rules; + } + + private IClasspathAttribute loadAttribute() throws IOException { + String name = loadString(); + String value = loadString(); + + return new ClasspathAttribute(name, value); + } + + private IClasspathAttribute[] loadAttributes() throws IOException { + int count = loadInt(); + + if (count == 0) + return ClasspathEntry.NO_EXTRA_ATTRIBUTES; + + IClasspathAttribute[] attributes = new IClasspathAttribute[count]; + + for (int i = 0; i < count; ++i) + attributes[i] = loadAttribute(); + + return attributes; + } + + private boolean loadBoolean() throws IOException { + return in.readBoolean(); + } + + private IClasspathEntry[] loadClasspathEntries() throws IOException { + int count = loadInt(); + IClasspathEntry[] entries = new IClasspathEntry[count]; + + for (int i = 0; i < count; ++i) + entries[i] = loadClasspathEntry(); + + return entries; + } + + private IClasspathEntry loadClasspathEntry() throws IOException { + int id = loadInt(); + + if (id < 0 || id > allClasspathEntryCount) + throw new IOException("Unexpected classpathentry id"); //$NON-NLS-1$ + + if (id < allClasspathEntryCount) + return allClasspathEntries[id]; + + int contentKind = loadInt(); + int entryKind = loadInt(); + IPath path = loadPath(); + IPath[] inclusionPatterns = loadPaths(); + IPath[] exclusionPatterns = loadPaths(); + IPath sourceAttachmentPath = loadPath(); + IPath sourceAttachmentRootPath = loadPath(); + IPath specificOutputLocation = loadPath(); + boolean isExported = loadBoolean(); + IAccessRule[] accessRules = loadAccessRules(); + boolean combineAccessRules = loadBoolean(); + IClasspathAttribute[] extraAttributes = loadAttributes(); + + IClasspathEntry entry = new ClasspathEntry(contentKind, entryKind, + path, inclusionPatterns, exclusionPatterns, + sourceAttachmentPath, sourceAttachmentRootPath, + specificOutputLocation, isExported, accessRules, + combineAccessRules, extraAttributes); + + IClasspathEntry[] array = allClasspathEntries; + + if (array == null || id == array.length) { + array = new IClasspathEntry[id + ArrayIncrement]; + + if (id != 0) + System.arraycopy(allClasspathEntries, 0, array, 0, id); + + allClasspathEntries = array; + } + + array[id] = entry; + allClasspathEntryCount = id + 1; + + return entry; + } + + private void loadContainers(IJavaProject project) throws IOException { + int count = loadInt(); + + for (int i = 0; i < count; ++i) { + IPath path = loadPath(); + IClasspathEntry[] entries = loadClasspathEntries(); + IClasspathContainer container = new PersistedClasspathContainer( + project, path, entries); + + JavaModelManager.this.containerPut(project, path, container); + + Map oldContainers = (Map) JavaModelManager.this.previousSessionContainers + .get(project); + + if (oldContainers == null) { + oldContainers = new HashMap(); + JavaModelManager.this.previousSessionContainers.put(project, + oldContainers); + } + + oldContainers.put(path, container); + } + } + + private int loadInt() throws IOException { + return in.readInt(); + } + + private IPath loadPath() throws IOException { + if (loadBoolean()) + return null; + + String portableString = loadString(); + IPath path = (IPath) allPaths.get(portableString); + + if (path == null) { + path = Path.fromPortableString(portableString); + allPaths.put(portableString, path); + } + + return path; + } + + private IPath[] loadPaths() throws IOException { + int count = loadInt(); + IPath[] pathArray = new IPath[count]; + + for (int i = 0; i < count; ++i) + pathArray[i] = loadPath(); + + return pathArray; + } + + private void loadProjects(IJavaModel model) throws IOException { + int count = loadInt(); + + for (int i = 0; i < count; ++i) { + String projectName = loadString(); + + loadContainers(model.getJavaProject(projectName)); + } + } + + private String loadString() throws IOException { + int id = loadInt(); + + if (id < 0 || id > allStringsCount) + throw new IOException("Unexpected string id"); //$NON-NLS-1$ + + if (id < allStringsCount) + return allStrings[id]; + + String string = in.readUTF(); + String[] array = allStrings; + + if (array == null || id == array.length) { + array = new String[id + ArrayIncrement]; + + if (id != 0) + System.arraycopy(allStrings, 0, array, 0, id); + + allStrings = array; + } + + array[id] = string; + allStringsCount = id + 1; + + return string; + } + + private void loadVariables() throws IOException { + int size = loadInt(); + Map loadedVars = new HashMap(size); + + for (int i = 0; i < size; ++i) { + String varName = loadString(); + IPath varPath = loadPath(); + + if (varPath != null) + loadedVars.put(varName, varPath); + } + + JavaModelManager.this.previousSessionVariables.putAll(loadedVars); + JavaModelManager.this.variables.putAll(loadedVars); + } + } + /** * Returns the info for this element without * disturbing the cache ordering. @@ -2324,6 +2607,10 @@ try { out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION); + if (VARIABLES_AND_CONTAINERS_FILE_VERSION == 2) + new VariablesAndContainersSaveHelper(out).save(); + else if (VARIABLES_AND_CONTAINERS_FILE_VERSION == 1) { + // old code retained for performance comparisons // variables out.writeInt(this.variables.size()); @@ -2384,7 +2671,7 @@ out.writeBytes(containerString); } } - + } } catch (IOException e) { IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving variables and containers", e); //$NON-NLS-1$ throw new CoreException(status); @@ -2399,13 +2686,210 @@ } } + private final class VariablesAndContainersSaveHelper { + + private final Map classpathEntryIds; // IClasspathEntry -> Integer + private final DataOutputStream out; + private final Map stringIds; // Strings -> Integer + + VariablesAndContainersSaveHelper(DataOutputStream out) { + super(); + this.classpathEntryIds = new HashMap(); + this.out = out; + this.stringIds = new HashMap(); + } + + void save() throws IOException, JavaModelException { + saveProjects(JavaModelManager.this.getJavaModel().getJavaProjects()); + saveVariables(JavaModelManager.this.variables); + } + + private void saveAccessRule(IAccessRule rule) throws IOException { + saveInt(rule.getKind()); + savePath(rule.getPattern()); + } + + private void saveAccessRules(IAccessRule[] rules) throws IOException { + int count = rules == null ? 0 : rules.length; + + saveInt(count); + for (int i = 0; i < count; ++i) + saveAccessRule(rules[i]); + } + + private void saveAttribute(IClasspathAttribute attribute) + throws IOException { + saveString(attribute.getName()); + saveString(attribute.getValue()); + } + + private void saveAttributes(IClasspathAttribute[] attributes) + throws IOException { + int count = attributes == null ? 0 : attributes.length; + + saveInt(count); + for (int i = 0; i < count; ++i) + saveAttribute(attributes[i]); + } + + private void saveClasspathEntries(IClasspathEntry[] entries) + throws IOException { + int count = entries == null ? 0 : entries.length; + + saveInt(count); + for (int i = 0; i < count; ++i) + saveClasspathEntry(entries[i]); + } + + private void saveClasspathEntry(IClasspathEntry entry) + throws IOException { + if (saveNewId(entry, classpathEntryIds)) { + saveInt(entry.getContentKind()); + saveInt(entry.getEntryKind()); + savePath(entry.getPath()); + savePaths(entry.getInclusionPatterns()); + savePaths(entry.getExclusionPatterns()); + savePath(entry.getSourceAttachmentPath()); + savePath(entry.getSourceAttachmentRootPath()); + savePath(entry.getOutputLocation()); + out.writeBoolean(entry.isExported()); + saveAccessRules(entry.getAccessRules()); + out.writeBoolean(entry.combineAccessRules()); + saveAttributes(entry.getExtraAttributes()); + } + } + + private void saveContainers(IJavaProject project, Map containerMap) + throws IOException { + saveInt(containerMap.size()); + + for (Iterator i = containerMap.entrySet().iterator(); i.hasNext();) { + Entry entry = (Entry) i.next(); + IPath path = (IPath) entry.getKey(); + IClasspathContainer container = (IClasspathContainer) entry + .getValue(); + IClasspathEntry[] cpEntries = null; + + if (container == null) { + // container has not been initialized yet, use previous + // session value + // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=73969) + container = JavaModelManager.this.getPreviousSessionContainer(path, + project); + } + + if (container != null) + cpEntries = container.getClasspathEntries(); + + savePath(path); + saveClasspathEntries(cpEntries); + } + } + + private void saveInt(int value) throws IOException { + out.writeInt(value); + } + + private boolean saveNewId(Object key, Map map) throws IOException { + Integer id = (Integer) map.get(key); + + if (id == null) { + int newId = map.size(); + + map.put(key, new Integer(newId)); + + saveInt(newId); + + return true; + } else { + saveInt(id.intValue()); + + return false; + } + } + + private void savePath(IPath path) throws IOException { + if (path == null) { + out.writeBoolean(true); + } else { + out.writeBoolean(false); + saveString(path.toPortableString()); + } + } + + private void savePaths(IPath[] paths) throws IOException { + int count = paths == null ? 0 : paths.length; + + saveInt(count); + for (int i = 0; i < count; ++i) + savePath(paths[i]); + } + + private void saveProjects(IJavaProject[] projects) throws IOException, + JavaModelException { + int count = projects.length; + + saveInt(count); + + for (int i = 0; i < count; ++i) { + IJavaProject project = projects[i]; + + saveString(project.getElementName()); + + Map containerMap = (Map) JavaModelManager.this.containers.get(project); + + if (containerMap == null) { + containerMap = Collections.EMPTY_MAP; + } else { + // clone while iterating + // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=59638) + containerMap = new HashMap(containerMap); + } + + saveContainers(project, containerMap); + } + } + + private void saveString(String string) throws IOException { + if (saveNewId(string, stringIds)) + out.writeUTF(string); + } + + private void saveVariables(Map map) throws IOException { + saveInt(map.size()); + + for (Iterator i = map.entrySet().iterator(); i.hasNext();) { + Entry entry = (Entry) i.next(); + String varName = (String) entry.getKey(); + IPath varPath = (IPath) entry.getValue(); + + saveString(varName); + savePath(varPath); + } + } + } + + private void traceVariableAndContainers(String action, long start) { + if (!VERBOSE) + return; + + Long delta = new Long(System.currentTimeMillis() - start); + Long length = new Long(getVariableAndContainersFile().length()); + String pattern = "{0} {1} bytes in variablesAndContainers.dat in {2}ms"; //$NON-NLS-1$ + String message = MessageFormat.format(pattern, new Object[]{action, length, delta}); + + System.out.println(message); + } + /** * @see ISaveParticipant */ public void saving(ISaveContext context) throws CoreException { // save variable and container values on snapshot/full save + long start = System.currentTimeMillis(); saveVariablesAndContainers(); + traceVariableAndContainers("Saved", start); //$NON-NLS-1$ if (context.getKind() == ISaveContext.FULL_SAVE) { // will need delta since this save (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38658) @@ -2589,7 +3073,9 @@ JavaCore.getPlugin().getPluginPreferences().addPropertyChangeListener(propertyListener); // retrieve variable values + long start = System.currentTimeMillis(); loadVariablesAndContainers(); + traceVariableAndContainers("Loaded", start); //$NON-NLS-1$ final IWorkspace workspace = ResourcesPlugin.getWorkspace(); workspace.addResourceChangeListener(