1 /* SimpleType.java --
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.xml.validation.datatype;
39 
40 import java.util.Iterator;
41 import java.util.Set;
42 import java.util.regex.Matcher;
43 import javax.xml.namespace.QName;
44 import org.relaxng.datatype.Datatype;
45 import org.relaxng.datatype.DatatypeException;
46 import org.relaxng.datatype.DatatypeStreamingValidator;
47 import org.relaxng.datatype.ValidationContext;
48 
49 /**
50  * An XML Schema simple type.
51  *
52  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
53  */
54 public class SimpleType
55   extends Type
56   implements Datatype
57 {
58 
59   /**
60    * The variety of the <code>anySimpleType</code> datatype.
61    */
62   public static final int ANY = 0;
63 
64   /**
65    * The atomic variety.
66    */
67   public static final int ATOMIC = 1;
68 
69   /**
70    * The list variety.
71    */
72   public static final int LIST = 2;
73 
74   /**
75    * The union variety.
76    */
77   public static final int UNION = 3;
78 
79   public static final int ID_TYPE_NULL = 0;
80   public static final int ID_TYPE_ID = 1;
81   public static final int ID_TYPE_IDREF = 2;
82   public static final int ID_TYPE_IDREFS = 3;
83 
84   /**
85    * The variety of this simple type.
86    */
87   public final int variety;
88 
89   /**
90    * The facets of this simple type.
91    */
92   public Set facets;
93 
94   /**
95    * The fundamental facets of this simple type.
96    */
97   public int fundamentalFacets;
98 
99   /**
100    * If this datatype has been derived by restriction, then the component
101    * from which it was derived.
102    */
103   public final SimpleType baseType;
104 
105   /**
106    * Optional annotation.
107    */
108   public final Annotation annotation;
109 
SimpleType(QName name, int variety, Set facets, int fundamentalFacets, SimpleType baseType, Annotation annotation)110   public SimpleType(QName name, int variety, Set facets,
111                     int fundamentalFacets, SimpleType baseType,
112                     Annotation annotation)
113   {
114     super(name);
115     this.variety = variety;
116     this.facets = facets;
117     this.fundamentalFacets = fundamentalFacets;
118     this.baseType = baseType;
119     this.annotation = annotation;
120   }
121 
122   /**
123    * Indicates whether this type permits the specified value.
124    */
isValid(String value, ValidationContext context)125   public boolean isValid(String value, ValidationContext context)
126   {
127     try
128       {
129         checkValid(value, context);
130         return true;
131       }
132     catch (DatatypeException e)
133       {
134         return false;
135       }
136   }
137 
checkValid(String value, ValidationContext context)138   public void checkValid(String value, ValidationContext context)
139     throws DatatypeException
140   {
141     if (facets != null && !facets.isEmpty())
142       {
143         Object parsedValue = createValue(value, context);
144         for (Iterator i = facets.iterator(); i.hasNext(); )
145           {
146             Facet facet = (Facet) i.next();
147             switch (facet.type)
148               {
149               case Facet.LENGTH:
150                 LengthFacet lf = (LengthFacet) facet;
151                 if (value.length() != lf.value)
152                   throw new DatatypeException("invalid length");
153                 break;
154               case Facet.MIN_LENGTH:
155                 MinLengthFacet nlf = (MinLengthFacet) facet;
156                 if (value.length() < nlf.value)
157                   throw new DatatypeException("invalid minimum length");
158                 break;
159               case Facet.MAX_LENGTH:
160                 MaxLengthFacet xlf = (MaxLengthFacet) facet;
161                 if (value.length() > xlf.value)
162                   throw new DatatypeException("invalid maximum length");
163                 break;
164               case Facet.PATTERN:
165                 PatternFacet pf = (PatternFacet) facet;
166                 Matcher matcher = pf.value.matcher(value);
167                 if (!matcher.find())
168                   throw new DatatypeException("invalid match for pattern");
169                 break;
170               case Facet.ENUMERATION:
171                 // TODO
172                 break;
173               case Facet.WHITESPACE:
174                 // TODO
175                 break;
176               case Facet.MAX_INCLUSIVE:
177                 MaxInclusiveFacet xif = (MaxInclusiveFacet) facet;
178                 if (!xif.matches(parsedValue))
179                   throw new DatatypeException("beyond upper bound");
180                 break;
181               case Facet.MAX_EXCLUSIVE:
182                 MaxExclusiveFacet xef = (MaxExclusiveFacet) facet;
183                 if (!xef.matches(parsedValue))
184                   throw new DatatypeException("beyond upper bound");
185                 break;
186               case Facet.MIN_EXCLUSIVE:
187                 MinExclusiveFacet nef = (MinExclusiveFacet) facet;
188                 if (!nef.matches(parsedValue))
189                   throw new DatatypeException("beyond lower bound");
190                 break;
191               case Facet.MIN_INCLUSIVE:
192                 MinInclusiveFacet nif = (MinInclusiveFacet) facet;
193                 if (!nif.matches(parsedValue))
194                   throw new DatatypeException("beyond lower bound");
195                 break;
196               case Facet.TOTAL_DIGITS:
197                 TotalDigitsFacet tdf = (TotalDigitsFacet) facet;
198                 if (countDigits(value, true) > tdf.value)
199                   throw new DatatypeException("too many digits");
200                 break;
201               case Facet.FRACTION_DIGITS:
202                 FractionDigitsFacet fdf = (FractionDigitsFacet) facet;
203                 if (countDigits(value, false) > fdf.value)
204                   throw new DatatypeException("too many fraction digits");
205                 break;
206               }
207           }
208       }
209   }
210 
countDigits(String value, boolean any)211   private static int countDigits(String value, boolean any)
212   {
213     int count = 0;
214     int len = value.length();
215     boolean seenDecimal = false;
216     for (int i = 0; i < len; i++)
217       {
218         char c = value.charAt(i);
219         if (c == 0x2e)
220           seenDecimal = true;
221         else if (c >= 0x30 && c <= 0x39 && (any || seenDecimal))
222           count++;
223       }
224     return count;
225   }
226 
227   // TODO createStreamingValidator
createStreamingValidator(ValidationContext context)228   public DatatypeStreamingValidator createStreamingValidator(ValidationContext context)
229   {
230     throw new UnsupportedOperationException();
231   }
232 
createValue(String literal, ValidationContext context)233   public Object createValue(String literal, ValidationContext context) {
234     return literal;
235   }
236 
sameValue(Object value1, Object value2)237   public boolean sameValue(Object value1, Object value2) {
238     return value1.equals(value2);
239   }
240 
valueHashCode(Object value)241   public int valueHashCode(Object value) {
242     return value.hashCode();
243   }
244 
getIdType()245   public int getIdType()
246   {
247     return ID_TYPE_NULL;
248   }
249 
isContextDependent()250   public boolean isContextDependent()
251   {
252     return false;
253   }
254 
255 }
256