Package org.exolab.castor.xml.schema.reader

Source Code of org.exolab.castor.xml.schema.reader.SchemaUnmarshaller$RemappedPrefixes

/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
*    statements and notices.  Redistributions must also contain a
*    copy of this document.
*
* 2. Redistributions in binary form must reproduce the
*    above copyright notice, this list of conditions and the
*    following disclaimer in the documentation and/or other
*    materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
*    products derived from this Software without prior written
*    permission of Intalio, Inc.  For written permission,
*    please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
*    nor may "Exolab" appear in their names without prior written
*    permission of Intalio, Inc. Exolab is a registered
*    trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
*    (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
*
* $Id: SchemaUnmarshaller.java 7506 2008-03-22 10:06:33Z wguttmn $
*/

package org.exolab.castor.xml.schema.reader;

//-- imported classes and packages
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Properties;
import java.util.StringTokenizer;

import org.exolab.castor.net.URIResolver;
import org.exolab.castor.net.util.URIResolverImpl;
import org.exolab.castor.xml.AttributeSet;
import org.exolab.castor.xml.Namespaces;
import org.exolab.castor.xml.XMLException;
import org.exolab.castor.xml.schema.Annotation;
import org.exolab.castor.xml.schema.AttributeDecl;
import org.exolab.castor.xml.schema.AttributeGroupDecl;
import org.exolab.castor.xml.schema.ComplexType;
import org.exolab.castor.xml.schema.ElementDecl;
import org.exolab.castor.xml.schema.Form;
import org.exolab.castor.xml.schema.SchemaContext;
import org.exolab.castor.xml.schema.ModelGroup;
import org.exolab.castor.xml.schema.RedefineSchema;
import org.exolab.castor.xml.schema.Schema;
import org.exolab.castor.xml.schema.SchemaException;
import org.exolab.castor.xml.schema.SchemaNames;
import org.exolab.castor.xml.schema.ScopableResolver;
import org.exolab.castor.xml.schema.SimpleType;
import org.exolab.castor.xml.util.AttributeSetImpl;

/**
* @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
* @version $Revision: 7506 $ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
**/
public class SchemaUnmarshaller extends ComponentReader {



    /**
     * W3C XML schema namespace.
     */
    public static final String XSD_NAMESPACE
        = "http://www.w3.org/2001/XMLSchema";


    /**
     * Unsupported namespace definitions, pointing to older
     * XML schema specifications.
     */
    public static final String[] UNSUPPORTED_NAMESPACES = {
        "http://www.w3.org/2000/10/XMLSchema",
        "http://www.w3.org/1999/XMLSchema"
    };

      //--------------------/
     //- Member Variables -/
    //--------------------/

    /**
     * Indicates whether the {@link Schema} processed represents an
     * included schema.
     */
    private boolean _include = false;
   
    /**
     * The current {@link ComponentReader}.
    **/
    private ComponentReader _unmarshaller;

    /**
     * Flag to indicate that we are inside an annotation element.
    **/
    private int _annotationDepth = 0;

    /**
     * The current branch depth.
    **/
    private int _depth = 0;

    boolean skipAll = false;

    Schema _schema = null;

    private boolean foundSchemaDef = false;


    /**
     * The default namespace URI to be used.
     */
    private String _defaultNS = null;

    /**
     * The {@link SchemaUnmarshaller} state.
     */
    private SchemaUnmarshallerState _state = null;
  
    /**
     * Remapped prefix mappings.
     */
    private RemappedPrefixes _prefixMappings = null;
   
      //----------------/
     //- Constructors -/
    //----------------/

    /**
     * Creates a {@link SchemaUnmarshaller} instance.
     * @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
     * @throws XMLException Indicates that the XML schema cannnot be processed
     */
    public SchemaUnmarshaller(final SchemaContext schemaContext)
    throws XMLException {
        this(schemaContext, null, null);
        foundSchemaDef = false;
    } //-- SchemaUnmarshaller

    /**
     * Creates a {@link SchemaUnmarshaller} instance.
     * @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
     * @param state A {@link SchemaUnmarshallerState} to be used during unmarshalling.
     * @throws XMLException Indicates that the XML schema cannnot be processed
     */
    public SchemaUnmarshaller(
            final SchemaContext schemaContext,
            final SchemaUnmarshallerState state)
    throws XMLException {
        this(schemaContext, null, null);
        _state = state;
        foundSchemaDef = false;
    } //-- SchemaUnmarshaller

    /**
     * Creates a {@link SchemaUnmarshaller} instance.
     * @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
     * @param include Indicates whether the {@link Schema} to be processed ia an included schema.
     * @param state A {@link SchemaUnmarshallerState} to be used during unmarshalling.
     * @param uriResolver {@link URIResolver} to be used during processing.
     * @throws XMLException Signals a problem in processing the XML schema.
     *
     * Called from IncludeUnmarshaller.
     *
     * @see {@link IncludeUnmarshaller}
     */
    public SchemaUnmarshaller(
            final SchemaContext schemaContext,
            final boolean include,
            final SchemaUnmarshallerState state,
            final URIResolver uriResolver)
        throws XMLException {

        this(schemaContext, null, uriResolver);
        _state = state;
        _include = include;
        foundSchemaDef = false;
    }

    /**
     * Creates a {@link SchemaUnmarshaller} instance.
     * Exists for backward compatibility
     * @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
     * @param atts Attribute set to be processed.
     * @throws XMLException Signals a problem in processing the XML schema.
     */
    public SchemaUnmarshaller(
            final SchemaContext schemaContext,
            final AttributeSet atts) throws XMLException {
        this(schemaContext, atts, null);
    }

    /**
     * Creates a {@link SchemaUnmarshaller} instance.
     * @param schemaContext A {@link SchemaContext} to be used during schema unmarshalling.
     * @param atts Attribute set to be processed.
     * @param uriResolver {@link URIResolver} to be used during processing.
     * @throws XMLException Signals a problem in processing the XML schema.
     */
    private SchemaUnmarshaller(
            final SchemaContext schemaContext,
            final AttributeSet atts,
            final URIResolver uriResolver)
    throws XMLException {
        super(schemaContext);

        _schema = new Schema();
        //--initialize the schema to ensure that the default namespace
        //--is not set
        _schema.removeNamespace("");
        if (getResolver() == null) {
            setResolver(new ScopableResolver());
        }
        if (uriResolver == null) {
            setURIResolver(new URIResolverImpl());
        } else {
            setURIResolver(uriResolver);
        }
        foundSchemaDef = true;
        _state = new SchemaUnmarshallerState();
        init(atts);
    } //-- SchemaUnmarshaller

    /**
     * Returns the {@link Schema} instance representing the XML schema (file) just
     * processed.
     * @return the {@link Schema} instance obtained from processing an XML schema file.
     */
    public Schema getSchema() {
        return _schema;
    }

    /**
     * Sets the {@link Schema} instance to be processed.
     * @param schema {@link Schema} instancetp be processed.
     */
    public void setSchema(final Schema schema) {
        _schema = schema;
    }

    /**
     * Returns the Object created by this ComponentReader.
     * @return the Object created by this ComponentReader
    **/
    public Object getObject() {
        return getSchema();
    } //-- getObject

    /**
     * Returns the name of the element that this ComponentReader
     * handles.
     * @return the name of the element that this ComponentReader
     * handles
    **/
    public String elementName() {
        return SchemaNames.SCHEMA;
    } //-- elementName


    /**
     * Initializes the Schema object with the given attribute list.
     * @param atts the AttributeList for the schema
     * @throws XMLException Signals a problem in initializing the {@link Schema}
     * object instance
     */
    private void init(final AttributeSet atts) throws XMLException {
        if (atts == null) {
            return;
        }

        String attValue = null;

        String nsURI = atts.getValue(SchemaNames.TARGET_NS_ATTR);
        if (nsURI != null &&  nsURI.length() == 0) {
            throw new SchemaException("empty string is not a legal namespace.");
        }
        if ((nsURI != null) && (nsURI.length() > 0)) {
            if (!_state.cacheIncludedSchemas) {
                //if we are including a schema we must take care
                //that the namespaces are the same
                if ((_include) && (!_schema.getTargetNamespace().equals(nsURI))) {
                    throw new SchemaException("The target namespace of the included "
                            + "components must be the same as the target namespace "
                            + "of the including schema");
                }
            }
               _schema.setTargetNamespace(nsURI);
        }

        _schema.setId(atts.getValue(SchemaNames.ID_ATTR));
        _schema.setVersion(atts.getValue(SchemaNames.VERSION_ATTR));

        //set the default locator of this schema
        if (!_include || _state.cacheIncludedSchemas) {
            _schema.setSchemaLocation(getDocumentLocator().getSystemId());
        }

        //-- attributeFormDefault
        String form = atts.getValue(SchemaNames.ATTR_FORM_DEFAULT_ATTR);
        if (form != null) {
            _schema.setAttributeFormDefault(Form.valueOf(form));
        }

        //-- elementFormDefault
        form = atts.getValue(SchemaNames.ELEM_FORM_DEFAULT_ATTR);
        if (form != null) {
            _schema.setElementFormDefault(Form.valueOf(form));
        }

        //-- @blockDefault
        attValue = atts.getValue(SchemaNames.BLOCK_DEFAULT_ATTR);
        if (attValue != null) {
            _schema.setBlockDefault(attValue);
        }

        //-- @finalDefault
        attValue = atts.getValue(SchemaNames.FINAL_DEFAULT_ATTR);
        if (attValue != null) {
            _schema.setFinalDefault(attValue);
        }

        //--@version
        attValue = atts.getValue(SchemaNames.VERSION_ATTR);
        if (attValue != null) {
            _schema.setVersion(attValue);
        }

    } //-- init

    /**
     * Handles namespace attributes.
     * @param namespaces The name space to handle.
     * @throws XMLException If there's a problem related to namespace handling.
     */
    private void handleNamespaces(final Namespaces namespaces)
        throws XMLException {

        if (namespaces == null) {
            return;
        }

        Enumeration enumeration = namespaces.getLocalNamespaces();

        while (enumeration.hasMoreElements()) {

            String ns = (String) enumeration.nextElement();
            String[] prefixes = namespaces.getNamespacePrefixes(ns, true);

            if (prefixes.length == 0) {
                //-- this should never happen, but report error just
                //-- in case there is a bug in Namespaces class.
                String error = "unexpected error processing the following "
                    + "namespace: '" + ns + "'; the prefix could not be resolved.";
                throw new XMLException(error);
            }

            boolean hasCollisions = false;
            for (int pIdx = 0; pIdx < prefixes.length; pIdx++) {
                String prefix = prefixes[pIdx];
               
                //-- Since the Schema Object Model does not yet support
                //-- namespace scoping, we need to checking for namespace
                //-- prefix collisions...and remap the prefixes
                String tmpURI = _schema.getNamespace(prefix);
                if ((tmpURI != null) && (foundSchemaDef)) {
                    if (!tmpURI.equals(ns)) {
                        if (!hasCollisions) {
                            hasCollisions = true;
                            if (_prefixMappings == null) {
                                _prefixMappings = new RemappedPrefixes();
                            } else {
                                _prefixMappings = _prefixMappings.newRemappedPrefixes();
                            }
                        }
                       
                        //-- create a new prefix
                        if (prefix.length() == 0) {
                            prefix = "ns";
                        }
                           
                        int count = 1;
                        String newPrefix = prefix + count;
                        tmpURI = _schema.getNamespace(newPrefix);
                        while (tmpURI != null) {
                            if (tmpURI.equals(ns)) {
                                //-- no remapping necessary
                                break;
                            }
                            ++count;
                            newPrefix = prefix + count;
                            tmpURI = _schema.getNamespace(newPrefix);
                        }
                        _prefixMappings.addMapping(prefix, newPrefix);
                        prefix = newPrefix;
                    } else {
                        //-- we may need to "reset" a currently mapped prefix
                        if (_prefixMappings != null) {
                            if (_prefixMappings.isRemappedPrefix(prefix)) {
                                //-- reset mapping in this scope
                                _prefixMappings.addMapping(prefix, prefix);
                            }
                        }
                    }
                }
                //-- end collision handling
               
                if (prefix.length() == 0) {
                    _defaultNS = ns;
                    //register the default namespace with the empty string
                    _schema.addNamespace("", _defaultNS);
                } else {
                    //-- check for old unsupported schema namespaces
                    for (int nsIdx = 0; nsIdx < UNSUPPORTED_NAMESPACES.length; nsIdx++) {
                        if (ns.equals(UNSUPPORTED_NAMESPACES[nsIdx])) {
                            error("The following namespace \"" + ns
                                    + "\" is no longer supported. Please update to "
                                    + " the W3C XML Schema Recommendation.");
                        }
                    }
                    _schema.addNamespace(prefix, ns);
                }
            }
        }

    } //-- handleNamespaces

    /**
     * Remaps any QName attributes for the given element and attributeSet.
     * This method is a work around for the lack of namespace scoping
     * support in the Schema Object Model
     *
     * @param name Name of the element handled.
     * @param namespace Namepace of the element processed.
     * @param atts The attributes of the element processed.
     */
    private void handleRemapping(final String name, final String namespace,
            final AttributeSetImpl atts) {
       
        if (_prefixMappings == null) {
            return;
        }
       
        //-- increase depth for scoping
        _prefixMappings.depth++;
       
        String[] remapAtts = (String[]) RemappedPrefixes.QNAME_TABLE.get(name);
       
        if (remapAtts != null) {
            for (int i = 0; i < remapAtts.length; i++) {
                String value = atts.getValue(remapAtts[i]);
                if (value != null) {
                    value = _prefixMappings.remapQName(value);
                    atts.setAttribute(remapAtts[i], value);
                }
            }
        }
       
    } //-- handleRemapping

    /**
     * Signals the start of an element with the given name.
     *
     * @param name the NCName of the element. It is an error
     * if the name is a QName (ie. contains a prefix).
     * @param namespace the namespace of the element. This may be null.
     * Note: A null namespace is not the same as the default namespace unless
     * the default namespace is also null.
     * @param atts the AttributeSet containing the attributes associated
     * with the element.
     * @param nsDecls the namespace declarations being declared for this
     * element. This may be null.
     * @throws XMLException To indicate a problem in processing the current element.
    **/
    public void startElement(final String name,
            String namespace, final AttributeSet atts,
            final Namespaces nsDecls) throws XMLException {

        if (skipAll) {
            return;
        }
       
        //-- DEBUG
        //System.out.println("#startElement: " + name + " {" + namespace + "}");
        //-- /DEBUG


        //-- process namespaces...unless we are inside an
        //-- annotation
        if (_annotationDepth == 0) {
            handleNamespaces(nsDecls);
        }

        //-- backward compatibility, we'll need to
        //-- remove this at some point
        if ((!foundSchemaDef) && (namespace == null)) {
            if (_defaultNS == null) {
                _defaultNS = XSD_NAMESPACE;
                namespace = XSD_NAMESPACE;
                System.out.println("No namespace declaration has been " +
                    "found for " + name);
                System.out.print("   * assuming default namespace of ");
                System.out.println(XSD_NAMESPACE);
            }
        }
        if (namespace == null) {
            namespace = _defaultNS;
            //-- end of backward compatibility
        }

        //-- keep track of annotations
        if (name.equals(SchemaNames.ANNOTATION)) {
            ++_annotationDepth;
        }

        //-- check namespace
        if (!XSD_NAMESPACE.equals(namespace)) {
            if (_annotationDepth == 0) {
                error("'" + name + "' has not been declared in the XML "
                        + "Schema namespace.");
            }
        }

        //-- handle namespace prefix remapping
        if (_annotationDepth == 0) {
            if (_prefixMappings != null) {
                handleRemapping(name, namespace, (AttributeSetImpl) atts);
            }
        }
       
        //-- Do delagation if necessary
        if (_unmarshaller != null) {
            try {
                _unmarshaller.startElement(name, namespace, atts, nsDecls);
            } catch (RuntimeException rtx) {
                error(rtx);
            }
            ++_depth;
            return;
        }

        if (name.equals(SchemaNames.SCHEMA)) {

            if (foundSchemaDef) {
                illegalElement(name);
            }

            foundSchemaDef = true;
            init(atts);
            return;
        }

        //-- <annotation>
        if (name.equals(SchemaNames.ANNOTATION)) {
            _unmarshaller = new AnnotationUnmarshaller(getSchemaContext(), atts);
        } else if (name.equals(SchemaNames.ATTRIBUTE)) {
            //--<attribute>
            _unmarshaller = new AttributeUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
            //-- <attributeGroup>
            _unmarshaller = new AttributeGroupUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
            //-- <complexType>
            _unmarshaller
                = new ComplexTypeUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.ELEMENT)) {
            //-- <element>
            _unmarshaller
                = new ElementUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
            //-- <simpleType>
            _unmarshaller = new SimpleTypeUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.GROUP)) {
            //-- <group>
             _unmarshaller = new ModelGroupUnmarshaller(getSchemaContext(), _schema, atts);
        } else if (name.equals(SchemaNames.INCLUDE)) {
            //-- <include>
            _unmarshaller
                = new IncludeUnmarshaller(getSchemaContext(), _schema, atts,
                        getURIResolver(), getDocumentLocator(), _state);
        } else if (name.equals(SchemaNames.IMPORT)) {
            //-- <import>
            _unmarshaller
                = new ImportUnmarshaller(getSchemaContext(), _schema, atts,
                        getURIResolver(), getDocumentLocator(), _state);
        } else if (name.equals(SchemaNames.REDEFINE)) {
            //-- <redefine>
            _unmarshaller
            = new RedefineUnmarshaller(getSchemaContext(), _schema, atts,
                    getURIResolver(), getDocumentLocator(), _state);
        } else {
            //-- we should throw a new Exception here
            //-- but since we don't support everything
            //-- yet, simply add an UnknownDef object
            System.out.print('<');
            System.out.print(name);
            System.out.print("> elements are either currently unsupported ");
            System.out.println("or non-valid schema elements.");
            _unmarshaller = new UnknownUnmarshaller(getSchemaContext(), name);
        }

//        unmarshaller.setDocumentLocator(getDocumentLocator());

    } //-- startElement

    /**
     * Signals to end of the element with the given name.
     *
     * @param name the NCName of the element. It is an error
     * if the name is a QName (ie. contains a prefix).
     * @param namespace the namespace of the element.
     * @throws XMLException To indicate that the current element cannnot be processed successfully.
    **/
    public void endElement(String name, String namespace)
        throws XMLException {
        if (skipAll) {
            return;
        }

        //-- DEBUG
        //System.out.println("#endElement: " + name + " {" + namespace + "}");
        //-- /DEBUG

        //-- backward compatibility
        if (namespace == null) {
            namespace =  _defaultNS;
        }

        //-- keep track of annotations
        if (name.equals(SchemaNames.ANNOTATION)) {
            --_annotationDepth;
        }
       
        //-- remove namespace remapping, if necessary
        if (_prefixMappings != null) {
            if (_prefixMappings.depth == 0) {
                _prefixMappings = _prefixMappings.getParent();
            } else {
                --_prefixMappings.depth;
            }
        }

        //-- Do delagation if necessary
        if ((_unmarshaller != null) && (_depth > 0)) {
            _unmarshaller.endElement(name, namespace);
            --_depth;
            return;
        }

        //-- use internal JVM String
        name = name.intern();

        if (name == SchemaNames.SCHEMA) {
            return;
        }

        //-- check for name mismatches
        if ((_unmarshaller != null)) {
            if (!name.equals(_unmarshaller.elementName())) {
                String err = "error: missing end element for ";
                err += _unmarshaller.elementName();
                throw new SchemaException(err);
            }
        } else {
            String err = "error: missing start element for " + name;
            throw new SchemaException(err);
        }

        //-- call unmarshaller.finish() to perform any necessary cleanup
        _unmarshaller.finish();

        //-- <annotation>
        if (name.equals(SchemaNames.ANNOTATION)) {
            _schema.addAnnotation((Annotation) _unmarshaller.getObject());
        } else if (name.equals(SchemaNames.ATTRIBUTE)) {
            //-- <attribute>
            _schema.addAttribute((AttributeDecl) _unmarshaller.getObject());
        } else if (name.equals(SchemaNames.ATTRIBUTE_GROUP)) {
            //-- <attributeGroup>
            Object obj = _unmarshaller.getObject();
            try {
                _schema.addAttributeGroup((AttributeGroupDecl) obj);
            } catch (ClassCastException ex) {
                String err = "Top-level AttributeGroups must be defining "
                    + "AttributeGroups and not referring AttributeGroups.";
                error(err);
            }
        } else if (name.equals(SchemaNames.COMPLEX_TYPE)) {
            //-- <complexType>
            ComplexType complexType = null;
            complexType = ((ComplexTypeUnmarshaller) _unmarshaller).getComplexType();
            _schema.addComplexType(complexType);
            if (complexType.getName() != null) {
                getResolver().addResolvable(complexType.getReferenceId(), complexType);
            } else {
                System.out.println("warning: top-level complexType with no name.");
            }
        } else if (name.equals(SchemaNames.SIMPLE_TYPE)) {
            //-- <simpleType>
            SimpleType simpleType = null;
            simpleType = ((SimpleTypeUnmarshaller) _unmarshaller).getSimpleType();
            _schema.addSimpleType(simpleType);
            getResolver().addResolvable(simpleType.getReferenceId(), simpleType);
        } else if (name.equals(SchemaNames.ELEMENT)) {
            //--<element>
            ElementDecl element = null;
            element = ((ElementUnmarshaller) _unmarshaller).getElement();
            _schema.addElementDecl(element);
        } else if (name.equals(SchemaNames.GROUP)) {
            //--<group>
            ModelGroup group = null;
            group = (((ModelGroupUnmarshaller) _unmarshaller).getGroup());
            _schema.addModelGroup(group);
        } else if (name.equals(SchemaNames.REDEFINE)) {
            //--<redefine>
            RedefineSchema redefine = null;
            redefine = (RedefineSchema) (((RedefineUnmarshaller) _unmarshaller).getObject());
            if ((redefine.getSchemaLocation() == null) && (redefine.hasRedefinition())) {
                _schema.removeRedefineSchema(redefine);
                String err = "A <redefine> structure with no 'schemaLocation' "
                    + "attribute must contain only <annotation> elements";
                error(err);
            }
        }

        _unmarshaller = null;
    } //-- endElement

    /**
     * {@inheritDoc}
     *
     * @see org.exolab.castor.xml.schema.reader.ComponentReader#characters(char[], int, int)
     */
    public void characters(final char[] ch, final int start, final int length)
        throws XMLException {
        //-- Do delagation if necessary
        if (_unmarshaller != null) {
            _unmarshaller.characters(ch, start, length);
        }
    } //-- characters
   
    /**
     * This class handles remapping of namespace prefixes
     * for attributes of type QName. This is needed to
     * work around a limitation in Castor's Schema Object
     * Model, which does not support proper namespace
     * scoping yet.
     */
    static class RemappedPrefixes {
       
        public static final String RESOURCE_NAME
            = "prefixremap.properties";
       
        public static final String RESOURCE_LOCATION =
            "/org/exolab/castor/xml/schema/reader/";
       
        public static final HashMap QNAME_TABLE = new HashMap();
        private static boolean initialized = false;
       
        static {
           
            synchronized (QNAME_TABLE) {
               
                if (!initialized) {
                   
                    initialized = true;
                   
                    //-- built in mappings
                   
                    //-- attribute                   
                    QNAME_TABLE.put(SchemaNames.ATTRIBUTE, new String [] {
                        SchemaNames.REF_ATTR, SchemaNames.TYPE_ATTR });
                       
                    //-- attributeGroup
                    QNAME_TABLE.put(SchemaNames.ATTRIBUTE_GROUP, new String [] {
                        SchemaNames.REF_ATTR });
                       
                    //-- element
                    QNAME_TABLE.put(SchemaNames.ELEMENT, new String [] {
                        SchemaNames.REF_ATTR, SchemaNames.TYPE_ATTR });
                       
                    //-- extension
                    QNAME_TABLE.put(SchemaNames.EXTENSION, new String [] {
                        SchemaNames.BASE_ATTR });

                    //-- group
                    QNAME_TABLE.put(SchemaNames.GROUP, new String [] {
                        SchemaNames.REF_ATTR });
                       
                    //-- restriction
                    QNAME_TABLE.put(SchemaNames.RESTRICTION, new String [] {
                        SchemaNames.BASE_ATTR });
                       
                   
                    //-- custom mappings
                    String filename = RESOURCE_LOCATION + RESOURCE_NAME;
                    InputStream is = SchemaUnmarshaller.class.getResourceAsStream(filename);
                    Properties props = new Properties();
                    if (is != null) {
                        try {
                            props.load(is);
                        } catch (java.io.IOException iox) {
                            //-- just use built-in mappings
                        }
                    }
                                       
                    Enumeration keys = props.propertyNames();
                    while (keys.hasMoreElements()) {
                        String name =  (String) keys.nextElement();
                        StringTokenizer st = new StringTokenizer(props.getProperty(name), ",");
                        String[] atts = new String[st.countTokens()];
                        int index = 0;
                        while (st.hasMoreTokens()) {
                            atts[index++] = st.nextToken();
                        }
                        QNAME_TABLE.put(name, atts);
                    }
                   
                }
            }
        }
       
        private HashMap _prefixes = null;
       
        private RemappedPrefixes _parent = null;
       
        int depth = 0;
       
        public boolean isRemappedPrefix(String prefix) {
           
            if (prefix == null) prefix = "";
           
            if (_prefixes != null) {
                if (_prefixes.get(prefix) != null) return true;
            }
           
            if (_parent != null) {
                return _parent.isRemappedPrefix(prefix);
            }
            return false;
        }
       
        public RemappedPrefixes getParent() {
            return _parent;
        }
       
        public String getPrefixMapping(final String oldPrefix) {
           
            if (_prefixes != null) {
                String newPrefix = (String)_prefixes.get(oldPrefix);
                if (newPrefix != null)
                    return newPrefix;
            }
           
            if (_parent != null) {
                return _parent.getPrefixMapping(oldPrefix);
            }
           
            return oldPrefix;
        }
       
        public RemappedPrefixes newRemappedPrefixes() {
            RemappedPrefixes rp = new RemappedPrefixes();
            rp._parent = this;
            return rp;
        }
       
        public void addMapping(final String oldPrefix, final String newPrefix) {
            if (_prefixes == null) {
                _prefixes = new HashMap();
            }
            _prefixes.put(oldPrefix, newPrefix);
        }

        public String remapQName(String value) {
            if (value == null) {
                return null;
            }
           
            //-- non-default namespace
            int idx = value.indexOf(':');
            String prefix = "";
            if (idx >= 0) {
                prefix = value.substring(0, idx);
            } else {
                idx = -1;           
            }
            String newPrefix = getPrefixMapping(prefix);
            if (!prefix.equals(newPrefix)) {
                if (newPrefix.length() == 0) {
                    value = value.substring(idx + 1);
                } else {
                    value = newPrefix + ":" + value.substring(idx + 1);
                }
            }
           
            return value;
        } //-- remapValue
       
    }
   
} //-- SchemaUnmarshaller

TOP

Related Classes of org.exolab.castor.xml.schema.reader.SchemaUnmarshaller$RemappedPrefixes

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.