View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  
37  package org.exolab.castor.xml.schema;
38  
39  import org.exolab.castor.xml.ValidationException;
40  
41  /**
42   * An XML Schema Attribute Definition
43   * 
44   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
45   * @version $Revision$ $Date: 2006-04-14 04:14:43 -0600 (Fri, 14 Apr 2006) $
46   **/
47  public final class AttributeDecl extends Annotated {
48    /** SerialVersionUID */
49    private static final long serialVersionUID = -8720345516857919305L;
50  
51    /**
52     * The use attribute value for optional
53     **/
54    public static final String USE_OPTIONAL = "optional";
55  
56    /**
57     * The use attribute value for prohibited
58     **/
59    public static final String USE_PROHIBITED = "prohibited";
60  
61    /**
62     * The use attribute value for required
63     **/
64    public static final String USE_REQUIRED = "required";
65  
66  
67    private static final short OPTIONAL = 3;
68    private static final short PROHIBITED = 4;
69    private static final short REQUIRED = 5;
70  
71    /**
72     * Error message for a null argument
73     **/
74    private static String NULL_ARGUMENT =
75        "A null argument was passed to the constructor of " + AttributeDecl.class.getName();
76  
77    /**
78     * The default namespace form for this AttributeDecl (optional).
79     **/
80    private Form _form = null;
81  
82    /**
83     * The id for this AttributeDecl
84     **/
85    private String _id = null;
86  
87    /**
88     * The name of attributes defined by this AttributeDecl
89     **/
90    private String _name = null;
91  
92    /**
93     * The parent for this AttributeDecl
94     **/
95    private Structure _parent = null;
96  
97    /**
98     * The Schema to which this AttributeDecl belongs
99     **/
100   private Schema _schema = null;
101 
102   /**
103    * The simple type for this AttributeDecl.
104    **/
105   private SimpleType _simpleType = null;
106 
107 
108   /**
109    * The current value of the 'use' property. The value is OPTIONAL by default.
110    **/
111   private short _useFlag = OPTIONAL;
112 
113   /**
114    * The fixed value for attribute instances of this attribute declaration.
115    **/
116   private String _fixed = null;
117 
118   /**
119    * The default value for attribute instances of this attribute declaration.
120    */
121   private String _default = null;
122 
123   /**
124    * A reference to a top-level attribute
125    */
126   private String _attributeRef = null;
127 
128   /**
129    * Creates a new AttrDecl with the given name
130    * 
131    * @param name of the Attribute defined by this attribute declaration
132    * @param schema the schema that contains the new attrDecl
133    **/
134   public AttributeDecl(Schema schema, String name) {
135 
136     if (schema == null) {
137       String err = NULL_ARGUMENT + "; 'schema' must not be null.";
138       throw new IllegalArgumentException(err);
139     }
140     _schema = schema;
141     setName(name);
142   } // -- AttributeDecl
143 
144   /**
145    * Creates a new AttrDecl in the given schema.
146    * 
147    * @param schema the schema that contains the new attrDecl
148    **/
149   public AttributeDecl(Schema schema) {
150 
151     if (schema == null) {
152       String err = NULL_ARGUMENT + "; 'schema' must not be null.";
153       throw new IllegalArgumentException(err);
154     }
155     _schema = schema;
156   } // -- AttributeDecl
157 
158 
159   /**
160    * Returns the Form for this attribute declaration. The Form object species whether or not names
161    * are qualified or unqualified for instances of this attribute declaration. If null, the Form
162    * should be obtained from the parent Schema.
163    *
164    * @return the Form for this attribute declaration, or null if not set.
165    **/
166   public Form getForm() {
167     return _form;
168   } // -- getForm
169 
170   /**
171    * Returns the Id for this attribute declaration
172    *
173    * @return the Id for this attribute declaration
174    **/
175   public String getId() {
176     return _id;
177   } // -- getId
178 
179   /**
180    * Returns the name of attributes defined by this AttributeDecl. If this AttributeDecl is a
181    * reference to another AttributeDecl, the reference will be resolved and the name of the
182    * referenced AttributeDecl will be returned. The name will always be an NCName, no namespace
183    * prefix will be included.
184    * 
185    * @return the name of attributes defined by this AttributeDecl.
186    **/
187   public String getName() {
188     return getName(false);
189   } // -- getName
190 
191   /**
192    * Returns the name of this Attribute declaration. The name will always be an NCName, no namespace
193    * prefix will be included.
194    *
195    * @param ignoreRef a boolean that when false, indicates that if this is an attribute reference to
196    *        return the reference name. Otherwise the only the local name is used.
197    *
198    * @return the name of this attribute declaration
199    **/
200   public String getName(boolean ignoreRef) {
201     if (isReference() && ignoreRef == false) {
202       // -- strip prefix we can only return
203       // -- an NCName from this method
204       String ncname = _attributeRef;
205       // -- check for namespace prefix
206       int idx = ncname.indexOf(':');
207       if (idx > 0) {
208         ncname = ncname.substring(idx + 1);
209       }
210       return ncname;
211     }
212     return _name;
213   } // -- getName
214 
215   /**
216    * Returns the parent of this AttributeDecl, this value may be null if no parent has been set.
217    *
218    * @return the parent Structure of this AttributeDecl.
219    **/
220   public Structure getParent() {
221     return _parent;
222   } // -- getParent
223 
224   /**
225    * Returns the data type associated with this AttributeDecl.
226    *
227    * @return the data type associated with this AttributeDecl.
228    **/
229   public SimpleType getSimpleType() {
230     SimpleType result = null;
231 
232     if (isReference()) {
233       AttributeDecl attribute = getReference();
234       if (attribute != null)
235         result = attribute.getSimpleType();
236       else
237         return null;
238     }
239 
240     if (_simpleType == null)
241       return null;
242     result = (SimpleType) _simpleType.getType();
243 
244     if (result != null) {
245       Schema tempSchema = result.getSchema().getMasterSchema();
246       if (tempSchema != null) {
247         SimpleType tempType = tempSchema.getSimpleType(result.getName());
248         if (tempType != null) {
249           result = tempType;
250         }
251       }
252     }
253     return result;
254   } // -- getSimpleType
255 
256   /**
257    * Returns the AttributeDecl that this attribute definition references. This will return null if
258    * this attribute definition does not reference a different attribute definition.
259    * 
260    * @return the AttributeDecl that this attribute definition references
261    **/
262   public AttributeDecl getReference() {
263     AttributeDecl result = null;
264     if (_attributeRef != null) {
265       result = _schema.getAttribute(_attributeRef);
266       if (result == null) {
267         String err = "Unable to find attribute referenced :\" ";
268         err += _attributeRef;
269         err += "\"";
270         throw new IllegalStateException(err);
271       }
272     }
273     return result;
274   } // -- getReference
275 
276   /**
277    * Returns the actual reference name of this AttributeDecl, or null if this AttributeDecl is not a
278    * reference. The name returned, if not null, will be a QName, possibly containing the namespace
279    * prefix.
280    * 
281    * @return the reference name
282    */
283   public String getReferenceName() {
284     return _attributeRef;
285   } // -- getReference
286 
287   /**
288    * Returns the Schema that this AttributeGroupDecl belongs to.
289    *
290    * @return the Schema that this AttributeGroupDecl belongs to.
291    **/
292   public Schema getSchema() {
293     return _schema;
294   } // -- getSchema
295 
296   /**
297    * Returns the value of the use attribute for this attribute declaration or attribute reference.
298    * If this is a reference the value of the use attribute will *not* be obtained from the
299    * referenced attribute declaration as top-level attributes do not take into account the use
300    * attribute.
301    *
302    * @return the value of the use attribute for this attribute declaration
303    */
304   public String getUse() {
305 
306     // -- Note: Do not resolve reference, since top-level
307     // -- atts do not specify the "use" attribute.
308 
309     switch (_useFlag) {
310       case PROHIBITED:
311         return USE_PROHIBITED;
312       case REQUIRED:
313         return USE_REQUIRED;
314       default:
315         return USE_OPTIONAL;
316     }
317 
318   } // -- getUse
319 
320   /**
321    * Returns the default value of this element definition.
322    *
323    * @return the default value of this element definition, or null if no default was specified.
324    **/
325   public String getDefaultValue() {
326     return _default;
327   } // -- getDefaultValue
328 
329   /**
330    * Returns the fixed value of this element definition.
331    *
332    * @return the fixed value of this element definition, or null if no default was specified.
333    */
334   public String getFixedValue() {
335     return _fixed;
336   } // -- getFixedValue
337 
338   /**
339    * Returns true if the "default" flag is set.
340    *
341    * @return true if the "default" flag is set.
342    */
343   public boolean isDefault() {
344     return (_default != null) && (_default.length() > 0);
345   } // -- isFixed
346 
347 
348   /**
349    * Returns true if the use attribute is equal to "optional".
350    *
351    * @return true if the use attribute is equal to "optional".
352    **/
353   public boolean isFixed() {
354     return (_fixed != null) && (_fixed.length() > 0);
355   } // -- isFixed
356 
357   /**
358    * Returns true if the use attribute is equal to "optional".
359    *
360    * @return true if the use attribute is equal to "optional".
361    **/
362   public boolean isOptional() {
363     String use = getUse();
364     return use.equals(USE_OPTIONAL);
365   } // -- isOptional
366 
367   /**
368    * Returns true if the use attribute is equal to "prohibited".
369    *
370    * @return true if the use attribute is equal to "prohibited".
371    **/
372   public boolean isProhibited() {
373     String use = getUse();
374     return use.equals(USE_PROHIBITED);
375   } // -- isProhibited
376 
377   /**
378    * Returns true if the 'use' attribute is equal to REQUIRED and there is no specified value. If a
379    * value is specifed and the 'use' attribute is "required" then required is will return false,
380    * because the attribute value automatically becomes fixed.
381    *
382    * @return true if the use attribute is equal to "required" and no default value has been
383    *         specified, otherwise false
384    **/
385   public boolean isRequired() {
386     String use = getUse();
387     return (use.equals(USE_REQUIRED));
388   } // -- getRequired
389 
390   /**
391    * Returns true if this attribute definition simply references another attribute Definition
392    * 
393    * @return true if this attribute definition is a reference
394    */
395   public boolean isReference() {
396     return (_attributeRef != null);
397   } // -- isReference
398 
399   /**
400    * Sets the Form for this attribute declaration. The Form object species whether or not names are
401    * qualified or unqualified for instances of this attribute declaration. If null, the Form is to
402    * be obtained from the parent Schema.
403    *
404    * @param form the Form type for this attribute declaration.
405    **/
406   public void setForm(Form form) {
407     _form = form;
408   } // -- setForm
409 
410   /**
411    * Sets the Id for this attribute declaration
412    *
413    * @param id the Id for this attribute declaration
414    **/
415   public void setId(String id) {
416     _id = id;
417   } // -- setId
418 
419   /**
420    * Sets the name of attributes defined by this attribute definition
421    * 
422    * @param name the name of the this AttributeDecl. Must be a valid NCName.
423    * @exception IllegalArgumentException when the name is not valid
424    **/
425   public void setName(String name) {
426     if (name == null) {
427       String err = "AttributeDecl#setName: 'name' must not be null.";
428       throw new IllegalArgumentException(err);
429     }
430 
431     // -- handle namespace if necessary
432     int idx = name.indexOf(':');
433     if (idx >= 0) {
434       // -- we should resolve nsPrefix...just ignore for now
435       // -- use local name
436       name = name.substring(idx + 1);
437     }
438 
439     if (name.length() == 0) {
440       String err = "AttributeDecl#setName: 'name' must not be " + "zero-length.";
441       throw new IllegalArgumentException(err);
442     }
443 
444     _name = name;
445   } // -- setName
446 
447   /**
448    * Sets the parent for this AttributeDecl
449    *
450    * @param parent the parent Structure for this AttributeDecl
451    **/
452   protected void setParent(Structure parent) {
453     if (parent != null) {
454       switch (parent.getStructureType()) {
455         case Structure.ATTRIBUTE_GROUP:
456         case Structure.COMPLEX_TYPE:
457         case Structure.SCHEMA:
458           break;
459         default:
460           String error = "Invalid parent for group";
461           throw new IllegalArgumentException(error);
462       }
463     }
464     _parent = parent;
465   } // -- setParent
466 
467   /**
468    * Sets the reference for this attribute definition
469    * 
470    * @param reference the Attribute definition that this definition references
471    **/
472   public void setReference(AttributeDecl reference) {
473     if (reference == null)
474       this._attributeRef = null;
475     else
476       this._attributeRef = reference.getName();
477   } // -- setReference
478 
479   /**
480    * Sets the reference for this attribute definition
481    * 
482    * @param reference the name of the attribute definition that this definition references
483    **/
484   public void setReference(String reference) {
485     this._attributeRef = reference;
486   } // -- setReference
487 
488   /**
489    * Sets the SimpleType for this attribute declaration
490    * 
491    * @param simpleType the SimpleType for this attribute declaration
492    **/
493   public void setSimpleType(SimpleType simpleType) {
494     _simpleType = simpleType;
495     if (simpleType != null) {
496       simpleType.setParent(this);
497     }
498   } // -- setSimpleType
499 
500   /**
501    * Sets the simple type of this attribute to be a reference.
502    *
503    * @param name the name of the simpleType being referenced, must not be null.
504    **/
505   public void setSimpleTypeReference(String name) {
506     SimpleTypeReference reference = new SimpleTypeReference(_schema, name);
507     setSimpleType(reference);
508   } // -- setSimpleTypeReference
509 
510 
511   /**
512    * Sets the 'use' attribute of this attribute declaration Note: this should not be used to set the
513    * flag to FIXED or DEFAULT
514    * 
515    * @param value one of the following: ("prohibited" | "optional" | "required")
516    *
517    * @see #USE_PROHIBITED
518    * @see #USE_OPTIONAL
519    * @see #USE_REQUIRED
520    **/
521   public void setUse(String value) {
522 
523     if (value == null) {
524       _useFlag = OPTIONAL;
525       return;
526     }
527 
528     if (value.equals(USE_REQUIRED))
529       _useFlag = REQUIRED;
530     else if (value.equals(USE_OPTIONAL))
531       _useFlag = OPTIONAL;
532     else if (value.equals(USE_PROHIBITED))
533       _useFlag = PROHIBITED;
534     else {
535       throw new IllegalArgumentException("Invalid value for 'use': " + value);
536     }
537   } // -- setUse
538 
539   /**
540    * Sets the DEFAULT value
541    */
542   public void setDefaultValue(String value) {
543     if ((_fixed != null) && (_fixed.length() > 0)) {
544       throw new IllegalStateException("'default' and 'fixed' must not be both present.");
545     }
546     _default = value;
547   }
548 
549   /**
550    * Sets the FIXED value.
551    */
552   public void setFixedValue(String value) {
553     if ((_default != null) && (_default.length() > 0)) {
554       throw new IllegalStateException("'default' and 'fixed' must not be both present.");
555     }
556     _fixed = value;
557   }
558 
559   // -------------------------------/
560   // - Implementation of Structure -/
561   // -------------------------------/
562 
563   /**
564    * Returns the type of this Schema Structure
565    * 
566    * @return the type of this Schema Structure
567    **/
568   public short getStructureType() {
569     return Structure.ATTRIBUTE;
570   } // -- getStructureType
571 
572   /**
573    * Checks the validity of this Attribute declaration
574    * 
575    * @exception ValidationException when this Attribute declaration is invalid
576    **/
577   public void validate() throws ValidationException {
578     if ((_attributeRef == null) && (_name == null)) {
579       String err = "<attribute> is missing required 'name' attribute.";
580       throw new ValidationException(err);
581     }
582 
583     if (_attributeRef != null) {
584       if (_schema.getAttribute(_attributeRef) == null) {
585         String err = "<attribute ref=\"" + _attributeRef + "\"> " + "is not resolvable.";
586         throw new ValidationException(err);
587       }
588       return;
589     }
590 
591   } // -- validate
592 
593   /**
594    * Set the parent schema of the current ElementDecl. The parent schema should at least have the
595    * same targetNamespace of the current schema.
596    * 
597    * This method is protected since it is only meant to be used by the internal API to propagate the
598    * parent XML Schema in case of a redefinition for instance.
599    * 
600    * @param schema
601    */
602   protected void setSchema(Schema schema) {
603     _schema = schema;
604   }
605 
606   /**
607    * Indicates whether a type is set for this element definiion.
608    * 
609    * @return True if a type is set.
610    */
611   public boolean hasXMLType() {
612     return (_simpleType != null);
613   }
614 
615 } // -- AttrDecl