/*
* @(#)$Id: ComplexTypeExp.java,v 1.18 2001/11/21 22:15:17 kk122374 Exp $
*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/
package com.sun.msv.grammar.xmlschema;
import com.sun.msv.datatype.xsd.XSDatatype;
import com.sun.msv.datatype.xsd.TypeIncubator;
import com.sun.msv.datatype.xsd.QnameType;
import com.sun.msv.reader.datatype.xsd.XSDatatypeExp;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.OtherExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.SimpleNameClass;
import com.sun.msv.grammar.ChoiceNameClass;
import com.sun.msv.grammar.trex.ElementPattern;
import com.sun.msv.grammar.util.ExpressionWalker;
import org.relaxng.datatype.ValidationContext;
import org.relaxng.datatype.DatatypeException;
/**
* ComplexType definition.
*
* ComplexTypeExp holds an expression (as a ReferenceExp) that matches to
* this type itself.
*
* <p>
* the {@link #body} field contains the expression that exactly matches
* to the declared content model (without any substitutable types).
*
* <p>
* the <code>exp</code> field contains the reference to the body field,
* if this complex type is not abstract. If abstract, then nullSet is set.
* You shouldn't directly manipulate the exp field. Instead, you should use
* the {@link #setAbstract} method to do it.
*
* <p>
* Note: The runtime type substitution
* (the use of <code>xsi:type</code> attribute)
* is implemented at the VGM layer. Therefore, AGMs of XML Schema does <b>NOT</b>
* precisely represent what are actually allowed and what are not.
*
*
* <h2>Complex Type Definition Schema Component Properties</h2>
* <p>
* This table shows the mapping between
* <a href="http://www.w3.org/TR/xmlschema-1/#Complex_Type_Definition_details">
* "complex type definition schema component properties"</a>
* (which is defined in the spec) and corresponding method/field of this class.
*
* <table border=1>
* <thead><tr>
* <td>Property of the spec</td>
* <td>method/field of this class</td>
* </tr></thead>
* <tbody><tr>
* <td>
* name
* </td><td>
* The {@link #name} field.
* </td>
* </tr><tr>
* <td>
* target namespace
* </td><td>
* the {@link #getTargetNamespace} method.
* </td>
* </tr><tr>
* <td>
* abstract
* </td><td>
* the {@link #isAbstract} method.
* </td>
* </tr><tr>
* <td>
* base type definition
* </td><td>
* {@link #simpleBaseType} or {@link #complexBaseType} field,
* depending on whether the base type is a simple type or a complex type.
* </td>
* </tr><tr>
* <td>
* derivation method
* </td><td>
* the {@link #derivationMethod} field.
* </td>
* </tr><tr>
* <td>
* final
* </td><td>
* the {@link #finalValue} field.
* </td>
* </tr><tr>
* <td>
* prohibited substitutions
* </td><td>
* the {@link #block} field.
* </td>
* </tr><tr>
* <td>
* attribtue uses <br> attribute wildcard <br> content type
* </td><td>
* Not directly accessible. Can be found by walking
* the children of the {@link #body} field.
* </td>
* </tr><tr>
* <td>
* annotation
* </td><td>
* Unaccessible. This information is removed during the parsing phase.
* </td>
* </tr></tbody>
* </table>
*
*
*
*
*
* <h3>Abstractness</h3>
*
* <p>
* The <code>exp</code> field and the <code>self</code> field are very similar.
* In fact, the only difference is that the former is affected by the abstract
* property, while the latter isn't.
*
* <p>
* So if it has to be affected by the
* abstract property (like referencing a complex type as the element body),
* you should use the <code>exp</code> field.
* If you don't want to be affected by the abstract property
* (like referencing a complex type as the base type of another complex type),
* then you should refer to the <code>body</code> field.
*
*
*
*
* @see ElementDeclExp
*
* @author <a href="mailto:kohsuke.kawaguchi@eng.sun.com">Kohsuke KAWAGUCHI</a>
*/
public class ComplexTypeExp extends XMLSchemaTypeExp {
public ComplexTypeExp( XMLSchemaSchema schema, String localName ) {
super(localName);
this.parent = schema;
setAbstract(false);
}
/** actual content model definition + attribute uses. */
public final ReferenceExp body = new ReferenceExp(null);
/** attribute wildcard as an expression. */
public final ReferenceExp attWildcard = new ReferenceExp(null,Expression.epsilon);
/** parent XMLSchemaSchema object to which this object belongs. */
public final XMLSchemaSchema parent;
/**
* Attribute wild card constraint.
*
* <p>
* Due to the nasty definition of the interaction between attribute wildcards,
* we cannot add the expression for validating wildcard until the very last moment.
*
* <p>
* Until the wrap-up phase of the schema parsing, this field will contain
* the "local wildcard definition." In the wrap-up phase, this field is replaced
* by the "complete wildcard definition."
*/
public AttributeWildcard wildcard;
public AttributeWildcard getAttributeWildcard() { return wildcard; }
public void setAttributeWildcard( AttributeWildcard local ) { wildcard=local; }
//
// Schema component properties
//======================================
//
/**
* gets the target namespace property of this component as
* <a href="http://www.w3.org/TR/xmlschema-1/#ct-target_namespace">
* specified in the spec</a>.
*
* <p>
* If the property is <a href="http://www.w3.org/TR/xmlschema-1/#key-null">
* absent</a>, then this method returns the empty string.
*
* <p>
* This method is just a shortcut for <code>parent.targetNamespace</code>.
*/
public final String getTargetNamespace() {
return parent.targetNamespace;
}
/**
* base type of this complex type.
*
* Either baseComplexType field or baseSimpleType field is set.
* If the base type is
* <a href="http://www.w3.org/TR/xmlschema-1/#section-Built-in-Complex-Type-Definition">
* ur-type</a>, both fields are set to null.
*
* @see #simpleBaseType
*/
public ComplexTypeExp complexBaseType;
/**
* base type of this complex type.
*
* @see #complexBaseType
*/
public XSDatatypeExp simpleBaseType;
/**
* the derivation method used to derive this complex type from the base type.
* Either RESTRICTION or EXTENSION.
*
* @see #complexBaseType
* #simpleBaseType
*/
public int derivationMethod = -1;
/**
* checks if this complex type is abstract.
*
* <p>
* This method corresponds to the abstract property of
* the complex type declaration schema component.
*
* @return
* true if this method is abstract. Flase if not.
*/
public boolean isAbstract() {
return exp==Expression.nullSet;
}
public void setAbstract( boolean isAbstract ) {
if( isAbstract ) exp=Expression.nullSet;
else exp=parent.pool.createSequence(body,attWildcard);
}
/**
* Checks if this type is a derived type of the specified type.
*
* <p>
* This method is an implementation of
* <a href="http://www.w3.org/TR/xmlschema-1/#cos-ct-derived-ok">
* "Type Derivation OK (Complex)"</a> test
* of the spec.
*
* <p>
* If you are not familiar with the abovementioned part of the spec,
* <b>don't use this method</b>. This method probably won't give you
* what you expected.
*
* @param constraint
* A bit field that represents the restricted derivation. This field
* must consists of bitwise and of {@link #EXTENSION} or {@link #RESTRICTION}.
*
* @return
* true if the specified type is "validly derived" from this type.
* false if not.
*/
public boolean isDerivedTypeOf( ComplexTypeExp baseType, int constraint ) {
ComplexTypeExp derived = this;
while( derived!=null ) {
if( derived==baseType ) return true;
if( (derived.derivationMethod&constraint)!=0 )
return false; // this type of derivation is prohibited.
derived = derived.complexBaseType;
}
return false;
}
/**
* @see #isDerivedTypeOf(ComplexTypeExp,int)
*/
public boolean isDerivedTypeOf( XSDatatype baseType, int constraint ) {
ComplexTypeExp derived = this;
while(true) {
if( derived.complexBaseType==null ) {
if( derived.simpleBaseType!=null )
return derived.simpleBaseType.getCreatedType().isDerivedTypeOf(
baseType, (constraint&RESTRICTION)==0 );
else
return false;
}
if( (derived.derivationMethod&constraint)!=0 )
return false; // this type of derivation is prohibited.
derived = derived.complexBaseType;
}
}
public boolean isDerivedTypeOf( XMLSchemaTypeExp exp, int constraint ) {
if( exp instanceof ComplexTypeExp )
return isDerivedTypeOf( (ComplexTypeExp)exp, constraint );
else
return isDerivedTypeOf( ((SimpleTypeExp)exp).getDatatype(), constraint );
}
/**
* The <a href="http://www.w3.org/TR/xmlschema-1/#ct-final">
* final property</a> of this schema component, implemented as a bit field.
*
* <p>
* 0, RESTRICTION, EXTENSION, or (RESTRICTION|EXTENSION).
*/
public int finalValue =0;
/**
* The <a href="http://www.w3.org/TR/xmlschema-1/#ct-block">
* block property</a> of this schema component, implemented as a bit field.
*
* <p>
* 0, RESTRICTION, EXTENSION, or (RESTRICTION|EXTENSION).
*/
public int block =0;
/**
* Gets the value of the block constraint.
* SimpleTypeExp always returns 0 because it doesn't have the block constraint.
*/
public int getBlock() { return block; }
//
// Other implementation details
//======================================
//
/** clone this object. */
public RedefinableExp getClone() {
ComplexTypeExp exp = new ComplexTypeExp(parent,super.name);
exp.redefine(this);
return exp;
}
public void redefine( RedefinableExp _rhs ) {
super.redefine(_rhs);
ComplexTypeExp rhs = (ComplexTypeExp)_rhs;
body.exp = rhs.body.exp;
attWildcard.exp = rhs.attWildcard.exp;
complexBaseType = rhs.complexBaseType;
simpleBaseType = rhs.simpleBaseType;
derivationMethod = rhs.derivationMethod;
finalValue = rhs.finalValue;
block = rhs.block;
if(rhs.wildcard==null) wildcard = null;
else wildcard = rhs.wildcard.copy();
if( this.parent != rhs.parent )
// those two must share the parent.
throw new IllegalArgumentException();
}
// /** derives a QName type that only accepts this type name. */
/* private static XSDatatype getQNameType( final String namespaceURI, final String localName ) {
try {
TypeIncubator ti = new TypeIncubator( QnameType.theInstance );
ti.addFacet( "enumeration", "foo:"+localName, true,
new ValidationContext() {
public String resolveNamespacePrefix( String prefix ) {
if( "foo".equals(prefix) ) return namespaceURI;
return null;
}
public boolean isUnparsedEntity( String entityName ) {
throw new Error(); // shall never be called.
}
public boolean isNotation( String notationName ) {
throw new Error(); // shall never be called.
}
public String getBaseUri() { return null; }
} );
return ti.derive(null);
} catch( DatatypeException e ) {
// assertion failed. this can't happen.
throw new Error();
}
}
*/
/**
* implementation detail.
*
* A ComplexTypeDecl is properly defined if its self is defined.
* Note that the default implementation of the isDefined method doesn't
* work for this class because the exp field is set by the constructor.
*/
public boolean isDefined() {
return body.isDefined();
}
}