Index: core/src/org/netbeans/core/LookupCache.java =================================================================== RCS file: core/src/org/netbeans/core/LookupCache.java diff -N core/src/org/netbeans/core/LookupCache.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/src/org/netbeans/core/LookupCache.java 7 Jan 2003 04:04:02 -0000 @@ -0,0 +1,407 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2002 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.netbeans.core; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.*; + +import org.openide.ErrorManager; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; +import org.openide.loaders.DataFolder; +import org.openide.loaders.FolderLookup; +import org.openide.util.Lookup; +import org.openide.util.Utilities; +import org.openide.util.io.NbObjectInputStream; +import org.openide.util.io.NbObjectOutputStream; + +import org.netbeans.core.modules.Module; +import org.netbeans.core.modules.ModuleManager; +import org.netbeans.core.perftool.StartLog; + +/** + * Responsible for persisting the structure of folder lookup. + *
A cache is kept in serialized form in $userdir/cache/folder-lookup.ser. + * Unless the cache is invalidated due to changes in module JARs or + * files in $userdir/system/**, it is restored after a regular startup. + * The actual objects in lookup are not serialized - only their classes, + * instanceof information, position in the Services folder, and so on. This + * permits us to avoid calling the XML parser for every .settings object etc. + * Other forms of lookup like META-INF/services/* are not persisted. + *
Can be enabled or disabled with the system property netbeans.cache.lookup.
+ * @author Jesse Glick, Jaroslav Tulach
+ * @see "#20190"
+ */
+class LookupCache {
+
+ /** whether to enable the cache for this session */
+ private static final boolean ENABLED = Boolean.valueOf(System.getProperty("netbeans.cache.lookup", "true")).booleanValue(); // NOI18N
+
+ /** private logging for this class */
+ private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.core.LookupCache"); // NOI18N
+
+ /**
+ * Get the Services/ folder lookup.
+ * May either do it the slow way, or might load quickly from a cache.
+ * @return the folder lookup for the system
+ */
+ public static Lookup load() {
+ err.log("enabled=" + ENABLED);
+ if (ENABLED && cacheHit()) {
+ try {
+ return loadCache();
+ } catch (Exception e) {
+ err.notify(ErrorManager.INFORMATIONAL, e);
+ }
+ }
+ return loadDirect();
+ }
+
+ /**
+ * Load folder lookup directly from the system file system, parsing
+ * as necessary (the slow way).
+ */
+ private static Lookup loadDirect() {
+ FileObject services = Repository.getDefault().getDefaultFileSystem().findResource("Services"); // NOI18N
+ if (services != null) {
+ StartLog.logProgress("Got Services folder"); // NOI18N
+ FolderLookup f = new FolderLookup(DataFolder.findFolder(services), "SL["); // NOI18N
+ StartLog.logProgress("created FolderLookup"); // NOI18N
+ err.log("loadDirect from Services");
+ return f.getLookup();
+ } else {
+ err.log("loadDirect, but no Services");
+ return Lookup.EMPTY;
+ }
+ }
+
+ /**
+ * Determine if there is an existing lookup cache which can be used
+ * now as is.
+ * If there is a cache and a stamp file, and the stamp agrees with
+ * a calculation of the files and timestamps currently available to
+ * constitute the folder lookup, then the cache is used.
+ */
+ private static boolean cacheHit() {
+ File f = cacheFile();
+ if (f == null || !f.exists()) {
+ err.log("no cache file");
+ return false;
+ }
+ File stampFile = stampFile();
+ if (stampFile == null || !stampFile.exists()) {
+ err.log("no stamp file");
+ return false;
+ }
+ StartLog.logStart("check for lookup cache hit"); // NOI18N
+ List files = relevantFiles(); // List Type: ProxyLookup
delegate so we can change the lookups on fly. */
- private static final class ProxyLkp extends ProxyLookup {
+ private static final class ProxyLkp extends ProxyLookup implements Serializable {
+
+ private static final long serialVersionUID = 1L;
/** FolderLookup
we are associated with. */
- private FolderLookup fl;
+ private transient FolderLookup fl;
/** Content to control the abstract lookup. */
- private AbstractLookup.Content content;
+ private transient AbstractLookup.Content content;
+ private transient boolean readFromStream;
/** Constructs lookup which holds all items+lookups from underlying world.
* @param folder FolderLookup
to associate to */
@@ -270,12 +277,45 @@
this.content = content;
}
+ private void writeObject (ObjectOutputStream oos) throws IOException {
+ Lookup[] ls = getLookups();
+ for (int i = 0; i < ls.length; i++) {
+ oos.writeObject(ls[i]);
+ }
+ oos.writeObject(null);
+ oos.writeObject (fl.folder);
+ oos.writeObject (fl.rootName);
+ oos.writeObject (content);
+ }
+
+ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ List ls = new ArrayList(); // ListInstanceCookie
. Item which
* the internal lookup data structure is made from. */
- private static final class ICItem extends AbstractLookup.Pair {
- private InstanceCookie ic;
+ private static final class ICItem extends AbstractLookup.Pair implements Serializable {
+ static final long serialVersionUID = 10L;
+
+ /** when deserialized only primary file is stored */
+ private FileObject fo;
+
+ private transient InstanceCookie ic;
/** source data object */
- private DataObject obj;
+ private transient DataObject obj;
/** reference to created object */
- private WeakReference ref;
+ private transient WeakReference ref;
/** root folder */
private String rootName;
@@ -317,6 +367,27 @@
this.ic = ic;
this.obj = obj;
this.rootName = rootName;
+ this.fo = obj.getPrimaryFile();
+ }
+
+ /** Initializes the item
+ */
+ public void init () {
+ if (ic != null) return;
+
+ ic = (InstanceCookie)obj.getCookie (InstanceCookie.class);
+ if (ic == null) {
+ // XXX handle more gracefully
+ throw new IllegalStateException ("No cookie: " + obj);
+ }
+ }
+
+
+ /** Initializes the cookie from data object.
+ */
+ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ ois.defaultReadObject();
+ obj = DataObject.find (fo);
}
@@ -324,6 +395,8 @@
* @return the class of the item
*/
protected boolean instanceOf (Class clazz) {
+ init ();
+
if (ic instanceof InstanceCookie.Of) {
// special handling for special cookies
InstanceCookie.Of of = (InstanceCookie.Of)ic;
@@ -345,6 +418,8 @@
* @return the instance of the object or null if it cannot be created
*/
public Object getInstance() {
+ init ();
+
try {
Object obj = ic.instanceCreate();
ref = new WeakReference (obj);
@@ -359,6 +434,8 @@
/** Hash code is the InstanceCookie
's code. */
public int hashCode () {
+ init ();
+
return System.identityHashCode (ic);
}
@@ -366,6 +443,8 @@
public boolean equals (Object obj) {
if (obj instanceof ICItem) {
ICItem i = (ICItem)obj;
+ i.init ();
+ init ();
return ic == i.ic;
}
return false;
@@ -375,11 +454,15 @@
* @return string representing the item, that can be used for
* persistance purposes to locate the same item next time */
public String getId() {
+ init ();
+
return objectName(rootName, obj);
}
/** Display name is extracted from name of the objects node. */
public String getDisplayName () {
+ init ();
+
return obj.getNodeDelegate ().getDisplayName ();
}
@@ -399,6 +482,8 @@
* @return the correct class
*/
public Class getType() {
+ init ();
+
try {
return ic.instanceClass ();
} catch (IOException ex) {
Index: openide/src/org/openide/loaders/XMLDataObject.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/XMLDataObject.java,v
retrieving revision 1.125
diff -u -r1.125 XMLDataObject.java
--- openide/src/org/openide/loaders/XMLDataObject.java 25 Sep 2002 11:43:23 -0000 1.125
+++ openide/src/org/openide/loaders/XMLDataObject.java 7 Jan 2003 04:04:05 -0000
@@ -1022,6 +1022,8 @@
/** result used for this lookup */
private Lookup.Result result;
+ private ThreadLocal QUERY = new ThreadLocal ();
+
//~~~~~~~~~~~~~~~~~~~~~ Task body and control of queue ~~~~~~~~~~~~~~~~~~~
/** Getter for public ID of the document.
@@ -1037,18 +1039,41 @@
*
* @param class to look for
*/
- public Object lookupCookie (Class clazz) {
- waitFinished ();
-
- Lookup l = lookup != null ? lookup : Lookup.EMPTY;
+ public Object lookupCookie (final Class clazz) {
+ if (QUERY.get () == clazz) {
+ // somebody is querying for the same cookie in the same thread
+ // probably neverending-loop - ignore
+ return new InstanceCookie () {
+ public Class instanceClass () {
+ return clazz;
+ }
+
+ public Object instanceCreate () throws IOException {
+ throw new IOException ("Cyclic reference, sorry: " + clazz);
+ }
+
+ public String instanceName () {
+ return clazz.getName ();
+ }
+ };
+ }
- Lookup.Result r = result;
- if (r != null) {
- // just to initialize all listeners
- r.allItems ();
+ Object previous = QUERY.get ();
+ try {
+ QUERY.set (clazz);
+ waitFinished ();
+
+ Lookup l = lookup != null ? lookup : Lookup.EMPTY;
+
+ Lookup.Result r = result;
+ if (r != null) {
+ // just to initialize all listeners
+ r.allItems ();
+ }
+ return l.lookup (clazz);
+ } finally {
+ QUERY.set (previous);
}
-
- return l.lookup (clazz);
}
/*
Index: openide/src/org/openide/util/lookup/AbstractLookup.java
===================================================================
RCS file: /cvs/openide/src/org/openide/util/lookup/AbstractLookup.java,v
retrieving revision 1.24
diff -u -r1.24 AbstractLookup.java
--- openide/src/org/openide/util/lookup/AbstractLookup.java 21 Dec 2002 08:40:35 -0000 1.24
+++ openide/src/org/openide/util/lookup/AbstractLookup.java 7 Jan 2003 04:04:05 -0000
@@ -13,7 +13,7 @@
package org.openide.util.lookup;
-
+import java.io.Serializable;
import java.lang.ref.*;
import java.util.*;
@@ -29,7 +29,9 @@
* @author Jaroslav Tulach
* @since 1.9
*/
-public class AbstractLookup extends Lookup {
+public class AbstractLookup extends Lookup implements Serializable {
+ static final long serialVersionUID = 5L;
+
/** lock for initialization of the map */
private Content treeLock;
/** the tree that registers all items */
@@ -40,7 +42,7 @@
/** set (Class, List (Reference (Result)) of all listeners that are waiting in
* changes in class Class
*/
- private Map reg;
+ private transient Map reg;
/** count of items in to lookup */
private int count;
@@ -447,7 +449,9 @@
/** Extension to the default lookup item that offers additional information
* for the data structures use in AbstractLookup
*/
- public static abstract class Pair extends Lookup.Item {
+ public static abstract class Pair extends Lookup.Item implements Serializable {
+ private static final long serialVersionUID = 1L;
+
/** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
int index = -1;
@@ -641,12 +645,14 @@
*
* @since 1.25
*/
- public static class Content extends Object {
+ public static class Content extends Object implements Serializable {
+
+ private static final long serialVersionUID = 1L;
// one of them is always null (except attach stage)
/** abstract lookup we are connected to */
private AbstractLookup al = null;
- private ArrayList earlyPairs = new ArrayList(3);
+ private transient ArrayList earlyPairs = new ArrayList(3);
/** A lookup attaches to this object.
*/
Index: openide/src/org/openide/util/lookup/InheritanceTree.java
===================================================================
RCS file: /cvs/openide/src/org/openide/util/lookup/InheritanceTree.java,v
retrieving revision 1.15
diff -u -r1.15 InheritanceTree.java
--- openide/src/org/openide/util/lookup/InheritanceTree.java 3 Dec 2002 14:12:15 -0000 1.15
+++ openide/src/org/openide/util/lookup/InheritanceTree.java 7 Jan 2003 04:04:05 -0000
@@ -14,22 +14,12 @@
package org.openide.util.lookup;
-
+import java.io.*;
import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.List;
-
-import org.openide.util.enum.AlterEnumeration;
-import org.openide.util.enum.EmptyEnumeration;
-import org.openide.util.enum.QueueEnumeration;
-import org.openide.util.enum.SequenceEnumeration;
-import org.openide.util.enum.SingletonEnumeration;
+import java.util.*;
+
+import org.openide.util.Lookup;
+import org.openide.util.enum.*;
/** A tree to represent classes with inheritance. Description of the
@@ -96,11 +86,15 @@
*
* @author Jaroslav Tulach
*/
-final class InheritanceTree extends Object implements java.util.Comparator {
+final class InheritanceTree extends Object implements Comparator, Serializable {
+ private static final long serialVersionUID = 1L;
+
/** the root item (represents Object) */
- private Node object;
- /** map of queried interfaces (Class, Set) */
- private Map interfaces;
+ private transient Node object;
+ /** Map of queried interfaces.
+ * Map<Class, (Collection<AbstractLookup.Pair> | AbstractLookup.Pair)>
+ */
+ private transient Map interfaces;
/** Constructor
*/
@@ -108,6 +102,33 @@
object = new Node (java.lang.Object.class);
}
+ private void writeObject (ObjectOutputStream oos) throws IOException {
+ oos.writeObject(object);
+ Iterator it = interfaces.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry e = (Map.Entry)it.next();
+ Class c = (Class)e.getKey();
+ oos.writeObject(c.getName());
+ Object o = e.getValue();
+ if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) throw new ClassCastException(String.valueOf(o));
+ oos.writeObject(o);
+ }
+ oos.writeObject(null);
+ }
+
+ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ object = (Node)ois.readObject();
+ interfaces = new WeakHashMap();
+ String clazz;
+ ClassLoader l = (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class);
+ while ((clazz = (String)ois.readObject()) != null) {
+ Object o = ois.readObject();
+ if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) throw new ClassCastException(String.valueOf(o));
+ Class c = Class.forName(clazz, false, l);
+ interfaces.put(c, o);
+ }
+ }
+
/** Adds an item into the tree.
* @param item to add
@@ -745,12 +766,13 @@
/** Node in the tree.
*/
- static final class Node extends WeakReference {
+ static final class Node extends WeakReference implements Serializable {
+ static final long serialVersionUID = 3L;
/** children nodes */
- public ArrayList children;
+ public ArrayList children; // List