package com.thaiopensource.datatype.xsd; import com.thaiopensource.datatype.Datatype2; import com.thaiopensource.util.Localizer; import org.relaxng.datatype.DatatypeException; import org.relaxng.datatype.DatatypeStreamingValidator; import org.relaxng.datatype.ValidationContext; import org.relaxng.datatype.helpers.StreamingValidatorImpl; abstract class DatatypeBase implements Datatype2 { abstract boolean lexicallyAllows(String str); private final int whiteSpace; static final int WHITE_SPACE_PRESERVE = 0; static final int WHITE_SPACE_REPLACE = 1; static final int WHITE_SPACE_COLLAPSE = 2; DatatypeBase() { whiteSpace = WHITE_SPACE_COLLAPSE; } DatatypeBase(int whiteSpace) { this.whiteSpace = whiteSpace; } int getWhiteSpace() { return whiteSpace; } public boolean isValid(String str, ValidationContext vc) { str = normalizeWhiteSpace(str); return lexicallyAllows(str) && allowsValue(str, vc); } public void checkValid(String str, ValidationContext vc) throws DatatypeException { str = normalizeWhiteSpace(str); checkLexicallyAllows(str); getValue(str, vc); } public Object createValue(String str, ValidationContext vc) { str = normalizeWhiteSpace(str); if (!lexicallyAllows(str)) return null; try { return getValue(str, vc); } catch (DatatypeException e) { return null; } } final String normalizeWhiteSpace(String str) { switch (whiteSpace) { case WHITE_SPACE_COLLAPSE: return collapseWhiteSpace(str); case WHITE_SPACE_REPLACE: return replaceWhiteSpace(str); } return str; } void checkLexicallyAllows(String str) throws DatatypeException { if (!lexicallyAllows(str)) throw createLexicallyInvalidException(); } String getDescriptionForRestriction() { return getLexicalSpaceDescription(getLexicalSpaceKey()); } final String getLexicalSpaceDescription(String key) { return localizer().message("lexical_space_" + key); } abstract String getLexicalSpaceKey(); DatatypeException createLexicallyInvalidException() { return new DatatypeException(localizer().message("lexical_violation", getLexicalSpaceDescription(getLexicalSpaceKey()))); } // Requires lexicallyAllows to be true boolean allowsValue(String str, ValidationContext vc) { try { getValue(str, vc); return true; } catch (DatatypeException e) { return false; } } /* Requires lexicallyAllows to be true. Throws DatatypeException if value does not satisfy constraints on value space. */ abstract Object getValue(String str, ValidationContext vc) throws DatatypeException; OrderRelation getOrderRelation() { return null; } /* For datatypes that have a length. */ Measure getMeasure() { return null; } static private String collapseWhiteSpace(String s) { int i = collapseStart(s); if (i < 0) return s; StringBuffer buf = new StringBuffer(s.substring(0, i)); boolean collapsing = (i == 0 || s.charAt(i - 1) == ' '); for (int len = s.length(); i < len; i++) { char c = s.charAt(i); switch (c) { case '\r': case '\n': case '\t': case ' ': if (!collapsing) { buf.append(' '); collapsing = true; } break; default: collapsing = false; buf.append(c); break; } } if (buf.length() > 0 && buf.charAt(buf.length() - 1) == ' ') buf.setLength(buf.length() - 1); return buf.toString(); } static private int collapseStart(String s) { for (int i = 0, len = s.length(); i < len; i++) { switch (s.charAt(i)) { case ' ': if (i == 0 || s.charAt(i - 1) == ' ' || i == len - 1) return i; break; case '\r': case '\n': case '\t': return i; } } return -1; } static private String replaceWhiteSpace(String s) { int len = s.length(); for (int i = 0; i < len; i++) switch (s.charAt(i)) { case '\r': case '\n': case '\t': { char[] buf = s.toCharArray(); buf[i] = ' '; for (++i; i < len; i++) switch (buf[i]) { case '\r': case '\n': case '\t': buf[i] = ' '; } return new String(buf); } } return s; } DatatypeBase getPrimitive() { return this; } public boolean isContextDependent() { return false; } public boolean alwaysValid() { return false; } public int getIdType() { return ID_TYPE_NULL; } public int valueHashCode(Object value) { return value.hashCode(); } public boolean sameValue(Object value1, Object value2) { return value1.equals(value2); } public DatatypeStreamingValidator createStreamingValidator(ValidationContext vc) { return new StreamingValidatorImpl(this, vc); } protected static Localizer localizer() { return DatatypeBuilderImpl.localizer; } }