--- /dev/null
+// 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