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-2000 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml.schema;
37  
38  import java.util.Enumeration;
39  
40  import org.exolab.castor.xml.ValidationException;
41  
42  /**
43   * An XML Schema SimpleType.
44   * 
45   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
46   * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
47   **/
48  
49  public abstract class SimpleType extends XMLType implements Referable {
50  
51    /**
52     * The value of the final attribute used for blocking all types of derivation.
53     **/
54    public static final String FINAL_ALL = "#all";
55  
56    /**
57     * The value of the final attribute used for blocking list derivation.
58     **/
59    public static final String FINAL_LIST = "list";
60  
61    /**
62     * The value of the final attribute used for blocking union derivation.
63     **/
64    public static final String FINAL_UNION = "union";
65  
66    /**
67     * The value of the final attribute used for blocking restriction derivation.
68     **/
69    public static final String FINAL_RESTRICTION = "restriction";
70  
71    /**
72     * The constraining facets of this type.
73     **/
74    private final FacetList _facets = new FacetList();
75  
76    /**
77     * The value of the final attribute (optional).
78     **/
79    private String _final = null;
80  
81    /**
82     * The parent structure of this {@link SimpleType}. (Schema, AttributeDecl or ElementDecl)
83     **/
84    private Structure _parent = null;
85  
86    /**
87     * The code for this simple type. (As defined by SimpleTypesFactory)
88     **/
89    private int _typeCode = SimpleTypesFactory.INVALID_TYPE;
90  
91    /**
92     * An attribute that indicates if this {@link SimpleType} is a redefinition.
93     */
94    private boolean _redefinition = false;
95  
96    /**
97     * Adds the given Facet to this Simpletype.
98     * 
99     * @param facet the Facet to add to this Simpletype
100    **/
101   public void addFacet(final Facet facet) {
102 
103     if (facet == null) {
104       return;
105     }
106 
107     String name = facet.getName();
108 
109     if (name == null) {
110       return;
111     }
112 
113     _facets.add(facet);
114 
115   }
116 
117   /**
118    * Returns the first facet associated with the given name.
119    * 
120    * @param name the name of the Facet to look for
121    * @return the first facet associated with the given name
122    **/
123   public Facet getFacet(final String name) {
124     Enumeration<Facet> facets = getFacets(name);
125 
126     if (facets == null) {
127       return null;
128     }
129 
130     return facets.nextElement();
131   }
132 
133   /**
134    * Returns the facets associated with the given name.
135    * 
136    * @param name the name of the Facet to look for
137    * @return the facets associated with the given name
138    **/
139   public Enumeration<Facet> getFacets(final String name) {
140     FacetListEnumerator fle = null;
141     SimpleType datatype = (SimpleType) getBaseType();
142     if (datatype != null) {
143       fle = (FacetListEnumerator) datatype.getFacets(name);
144     }
145     fle = new FacetListEnumerator(_facets, fle);
146     fle.setMask(name);
147     return fle;
148   } // -- getFacets
149 
150   /**
151    * Returns an Enumeration of all the Facets (including inherited) facets for this type.
152    * 
153    * @return an Enumeration of all the Facets for this type
154    **/
155   public Enumeration<Facet> getFacets() {
156     FacetListEnumerator fle = null;
157     SimpleType datatype = (SimpleType) getBaseType();
158     if (datatype != null) {
159       fle = (FacetListEnumerator) datatype.getFacets();
160     }
161     fle = new FacetListEnumerator(_facets, fle);
162     return fle;
163   }
164 
165   /**
166    * Returns the value of the 'final' property, indicating which types of derivation are not
167    * allowed, or null if the final property has not been set.
168    * 
169    * @return the value of the final property or null if no value has been set
170    **/
171   public String getFinal() {
172     return _final;
173   }
174 
175   /**
176    * Returns the facets of this type (without the parent's facets).
177    * 
178    * @return the local facets of this type.
179    */
180   public Enumeration<Facet> getLocalFacets() {
181     if (_facets == null) {
182       return null;
183     }
184     return _facets.enumerate();
185   }
186 
187   /**
188    * Returns an enumeration of the effective facets for this type. A set of effective facets
189    * contains all local facets and only those inherited facets that are not overridden by the local
190    * facets.
191    * 
192    * @return an enumeration of the effective facets for this type.
193    * 
194    * @see #getLocalFacets()
195    * @see #getFacets()
196    */
197   public Enumeration<Facet> getEffectiveFacets() {
198     final Enumeration<Facet> localFacets = getLocalFacets();
199     final SimpleType baseType = (SimpleType) getBaseType();
200     if (baseType == null) {
201       // There's no base type ==> return local facets
202       return localFacets;
203     }
204     final Enumeration<Facet> effectiveBaseFacets = baseType.getEffectiveFacets();
205     if (localFacets == null) {
206       // There's a base type, but no local facets ==> return
207       // effective facets of the base type
208       return effectiveBaseFacets;
209     }
210     // There are both local and inherited facets ==> merge them
211     final FacetList filteredBaseFacets = new FacetList();
212     OUTER: while (effectiveBaseFacets.hasMoreElements()) {
213       final Facet baseFacet = effectiveBaseFacets.nextElement();
214       // Check whether one of the local facets
215       // overrides the inherited facet
216       for (int i = 0; i < _facets.size(); i++) {
217         final Facet localFacet = _facets.get(i);
218         if (localFacet.overridesBase(baseFacet)) {
219           continue OUTER;
220         }
221       }
222       // Base facet is not overridden ==> keep it in the list
223       filteredBaseFacets.add(baseFacet);
224     }
225     return new FacetListEnumerator(_facets, (FacetListEnumerator) filteredBaseFacets.enumerate());
226   }
227 
228   /**
229    * Returns the built in type this type is derived from.
230    */
231   public SimpleType getBuiltInBaseType() {
232     SimpleType base = this;
233     while ((base != null) && (!SimpleTypesFactory.isBuiltInType(base.getTypeCode()))) {
234       base = (SimpleType) base.getBaseType();
235     }
236     return base;
237   }
238 
239   /**
240    * Returns the parent Structure that contains this SimpleType. This can be either a Schema,
241    * AttributeDecl or ElementDecl.
242    * 
243    * @return the parent of this SimpleType
244    **/
245   public Structure getParent() {
246     return _parent;
247   } // -- getParent
248 
249   /**
250    * Returns the Id used to Refer to this Object.
251    * 
252    * @return the Id used to Refer to this Object
253    * @see org.exolab.castor.xml.schema.Referable
254    **/
255   public String getReferenceId() {
256     return "datatype:" + getName();
257   } // -- getReferenceId
258 
259   /**
260    * Returns true if this {@link SimpleType} has a specified {@link Facet} with the given name.
261    * 
262    * @param name the name of the {@link Facet} to look for
263    * @return true if this {@link SimpleType} has a specified {@link Facet} with the given name
264    **/
265   public boolean hasFacet(final String name) {
266     if (name == null) {
267       return false;
268     }
269     for (int i = 0; i < _facets.size(); i++) {
270       Facet facet = _facets.get(i);
271       if (name.equals(facet.getName())) {
272         return true;
273       }
274     }
275     return false;
276   }
277 
278   /**
279    * Returns true if this SimpleType is a built in type.
280    * 
281    * @return true if this SimpleType is a built in type
282    **/
283   public boolean isBuiltInType() {
284     return SimpleTypesFactory.isBuiltInType(_typeCode);
285   }
286 
287   /**
288    * Indicates whether this {@link SimpleType} is a numeric type.
289    * 
290    * @return True if this SimpleType is a numeric type
291    **/
292   public boolean isNumericType() {
293     if (!isBuiltInType()) {
294       return ((SimpleType) getBaseType()).isNumericType();
295     }
296     return false;
297   }
298 
299   /**
300    * Indicates whether this {@link SimpleType} is a date/time type.
301    * 
302    * @return True if this SimpleType is a date/time type
303    **/
304   public boolean isDateTimeType() {
305     return SimpleTypesFactory.isDateTimeType(_typeCode);
306   }
307 
308   /**
309    * Returns true if this simpleType is a redefinition.
310    * 
311    * @return true if this simpleType is a redefinition.
312    */
313   public boolean isRedefined() {
314     return _redefinition;
315   }
316 
317   /**
318    * Sets this Group has redefined.
319    */
320   public void setRedefined() {
321     _redefinition = true;
322   }
323 
324   /**
325    * Gets the code for this simple type. (as defined in SimpleTypesFactory)
326    * 
327    * @return the type code for this simple type
328    **/
329   public int getTypeCode() {
330     return _typeCode;
331   }
332 
333   /**
334    * Package private setter of the code for this simple type.
335    **/
336   void setTypeCode(final int code) {
337     _typeCode = code;
338   }
339 
340   // ///////////////////////////////////////////////////////
341   // Helpers to get the min/max/length facets
342   // (so that they are shared between listType
343   // and binary, uriref, string
344   //
345 
346   /**
347    * Returns the value of the length facet result can be null
348    **/
349   public Long getLength() {
350     Facet lengthFacet = getFacet(Facet.LENGTH);
351     if (lengthFacet == null)
352       return null;
353 
354     try {
355       return Long.valueOf(lengthFacet.toLong());
356     } catch (Exception e) {
357       return null;
358     }
359   }
360 
361   /**
362    * Returns the value of the minlength facet result can be null
363    **/
364   public Long getMinLength() {
365     Facet minLengthFacet = getFacet(Facet.MIN_LENGTH);
366     if (minLengthFacet == null)
367       return null;
368 
369     try {
370       return Long.valueOf(minLengthFacet.toLong());
371     } catch (Exception e) {
372       return null;
373     }
374   }
375 
376   /**
377    * Returns the value of the maxlength facet result can be null
378    **/
379   public Long getMaxLength() {
380     Facet maxLengthFacet = getFacet(Facet.MAX_LENGTH);
381     if (maxLengthFacet == null)
382       return null;
383 
384     try {
385       return Long.valueOf(maxLengthFacet.toLong());
386     } catch (Exception e) {
387       return null;
388     }
389   }
390 
391   /**
392    * Removes the given Facet from this SimpleType. Returns true if this SimpleType actually contains
393    * the given facet.
394    * 
395    * <p>
396    * Removes only local facets.
397    * </p>
398    * 
399    * @param facet the Facet to remove
400    * @return true if the specified Facet has been removed
401    */
402   public boolean removeFacet(Facet facet) {
403     if (facet == null)
404       return false;
405     return _facets.remove(facet);
406   }
407 
408   /**
409    * Removes the facet with the given name from this SimpleType. Returns true if this Simpletype has
410    * a facet with the given name and it is successfully removed.
411    * 
412    * <p>
413    * Removes only local facets.
414    * </p>
415    * 
416    * @param name the name of the Facet to remove
417    * @return true if the specified Facet has been removed
418    */
419   public boolean removeFacet(String name) {
420     if (name == null)
421       return false;
422     for (int i = _facets.size() - 1; i > 0; i--) {
423       Facet facet = _facets.get(i);
424       if (name.equals(facet.getName())) {
425         _facets.remove(i);
426         return true;
427       }
428     }
429     return false;
430   }
431 
432   /**
433    * Sets the value of the 'final' property, indicating which types of derivation are not allowed. A
434    * null value will indicate all types of derivation (list, restriction, union) are allowed.
435    * 
436    * @param finalValue the value of the final property.
437    * @exception IllegalArgumentException when the value is not a valid value.
438    **/
439   public void setFinal(String finalValue) {
440     if ((finalValue == null) || finalValue.equals(FINAL_ALL) || finalValue.equals(FINAL_UNION)
441         || finalValue.equals(FINAL_LIST) || finalValue.equals(FINAL_RESTRICTION)) {
442       _final = finalValue;
443     } else {
444       String err = "The value '" + finalValue + "' is not a valid" + "value of the final property.";
445       throw new IllegalArgumentException(err);
446     }
447   }
448 
449   /**
450    * Returns the type of this Schema Structure
451    * 
452    * @return the type of this Schema Structure
453    **/
454   public short getStructureType() {
455     return Structure.SIMPLE_TYPE;
456   }
457 
458   /**
459    * Checks the validity of this SimpleType definition.
460    * 
461    * @throws ValidationException when this SimpleType definition is invalid.
462    **/
463   public void validate() throws ValidationException {
464     final Enumeration<Facet> localFacets = getLocalFacets();
465     final SimpleType datatype = (SimpleType) getBaseType();
466     if (localFacets != null) {
467       while (localFacets.hasMoreElements()) {
468         final Facet facet = localFacets.nextElement();
469         Enumeration<Facet> baseFacets = null;
470         if (datatype != null) {
471           baseFacets = datatype.getFacets();
472         }
473         try {
474           facet.checkConstraints(getLocalFacets(), baseFacets);
475         } catch (SchemaException e) {
476           throw new ValidationException("Facet validation failed for type '" + getName() + "'", e);
477         }
478       }
479     }
480 
481     // -- TODO: NOT YET FULLY IMPLEMENTED
482 
483   }
484 
485   /**
486    * A helper method for classes which extend SimpleType. This method allows creating a reference to
487    * a SimpleType.
488    * 
489    * @return the reference to the SimpleType.
490    **/
491   protected SimpleType createReference(String name) {
492     return new SimpleTypeReference(getSchema(), name);
493   }
494 
495   /**
496    * A helper method for classes which extend SimpleType. This method allows resolving a SimpleType
497    * reference to a SimpleType.
498    * 
499    * @return the resolved SimpleType.
500    * @see #createReference
501    **/
502   protected static SimpleType resolveReference(SimpleType simpleType) {
503     return (SimpleType) simpleType.getType();
504   }
505 
506   /**
507    * Sets the parent for this SimpleType
508    * 
509    * @param parent the Structure that contains this SimpleType. Currently this should only be
510    *        Schema, ElementDecl or AttributeDecl.
511    **/
512   protected void setParent(Structure parent) {
513     this._parent = parent;
514   }
515 
516   /**
517    * Copy this type's facets to the target type.
518    * 
519    * @param target the SimpleType to copy facets to
520    */
521   protected void copyFacets(SimpleType target) {
522     target._facets.add(_facets);
523   }
524 
525   /**
526    * Returns the number of facets named 'name' within the list of facets of this simple type.
527    * 
528    * @param name Name (type) of the facet.
529    * @return number of facets named 'name'
530    */
531   public int getNumberOfFacets(final String name) {
532     int counter = 0;
533     for (Enumeration<Facet> enumerator = getFacets(); enumerator.hasMoreElements();) {
534       Facet facet = enumerator.nextElement();
535       if (facet.getName().equals(name)) {
536         counter++;
537       }
538     }
539     return counter;
540   }
541 
542 }