001: // AttributeHolder.java
002: // $Id: AttributeHolder.java,v 1.15 2007/03/10 12:34:47 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:
010: import java.io.PrintStream;
011:
012: /**
013: * An attribute holder is an object that holds a list of attributes.
014: * Each of the attributes maintained by a holder are described by an
015: * Attribute object, wich is able to pickle/unpickle its value, provides
016: * the status of the attribute (eg mandatory, editable, etc), etc.
017: * <p>Given this, an attribute holder is able to pickle its state (made of
018: * its attribute values), and unpickle it to any DataOutputStream (resp.
019: * DataInputStream).
020: * @see Attribute
021: * @see Resource
022: */
023:
024: public class AttributeHolder implements Cloneable {
025: /**
026: * Pointer to this class registered list of attributes.
027: */
028: protected Attribute attributes[] = null;
029: /**
030: * Attribute values.
031: */
032: protected Object values[] = null;
033:
034: /**
035: * Clone this attribute holder, and init it with the given attributes.
036: * @param values Attribute values to overide in the clone.
037: * @return A clone of this resource.
038: */
039:
040: public Object getClone(Object values[]) {
041: try {
042: // Continue with normal cloning:
043: AttributeHolder cl = (AttributeHolder) getClass()
044: .newInstance();
045: cl.initialize(values);
046: return cl;
047: } catch (Exception ex) {
048: String msg = ("Unable to create an instance of " + getClass());
049: throw new HolderInitException(msg);
050: }
051: }
052:
053: /**
054: * Clone this attribute holder.
055: * The resulting clone will <em>share</em> the attribute values of
056: * the cloned attribute holder.
057: * @return An attribute holder sharing its ancestor attribute values.
058: */
059:
060: public synchronized Object getClone() {
061: Object vs[] = new Object[attributes.length];
062: System.arraycopy(values, 0, vs, 0, vs.length);
063: return getClone(vs);
064: }
065:
066: /**
067: * Clone this AttributeHolder instance, and initialize it with defaults.
068: * This method first clones the receiving attribute holder, and then
069: * uses the defaults provided to finish the initialization.
070: * @param defs The attribute values, in a Hashtable.
071: * @return The clone.
072: */
073:
074: public synchronized Object getClone(Hashtable defs) {
075: try {
076: Object vs[] = new Object[attributes.length];
077: System.arraycopy(values, 0, vs, 0, vs.length);
078: // Merge the provided attribute values:
079: for (int i = 0; i < attributes.length; i++) {
080: Object value = defs.get(attributes[i].getName());
081: if (value != null)
082: vs[i] = value;
083: }
084: return getClone(vs);
085: } catch (Exception ex) {
086: String msg = ("Unable to create an instance of " + getClass());
087: throw new HolderInitException(msg);
088: }
089: }
090:
091: /**
092: * Get this attribute holders attributes description.
093: * The attribute list is guaranteed to be returned always in the same
094: * order, wich is fixed at compilation time. This allows for fast access
095: * to resource by their position rather than by name.
096: * @return An array of Attribute objects, each one containing the
097: * description of one single attribute of the resource.
098: * @see org.w3c.tools.resources.Attribute
099: */
100:
101: public Attribute[] getAttributes() {
102: return attributes;
103: }
104:
105: /**
106: * Lookup up the index of an attribute in our attribute description.
107: * @param name The name of the attribute to look for.
108: * @return An integer, positive if found, negative otherwise.
109: */
110:
111: public int lookupAttribute(String name) {
112: for (int i = 0; i < attributes.length; i++) {
113: if (name == attributes[i].getName()) {
114: return i;
115: }
116: }
117: return -1;
118: }
119:
120: /**
121: * Set an attribute value.
122: * This method sets the value of some attribute of the resource. It marks
123: * the resource as being modified, and alert its resource store (so
124: * that it knows it will have to save the object at some time in the
125: * future).
126: * @param idx The attribute index, in the list of attributes advertized by
127: * the resource.
128: * @param value The new value for this attribute.
129: * @exception IllegalAttributeAccess if the provided value doesn't
130: * match the attribute expected type.
131: */
132:
133: synchronized public void setValue(int idx, Object value) {
134: // Check the index value:
135: if ((idx < 0) || (idx >= attributes.length))
136: throw new IllegalAttributeAccess(this , idx);
137: // Check the requested attribute's type
138: Attribute attr = attributes[idx];
139: if (attr.checkValue(value)) {
140: values[idx] = value;
141: } else {
142: throw new IllegalAttributeAccess(this , attr, value);
143: }
144: }
145:
146: /**
147: * Set an attribute value.
148: * This method sets the value of an attribute, referenced by its name.
149: * @param name The attribute name.
150: * @param value The new value for the attribute.
151: * @exception IllegalAttributeAccess if the provided value doesn't match
152: * the attribute expected type.
153: */
154:
155: public void setValue(String name, Object value) {
156: setValue(lookupAttribute(name), value);
157: }
158:
159: public void setBoolean(int idx, boolean b) {
160: setValue(idx, (b ? Boolean.TRUE : Boolean.FALSE));
161: }
162:
163: public void setChar(int idx, char ch) throws IllegalAttributeAccess {
164: setValue(idx, new Character(ch));
165: }
166:
167: public void setDouble(int idx, double d)
168: throws IllegalAttributeAccess {
169: setValue(idx, new Double(d));
170: }
171:
172: public void setFloat(int idx, float f)
173: throws IllegalAttributeAccess {
174: setValue(idx, new Float(f));
175: }
176:
177: public void setInt(int idx, int i) throws IllegalAttributeAccess {
178: setValue(idx, new Integer(i));
179: }
180:
181: public void setLong(int idx, long l) throws IllegalAttributeAccess {
182: setValue(idx, new Long(l));
183: }
184:
185: public void setString(int idx, String s)
186: throws IllegalAttributeAccess {
187: setValue(idx, (Object) s);
188: }
189:
190: /**
191: * Generic get of an attribute value.
192: * Retreive an attribute value from its index in the resource's attribute
193: * list.
194: * @param idx The index of the attribute whose value is queried.
195: * @param def The default value (if the attribute isn't defined).
196: * @return An object, giving the attribute value, or the provided
197: * default if this attribute isn't currently define for the resource.
198: * @exception IllegalAttributeAccess if the given index doesn't match any
199: * of the resource's attributes.
200: */
201:
202: synchronized public Object getValue(int idx, Object def)
203: throws IllegalAttributeAccess {
204: // Check the provided index:
205: if ((idx < 0) || (idx >= attributes.length))
206: throw new IllegalAttributeAccess(this , idx);
207: Object value = values[idx];
208: if (value == null)
209: return (def == null) ? attributes[idx].getDefault() : def;
210: else
211: return value;
212: }
213:
214: /**
215: * Generic get of an attribute value.
216: * Retreive an attribute value from its index in the resource's attribute
217: * list.
218: * THIS VERSION IS NOT SYNCHRONIZED AND THEREFORE SHOULD BE USED
219: * ONLY WHEN YOU ARE SURE YOU SHOULD USE THIS, WHICH MEANS ALMOST
220: * NEVER!
221: * @param idx The index of the attribute whose value is queried.
222: * @param def The default value (if the attribute isn't defined).
223: * @return An object, giving the attribute value, or the provided
224: * default if this attribute isn't currently define for the resource.
225: * @exception IllegalAttributeAccess if the given index doesn't match any
226: * of the resource's attributes.
227: */
228:
229: public Object unsafeGetValue(int idx, Object def)
230: throws IllegalAttributeAccess {
231: // Check the provided index:
232: if ((idx < 0) || (idx >= attributes.length))
233: throw new IllegalAttributeAccess(this , idx);
234: Object value = values[idx];
235: if (value == null)
236: return (def == null) ? attributes[idx].getDefault() : def;
237: else
238: return value;
239: }
240:
241: /**
242: * Generic get of an attribute value.
243: * Get the method of an attribute, by name.
244: * @param name The name of the queried attribute.
245: * @param def The default value.
246: * @exception IllegalAttributeAccess if the given name doesn't match any
247: * of the attribute's name.
248: */
249:
250: public Object getValue(String name, Object def)
251: throws IllegalAttributeAccess {
252: return getValue(lookupAttribute(name), def);
253: }
254:
255: public boolean getBoolean(int idx, boolean def) {
256: Object value = getValue(idx, null);
257: if (value == null) {
258: return def;
259: } else if (value instanceof Boolean) {
260: return ((Boolean) value).booleanValue();
261: } else {
262: throw new IllegalAttributeAccess(this , attributes[idx],
263: "getBoolean");
264: }
265: }
266:
267: public char getChar(int idx, char def) {
268: Object value = getValue(idx, null);
269: if (value == null) {
270: return def;
271: } else if (value instanceof Character) {
272: return ((Character) value).charValue();
273: } else {
274: throw new IllegalAttributeAccess(this , attributes[idx],
275: "getChar");
276: }
277: }
278:
279: public double getDouble(int idx, double def) {
280: Object value = getValue(idx, null);
281: if (value == null) {
282: return def;
283: } else if (value instanceof Double) {
284: return ((Double) value).doubleValue();
285: } else {
286: throw new IllegalAttributeAccess(this , attributes[idx],
287: "getDouble");
288: }
289: }
290:
291: public double unsafeGetDouble(int idx, double def) {
292: Object value = unsafeGetValue(idx, null);
293: if (value == null) {
294: return def;
295: } else if (value instanceof Double) {
296: return ((Double) value).doubleValue();
297: } else {
298: throw new IllegalAttributeAccess(this , attributes[idx],
299: "getDouble");
300: }
301: }
302:
303: public float getFloat(int idx, float def) {
304: Object value = getValue(idx, null);
305: if (value == null) {
306: return def;
307: } else if (value instanceof Float) {
308: return ((Float) value).floatValue();
309: } else {
310: throw new IllegalAttributeAccess(this , attributes[idx],
311: "getFloat");
312: }
313: }
314:
315: public int getInt(int idx, int def) {
316: Object value = getValue(idx, null);
317: if (value == null) {
318: return def;
319: } else if (value instanceof Integer) {
320: return ((Integer) value).intValue();
321: } else {
322: throw new IllegalAttributeAccess(this , attributes[idx],
323: "getInt");
324: }
325: }
326:
327: public long getLong(int idx, long def) {
328: Object value = getValue(idx, null);
329: if (value == null) {
330: return def;
331: } else if (value instanceof Long) {
332: return ((Long) value).longValue();
333: } else {
334: throw new IllegalAttributeAccess(this , attributes[idx],
335: "getLong");
336: }
337: }
338:
339: public String getString(int idx, String def) {
340: Object value = getValue(idx, null);
341: if (value == null) {
342: return def;
343: } else if (value instanceof String) {
344: return (String) value;
345: } else {
346: throw new IllegalAttributeAccess(this , attributes[idx],
347: "getString");
348: }
349: }
350:
351: public String unsafeGetString(int idx, String def) {
352: Object value = unsafeGetValue(idx, null);
353: if (value == null) {
354: return def;
355: } else if (value instanceof String) {
356: return (String) value;
357: } else {
358: throw new IllegalAttributeAccess(this , attributes[idx],
359: "getString");
360: }
361: }
362:
363: /**
364: * Does this resource has defined a value for the given attribute.
365: * @param idx The index of the attribute to check.
366: * @return A boolean <strong>true</strong> if the resource has a value
367: * for this attribute, <strong>false</strong> otherwise.
368: */
369:
370: public boolean definesAttribute(int idx)
371: throws IllegalAttributeAccess {
372: return (getValue(idx, null) != null);
373: }
374:
375: /**
376: * Does this resource has defined a value for the given attribute.
377: * @param idx The index of the attribute to check.
378: * @return A boolean <strong>true</strong> if the resource has a value
379: * for this attribute, <strong>false</strong> otherwise.
380: */
381:
382: public boolean unsafeDefinesAttribute(int idx)
383: throws IllegalAttributeAccess {
384: // Check the provided index:
385: if ((idx < 0) || (idx >= attributes.length))
386: throw new IllegalAttributeAccess(this , idx);
387: Object value = values[idx];
388: return (value != null);
389: }
390:
391: /**
392: * Does this resource has defined a value for the given attribute.
393: * @param name The name of the attribute to check.
394: * @return A boolean <strong>true</strong> if the resource has a value
395: * for this attribute, <strong>false</strong> otherwise.
396: */
397:
398: public boolean definesAttribute(String name)
399: throws IllegalAttributeAccess {
400: int idx = lookupAttribute(name);
401: return (idx >= 0) ? (getValue(idx, null) != null) : false;
402: }
403:
404: /**
405: * Set the values. (MUST be called before initialize).
406: * @param defs The Hashtable containing the values.
407: */
408: public synchronized void pickleValues(Hashtable defs) {
409: Object nvalues[] = new Object[attributes.length];
410: for (int i = 0; i < nvalues.length; i++) {
411: String attrname = attributes[i].getName();
412: nvalues[i] = defs.get(attrname);
413: }
414: this .values = nvalues;
415: }
416:
417: /**
418: * Initialization method for attribute holders.
419: * Each time an attribute holder get restored, its <code>initialize</code>
420: * method gets called. The holder should initialize itself with the set
421: * of provided values and perform any additional startup code.
422: * @param values The attribute values the holder should initialize from.
423: */
424:
425: public synchronized void initialize(Object nvalues[]) {
426: if (this .values != null) {
427: for (int i = 0; i < nvalues.length; i++) {
428: if (this .values[i] == null) {
429: this .values[i] = nvalues[i];
430: }
431: }
432: } else {
433: this .values = nvalues;
434: }
435: }
436:
437: /**
438: * Initialization method for attribute holders.
439: * This method allows to initialize an attribute holder by providing
440: * its attributes values through a Hashtable mapping attribute names
441: * to attribute values.
442: * @param defs The Hashtable containing the default values.
443: */
444:
445: public synchronized void initialize(Hashtable defs) {
446: Object values[] = ((this .values == null) ? new Object[attributes.length]
447: : this .values);
448: for (int i = 0; i < values.length; i++) {
449: String attrname = attributes[i].getName();
450: Object def = defs.get(attrname);
451: if (values[i] == null) {
452: values[i] = def;
453: }
454: }
455: initialize(values);
456: }
457:
458: /**
459: * Debugging purposes only, print this attribute holder.
460: * @param out The print stream to print to.
461: */
462:
463: public void print(PrintStream out) {
464: for (int i = 0; i < attributes.length; i++) {
465: if (values[i] != null)
466: System.out.println(attributes[i].getName() + "="
467: + values[i]);
468: }
469: }
470:
471: /**
472: * Create an attribute holder.
473: */
474:
475: public AttributeHolder() {
476: this .attributes = AttributeRegistry
477: .getClassAttributes(getClass());
478: if ((attributes != null) && (attributes.length > 0))
479: this .values = new Object[attributes.length];
480: }
481:
482: }
|