001: // Resource.java
002: // $Id: Resource.java,v 1.27 2007/03/06 10:41:41 ylafon Exp $
003: // (c) COPYRIGHT MIT and INRIA, 1996.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.tools.resources;
007:
008: import java.util.Hashtable;
009: import java.util.Vector;
010:
011: import java.lang.ArrayIndexOutOfBoundsException;
012:
013: /**
014: * The resource class describes an object, accessible through the server.
015: * Resource objects are required to have the following properties:
016: * <ul>
017: * <li>They must be persistent (their life-time can span multiple server
018: * life-time).
019: * <li>They must be editable, so that one can change some of their aspects
020: * (such as any associated attribute).
021: * <li>They must be self-described: each resource must now what kind
022: * of attribute it <em>understands</em>.
023: * <li>They must be able to update themselves: some of the meta-information
024: * associated with a resource may require lot of CPU to compute.
025: * <li>They must implement some name-service policy.
026: * </ul>
027: * <p>These resource objects do not define how they are accessed. See the
028: * sub-classes for specific accesses.
029: */
030:
031: public class Resource extends AttributeHolder {
032: private static final boolean debugunload = false;
033:
034: /**
035: * Attribute index - The index of the resource store entry attribute.
036: */
037: protected static int ATTR_STORE_ENTRY = -1;
038: /**
039: * Attribute index - The index for the identifier attribute.
040: */
041: protected static int ATTR_IDENTIFIER = -1;
042: /**
043: * Attribute index - Associated resource frames
044: */
045: protected static int ATTR_RESOURCE_FRAMES = -1;
046: /**
047: * Attribute index - The index for our parent attribute.
048: */
049: protected static int ATTR_PARENT = -1;
050: /**
051: * Attribute index - The hierarchical context of the resource.
052: */
053: protected static int ATTR_CONTEXT = -1;
054: /**
055: * Attribute index - The index for our URL attribute.
056: */
057: protected static int ATTR_URL = -1;
058: /**
059: * Attribute index - The index for the last-modified attribute.
060: */
061: protected static int ATTR_LAST_MODIFIED = -1;
062: /**
063: * Attribute index - The help URL for this resource (Ref doc)
064: */
065: protected static int ATTR_HELP_URL = -1;
066:
067: public static String id = "identifier".intern();
068: public static String co = "context".intern();
069:
070: static {
071: Attribute a = null;
072: Class cls = null;
073: // Get a pointer to our own class:
074: try {
075: cls = Class.forName("org.w3c.tools.resources.Resource");
076: } catch (Exception ex) {
077: ex.printStackTrace();
078: System.exit(1);
079: }
080: // Our parent resource (the one that created us)
081: a = new ObjectAttribute("parent",
082: "org.w3c.tools.resources.Resource", null,
083: Attribute.COMPUTED | Attribute.DONTSAVE);
084: ATTR_PARENT = AttributeRegistry.registerAttribute(cls, a);
085: // Our runtime context
086: a = new ObjectAttribute("context",
087: "org.w3c.tools.resources.ResourceContext", null,
088: Attribute.COMPUTED | Attribute.DONTSAVE);
089: ATTR_CONTEXT = AttributeRegistry.registerAttribute(cls, a);
090: // The resource store entry for that resource:
091: a = new ObjectAttribute("store-entry", "java.lang.Object",
092: null, Attribute.DONTSAVE);
093: ATTR_STORE_ENTRY = AttributeRegistry.registerAttribute(cls, a);
094: // The identifier attribute:
095: a = new StringAttribute("identifier", null, Attribute.MANDATORY
096: | Attribute.EDITABLE);
097: ATTR_IDENTIFIER = AttributeRegistry.registerAttribute(cls, a);
098: // The frames associated to that resource:
099: a = new FrameArrayAttribute("frames", null, Attribute.COMPUTED);
100: ATTR_RESOURCE_FRAMES = AttributeRegistry.registerAttribute(cls,
101: a);
102: // Our URL
103: a = new StringAttribute("url", null, Attribute.COMPUTED
104: | Attribute.DONTSAVE);
105: ATTR_URL = AttributeRegistry.registerAttribute(cls, a);
106: // The last modified attribute:
107: a = new DateAttribute("last-modified", null, Attribute.COMPUTED
108: | Attribute.EDITABLE);
109: ATTR_LAST_MODIFIED = AttributeRegistry
110: .registerAttribute(cls, a);
111: // The help url attribute
112: a = new StringAttribute("help-url", null, Attribute.COMPUTED);
113: ATTR_HELP_URL = AttributeRegistry.registerAttribute(cls, a);
114: }
115:
116: public Object getClone(Object values[]) {
117: // The frame attribute needs one more level of cloning:
118: ResourceFrame f[] = (ResourceFrame[]) values[ATTR_RESOURCE_FRAMES];
119: if (f != null) {
120: ResourceFrame c[] = new ResourceFrame[f.length];
121: for (int i = 0; i < f.length; i++) {
122: if (f[i] == null)
123: c[i] = null;
124: else
125: c[i] = (ResourceFrame) f[i].getClone();
126: }
127: values[ATTR_RESOURCE_FRAMES] = c;
128: }
129: return super .getClone(values);
130: }
131:
132: /**
133: * Get this resource parent resource.
134: * The parent of a resource can be either <strong>null</strong> if it is
135: * the server root resource, or any Resource.
136: * @return An instance of ResourceReference, or <strong>null</strong>
137: */
138: public ResourceReference getParent() {
139: ResourceContext context = unsafeGetContext();
140: if (context == null) //are we external?
141: return null;
142: return context.getContainer();
143: }
144:
145: /**
146: * Get the file part of the URL this resource is attached to.
147: * @return An URL object specifying the location in the information
148: * space of this resource.
149: */
150: public String getURLPath() {
151: return getString(ATTR_URL, null);
152: }
153:
154: /**
155: * Get the file part of the URL this resource is attached to.
156: * @return An URL object specifying the location in the information
157: * space of this resource.
158: */
159: public String unsafeGetURLPath() {
160: return unsafeGetString(ATTR_URL, null);
161: }
162:
163: /**
164: * Get the server this resource is served by.
165: * @return The first instance of Jigsaw this resource was attached to.
166: */
167: public ServerInterface getServer() {
168: return ((ResourceContext) unsafeGetValue(ATTR_CONTEXT, null))
169: .getServer();
170: }
171:
172: /**
173: * Get this resource's help url.
174: * @return An URL, encoded as a String, or <strong>null</strong> if not
175: * available.
176: */
177: public String getHelpURL() {
178: return getString(ATTR_HELP_URL, null);
179: }
180:
181: private String computeHelpUrl() {
182: try {
183: StringBuffer sb = new StringBuffer(128);
184: sb.append(getServer().getDocumentationURL());
185: sb.append('/');
186: sb.append(getClass().getName());
187: sb.append(".html");
188: return sb.toString().intern();
189: } catch (Exception ex) {
190: return null;
191: }
192:
193: }
194:
195: synchronized public Object getValue(int idx, Object def) {
196: if ((idx == ATTR_HELP_URL) && (values[ATTR_HELP_URL] == null))
197: values[ATTR_HELP_URL] = computeHelpUrl();
198: return super .getValue(idx, def);
199: }
200:
201: public Object unsafeGetValue(int idx, Object def) {
202: if ((idx == ATTR_HELP_URL) && (values[ATTR_HELP_URL] == null))
203: values[ATTR_HELP_URL] = computeHelpUrl();
204: return super .unsafeGetValue(idx, def);
205: }
206:
207: /**
208: * Get the help URL for that resource's topic.
209: * @param topic The topic you want help for.
210: * @return A String encoded URL, or <strong>null</strong> if none
211: * was found.
212: */
213: public String getHelpURL(String topics) {
214: return null;
215: }
216:
217: /**
218: * Get the hierarchical context for that resource.
219: * @return A ResourceContext instance, guaranteed not to be <strong>null
220: * </strong>
221: */
222: protected ResourceContext getContext() {
223: return (ResourceContext) getValue(ATTR_CONTEXT, null);
224: }
225:
226: protected ResourceContext unsafeGetContext() {
227: return (ResourceContext) unsafeGetValue(ATTR_CONTEXT, null);
228: }
229:
230: /**
231: * Set the given context as the current context of this resource.
232: * @param context The new context.
233: */
234: protected void setContext(ResourceContext context) {
235: context.setResourceReference(getResourceReference());
236: setValue(ATTR_CONTEXT, context);
237: }
238:
239: /**
240: * Set the given context as the current context of this resource.
241: * @param context The new context.
242: * @param keepmodules If true the new context will have the same
243: * modules than the old one.
244: */
245: protected void setContext(ResourceContext context,
246: boolean keepmodules) {
247: context.setResourceReference(getResourceReference());
248: if (keepmodules) {
249: ResourceContext ctxt = getContext();
250: if (ctxt != null)
251: context.modules = ctxt.modules;
252: }
253: setValue(ATTR_CONTEXT, context);
254: }
255:
256: /**
257: * Get the store entry for that resource.
258: * Only the resource store in charge of this resource knows about the
259: * type of the resulting object. Buy declaring the class of that object
260: * private, the resource store can assume some private access to it.
261: * @return A java Object instance, or <strong>null</strong> if no
262: * store entry is attached to that resource.
263: */
264:
265: public Object getStoreEntry() {
266: return getValue(ATTR_STORE_ENTRY, null);
267: }
268:
269: /**
270: * Get this resource identifier.
271: * @return The String value for the identifier.
272: */
273: public String getIdentifier() {
274: return getString(ATTR_IDENTIFIER, null);
275: }
276:
277: /**
278: * Get this resource identifier.
279: * @return The String value for the identifier.
280: */
281: public String unsafeGetIdentifier() {
282: return unsafeGetString(ATTR_IDENTIFIER, null);
283: }
284:
285: /**
286: * Get the space entry for that resource. This Object is use to
287: * retrieve the resource in the resource space.
288: * @return A spaceEntry instance.
289: */
290: protected SpaceEntry getSpaceEntry() {
291: ResourceReference rr = getParent();
292: if (rr != null) {
293: try {
294: ContainerResource cont = (ContainerResource) rr.lock();
295: return new SpaceEntryImpl(cont);
296: } catch (InvalidResourceException ex) {
297: return null;
298: } finally {
299: rr.unlock();
300: }
301: }
302: return null;
303: }
304:
305: /**
306: * Get the ResourceSpace where this resource is stored.
307: * @return A ResourceSpace instance.
308: */
309: protected ResourceSpace getSpace() {
310: ResourceContext context = unsafeGetContext();
311: if (context == null) {
312: context = getContext();
313: }
314: if (context != null) {
315: return context.getSpace();
316: }
317: return null;
318: }
319:
320: /**
321: * Get the ResourceReference of that resource. ResourceReference is the
322: * only public way to access a resource.
323: * @return a ResourceReference instance.
324: */
325: public ResourceReference getResourceReference() {
326: ResourceContext context = getContext();
327: if (context != null)
328: return context.getResourceReference();
329: return null;
330: }
331:
332: /**
333: * Get the ResourceReference of that resource. ResourceReference is the
334: * only public way to access a resource.
335: * @return a ResourceReference instance.
336: */
337: public ResourceReference unsafeGetResourceReference() {
338: ResourceContext context = unsafeGetContext();
339: if (context != null)
340: return context.getResourceReference();
341: return null;
342: }
343:
344: /**
345: * Initialize and attach a new ResourceFrame to that resource.
346: * @param frame An uninitialized ResourceFrame instance.
347: * @param defs A default set of attribute values.
348: */
349: public void registerFrame(ResourceFrame frame, Hashtable defs) {
350: synchronized (this ) {
351: ResourceFrame frames[] = null;
352: frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES,
353: null);
354: // Initialize the frame with given default attributes:
355: if (defs.get(id) == null) {
356: String fname = "frame-"
357: + ((frames == null) ? 0 : frames.length);
358: defs.put(id, fname.intern());
359: }
360: frame.initialize(defs);
361: // Look for a free slot frame:
362: if (frames == null) {
363: frames = new ResourceFrame[1];
364: frames[0] = frame;
365: } else {
366: int slot = -1;
367: // Look for a free slot:
368: for (int i = 0; i < frames.length; i++) {
369: if (frames[i] == null) {
370: slot = i;
371: break;
372: }
373: }
374: if (slot >= 0) {
375: // Free slot available:
376: frames[slot] = frame;
377: } else {
378: // Resize frames:
379: ResourceFrame nf[] = new ResourceFrame[frames.length + 1];
380: System.arraycopy(frames, 0, nf, 0, frames.length);
381: nf[frames.length] = frame;
382: frames = nf;
383: }
384: }
385: // Set the frames:
386: setValue(ATTR_RESOURCE_FRAMES, frames);
387: }
388: }
389:
390: /**
391: * Unregister a resource frame from the given resource.
392: * @param frame The frame to unregister from the resource.
393: */
394: public synchronized void unregisterFrame(ResourceFrame frame) {
395: ResourceFrame frames[] = null;
396: frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);
397: if (frames != null) {
398: ResourceFrame f[] = new ResourceFrame[frames.length - 1];
399: int j = 0;
400: for (int i = 0; i < frames.length; i++) {
401: if (frames[i] == frame) {
402: // got it, copy the end of the array
403: System.arraycopy(frames, i + 1, f, j, frames.length
404: - i - 1);
405: setValue(ATTR_RESOURCE_FRAMES, f);
406: return;
407: } else {
408: try {
409: f[j++] = frames[i];
410: } catch (ArrayIndexOutOfBoundsException ex) {
411: return; // no modifications, return
412: }
413: }
414: }
415: }
416: }
417:
418: /**
419: * Collect all frames.
420: * @return An array of ResourceFrame, containing a set of frames instances
421: * or <strong>null</strong> if no resource frame is available.
422: */
423: public synchronized ResourceFrame[] getFrames() {
424: return (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);
425: }
426:
427: /**
428: * Collect all frames.
429: * @return An array of ResourceFrame, containing a set of frames instances
430: * or <strong>null</strong> if no resource frame is available.
431: */
432: public ResourceFrame[] unsafeGetFrames() {
433: return (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES,
434: null);
435: }
436:
437: /**
438: * Collect any frame that's an instance of the given class.
439: * @param cls The class of frames we are looking for.
440: * @return An array of ResourceFrame, containing a set of frames instances
441: * of the given class, or <strong>null</strong> if no resource frame is
442: * available.
443: */
444: public synchronized ResourceFrame[] collectFrames(Class c) {
445: ResourceFrame frames[] = null;
446: frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);
447: if (frames != null) {
448: Vector v = new Vector(frames.length);
449: for (int i = 0; i < frames.length; i++) {
450: if (c.isInstance(frames[i]))
451: v.addElement(frames[i]);
452: }
453: int sz = v.size();
454: if (sz > 0) {
455: ResourceFrame ret[] = new ResourceFrame[sz];
456: v.copyInto(ret);
457: return ret;
458: }
459: }
460: return null;
461: }
462:
463: /**
464: * Collect any frame that's an instance of the given class.
465: * @param cls The class of frames we are looking for.
466: * @return An array of ResourceFrame, containing a set of frames instances
467: * of the given class, or <strong>null</strong> if no resource frame is
468: * available.
469: */
470: ResourceFrame[] unsafeCollectFrames(Class c) {
471: ResourceFrame frames[] = null;
472: frames = (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES,
473: null);
474: if (frames != null) {
475: Vector v = new Vector(frames.length);
476: for (int i = 0; i < frames.length; i++) {
477: if (c.isInstance(frames[i]))
478: v.addElement(frames[i]);
479: }
480: int sz = v.size();
481: if (sz > 0) {
482: ResourceFrame ret[] = new ResourceFrame[sz];
483: v.copyInto(ret);
484: return ret;
485: }
486: }
487: return null;
488: }
489:
490: /**
491: * Get the first occurence of a frame of the given class.
492: * @param cls The class of te frame to look for.
493: * @return A ResourceFrame instance, or <strong>null</strong>.
494: */
495: public synchronized ResourceFrame getFrame(Class c) {
496: ResourceFrame frames[] = null;
497: frames = (ResourceFrame[]) getValue(ATTR_RESOURCE_FRAMES, null);
498: if (frames != null) {
499: for (int i = 0; i < frames.length; i++) {
500: if (c.isInstance(frames[i]))
501: return frames[i];
502: }
503: }
504: return null;
505: }
506:
507: /**
508: * Get the first occurence of a frame of the given class.
509: * @param cls The class of te frame to look for.
510: * @return A ResourceFrame instance, or <strong>null</strong>.
511: */
512: public ResourceFrame unsafeGetFrame(Class c) {
513: ResourceFrame frames[] = null;
514: frames = (ResourceFrame[]) unsafeGetValue(ATTR_RESOURCE_FRAMES,
515: null);
516: if (frames != null) {
517: for (int i = 0; i < frames.length; i++) {
518: if (c.isInstance(frames[i]))
519: return frames[i];
520: }
521: }
522: return null;
523: }
524:
525: /**
526: * Get an attached frame attribute value.
527: * This method really is a short-hand that combines a <code>getFrame</code>
528: * and <code>getValue</code> method call.
529: * @param cls The class of the frame we want the value of.
530: * @param idx The attribute index.
531: * @param def The default value (if the attribute value isn't defined).
532: * @return The attribute value as an Object instance, or the provided
533: * default value if the attribute value isn't defined.
534: */
535: public synchronized Object getValue(Class c, int idx, Object def) {
536: ResourceFrame frame = getFrame(c);
537: if (frame != null)
538: return frame.getValue(idx, def);
539: throw new IllegalAttributeAccess(this , idx);
540: }
541:
542: /**
543: * Set an attached frame attribute value.
544: * This method really is a short-hand that combines a <code>getFrame</code>
545: * and a <code>setValue</code> method call.
546: * @param cls The class of the frame we want to modify.
547: * @param idx The attribute to modify.
548: * @param val The new attribute value.
549: */
550: public synchronized void setValue(Class c, int idx, Object val) {
551: ResourceFrame frame = getFrame(c);
552: if (frame != null) {
553: frame.setValue(idx, val);
554: markModified();
555: return;
556: }
557: throw new IllegalAttributeAccess(this , idx);
558: }
559:
560: /**
561: * Get this resource last modification time.
562: * @return A long giving the date of the last modification time, or
563: * <strong>-1</strong> if undefined.
564: */
565: public long getLastModified() {
566: return getLong(ATTR_LAST_MODIFIED, (long) -1);
567: }
568:
569: /**
570: * Mark this resource as having been modified.
571: */
572: public void markModified() {
573: ResourceSpace space = getSpace();
574: if ((space != null) && (getSpaceEntry() != null)) {
575: synchronized (this ) {
576: space.markModified(getSpaceEntry(), this );
577: }
578: }
579: super .setValue(ATTR_LAST_MODIFIED, new Long(System
580: .currentTimeMillis()));
581: }
582:
583: /**
584: * We overide setValue, to mark the resource as modified.
585: * @param idx The index of the attribute to modify.
586: * @param value The new attribute value.
587: */
588: public void setValue(int idx, Object value) {
589: // Changing the identifier of a resource needs some special tricks:
590: if (idx == ATTR_IDENTIFIER) {
591: String oldid = getIdentifier();
592: try {
593: super .setValue(idx, value);
594: } catch (IllegalAttributeAccess ex) {
595: // We were not able to change the identifier, rethrow
596: throw ex;
597: }
598: // Change was successfull, update the resource space:
599: if (getSpaceEntry() != null) {
600: ResourceSpace space = getSpace();
601: space.renameResource(getSpaceEntry(), oldid,
602: (String) value);
603: }
604: //modify the URL path
605: ResourceReference rr = getParent();
606: if (rr != null) {
607: try {
608: Resource r = rr.lock();
609: setValue(ATTR_URL, r.getURLPath()
610: + java.net.URLEncoder
611: .encode((String) value));
612: } catch (Exception ex) {
613: ex.printStackTrace();
614: } finally {
615: rr.unlock();
616: }
617: }
618: markModified();
619: return;
620: }
621: // Normal setValue, but markModified before leaving:
622: super .setValue(idx, value);
623: if ((!attributes[idx].checkFlag(Attribute.DONTSAVE))
624: && (idx != ATTR_LAST_MODIFIED))
625: markModified();
626: }
627:
628: /**
629: * Is that resource willing to be unloaded.
630: * This method is a bit tricky to implement. The guideline is that you
631: * should not dynamically change the returned value (since you can't
632: * control what happens between a call to that method and a call to
633: * the <code>notifyUnload</code> method).
634: * <p>Returning <strong>false</strong> should never be needed, except
635: * for very strange resources.
636: * @return A boolean <strong>true</strong> if the resource can be unloaded
637: * <strong>false</strong> otherwise.
638: */
639:
640: public boolean acceptUnload() {
641: if (debugunload) {
642: try {
643: System.out.println(getValue("url", "<??>")
644: + ": acceptUnload");
645: } catch (IllegalAttributeAccess ex) {
646: }
647: }
648: return true;
649: }
650:
651: /**
652: * This resource is being unloaded.
653: * The resource is being unloaded from memory, perform any additional
654: * cleanup required.
655: */
656: public void notifyUnload() {
657: if (debugunload) {
658: try {
659: System.out.println(getValue("url", "<??>")
660: + ": unloaded.");
661: } catch (IllegalAttributeAccess ex) {
662: }
663: }
664: values = null;
665: }
666:
667: /**
668: * unloaded?
669: * @return true if the resource has been unloaded.
670: */
671: public boolean isUnloaded() {
672: return (values == null);
673: }
674:
675: /**
676: * The web admin wants us to update any out of date attribute.
677: */
678: public void updateAttributes() {
679: return;
680: }
681:
682: /**
683: * Check if this resource is loked more than one time.
684: * @exception MultipleLockException is thrown if true.
685: */
686: protected void checkMultipleLock(ResourceReference rr)
687: throws MultipleLockException {
688: if (rr.nbLock() > 1)
689: throw new MultipleLockException(rr.nbLock(), this ,
690: "can't delete");
691: }
692:
693: /**
694: * Delete this Resource instance, and remove it from its store.
695: * This method will erase definitely this resource, for ever, by removing
696: * it from its resource store (when doable).
697: * @exception MultipleLockException if someone else has locked this
698: * resource
699: */
700: public synchronized void delete() throws MultipleLockException {
701: ResourceSpace space = getSpace();
702:
703: if ((space != null) && (getSpaceEntry() != null)) {
704: ResourceReference self = getResourceReference();
705: if (self != null) {
706: synchronized (self) {
707: checkMultipleLock(self);
708: space.deleteResource(getSpaceEntry(), this );
709: }
710: } else {
711: space.deleteResource(getSpaceEntry(), this );
712: }
713: }
714: }
715:
716: public boolean isInitialized() {
717: return (values != null);
718: }
719:
720: /**
721: * Set the values. (MUST be called before initialize).
722: * @param defs The Hashtable containing the values.
723: */
724: public void pickleValues(Hashtable defs) {
725: Object nvalues[] = new Object[attributes.length];
726: for (int i = 0; i < nvalues.length; i++) {
727: String attrname = attributes[i].getName();
728: Object def = defs.get(attrname);
729: if ((i == ATTR_HELP_URL) && (def != null)
730: && (def instanceof String)) {
731: nvalues[i] = ((String) def).intern();
732: } else {
733: nvalues[i] = def;
734: }
735: }
736: this .values = nvalues;
737: }
738:
739: /**
740: * Initialization method for attribute holders.
741: * This method allows to initialize an attribute holder by providing
742: * its attributes values through a Hashtable mapping attribute names
743: * to attribute values.
744: * @param defs The Hashtable containing the default values.
745: */
746:
747: public void initialize(Hashtable defs) {
748: Object values[] = ((this .values == null) ? new Object[attributes.length]
749: : this .values);
750: for (int i = 0; i < values.length; i++) {
751: String attrname = attributes[i].getName();
752: Object def = defs.get(attrname);
753: if (values[i] == null) {
754: // for help_url, we can save lots of space by using
755: // String.intern()
756: if ((i == ATTR_HELP_URL) && (def != null)
757: && (def instanceof String)) {
758: values[i] = ((String) def).intern();
759: } else {
760: values[i] = def;
761: }
762: }
763: }
764: initialize(values);
765: }
766:
767: public void initialize(Object values[]) {
768: super .initialize(values);
769: }
770:
771: /**
772: * Create an empty resource instance.
773: * Initialize the instance attributes description, and its values.
774: */
775: public Resource() {
776: super();
777: }
778: }
|