001: package net.sf.saxon.type;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.StaticContext;
005: import net.sf.saxon.expr.XPathContext;
006: import net.sf.saxon.instruct.ValueOf;
007: import net.sf.saxon.om.*;
008: import net.sf.saxon.style.StandardNames;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.value.AtomicValue;
011: import net.sf.saxon.value.ObjectValue;
012: import net.sf.saxon.value.Value;
013: import net.sf.saxon.value.Whitespace;
014: import java.io.Serializable;
015:
016: /**
017: * This class represents the type of an external Java object returned by
018: * an extension function, or supplied as an external variable/parameter.
019: */
020:
021: public class ExternalObjectType implements AtomicType, Serializable {
022:
023: private Class javaClass;
024: int fingerprint;
025: int baseFingerprint = -1;
026:
027: public ExternalObjectType(Class javaClass) {
028: this .javaClass = javaClass;
029: this .fingerprint = StandardNames.SAXON_JAVA_LANG_OBJECT;
030: }
031:
032: /**
033: * Get the most specific possible atomic type that all items in this SimpleType belong to
034: * @return the lowest common supertype of all member types
035: */
036:
037: public AtomicType getCommonAtomicType() {
038: return this ;
039: }
040:
041: /**
042: * Get the validation status - always valid
043: */
044: public final int getValidationStatus() {
045: return VALIDATED;
046: }
047:
048: /**
049: * Returns the value of the 'block' attribute for this type, as a bit-signnificant
050: * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION}
051: *
052: * @return the value of the 'block' attribute for this type
053: */
054:
055: public final int getBlock() {
056: return 0;
057: }
058:
059: /**
060: * Gets the integer code of the derivation method used to derive this type from its
061: * parent. Returns zero for primitive types.
062: *
063: * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION}
064: */
065:
066: public final int getDerivationMethod() {
067: return SchemaType.DERIVATION_RESTRICTION;
068: }
069:
070: /**
071: * Determines whether derivation (of a particular kind)
072: * from this type is allowed, based on the "final" property
073: *
074: * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST}
075: * @return true if this kind of derivation is allowed
076: */
077:
078: public final boolean allowsDerivation(int derivation) {
079: return true;
080: }
081:
082: /**
083: * Get the namecode of the name of this type. This includes the prefix from the original
084: * type declaration: in the case of built-in types, there may be a conventional prefix
085: * or there may be no prefix.
086: */
087:
088: public int getNameCode() {
089: return fingerprint;
090: }
091:
092: /**
093: * Test whether this SchemaType is a complex type
094: *
095: * @return true if this SchemaType is a complex type
096: */
097:
098: public final boolean isComplexType() {
099: return false;
100: }
101:
102: /**
103: * Returns the base type that this type inherits from. This method can be used to get the
104: * base type of a type that is known to be valid.
105: * If this type is a Simpletype that is a built in primitive type then null is returned.
106: *
107: * @return the base type.
108: * @throws IllegalStateException if this type is not valid.
109: */
110:
111: public final SchemaType getBaseType() {
112: return BuiltInSchemaFactory
113: .getSchemaType(StandardNames.XDT_ANY_ATOMIC_TYPE);
114: }
115:
116: /**
117: * Get the primitive item type corresponding to this item type. For item(),
118: * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
119: * it is the value representing the node kind, for example Type.ELEMENT.
120: * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER.
121: * For other atomic types it is the primitive type as defined in XML Schema,
122: * except that INTEGER is considered to be a primitive type.
123: */
124:
125: public ItemType getPrimitiveItemType() {
126: return this ;
127: }
128:
129: /**
130: * Get the primitive type corresponding to this item type. For item(),
131: * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds,
132: * it is the value representing the node kind, for example Type.ELEMENT.
133: * For anyAtomicValue it is Type.ATOMIC. For numeric it is Type.NUMBER.
134: * For other atomic types it is the primitive type as defined in XML Schema,
135: * except that INTEGER is considered to be a primitive type.
136: */
137:
138: public int getPrimitiveType() {
139: return Type.ANY_ATOMIC;
140: }
141:
142: /**
143: * Produce a representation of this type name for use in error messages.
144: * Where this is a QName, it will use conventional prefixes
145: */
146:
147: public String toString(NamePool pool) {
148: return getDisplayName();
149: }
150:
151: /**
152: * Get the item type of the atomic values that will be produced when an item
153: * of this type is atomized
154: */
155:
156: public AtomicType getAtomizedItemType() {
157: return this ;
158: }
159:
160: /**
161: * Returns the base type that this type inherits from. This method can be used to get the
162: * base type of a type that is known to be valid.
163: * If this type is a Simpletype that is a built in primitive type then null is returned.
164: *
165: * @return the base type.
166: * @throws IllegalStateException if this type is not valid.
167: */
168:
169: public SchemaType getKnownBaseType() {
170: return getBaseType();
171: }
172:
173: /**
174: * Test whether this is the same type as another type. They are considered to be the same type
175: * if they are derived from the same type definition in the original XML representation (which
176: * can happen when there are multiple includes of the same file)
177: */
178:
179: public boolean isSameType(SchemaType other) {
180: return (other.getFingerprint() == this .getFingerprint());
181: }
182:
183: public String getDescription() {
184: return getDisplayName();
185: }
186:
187: /**
188: * Check that this type is validly derived from a given type
189: *
190: * @param type the type from which this type is derived
191: * @param block the derivations that are blocked by the relevant element declaration
192: * @throws SchemaException if the derivation is not allowed
193: */
194:
195: public void isTypeDerivationOK(SchemaType type, int block)
196: throws SchemaException, ValidationException {
197: return;
198: }
199:
200: /**
201: * Returns true if this SchemaType is a SimpleType
202: *
203: * @return true (always)
204: */
205:
206: public final boolean isSimpleType() {
207: return true;
208: }
209:
210: /**
211: * Test whether this Simple Type is an atomic type
212: * @return true, this is considered to be an atomic type
213: */
214:
215: public boolean isAtomicType() {
216: return true;
217: }
218:
219: /**
220: * Returns true if this type is derived by list, or if it is derived by restriction
221: * from a list type, or if it is a union that contains a list as one of its members
222: *
223: * @return true if this is a list type
224: */
225:
226: public boolean isListType() {
227: return false;
228: }
229:
230: /**
231: * Return true if this type is a union type (that is, if its variety is union)
232: *
233: * @return true for a union type
234: */
235:
236: public boolean isUnionType() {
237: return false;
238: }
239:
240: /**
241: * Determine the whitespace normalization required for values of this type
242: *
243: * @return one of PRESERVE, REPLACE, COLLAPSE
244: * @param th
245: */
246:
247: public int getWhitespaceAction(TypeHierarchy th) {
248: return Whitespace.PRESERVE;
249: }
250:
251: /**
252: * Apply the whitespace normalization rules for this simple type
253: *
254: * @param value the string before whitespace normalization
255: * @return the string after whitespace normalization
256: */
257:
258: public CharSequence applyWhitespaceNormalization(CharSequence value)
259: throws ValidationException {
260: return value;
261: }
262:
263: /**
264: * Returns the built-in base type this type is derived from.
265: *
266: * @return the first built-in type found when searching up the type hierarchy
267: */
268: public SchemaType getBuiltInBaseType() throws ValidationException {
269: return this ;
270: }
271:
272: /**
273: * Test whether this simple type is namespace-sensitive, that is, whether
274: * it is derived from xs:QName or xs:NOTATION
275: *
276: * @return true if this type is derived from xs:QName or xs:NOTATION
277: */
278:
279: public boolean isNamespaceSensitive() {
280: return false;
281: }
282:
283: /**
284: * Get the typed value of a node that is annotated with this schema type
285: *
286: * @param node the node whose typed value is required
287: * @return an iterator over the items making up the typed value of this node. The objects
288: * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
289: */
290:
291: public final SequenceIterator getTypedValue(NodeInfo node) {
292: throw new IllegalStateException(
293: "The type annotation of a node cannot be an external object type");
294: }
295:
296: /**
297: * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method
298: * {@link #getTypedValue}. However, this method is often more convenient and may be
299: * more efficient, especially in the common case where the value is expected to be a singleton.
300: *
301: * @param node the node whose typed value is required
302: * @return the typed value.
303: * @since 8.5
304: */
305:
306: public Value atomize(NodeInfo node) throws XPathException {
307: throw new IllegalStateException(
308: "The type annotation of a node cannot be an external object type");
309: }
310:
311: /**
312: * Get the typed value corresponding to a given string value, assuming it is
313: * valid against this type
314: *
315: * @param value the string value
316: * @param resolver a namespace resolver used to resolve any namespace prefixes appearing
317: * in the content of values. Can supply null, in which case any namespace-sensitive content
318: * will be rejected.
319: * @param nameChecker
320: * @return an iterator over the atomic sequence comprising the typed value. The objects
321: * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}
322: */
323:
324: public SequenceIterator getTypedValue(CharSequence value,
325: NamespaceResolver resolver, NameChecker nameChecker)
326: throws ValidationException {
327: throw new ValidationException(
328: "Cannot validate a string against an external object type");
329: }
330:
331: /**
332: * Factory method to create values of a derived atomic type. This method
333: * is not used to create values of a built-in type, even one that is not
334: * primitive.
335: *
336: * @param primValue the value in the value space of the primitive type
337: * @param lexicalValue the value in the lexical space. If null, the string value of primValue
338: * @param validate true if the value is to be validated against the facets of the derived
339: * type; false if the caller knows that the value is already valid.
340: */
341:
342: public AtomicValue makeDerivedValue(AtomicValue primValue,
343: CharSequence lexicalValue, boolean validate) {
344: throw new UnsupportedOperationException(
345: "makeDerivedValue is not supported for external object types");
346: }
347:
348: /**
349: * Analyze an expression to see whether the expression is capable of delivering a value of this
350: * type.
351: *
352: * @param expression the expression that delivers the content
353: * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
354: * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
355: * @param env
356: * @throws net.sf.saxon.trans.XPathException
357: * if the expression will never deliver a value of the correct type
358: */
359:
360: public void analyzeContentExpression(Expression expression,
361: int kind, StaticContext env) throws XPathException {
362: analyzeContentExpression(this , expression, env, kind);
363: }
364:
365: /**
366: * Analyze an expression to see whether the expression is capable of delivering a value of this
367: * type.
368: * @param simpleType the simple type against which the expression is to be checked
369: * @param expression the expression that delivers the content
370: * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT},
371: * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT}
372: * @throws net.sf.saxon.trans.XPathException
373: * if the expression will never deliver a value of the correct type
374: */
375:
376: public static void analyzeContentExpression(SimpleType simpleType,
377: Expression expression, StaticContext env, int kind)
378: throws XPathException {
379: if (kind == Type.ELEMENT) {
380: expression.checkPermittedContents(simpleType, env, true);
381: } else if (kind == Type.ATTRIBUTE) {
382: // for attributes, do a check only for text nodes and atomic values: anything else gets atomized
383: if (expression instanceof ValueOf
384: || expression instanceof Value) {
385: expression
386: .checkPermittedContents(simpleType, env, true);
387: }
388: }
389: }
390:
391: public Class getJavaClass() {
392: return javaClass;
393: }
394:
395: public boolean isBuiltIn() {
396: return true;
397: }
398:
399: public boolean matchesItem(Item item, XPathContext context) {
400: if (item instanceof ObjectValue) {
401: Object obj = ((ObjectValue) item).getObject();
402: return javaClass.isAssignableFrom(obj.getClass());
403: }
404: return false;
405: }
406:
407: /**
408: * Check whether a given input string is valid according to this SimpleType
409: * @param value the input string to be checked
410: * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type
411: * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive
412: * content will throw an UnsupportedOperationException.
413: * @param nameChecker
414: * @return null if validation succeeds; return a ValidationException describing the validation failure
415: * if validation fails, unless throwException is true, in which case the exception is thrown rather than
416: * being returned.
417: * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace
418: * resolver is supplied
419: */
420:
421: public ValidationException validateContent(CharSequence value,
422: NamespaceResolver nsResolver, NameChecker nameChecker) {
423: throw new UnsupportedOperationException(
424: "Cannot use an external object type for validation");
425: }
426:
427: public ItemType getSuperType(TypeHierarchy th) {
428: // TODO: reflect the Java class hierarchy, to give better type checking
429: return Type.ANY_ATOMIC_TYPE;
430: }
431:
432: public int getFingerprint() {
433: return StandardNames.SAXON_JAVA_LANG_OBJECT;
434: }
435:
436: public String toString() {
437: String name = javaClass.getName();
438: name = name.replace('$', '-');
439: return "java:" + name;
440: }
441:
442: public String getDisplayName() {
443: return toString();
444: }
445: }
446:
447: //
448: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
449: // you may not use this file except in compliance with the License. You may obtain a copy of the
450: // License at http://www.mozilla.org/MPL/
451: //
452: // Software distributed under the License is distributed on an "AS IS" basis,
453: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
454: // See the License for the specific language governing rights and limitations under the License.
455: //
456: // The Original Code is: all this file.
457: //
458: // The Initial Developer of the Original Code is Saxonica Limited
459: //
460: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
461: //
462: // Contributor(s): none
463: //
|