/*
* @(#)$Id: ElementDeclExp.java,v 1.14 2002/02/24 01:30:01 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.grammar.ChoiceExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.SimpleNameClass;
import com.sun.msv.grammar.NameClass;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.util.ExpressionWalker;
import java.util.Vector;
/**
* Element declaration.
*
* <p>
* the inherited exp field holds an expression that
* also matches to substituted element declarations.
*
* <p>
* The <code>body</code> field contains an expression that matches
* only to this element declaration without no substituted element decls.
*
*
* <h2>Element Declaration Schema Component Properties</h2>
* <p>
* This table shows the mapping between
* <a href="http://www.w3.org/TR/xmlschema-1/#Element_Declaration_details">
* "element declaration 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>
* type definition
* </td><td>
* {@link getTypeDefinition()} method.
* </td>
* </tr><tr>
* <td>
* scope
* </td><td>
* <b>To be implemented</b>
* </td>
* </tr><tr>
* <td>
* value constraint
* </td><td>
* <b>To be implemented</b>. Accessible through the {@link body} field.
* </td>
* </tr><tr>
* <td>
* nillable
* </td><td>
* the {@link #isNillable} field.
* </td>
* </tr><tr>
* <td>
* identity constraints
* </td><td>
* The <code>identityConstraints</code> field of the {@link XSElementExp},
* which in turn can be obtained throught the {@link body} field.
* </td>
* </tr><tr>
* <td>
* substitution group affiliation
* </td><td>
* The {@link #substitutionAffiliation} field.
* </td>
* </tr><tr>
* <td>
* substitution group exclusion
* </td><td>
* The {@link #finalValue} field.
* </td>
* </tr><tr>
* <td>
* disallowed substitution
* </td><td>
* The {@link #block} field.
* </td>
* </tr><tr>
* <td>
* abstract
* </td><td>
* the {@link #isAbstract} method.
* </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.
*
*
* @author <a href="mailto:kohsuke.kawaguchi@eng.sun.com">Kohsuke KAWAGUCHI</a>
*/
public class ElementDeclExp extends ReferenceExp
{
public ElementDeclExp( XMLSchemaSchema schema, String typeLocalName ) {
super(typeLocalName);
this.parent = schema;
this.substitutions = new ReferenceExp( typeLocalName+":substitutions" );
this.substitutions.exp = Expression.nullSet;
}
/**
* <a href="http://www.w3.org/TR/xmlschema-1/#class_exemplar">
* The substitution group affiliation property</a>
* of this component, if any.
* Otherwise null.
*/
public ElementDeclExp substitutionAffiliation;
/**
* The expression that represents the "body" of this expression.
* Usually, this refers to XSElementExp, but not necessarily.
*/
public final ReferenceExp body = new ReferenceExp(null);
private XSElementExp element;
public void setElementExp( XSElementExp exp ) {
this.element = exp;
body.exp = exp;
}
public XSElementExp getElementExp() { return element; }
/**
* choices of all elements that can validly substitute this element.
*/
public final ReferenceExp substitutions;
/**
* gets the pattern that represents the content model of
* this element declaration.
*
* This method is just a short cut for <code>self.contentModel</code>.
*/
public Expression getContentModel() {
return element.contentModel;
}
/** parent XMLSchemaSchema object to which this object belongs. */
public final XMLSchemaSchema parent;
/**
* XML Schema version of {@link ElementExp}.
*
* @author <a href="mailto:kohsuke.kawaguchi@eng.sun.com">Kohsuke KAWAGUCHI</a>
*/
public class XSElementExp extends ElementExp {
public final SimpleNameClass elementName;
public final NameClass getNameClass() { return elementName; }
public XSElementExp( SimpleNameClass elementName, Expression contentModel ) {
super(contentModel,false);
this.elementName = elementName;
parent = ElementDeclExp.this;
}
/**
* identity constraints associated to this declaration.
* When no constraint exists, this field may be null (or empty vector).
* Items are of derived types of {@link IdentityConstraint} class.
*
* <p>
* These identity constraints are not enforced by the default Verifier
* implementation.
*/
public final Vector identityConstraints = new Vector();
public final ElementDeclExp parent;
}
//
// Schema component properties
//======================================
//
/**
* gets the nillable property of this component as
* <a href="http://www.w3.org/TR/xmlschema-1/#nillable">
* specified in the spec</a>.
*/
public boolean isNillable;
/**
* gets the scope property of this component as
* <a href="http://www.w3.org/TR/xmlschema-1/#e-scope">
* specified in the spec</a>.
*
* @return
* <b>true</b> if this component is global.
* <b>false</b> if this component is local.
*/
public boolean isGlobal() {
return parent.elementDecls.get(name)==this;
}
/**
* gets the target namespace property of this component as
* <a href="http://www.w3.org/TR/xmlschema-1/#e-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;
}
/**
* checks if this element declaration is abstract.
*
* @return
* true if this method is abstract.
*/
public boolean isAbstract() {
if( exp instanceof ChoiceExp ) {
ChoiceExp cexp = (ChoiceExp)exp;
if(cexp.exp1!=body && cexp.exp2!=body)
throw new Error(); // assertion failed
return true;
}
if(exp!=substitutions)
throw new Error(); // assertion failed
return false;
}
public void setAbstract( boolean isAbstract ) {
if(isAbstract) exp = substitutions;
else exp = parent.pool.createChoice( substitutions, body );
}
public static final int RESTRICTION = 0x1;
public static final int EXTENSION = 0x2;
public static final int SUBSTITUTION= 0x4;
/**
* The <a href="http://www.w3.org/TR/xmlschema-1/#e-final">
* substitution group exclusions property</a> of this schema component,
* implemented as a bit field.
*
* <p>
* a bit-wise OR of RESTRICTION and EXTENSION.
*/
public int finalValue =0;
/**
* The <a href="http://www.w3.org/TR/xmlschema-1/#e-exact">
* disallowed substitution property</a> of this schema component,
* implemented as a bit field.
*
* <p>
* a bit-wise OR of RESTRICTION, EXTENSION, and SUBSTITUTION.
*/
public int block =0;
public boolean isSubstitutionBlocked() { return (block&SUBSTITUTION)!=0; }
public boolean isRestrictionBlocked() { return (block&RESTRICTION)!=0; }
/**
* gets the <a href="http://www.w3.org/TR/xmlschema-1/#type_definition">
* type definition property</a> of this schema component.
*/
public XMLSchemaTypeExp getTypeDefinition() {
final RuntimeException eureka = new RuntimeException();
final XMLSchemaTypeExp[] result = new XMLSchemaTypeExp[1];
try {
getContentModel().visit( new ExpressionWalker(){
public void onElement( ElementExp exp ) {}
public void onRef( ReferenceExp exp ) {
if(exp instanceof XMLSchemaTypeExp) {
result[0] = (XMLSchemaTypeExp)exp;
throw eureka;
}
super.onRef(exp);
}
});
// assertion failed. It couldn't be found.
throw new Error();
} catch( RuntimeException e ) {
if(e==eureka) return result[0];
throw e;
}
}
//
// Implementation details
//=========================================
public boolean isDefined() {
return super.isDefined() && element!=null;
}
}