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