1 22 23 package org.xquark.schema.datatypes; 24 25 import java.util.*; 26 27 import org.apache.xerces.impl.xpath.regex.RegularExpression; 28 import org.xquark.schema.Facet; 29 import org.xquark.schema.SchemaConstants; 30 import org.xquark.schema.SchemaException; 31 import org.xquark.schema.validation.ValidationContextProvider; 32 33 public abstract class PrimitiveType implements Cloneable , SchemaConstants { 34 private static final String RCSRevision = "$Revision: 1.3 $"; 35 private static final String RCSName = "$Name: $"; 36 public static final int VOID = 0; 37 public static final int STRING = 1; 38 public static final int BOOLEAN = 2; 39 public static final int DECIMAL = 3; 40 public static final int DOUBLE = 4; 41 public static final int FLOAT = 5; 42 public static final int DURATION = 6; 43 public static final int DATE_TIME = 7; 44 public static final int TIME = 8; 45 public static final int DATE = 9; 46 public static final int GYEAR_MONTH = 10; 47 public static final int GYEAR = 11; 48 public static final int GMONTH_DAY = 12; 49 public static final int GDAY = 13; 50 public static final int GMONTH = 14; 51 public static final int HEX_BINARY = 15; 52 public static final int BASE64_BINARY = 16; 53 public static final int ANY_URI = 17; 54 public static final int QNAME = 18; 55 public static final int NOTATION = 19; 56 57 public static final int ID = 20; 58 public static final int IDREF = 21; 59 60 public static final int LIST = 30; 61 public static final int UNION = 31; 62 public static final int ANYSIMPLETYPE = 32; 63 64 public static final int PRESERVE = 0; 66 public static final int REPLACE = 1; 67 public static final int COLLAPSE = 2; 68 69 public static final int LENGTH_FACET = 0; 71 public static final int MIN_LENGTH_FACET = 1; 72 public static final int MAX_LENGTH_FACET = 2; 73 public static final int PATTERN_FACET = 3; 74 public static final int ENUMERATION_FACET = 4; 75 public static final int WHITESPACE_FACET = 5; 76 public static final int MIN_EXCLUSIVE_FACET = 6; 77 public static final int MIN_INCLUSIVE_FACET = 7; 78 public static final int MAX_EXCLUSIVE_FACET = 8; 79 public static final int MAX_INCLUSIVE_FACET = 9; 80 public static final int TOTALDIGITS_FACET = 10; 81 public static final int FRACTIONDIGITS_FACET = 11; 82 83 private String name; 84 private int type; 85 protected int nWhiteSpace = COLLAPSE; protected int fixedBitSet = 1 << WHITESPACE_FACET; 87 88 private ArrayList patterns = null; 90 91 PrimitiveType(String name, int type) { 92 this.name = name; 93 this.type = type; 94 } 95 96 public Object clone() throws CloneNotSupportedException { 97 PrimitiveType result = (PrimitiveType) super.clone(); 98 if (patterns != null) 99 result.patterns = (ArrayList) patterns.clone(); 100 return result; 101 } 102 103 public String getName() { 104 return name; 105 } 106 107 public int getType() { 108 return type; 109 } 110 111 public int getLength() { 112 return -1; 113 } 114 115 public int getMinLength() { 116 return -1; 117 } 118 119 public int getMaxLength() { 120 return -1; 121 } 122 123 public int getTotalDigits() { 124 return -1; 125 } 126 127 public int getFractionDigits() { 128 return -1; 129 } 130 131 public Comparable getMinValue() { 132 return null; 133 } 134 135 public Comparable getMaxValue() { 136 return null; 137 } 138 139 public boolean isMinInclusive() { 140 return false; 141 } 142 143 public boolean isMaxInclusive() { 144 return false; 145 } 146 147 public List getValues() { 148 return null; 149 } 150 151 public String toString() { 152 return "Datatype " + name; 153 } 154 155 public String normalizedValue(String value) { 156 return normalize(value, 0, value.length(), nWhiteSpace); 157 } 158 159 public StringBuffer normalizedValue(StringBuffer value, StringBuffer out) { 160 if (out == null) 161 out = new StringBuffer (); 162 return normalize(value, 0, value.length(), nWhiteSpace, out); 163 } 164 165 168 public StringBuffer normalizedValue(StringBuffer value) { 169 return normalize(value, 0, value.length(), nWhiteSpace, value); 170 } 171 172 public String toXMLString(Object data, ValidationContextProvider context) { 173 if (data == null) return null; 174 else return data.toString(); 175 } 176 177 public Object convert(String string, boolean normalize, ValidationContextProvider context) throws SchemaException { 178 String value = string; 179 if (normalize) value = normalize(string, 0, string.length(), nWhiteSpace); 180 return convert(value, context); 181 } 182 183 public Object convertObject(Object data) throws SchemaException { 184 if (data == null) return null; 185 Object value = null; 186 try { 187 value = toValidType(data); 188 } catch (ClassCastException e) { 189 throw new SchemaException(e); 190 } 191 checkFacets(value); 192 return value; 193 } 194 195 protected abstract Object toValidType(Object data); 196 197 205 public Object convert(StringBuffer string, boolean normalize, ValidationContextProvider context) 206 throws SchemaException { 207 if (normalize) normalize(string, 0, string.length(), nWhiteSpace, string); 208 return convert(string.toString(), context); 209 } 210 211 public Object convert(String string, boolean normalize) throws SchemaException { 212 return convert(string, normalize, null); 213 } 214 215 public Object convert(StringBuffer string, boolean normalize) throws SchemaException { 216 return convert(string, normalize, null); 217 } 218 219 protected void setPattern(String value) throws SchemaException { 220 try { 221 RegularExpression pattern = new RegularExpression(value, "X"); 222 if (patterns == null) 223 patterns = new ArrayList(); 224 patterns.add(pattern); 225 } catch (Exception e) { 226 throw new SchemaException("unknown-error-code.2"); 228 } 229 } 230 231 public void checkPattern(String value) throws SchemaException { 232 if (patterns == null) 233 return; 234 Iterator it = patterns.iterator(); 235 while (it.hasNext()) { 236 RegularExpression pattern = (RegularExpression) it.next(); 237 if (!pattern.matches(value)) 238 invalidFacet("cvc-pattern-valid.1", pattern.getPattern(), value); 239 } 240 } 241 242 public abstract void checkFacets(Object valueSpace) throws SchemaException; 243 abstract protected Object toValueSpace(String value, ValidationContextProvider context) throws SchemaException; 244 245 protected Object convert(String value, ValidationContextProvider context) throws SchemaException { 246 checkPattern(value); 247 Object result = toValueSpace(value, context); 248 checkFacets(result); 249 return result; 250 } 251 252 static public PrimitiveType createType(String name) { 253 if (name.equals("anySimpleType")) 254 return new AnySimpleType(); 255 else if (name.equals("string")) 256 return new StringType(); 257 else if (name.equals("boolean")) 258 return new BooleanType(); 259 else if (name.equals("decimal")) 260 return new DecimalType(); 261 else if (name.equals("float")) 262 return new FloatType(); 263 else if (name.equals("double")) 264 return new DoubleType(); 265 else if (name.equals("duration")) 266 return new DurationType(); 267 else if (name.equals("dateTime")) 268 return new DateTimeType(); 269 else if (name.equals("time")) 270 return new TimeType(); 271 else if (name.equals("date")) 272 return new DateType(); 273 else if (name.equals("gYearMonth")) 274 return new GYearMonthType(); 275 else if (name.equals("gYear")) 276 return new GYearType(); 277 else if (name.equals("gMonthDay")) 278 return new GMonthDayType(); 279 else if (name.equals("gDay")) 280 return new GDayType(); 281 else if (name.equals("gMonth")) 282 return new GMonthType(); 283 else if (name.equals("hexBinary")) 284 return new HexBinaryType(); 285 else if (name.equals("base64Binary")) 286 return new Base64BinaryType(); 287 else if (name.equals("anyURI")) 288 return new AnyURIType(); 289 else if (name.equals("QName")) 290 return new QNameType(); 291 else if (name.equals("NOTATION")) 292 return new NOTATIONType(); 293 294 else 295 return null; 296 } 297 298 static public PrimitiveType createListType(PrimitiveType itemPrimitive) { 299 return new PrimitiveListType(itemPrimitive); 300 } 301 302 static public PrimitiveType createUnionType(ArrayList primitives, String unionName) { 303 return new PrimitiveUnionType(primitives, unionName); 304 } 305 306 public void setFacet(Facet aFacet, ValidationContextProvider vcProvider) throws SchemaException { 307 String facetName = aFacet.getName(); 308 String value = aFacet.getValue(); 309 boolean fixed = aFacet.isFixed(); 310 311 try { 312 if (facetName.equals(LENGTH_TAG)) 313 setLength(value, fixed); 314 else if (facetName.equals(MIN_LENGTH_TAG)) 315 setMinLength(value, fixed); 316 else if (facetName.equals(MAX_LENGTH_TAG)) 317 setMaxLength(value, fixed); 318 else if (facetName.equals(PATTERN_TAG)) 319 setPattern(value); 320 else if (facetName.equals(ENUMERATION_TAG)) 321 setEnumeration(aFacet.getEnumFacets(), vcProvider); 322 else if (facetName.equals(WHITESPACE_TAG)) 323 setWhiteSpace(value, fixed); 324 else if (facetName.equals(MIN_EXCLUSIVE_TAG)) 325 setMinExclusive(value, fixed); 326 else if (facetName.equals(MIN_INCLUSIVE_TAG)) 327 setMinInclusive(value, fixed); 328 else if (facetName.equals(MAX_EXCLUSIVE_TAG)) 329 setMaxExclusive(value, fixed); 330 else if (facetName.equals(MAX_INCLUSIVE_TAG)) 331 setMaxInclusive(value, fixed); 332 else if (facetName.equals(TOTALDIGITS_TAG)) 333 setTotalDigits(value, fixed); 334 else if (facetName.equals(FRACTIONDIGITS_TAG)) 335 setFractionDigits(value, fixed); 336 } catch (SchemaException se) { 337 throw new SchemaException(se.getErrorCode(), aFacet, se); 338 } 339 } 340 341 protected void setLength(String value, boolean fixed) throws SchemaException { 342 throw new SchemaException("cos-applicable-facets"); 344 } 345 346 protected void setMinLength(String value, boolean fixed) throws SchemaException { 347 throw new SchemaException("cos-applicable-facets"); 349 } 350 351 protected void setMaxLength(String value, boolean fixed) throws SchemaException { 352 throw new SchemaException("cos-applicable-facets"); 354 } 355 356 protected void setEnumeration(HashSet value, ValidationContextProvider vcProvider) throws SchemaException { 357 throw new SchemaException("cos-applicable-facets"); 359 } 360 361 protected void setMinExclusive(String value, boolean fixed) throws SchemaException { 362 throw new SchemaException("cos-applicable-facets"); 364 } 365 366 protected void setMinInclusive(String value, boolean fixed) throws SchemaException { 367 throw new SchemaException("cos-applicable-facets"); 369 } 370 371 protected void setMaxExclusive(String value, boolean fixed) throws SchemaException { 372 throw new SchemaException("cos-applicable-facets"); 374 } 375 376 protected void setMaxInclusive(String value, boolean fixed) throws SchemaException { 377 throw new SchemaException("cos-applicable-facets"); 379 } 380 381 protected void setTotalDigits(String value, boolean fixed) throws SchemaException { 382 throw new SchemaException("cos-applicable-facets"); 384 } 385 386 protected void setFractionDigits(String value, boolean fixed) throws SchemaException { 387 throw new SchemaException("cos-applicable-facets"); 389 } 390 391 protected void setWhiteSpace(String value, boolean fixed) throws SchemaException { 392 int ws = -1; 393 if ("preserve".equals(value)) 394 ws = PRESERVE; 395 else if ("replace".equals(value)) 396 ws = REPLACE; 397 else if ("collapse".equals(value)) 398 ws = COLLAPSE; 399 400 if ((isFixed(WHITESPACE_FACET) && ws != nWhiteSpace)) { 402 throw new SchemaException("unknown-error-code.1"); 404 } 405 406 if ((ws == PRESERVE || ws == REPLACE) && nWhiteSpace == COLLAPSE) { 407 throw new SchemaException("whiteSpace-valid-restriction.1"); 409 } 410 411 if (ws == PRESERVE && nWhiteSpace == REPLACE) { 412 throw new SchemaException("whiteSpace-valid-restriction.2"); 414 } 415 416 nWhiteSpace = ws; 417 setFixed(WHITESPACE_FACET, fixed); 418 } 419 420 public int getWhiteSpace() { 421 return nWhiteSpace; 422 } 423 424 protected boolean isFixed(int facet) { 425 int mask = 1 << facet; 426 return (mask & fixedBitSet) != 0; 427 } 428 429 protected void setFixed(int facet, boolean fixed) { 430 if (fixed) { 431 int mask = 1 << facet; 432 fixedBitSet |= mask; 433 } 434 } 435 436 protected void invalidFacet(String errCode, Object facetVal, String value) throws SchemaException { 437 Object invalidFacet = "Constraint: " + facetVal + ", value: " + value; 438 SchemaException se = new SchemaException(errCode, invalidFacet); 439 if ("cvc-pattern-valid".equals(errCode)) 440 throw new SchemaException("cvc-datatype-valid.1.1", this, se); 441 else 442 throw new SchemaException("cvc-datatype-valid.2", this, se); 443 } 444 445 protected void invalidValue(String value) throws SchemaException { 446 throw new SchemaException("cvc-datatype-valid.1.2.1", "value = " + value); 447 } 448 449 public static boolean isXMLWhitespace(char c) { 450 switch (c) { 451 case 0x20 : 452 case 0x9 : 453 case 0xA : 454 case 0xD : 455 return true; 456 default : 457 return false; 458 } 459 } 460 461 private static String normalize(String value, int offset, int length, int whitespace) { 462 StringBuffer result; 463 switch (whitespace) { 464 case PRESERVE : 465 if (offset == 0 && length == value.length()) 466 return value; 467 else 468 return value.substring(offset, length); 469 case REPLACE : 470 result = new StringBuffer (); 471 for (int i = offset; i < offset + length; i++) { 472 if (isXMLWhitespace(value.charAt(i))) 473 result.append((char) 0x20); 474 else 475 result.append(value.charAt(i)); 476 } 477 return result.toString(); 478 case COLLAPSE : 479 result = new StringBuffer (); 480 boolean start = true; 481 int nIndex = 0; 482 for (int i = offset; i < offset + length; i++) { 483 if (isXMLWhitespace(value.charAt(i))) { 484 if (!start) { 486 if (result.charAt(nIndex - 1) != 0x20) { 488 result.append((char) 0x20); 489 nIndex++; 490 } 491 } 492 } else { 493 result.append(value.charAt(i)); 494 nIndex++; 495 start = false; 496 } 497 } 498 if (nIndex > 0 && result.charAt(nIndex - 1) == 0x20) 500 result.setLength(nIndex - 1); 501 return result.toString(); 502 default : 503 throw new IllegalArgumentException ("Illegal value for whitespace handling"); 504 } 505 } 506 507 private static StringBuffer normalize( 508 StringBuffer value, 509 int offset, 510 int length, 511 int whitespace, 512 StringBuffer result) { 513 int nIndex = offset; 514 switch (whitespace) { 515 case PRESERVE : 516 if (result != value) { 517 if (offset == 0 && length == value.length()) { 518 result.append(value); 519 } else { 520 result.append(value.substring(offset, length)); 521 } 522 } 523 return result; 524 case REPLACE : 525 if (result != value) { 526 nIndex = result.length(); 527 result.setLength(nIndex + length); 528 } 529 for (int i = offset; i < offset + length; i++) { 530 if (isXMLWhitespace(value.charAt(i))) 531 result.setCharAt(nIndex, (char) 0x20); 532 else 533 result.setCharAt(nIndex, value.charAt(i)); 534 nIndex++; 535 } 536 return result; 537 case COLLAPSE : 538 if (result != value) { 539 nIndex = result.length(); 540 result.setLength(nIndex + length); 541 } 542 boolean start = true; 543 for (int i = offset; i < offset + length; i++) { 544 if (isXMLWhitespace(value.charAt(i))) { 545 if (!start) { 547 if (result.charAt(nIndex - 1) != 0x20) { 549 result.setCharAt(nIndex, (char) 0x20); 550 nIndex++; 551 } 552 } 553 } else { 554 result.setCharAt(nIndex, value.charAt(i)); 555 nIndex++; 556 start = false; 557 } 558 } 559 if (!start && result.charAt(nIndex - 1) == 0x20) 561 nIndex--; 562 if (result != value) 563 result.setLength(nIndex); 564 else 565 result.delete(nIndex, offset + length); 566 return result; 567 default : 568 throw new IllegalArgumentException ("Illegal value for whitespace handling"); 569 } 570 } 571 572 } 573 | Popular Tags |