/* * eXist Open Source Native XML Database * Copyright (C) 2001-2009 The eXist Project * http://exist-db.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ package org.exist.xquery.value; import java.util.HashSet; import org.apache.log4j.Logger; import org.exist.Namespaces; import org.exist.dom.QName; import org.exist.util.hashtable.Int2ObjectHashMap; import org.exist.util.hashtable.Object2IntHashMap; import org.exist.xquery.XPathException; /** * Defines all built-in types and their relations. * * @author Wolfgang Meier (wolfgang@exist-db.org) */ public class Type { private final static Logger LOG = Logger.getLogger(Type.class); public final static String[] NODETYPES = { "node", "element", "attribute", "text", "processing-instruction", "comment", "document", "namespace", "cdata-section" }; public static final int NODE = -1; public final static int ELEMENT = 1; public final static int ATTRIBUTE = 2; public final static int TEXT = 3; public final static int PROCESSING_INSTRUCTION = 4; public final static int COMMENT = 5; public final static int DOCUMENT = 6; public final static int NAMESPACE = 500; public final static int CDATA_SECTION = 501; public final static int EMPTY = 10; public final static int ITEM = 11; public final static int ANY_TYPE = 12; public final static int ANY_SIMPLE_TYPE = 13; public final static int UNTYPED = 14; public final static int ATOMIC = 20; public final static int UNTYPED_ATOMIC = 21; public final static int STRING = 22; public final static int BOOLEAN = 23; public final static int QNAME = 24; public final static int ANY_URI = 25; public final static int BASE64_BINARY = 26; public final static int HEX_BINARY = 27; public final static int NOTATION = 28; public final static int NUMBER = 30; public final static int INTEGER = 31; public final static int DECIMAL = 32; public final static int FLOAT = 33; public final static int DOUBLE = 34; public final static int NON_POSITIVE_INTEGER = 35; public final static int NEGATIVE_INTEGER = 36; public final static int LONG = 37; public final static int INT = 38; public final static int SHORT = 39; public final static int BYTE = 40; public final static int NON_NEGATIVE_INTEGER = 41; public final static int UNSIGNED_LONG = 42; public final static int UNSIGNED_INT = 43; public final static int UNSIGNED_SHORT = 44; public final static int UNSIGNED_BYTE = 45; public final static int POSITIVE_INTEGER = 46; public final static int DATE_TIME = 50; public final static int DATE = 51; public final static int TIME = 52; public final static int DURATION = 53; public final static int YEAR_MONTH_DURATION = 54; public final static int DAY_TIME_DURATION = 55; public final static int GYEAR = 56; public final static int GMONTH = 57; public final static int GDAY = 58; public final static int GYEARMONTH = 59; public final static int GMONTHDAY = 71; public final static int TOKEN = 60; public final static int NORMALIZED_STRING = 61; public final static int LANGUAGE = 62; public final static int NMTOKEN = 63; public final static int NAME = 64; public final static int NCNAME = 65; public final static int ID = 66; public final static int IDREF = 67; public final static int ENTITY = 68; public final static int JAVA_OBJECT = 100; public final static int FUNCTION_REFERENCE = 101; /** * Special type constant to indicate that an item has been * fulltext indexed. */ public final static int IDX_FULLTEXT = 200; private final static int[] superTypes = new int[512]; static { defineSubType(ANY_TYPE, ANY_SIMPLE_TYPE); defineSubType(ANY_TYPE, UNTYPED); defineSubType(ANY_SIMPLE_TYPE, ATOMIC); defineSubType(NODE, ELEMENT); defineSubType(NODE, ATTRIBUTE); defineSubType(NODE, TEXT); defineSubType(NODE, PROCESSING_INSTRUCTION); defineSubType(NODE, COMMENT); defineSubType(NODE, DOCUMENT); defineSubType(NODE, NAMESPACE); defineSubType(NODE, CDATA_SECTION); defineSubType(ITEM, ATOMIC); defineSubType(ATOMIC, STRING); defineSubType(ATOMIC, BOOLEAN); defineSubType(ATOMIC, QNAME); defineSubType(ATOMIC, ANY_URI); defineSubType(ATOMIC, NUMBER); defineSubType(ATOMIC, UNTYPED_ATOMIC); defineSubType(ATOMIC, JAVA_OBJECT); defineSubType(ATOMIC, FUNCTION_REFERENCE); defineSubType(ATOMIC, DATE_TIME); defineSubType(ATOMIC, DATE); defineSubType(ATOMIC, TIME); defineSubType(ATOMIC, DURATION); defineSubType(ATOMIC, GYEAR); defineSubType(ATOMIC, GMONTH); defineSubType(ATOMIC, GDAY); defineSubType(ATOMIC, GYEARMONTH); defineSubType(ATOMIC, GMONTHDAY); defineSubType(ATOMIC, BASE64_BINARY); defineSubType(ATOMIC, HEX_BINARY); defineSubType(ATOMIC, NOTATION); defineSubType(DURATION, YEAR_MONTH_DURATION); defineSubType(DURATION, DAY_TIME_DURATION); defineSubType(NUMBER, DECIMAL); defineSubType(NUMBER, FLOAT); defineSubType(NUMBER, DOUBLE); defineSubType(DECIMAL, INTEGER); defineSubType(INTEGER, NON_POSITIVE_INTEGER); defineSubType(NON_POSITIVE_INTEGER, NEGATIVE_INTEGER); defineSubType(INTEGER, LONG); defineSubType(LONG, INT); defineSubType(INT, SHORT); defineSubType(SHORT, BYTE); defineSubType(INTEGER, NON_NEGATIVE_INTEGER); defineSubType(NON_NEGATIVE_INTEGER, POSITIVE_INTEGER); defineSubType(NON_NEGATIVE_INTEGER, UNSIGNED_LONG); defineSubType(UNSIGNED_LONG, UNSIGNED_INT); defineSubType(UNSIGNED_INT, UNSIGNED_SHORT); defineSubType(UNSIGNED_SHORT, UNSIGNED_BYTE); defineSubType(STRING, NORMALIZED_STRING); defineSubType(NORMALIZED_STRING, TOKEN); defineSubType(TOKEN, LANGUAGE); defineSubType(TOKEN, NMTOKEN); defineSubType(TOKEN, NAME); defineSubType(NAME, NCNAME); defineSubType(NCNAME, ID); defineSubType(NCNAME, IDREF); defineSubType(NCNAME, ENTITY); } private final static Int2ObjectHashMap typeNames = new Int2ObjectHashMap(100); private final static Object2IntHashMap typeCodes = new Object2IntHashMap(100); static { //TODO : use NODETYPES above ? //TODO use parentheses after the nodes name ? defineBuiltInType(NODE, "node()"); defineBuiltInType(ITEM, "item()"); defineBuiltInType(EMPTY, "empty()"); defineBuiltInType(ELEMENT, "element()"); defineBuiltInType(DOCUMENT, "document-node()"); defineBuiltInType(ATTRIBUTE, "attribute()"); defineBuiltInType(TEXT, "text()"); defineBuiltInType(PROCESSING_INSTRUCTION, "processing-instruction()"); defineBuiltInType(COMMENT, "comment()"); defineBuiltInType(NAMESPACE, "namespace()"); defineBuiltInType(CDATA_SECTION, "cdata-section()"); defineBuiltInType(JAVA_OBJECT, "object"); defineBuiltInType(FUNCTION_REFERENCE, "function"); defineBuiltInType(NUMBER, "numeric"); defineBuiltInType(ANY_TYPE, "xs:anyType"); defineBuiltInType(ANY_SIMPLE_TYPE, "xs:anySimpleType"); defineBuiltInType(UNTYPED, "xs:untyped"); //Duplicate definition : new one first defineBuiltInType(ATOMIC, "xs:anyAtomicType"); defineBuiltInType(ATOMIC, "xdt:anyAtomicType"); //Duplicate definition : new one first defineBuiltInType(UNTYPED_ATOMIC, "xs:untypedAtomic"); defineBuiltInType(UNTYPED_ATOMIC, "xdt:untypedAtomic"); defineBuiltInType(BOOLEAN, "xs:boolean"); defineBuiltInType(DECIMAL, "xs:decimal"); defineBuiltInType(FLOAT, "xs:float"); defineBuiltInType(DOUBLE, "xs:double"); defineBuiltInType(INTEGER, "xs:integer"); defineBuiltInType(NON_POSITIVE_INTEGER, "xs:nonPositiveInteger"); defineBuiltInType(NEGATIVE_INTEGER, "xs:negativeInteger"); defineBuiltInType(LONG, "xs:long"); defineBuiltInType(INT, "xs:int"); defineBuiltInType(SHORT, "xs:short"); defineBuiltInType(BYTE, "xs:byte"); defineBuiltInType(NON_NEGATIVE_INTEGER, "xs:nonNegativeInteger"); defineBuiltInType(UNSIGNED_LONG, "xs:unsignedLong"); defineBuiltInType(UNSIGNED_INT, "xs:unsignedInt"); defineBuiltInType(UNSIGNED_SHORT, "xs:unsignedShort"); defineBuiltInType(UNSIGNED_BYTE, "xs:unsignedByte"); defineBuiltInType(POSITIVE_INTEGER, "xs:positiveInteger"); defineBuiltInType(STRING, "xs:string"); defineBuiltInType(QNAME, "xs:QName"); defineBuiltInType(ANY_URI, "xs:anyURI"); defineBuiltInType(BASE64_BINARY, "xs:base64Binary"); defineBuiltInType(HEX_BINARY, "xs:hexBinary"); defineBuiltInType(NOTATION, "xs:NOTATION"); defineBuiltInType(DATE_TIME, "xs:dateTime"); defineBuiltInType(DATE, "xs:date"); defineBuiltInType(TIME, "xs:time"); defineBuiltInType(DURATION, "xs:duration"); defineBuiltInType(GYEAR, "xs:gYear"); defineBuiltInType(GMONTH, "xs:gMonth"); defineBuiltInType(GDAY, "xs:gDay"); defineBuiltInType(GYEARMONTH, "xs:gYearMonth"); defineBuiltInType(GMONTHDAY, "xs:gMonthDay"); //Duplicate definition : new one first defineBuiltInType(YEAR_MONTH_DURATION, "xs:yearMonthDuration"); defineBuiltInType(YEAR_MONTH_DURATION, "xdt:yearMonthDuration"); //Duplicate definition : new one first defineBuiltInType(DAY_TIME_DURATION, "xs:dayTimeDuration"); defineBuiltInType(DAY_TIME_DURATION, "xdt:dayTimeDuration"); defineBuiltInType(NORMALIZED_STRING, "xs:normalizedString"); defineBuiltInType(TOKEN, "xs:token"); defineBuiltInType(LANGUAGE, "xs:language"); defineBuiltInType(NMTOKEN, "xs:NMTOKEN"); defineBuiltInType(NAME, "xs:Name"); defineBuiltInType(NCNAME, "xs:NCName"); defineBuiltInType(ID, "xs:ID"); defineBuiltInType(IDREF, "xs:IDREF"); defineBuiltInType(ENTITY, "xs:ENTITY"); } public final static void defineBuiltInType(int type, String name) { typeNames.put(type, name); typeCodes.put(name, type); } /** * Get the internal name for the built-in type. * * @param type */ public final static String getTypeName(int type) { return (String) typeNames.get(type); } /** * Get the type code for a type identified by its internal name. * * @param name * @throws XPathException */ public final static int getType(String name) throws XPathException { //if (name.equals("node")) // return NODE; int code = typeCodes.get(name); if (code == Object2IntHashMap.UNKNOWN_KEY) throw new XPathException("Type: " + name + " is not defined"); return code; } /** * Get the type code for a type identified by its QName. * * @param qname * @throws XPathException */ public final static int getType(QName qname) throws XPathException { String uri = qname.getNamespaceURI(); if (uri.equals(Namespaces.SCHEMA_NS)) return getType("xs:" + qname.getLocalName()); else if (uri.equals(Namespaces.XPATH_DATATYPES_NS)) return getType("xdt:" + qname.getLocalName()); else return getType(qname.getLocalName()); } /** * Define supertype/subtype relation. * * @param supertype * @param subtype */ public final static void defineSubType(int supertype, int subtype) { superTypes[subtype] = supertype; } /** * Check if the given type code is a subtype of the specified supertype. * * @param subtype * @param supertype */ public final static boolean subTypeOf(int subtype, int supertype) { if (subtype == supertype) return true; //Note that it will return true even if subtype == EMPTY if (supertype == ITEM || supertype == ANY_TYPE) //maybe return subtype != EMPTY ? return true; //Note that EMPTY is *not* a sub-type of anything else than itself //EmptySequence has to take care of this when it checks its type if (subtype == ITEM || subtype == EMPTY || subtype == ANY_TYPE || subtype == NODE) return false; subtype = superTypes[subtype]; if (subtype == 0) throw new IllegalArgumentException( "type " + subtype + " is not a valid type"); return subTypeOf(subtype, supertype); } /** * Get the type code of the supertype of the specified subtype. * * @param subtype */ public final static int getSuperType(int subtype) { if (subtype == ITEM || subtype == NODE) return ITEM; int supertype = superTypes[subtype]; if(supertype == 0) { LOG.warn("no supertype for " + getTypeName(subtype), new Throwable()); return ITEM; } return supertype; } /** * Find a common supertype for two given type codes. * * Type.ITEM is returned if no other common supertype * is found. * * @param type1 * @param type2 */ public static int getCommonSuperType(int type1, int type2) { //Super shortcut if(type1 == type2) return type1; //TODO : optimize by swapping the arguments based on their numeric values ? //Processing lower value first *should* reduce the size of the Set //Collect type1's super-types HashSet t1 = new HashSet(); //Don't introduce a shortcut (starting at getSuperType(type1) here //type2 might be a super-type of type1 int t; for(t = type1; t != ITEM; t = getSuperType(t)) { //Shortcut if (t == type2) return t; t1.add(new Integer(t)); } //Starting from type2's super type : the shortcut should have done its job for(t = getSuperType(type2); t != ITEM ; t = getSuperType(t)) { if (t1.contains(new Integer(t))) return t; } return ITEM; } }