Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / tools / resources / Resource.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/tools/resources/Resource.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/tools/resources/Resource.java
new file mode 100644 (file)
index 0000000..f5e435f
--- /dev/null
@@ -0,0 +1,784 @@
+// Resource.java\r
+// $Id: Resource.java,v 1.2 2010/06/15 17:52:59 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.tools.resources ;\r
+\r
+import java.util.Hashtable;\r
+import java.util.Vector;\r
+\r
+import java.lang.ArrayIndexOutOfBoundsException;\r
+\r
+/**\r
+ * The resource class describes an object, accessible through the server.\r
+ * Resource objects are required to have the following properties: \r
+ * <ul>\r
+ * <li>They must be persistent (their life-time can span multiple server \r
+ * life-time).\r
+ * <li>They must be editable, so that one can change some of their aspects\r
+ * (such as any associated attribute).\r
+ * <li>They must be self-described: each resource must now what kind\r
+ * of attribute it <em>understands</em>.\r
+ * <li>They must be able to update themselves: some of the meta-information\r
+ * associated with a resource may require lot of CPU to compute. \r
+ * <li>They must implement some name-service policy.\r
+ * </ul>\r
+ * <p>These resource objects do not define how they are accessed. See the\r
+ * sub-classes for specific accesses. \r
+ */\r
+\r
+public class Resource extends AttributeHolder {\r
+    private static final boolean debugunload = false;\r
+\r
+    /**\r
+     * Attribute index - The index of the resource store entry attribute.\r
+     */\r
+    protected static int ATTR_STORE_ENTRY = -1;\r
+    /**\r
+     * Attribute index - The index for the identifier attribute.\r
+     */\r
+    protected static int ATTR_IDENTIFIER = -1 ;\r
+    /**\r
+     * Attribute index - Associated resource frames\r
+     */\r
+    protected static int ATTR_RESOURCE_FRAMES = -1;\r
+    /**\r
+     * Attribute index - The index for our parent attribute.\r
+     */\r
+    protected static int ATTR_PARENT = -1 ;\r
+    /**\r
+     * Attribute index - The hierarchical context of the resource.\r
+     */\r
+    protected static int ATTR_CONTEXT = -1;\r
+    /**\r
+     * Attribute index - The index for our URL attribute.\r
+     */\r
+    protected static int ATTR_URL = -1;\r
+    /**\r
+     * Attribute index - The index for the last-modified attribute.\r
+     */\r
+    protected static int ATTR_LAST_MODIFIED = -1 ;\r
+    /**\r
+     * Attribute index - The help URL for this resource (Ref doc)\r
+     */\r
+    protected static int ATTR_HELP_URL = -1 ;\r
+\r
+    public static String id = "identifier".intern();\r
+    public static String co = "context".intern();\r
+\r
+    static {\r
+       Attribute a   = null ;\r
+       Class     cls = null ;\r
+       // Get a pointer to our own class:\r
+       try {\r
+           cls  = Class.forName("org.w3c.tools.resources.Resource") ;\r
+           //Added by Jeff Huang\r
+           //TODO: FIXIT\r
+       } catch (Exception ex) {\r
+           ex.printStackTrace() ;\r
+           System.exit(1) ;\r
+       }\r
+       // Our parent resource (the one that created us)\r
+       a = new ObjectAttribute("parent",\r
+                               "org.w3c.tools.resources.Resource",\r
+                               null,\r
+                               Attribute.COMPUTED|Attribute.DONTSAVE);\r
+       ATTR_PARENT = AttributeRegistry.registerAttribute(cls, a) ;\r
+        // Our runtime context\r
+       a = new ObjectAttribute("context",\r
+                               "org.w3c.tools.resources.ResourceContext",\r
+                               null,\r
+                               Attribute.COMPUTED|Attribute.DONTSAVE);\r
+       ATTR_CONTEXT = AttributeRegistry.registerAttribute(cls, a) ;\r
+       // The resource store entry for that resource:\r
+       a = new ObjectAttribute("store-entry"\r
+                               , "java.lang.Object"\r
+                               , null\r
+                               , Attribute.DONTSAVE);\r
+       ATTR_STORE_ENTRY = AttributeRegistry.registerAttribute(cls, a);\r
+       // The identifier attribute:\r
+       a = new StringAttribute("identifier"\r
+                               , null\r
+                               , Attribute.MANDATORY|Attribute.EDITABLE);\r
+       ATTR_IDENTIFIER = AttributeRegistry.registerAttribute(cls, a);\r
+       // The frames associated to that resource:\r
+       a = new FrameArrayAttribute("frames"\r
+                                   , null\r
+                                   , Attribute.COMPUTED);\r
+       ATTR_RESOURCE_FRAMES = AttributeRegistry.registerAttribute(cls, a);\r
+       // Our URL\r
+       a = new StringAttribute("url",\r
+                               null,\r
+                               Attribute.COMPUTED|Attribute.DONTSAVE);\r
+       ATTR_URL = AttributeRegistry.registerAttribute(cls, a) ;\r
+       // The last modified attribute:\r
+       a = new DateAttribute("last-modified",\r
+                             null,\r
+                             Attribute.COMPUTED|Attribute.EDITABLE) ;\r
+       ATTR_LAST_MODIFIED = AttributeRegistry.registerAttribute(cls,a);\r
+       // The help url attribute\r
+       a = new StringAttribute("help-url",\r
+                               null,\r
+                               Attribute.COMPUTED);\r
+       ATTR_HELP_URL = AttributeRegistry.registerAttribute(cls,a);\r
+    }\r
+\r
+    public Object getClone(Object values[]) {\r
+       // The frame attribute needs one more level of cloning:\r
+       ResourceFrame f[] = (ResourceFrame[]) values[ATTR_RESOURCE_FRAMES];\r
+       if ( f != null ) {\r
+           ResourceFrame c[] = new ResourceFrame[f.length] ;\r
+           for (int i = 0 ; i < f.length ; i++) {\r
+               if ( f[i] == null )\r
+                   c[i] = null;\r
+               else\r
+                   c[i] = (ResourceFrame) f[i].getClone();\r
+           }\r
+           values[ATTR_RESOURCE_FRAMES] = c;\r
+       }\r
+       return super.getClone(values);\r
+    }\r
+\r
+    /**\r
+     * Get this resource parent resource.\r
+     * The parent of a resource can be either <strong>null</strong> if it is\r
+     * the server root resource, or any Resource.\r
+     * @return An instance of ResourceReference, or <strong>null</strong>\r
+     */\r
+    public ResourceReference getParent() {\r
+       ResourceContext context = unsafeGetContext();\r
+       if (context == null) //are we external?\r
+           return null;\r
+       return context.getContainer();\r
+    }\r
+\r
+    /**\r
+     * Get the file part of the URL this resource is attached to.\r
+     * @return An URL object specifying the location in the information \r
+     *    space of this resource.\r
+     */\r
+    public String getURLPath() {\r
+       return getString(ATTR_URL, null) ;\r
+    }\r
+\r
+\r
+    /**\r
+     * Get the file part of the URL this resource is attached to.\r
+     * @return An URL object specifying the location in the information \r
+     *    space of this resource.\r
+     */\r
+    public String unsafeGetURLPath() {\r
+       return unsafeGetString(ATTR_URL, null) ;\r
+    }\r
+\r
+    /**\r
+     * Get the server this resource is served by.\r
+     * @return The first instance of Jigsaw this resource was attached to.\r
+     */\r
+    public ServerInterface getServer() {\r
+       return ((ResourceContext) \r
+                             unsafeGetValue(ATTR_CONTEXT, null)).getServer();\r
+    }\r
+\r
+    /**\r
+     * Get this resource's help url.\r
+     * @return An URL, encoded as a String, or <strong>null</strong> if not\r
+     * available.\r
+     */\r
+    public String getHelpURL() {\r
+       return getString(ATTR_HELP_URL, null);\r
+    }\r
+\r
+    private String computeHelpUrl() {\r
+       try {\r
+           StringBuffer sb = new StringBuffer(128);\r
+           sb.append(getServer().getDocumentationURL());\r
+           sb.append('/');\r
+           sb.append(getClass().getName());\r
+           sb.append(".html");\r
+           return sb.toString().intern();\r
+       } catch (Exception ex) {\r
+           return null;\r
+       }\r
+       \r
+    }\r
+\r
+    synchronized public Object getValue (int idx, Object def) {\r
+       if ((idx == ATTR_HELP_URL) && (values[ATTR_HELP_URL] == null))\r
+           values[ATTR_HELP_URL] = computeHelpUrl();\r
+       return super.getValue(idx, def);\r
+    }\r
+    \r
+    public Object unsafeGetValue (int idx, Object def) {\r
+       if ((idx == ATTR_HELP_URL) && (values[ATTR_HELP_URL] == null))\r
+           values[ATTR_HELP_URL] = computeHelpUrl();\r
+       return super.unsafeGetValue(idx, def);\r
+    }\r
+\r
+    /**\r
+     * Get the help URL for that resource's topic.\r
+     * @param topic The topic you want help for.\r
+     * @return A String encoded URL, or <strong>null</strong> if none\r
+     * was found.\r
+     */\r
+    public String getHelpURL(String topics) {\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Get the hierarchical context for that resource.\r
+     * @return A ResourceContext instance, guaranteed not to be <strong>null\r
+     * </strong>\r
+     */\r
+    protected ResourceContext getContext() {\r
+       return (ResourceContext) getValue(ATTR_CONTEXT, null);\r
+    }\r
+\r
+    protected ResourceContext unsafeGetContext() {\r
+       return (ResourceContext) unsafeGetValue(ATTR_CONTEXT, null);\r
+    }\r
+\r
+    /**\r
+     * Set the given context as the current context of this resource.\r
+     * @param context The new context.\r
+     */\r
+    protected void setContext(ResourceContext context) {\r
+       context.setResourceReference(getResourceReference());\r
+       setValue(ATTR_CONTEXT, context);\r
+    }\r
+\r
+    /**\r
+     * Set the given context as the current context of this resource.\r
+     * @param context The new context.\r
+     * @param keepmodules If true the new context will have the same\r
+     * modules than the old one.\r
+     */\r
+    protected void setContext(ResourceContext context, boolean keepmodules) {\r
+       context.setResourceReference(getResourceReference());\r
+       if (keepmodules) {\r
+           ResourceContext ctxt = getContext();\r
+           if (ctxt != null)\r
+               context.modules = ctxt.modules;\r
+       }\r
+       setValue(ATTR_CONTEXT, context);\r
+    }\r
+\r
+    /**\r
+     * Get the store entry for that resource.\r
+     * Only the resource store in charge of this resource knows about the\r
+     * type of the resulting object. Buy declaring the class of that object\r
+     * private, the resource store can assume some private access to it.\r
+     * @return A java Object instance, or <strong>null</strong> if no \r
+     * store entry is attached to that resource.\r
+     */\r
+\r
+    public Object getStoreEntry() {\r
+       return getValue(ATTR_STORE_ENTRY, null);\r
+    }\r
+\r
+    /**\r
+     * Get this resource identifier.\r
+     * @return The String value for the identifier.\r
+     */\r
+    public String getIdentifier() {\r
+       return getString(ATTR_IDENTIFIER, null) ;\r
+    }\r
+\r
+    /**\r
+     * Get this resource identifier.\r
+     * @return The String value for the identifier.\r
+     */\r
+    public String unsafeGetIdentifier() {\r
+       return unsafeGetString(ATTR_IDENTIFIER, null) ;\r
+    }\r
+\r
+    /**\r
+     * Get the space entry for that resource. This Object is use to\r
+     * retrieve the resource in the resource space.\r
+     * @return A spaceEntry instance.\r
+     */\r
+    protected SpaceEntry getSpaceEntry() {\r
+       ResourceReference rr = getParent();\r
+       if (rr != null) {\r
+           try {\r
+               ContainerResource cont = (ContainerResource) rr.lock();\r
+               return new SpaceEntryImpl(cont);\r
+           } catch (InvalidResourceException ex) {\r
+               return null;\r
+           } finally {\r
+               rr.unlock();\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Get the ResourceSpace where this resource is stored.\r
+     * @return A ResourceSpace instance.\r
+     */\r
+    protected ResourceSpace getSpace() {\r
+       ResourceContext context = unsafeGetContext();\r
+       if (context == null) {\r
+           context = getContext();\r
+       }\r
+       if (context != null) {\r
+           return context.getSpace();\r
+       }\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Get the ResourceReference of that resource. ResourceReference is the\r
+     * only public way to access a resource.\r
+     * @return a ResourceReference instance.\r
+     */\r
+    public ResourceReference getResourceReference() {\r
+       ResourceContext context = getContext();\r
+       if (context != null)\r
+           return context.getResourceReference();\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Get the ResourceReference of that resource. ResourceReference is the\r
+     * only public way to access a resource.\r
+     * @return a ResourceReference instance.\r
+     */\r
+    public ResourceReference unsafeGetResourceReference() {\r
+       ResourceContext context = unsafeGetContext();\r
+       if (context != null)\r
+           return context.getResourceReference();\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Initialize and attach a new ResourceFrame to that resource.\r
+     * @param frame An uninitialized ResourceFrame instance.\r
+     * @param defs A default set of attribute values.\r
+     */\r
+    public void registerFrame(ResourceFrame frame, Hashtable defs) {\r
+       synchronized (this) {\r
+           ResourceFrame frames[] = null;\r
+           frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);\r
+           // Initialize the frame with given default attributes:\r
+           if ( defs.get(id) == null ) {\r
+               String fname = "frame-"+((frames == null) ? 0 : frames.length);\r
+               defs.put(id, fname.intern());\r
+           }\r
+           frame.initialize(defs);\r
+           // Look for a free slot frame:\r
+           if ( frames == null ) {\r
+               frames    = new ResourceFrame[1];\r
+               frames[0] = frame;\r
+           } else {\r
+               int slot = -1;\r
+               // Look for a free slot:\r
+               for (int i = 0 ; i < frames.length ; i++) {\r
+                   if ( frames[i] == null ) {\r
+                       slot = i;\r
+                       break;\r
+                   }\r
+               }\r
+               if ( slot >= 0 ) {\r
+                   // Free slot available:\r
+                   frames[slot] = frame;\r
+               } else {\r
+                   // Resize frames:\r
+                   ResourceFrame nf[] = new ResourceFrame[frames.length+1];\r
+                   System.arraycopy(frames, 0, nf, 0, frames.length);\r
+                   nf[frames.length] = frame;\r
+                   frames = nf;\r
+               }\r
+           }\r
+           // Set the frames:\r
+           setValue(ATTR_RESOURCE_FRAMES, frames);\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Unregister a resource frame from the given resource.\r
+     * @param frame The frame to unregister from the resource.\r
+     */\r
+    public synchronized void unregisterFrame(ResourceFrame frame) {\r
+       ResourceFrame frames[] = null;\r
+       frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);\r
+       if ( frames != null ) {\r
+           ResourceFrame f[] = new ResourceFrame[frames.length-1];\r
+           int j=0;\r
+           for (int i = 0; i < frames.length ; i++) {\r
+               if ( frames[i] == frame ) {\r
+                   // got it, copy the end of the array\r
+                   System.arraycopy(frames, i+1, f, j, frames.length-i-1);\r
+                   setValue(ATTR_RESOURCE_FRAMES, f);\r
+                   return;\r
+               } else {\r
+                   try {\r
+                       f[j++] = frames[i];\r
+                   } catch (ArrayIndexOutOfBoundsException ex) {\r
+                       return; // no modifications, return\r
+                   }\r
+               }\r
+           }\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Collect all frames.\r
+     * @return An array of ResourceFrame, containing a set of frames instances\r
+     * or <strong>null</strong> if no resource frame is available.\r
+     */\r
+    public synchronized ResourceFrame[] getFrames() {\r
+       return (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);\r
+    }\r
+\r
+    /**\r
+     * Collect all frames.\r
+     * @return An array of ResourceFrame, containing a set of frames instances\r
+     * or <strong>null</strong> if no resource frame is available.\r
+     */\r
+    public ResourceFrame[] unsafeGetFrames() {\r
+       return (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES, null);\r
+    }\r
+\r
+    /**\r
+     * Collect any frame that's an instance of the given class.\r
+     * @param cls The class of frames we are looking for.\r
+     * @return An array of ResourceFrame, containing a set of frames instances\r
+     * of the given class, or <strong>null</strong> if no resource frame is\r
+     * available.\r
+     */\r
+    public synchronized ResourceFrame[] collectFrames(Class c) {\r
+       ResourceFrame frames[] = null;\r
+       frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);\r
+       if ( frames != null ) {\r
+           Vector v = new Vector(frames.length);\r
+           for (int i = 0 ; i < frames.length ; i++) {\r
+               if ( c.isInstance(frames[i]) )\r
+                   v.addElement(frames[i]);\r
+           }\r
+           int sz = v.size();\r
+           if ( sz > 0 ) {\r
+               ResourceFrame ret[] = new ResourceFrame[sz];\r
+               v.copyInto(ret);\r
+               return ret;\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+\r
+\r
+    /**\r
+     * Collect any frame that's an instance of the given class.\r
+     * @param cls The class of frames we are looking for.\r
+     * @return An array of ResourceFrame, containing a set of frames instances\r
+     * of the given class, or <strong>null</strong> if no resource frame is\r
+     * available.\r
+     */\r
+    ResourceFrame[] unsafeCollectFrames(Class c) {\r
+       ResourceFrame frames[] = null;\r
+       frames = (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES, null);\r
+       if ( frames != null ) {\r
+           Vector v = new Vector(frames.length);\r
+           for (int i = 0 ; i < frames.length ; i++) {\r
+               if ( c.isInstance(frames[i]) )\r
+                   v.addElement(frames[i]);\r
+           }\r
+           int sz = v.size();\r
+           if ( sz > 0 ) {\r
+               ResourceFrame ret[] = new ResourceFrame[sz];\r
+               v.copyInto(ret);\r
+               return ret;\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+\r
+    /**\r
+     * Get the first occurence of a frame of the given class.\r
+     * @param cls The class of te frame to look for.\r
+     * @return A ResourceFrame instance, or <strong>null</strong>.\r
+     */\r
+    public synchronized ResourceFrame getFrame(Class c) {\r
+       ResourceFrame frames[] = null;\r
+       frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);\r
+       if ( frames != null ) {\r
+           for (int i = 0 ; i < frames.length ; i++) {\r
+               if ( c.isInstance(frames[i]) )\r
+                   return frames[i];\r
+           }\r
+       }\r
+       return null;\r
+    }\r
+       \r
+    /**\r
+     * Get the first occurence of a frame of the given class.\r
+     * @param cls The class of te frame to look for.\r
+     * @return A ResourceFrame instance, or <strong>null</strong>.\r
+     */\r
+    public ResourceFrame unsafeGetFrame(Class c) {\r
+       ResourceFrame frames[] = null;\r
+       frames = (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES, null);\r
+       if ( frames != null ) {\r
+           for (int i = 0 ; i < frames.length ; i++) {\r
+               if ( c.isInstance(frames[i]) )\r
+                   return frames[i];\r
+           }\r
+       }\r
+       return null;\r
+    }    \r
+\r
+    /**\r
+     * Get an attached frame attribute value.\r
+     * This method really is a short-hand that combines a <code>getFrame</code>\r
+     * and <code>getValue</code> method call.\r
+     * @param cls The class of the frame we want the value of.\r
+     * @param idx The attribute index.\r
+     * @param def The default value (if the attribute value isn't defined).\r
+     * @return The attribute value as an Object instance, or the provided\r
+     * default value if the attribute value isn't defined.\r
+     */\r
+    public synchronized Object getValue(Class c, int idx, Object def) {\r
+       ResourceFrame frame = getFrame(c);\r
+       if ( frame != null )\r
+           return frame.getValue(idx, def);\r
+       throw new IllegalAttributeAccess(this, idx);\r
+    }\r
+\r
+    /**\r
+     * Set an attached frame attribute value.\r
+     * This method really is a short-hand that combines a <code>getFrame</code>\r
+     * and a <code>setValue</code> method call.\r
+     * @param cls The class of the frame we want to modify.\r
+     * @param idx The attribute to modify.\r
+     * @param val The new attribute value.\r
+     */\r
+    public synchronized void setValue(Class c, int idx, Object val) {\r
+       ResourceFrame frame = getFrame(c);\r
+       if ( frame != null ) {\r
+           frame.setValue(idx, val);\r
+           markModified();\r
+           return;\r
+       }\r
+       throw new IllegalAttributeAccess(this, idx);\r
+    }\r
+\r
+    /**\r
+     * Get this resource last modification time.\r
+     * @return A long giving the date of the last modification time, or\r
+     *    <strong>-1</strong> if undefined.\r
+     */\r
+    public long getLastModified() {\r
+       return getLong(ATTR_LAST_MODIFIED, (long) -1) ;\r
+    }\r
+\r
+    /**\r
+     * Mark this resource as having been modified.\r
+     */\r
+    public void markModified() {\r
+       ResourceSpace space = getSpace();\r
+       if ((space != null) && (getSpaceEntry() != null)) {\r
+           synchronized (this) {\r
+               space.markModified(getSpaceEntry(), this);\r
+           }\r
+       }\r
+       super.setValue(ATTR_LAST_MODIFIED, \r
+                      new Long(System.currentTimeMillis()));\r
+    }\r
+\r
+    /**\r
+     * We overide setValue, to mark the resource as modified.\r
+     * @param idx The index of the attribute to modify.\r
+     * @param value The new attribute value.\r
+     */\r
+    public void setValue(int idx, Object value) {\r
+       // Changing the identifier of a resource needs some special tricks:\r
+       if ( idx == ATTR_IDENTIFIER ) {\r
+           String oldid = getIdentifier();\r
+           try {\r
+               super.setValue(idx, value);\r
+           } catch (IllegalAttributeAccess ex) {\r
+               // We were not able to change the identifier, rethrow\r
+               throw ex;\r
+           }\r
+           // Change was successfull, update the resource space:\r
+           if (getSpaceEntry() != null) {\r
+               ResourceSpace space = getSpace();\r
+               space.renameResource(getSpaceEntry(), oldid, (String) value);\r
+           }\r
+           //modify the URL path\r
+           ResourceReference rr = getParent();\r
+           if (rr != null) {\r
+               try {\r
+                   Resource r = rr.lock();\r
+                   setValue(ATTR_URL,\r
+                            r.getURLPath()+\r
+                            java.net.URLEncoder.encode((String) value));\r
+               } catch(Exception ex) {\r
+                   ex.printStackTrace();\r
+               } finally {\r
+                   rr.unlock();\r
+               }\r
+           }\r
+           markModified();\r
+           return;\r
+       }\r
+       // Normal setValue, but markModified before leaving:\r
+       super.setValue(idx, value) ;\r
+       if (( ! attributes[idx].checkFlag(Attribute.DONTSAVE) ) &&\r
+           ( idx != ATTR_LAST_MODIFIED))\r
+           markModified() ;\r
+    }\r
+\r
+    /**\r
+     * Is that resource willing to be unloaded.\r
+     * This method is a bit tricky to implement. The guideline is that you\r
+     * should not dynamically change the returned value (since you can't \r
+     * control what happens between a call to that method and a call to\r
+     * the <code>notifyUnload</code> method).\r
+     * <p>Returning <strong>false</strong> should never be needed, except\r
+     * for very strange resources.\r
+     * @return A boolean <strong>true</strong> if the resource can be unloaded\r
+     * <strong>false</strong> otherwise.\r
+     */\r
+\r
+    public boolean acceptUnload() {\r
+       if ( debugunload ) {\r
+           try {\r
+               System.out.println(getValue("url","<??>")+": acceptUnload");\r
+           } catch (IllegalAttributeAccess ex) {\r
+           }\r
+       }\r
+       return true;\r
+    }\r
+\r
+    /**\r
+     * This resource is being unloaded.\r
+     * The resource is being unloaded from memory, perform any additional\r
+     * cleanup required.\r
+     */\r
+    public void notifyUnload() {\r
+       if ( debugunload ) {\r
+           try {\r
+               System.out.println(getValue("url","<??>")+": unloaded.");\r
+           } catch (IllegalAttributeAccess ex) {\r
+           }\r
+       }\r
+       values = null ;\r
+    }\r
+\r
+    /**\r
+     * unloaded?\r
+     * @return true if the resource has been unloaded.\r
+     */\r
+    public boolean isUnloaded() {\r
+       return (values == null);\r
+    }\r
+\r
+    /**\r
+     * The web admin wants us to update any out of date attribute.\r
+     */\r
+    public void updateAttributes() {\r
+       return ;\r
+    }\r
+\r
+    /**\r
+     * Check if this resource is loked more than one time.\r
+     * @exception MultipleLockException is thrown if true.\r
+     */\r
+    protected void checkMultipleLock(ResourceReference rr) \r
+       throws MultipleLockException\r
+    {\r
+       if (rr.nbLock() > 1)\r
+           throw new MultipleLockException(rr.nbLock(), this, "can't delete");\r
+    }\r
+\r
+    /**\r
+     * Delete this Resource instance, and remove it from its store.\r
+     * This method will erase definitely this resource, for ever, by removing\r
+     * it from its resource store (when doable).\r
+     * @exception MultipleLockException if someone else has locked this \r
+     * resource\r
+     */\r
+    public synchronized void delete() \r
+       throws MultipleLockException\r
+    {\r
+       ResourceSpace space = getSpace();\r
+\r
+       if ((space != null) && (getSpaceEntry() != null)) {\r
+           ResourceReference self = getResourceReference();\r
+           if (self != null) {\r
+               synchronized (self) {\r
+                   checkMultipleLock(self);\r
+                   space.deleteResource(getSpaceEntry(), this);\r
+               }\r
+           } else {\r
+               space.deleteResource(getSpaceEntry(), this);\r
+           }\r
+       }\r
+    }\r
+\r
+    public boolean isInitialized() {\r
+       return (values != null);\r
+    }\r
+\r
+    /**\r
+     * Set the values. (MUST be called before initialize).\r
+     * @param defs The Hashtable containing the values.\r
+     */\r
+    public void pickleValues(Hashtable defs) {\r
+       Object nvalues[] = new Object[attributes.length];\r
+       for (int i = 0 ; i < nvalues.length ; i++) {\r
+           String attrname = attributes[i].getName() ;\r
+           Object def      = defs.get(attrname) ;\r
+           if ((i == ATTR_HELP_URL) && (def != null) \r
+               && (def instanceof String)) {\r
+               nvalues[i] = ((String) def).intern();\r
+           } else {        \r
+               nvalues[i] = def ;\r
+           }       \r
+       }\r
+       this.values = nvalues ;\r
+    }\r
+\r
+   /**\r
+     * Initialization method for attribute holders.\r
+     * This method allows to initialize an attribute holder by providing\r
+     * its attributes values through a Hashtable mapping attribute names\r
+     * to attribute values.\r
+     * @param defs The Hashtable containing the default values.\r
+     */\r
+\r
+    public void initialize(Hashtable defs) {\r
+       Object values[] = ((this.values == null)\r
+                          ? new Object[attributes.length] \r
+                          : this.values);\r
+       for (int i = 0 ; i < values.length ; i++) {\r
+           String attrname = attributes[i].getName() ;\r
+           Object def      = defs.get(attrname) ;\r
+           if ( values[i] == null ) {\r
+               // for help_url, we can save lots of space by using \r
+               // String.intern()\r
+               if ((i == ATTR_HELP_URL) && (def != null) \r
+                       && (def instanceof String)) {\r
+                   values[i] = ((String) def).intern();\r
+               } else {            \r
+                   values[i] = def ;\r
+               }\r
+           }\r
+       }\r
+       initialize(values) ;\r
+    }\r
+\r
+    public void initialize(Object values[]) {\r
+       super.initialize(values);\r
+    }\r
+\r
+    /**\r
+     * Create an empty resource instance.\r
+     * Initialize the instance attributes description, and its values.\r
+     */\r
+    public Resource() {\r
+       super() ;\r
+    }\r
+}\r