All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.impl.values.XmlObjectBase Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

The newest version!
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.xmlbeans.impl.values;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamReader;

import org.apache.xmlbeans.xml.stream.XMLInputStream;

import java.math.BigInteger;
import java.math.BigDecimal;
import java.io.Serializable;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.lang.reflect.Array;
import java.util.Date;
import java.util.List;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.Calendar;
import java.util.Collection;
import java.util.ArrayList;

import org.apache.xmlbeans.impl.common.XmlLocale;
import org.apache.xmlbeans.impl.common.XmlWhitespace;
import org.apache.xmlbeans.impl.common.ValidationContext;
import org.apache.xmlbeans.impl.common.GlobalLock;
import org.apache.xmlbeans.impl.common.XmlErrorWatcher;
import org.apache.xmlbeans.impl.common.QNameHelper;
import org.apache.xmlbeans.impl.schema.SchemaTypeImpl;
import org.apache.xmlbeans.impl.schema.SchemaTypeVisitorImpl;
import org.apache.xmlbeans.impl.validator.Validator;
import org.apache.xmlbeans.XmlErrorCodes;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.SchemaAttributeModel;
import org.apache.xmlbeans.XmlAnySimpleType;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlDocumentProperties;
import org.apache.xmlbeans.SimpleValue;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.SchemaField;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlRuntimeException;
import org.apache.xmlbeans.QNameSet;
import org.apache.xmlbeans.GDate;
import org.apache.xmlbeans.GDuration;
import org.apache.xmlbeans.GDateSpecification;
import org.apache.xmlbeans.GDurationSpecification;
import org.apache.xmlbeans.StringEnumAbstractBase;
import org.apache.xmlbeans.XmlBeans;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.SchemaLocalAttribute;
import org.apache.xmlbeans.DelegateXmlObject;
import org.apache.xmlbeans.SchemaTypeLoader;

import org.w3c.dom.Node;

import org.xml.sax.ContentHandler;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.SAXException;

public abstract class XmlObjectBase implements TypeStoreUser, Serializable, XmlObject, SimpleValue
{
    public static final short MAJOR_VERSION_NUMBER = (short) 1; // for serialization
    public static final short MINOR_VERSION_NUMBER = (short) 1; // for serialization

    public static final short KIND_SETTERHELPER_SINGLETON = 1;
    public static final short KIND_SETTERHELPER_ARRAYITEM = 2;

    public final Object monitor()
    {
        if (has_store())
            return get_store().get_locale();
        return this;
    }

    private static XmlObjectBase underlying(XmlObject obj)
    {
        if (obj == null)
            return null;
        if (obj instanceof XmlObjectBase)
            return (XmlObjectBase)obj;
        while (obj instanceof DelegateXmlObject)
            obj = ((DelegateXmlObject)obj).underlyingXmlObject();
        if (obj instanceof XmlObjectBase)
            return (XmlObjectBase)obj;
        throw new IllegalStateException("Non-native implementations of XmlObject should extend FilterXmlObject or implement DelegateXmlObject");
    }

    public final XmlObject copy()
    {
        if (preCheck())
            return _copy();
        else
            synchronized (monitor())
            {
                return _copy();
            }
    }

    public final XmlObject copy(XmlOptions options)
    {
        if (preCheck())
            return _copy(options);
        else
            synchronized (monitor())
            {
                return _copy(options);
            }
    }

    private boolean preCheck()
    {
//        if ( isImmutable() )
//            return true;
        if ( has_store() )
            return get_store().get_locale().noSync();
        return false;
    }

    /**
     * Same as copy() but unsynchronized.
     * Warning: Using this method in mutithreaded environment can cause invalid states.
     */
    public final XmlObject _copy()
    {
        return _copy(null);
    }

    /**
     * Same as copy() but unsynchronized.
     * If Locale.COPY_USE_NEW_LOCALE is set in the options, a new locale will be created for the copy.
     * Warning: Using this method in mutithreaded environment can cause invalid states.
     */
    public final XmlObject _copy(XmlOptions xmlOptions)
    {
        // immutable objects don't get copied. They're immutable
        if (isImmutable())
            return this;

        check_orphaned();

        SchemaTypeLoader stl = get_store().get_schematypeloader();
        XmlObject result = (XmlObject)get_store().copy(stl, schemaType(), xmlOptions);

        return result;
    }

    public XmlDocumentProperties documentProperties()
        { XmlCursor cur = newCursorForce(); try { return cur.documentProperties(); } finally { cur.dispose(); } }

    /**
     * @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
     */
    public XMLInputStream newXMLInputStream()
        { return newXMLInputStream(null); }

    /**
     * @deprecated XMLInputStream was deprecated by XMLStreamReader from STaX - jsr173 API.
     */
    public XMLInputStream newXMLInputStream(XmlOptions options)
        { XmlCursor cur = newCursorForce(); try { return cur.newXMLInputStream(makeInnerOptions(options)); } finally { cur.dispose(); } }

    public XMLStreamReader newXMLStreamReader()
        { return newXMLStreamReader(null); }

    public XMLStreamReader newXMLStreamReader(XmlOptions options)
        { XmlCursor cur = newCursorForce(); try { return cur.newXMLStreamReader(makeInnerOptions(options)); } finally { cur.dispose(); } }

    public InputStream newInputStream()
        { return newInputStream(null); }

    public InputStream newInputStream(XmlOptions options)
        { XmlCursor cur = newCursorForce(); try { return cur.newInputStream(makeInnerOptions(options)); } finally { cur.dispose(); } }

    public Reader newReader()
        { return newReader(null); }

    public Reader newReader(XmlOptions options)
        { XmlCursor cur = newCursorForce(); try { return cur.newReader(makeInnerOptions(options)); } finally { cur.dispose(); } }

    public Node getDomNode()
        { XmlCursor cur = newCursorForce(); try { return cur.getDomNode(); } finally { cur.dispose(); } }

    public Node newDomNode()
        { return newDomNode(null); }

    public Node newDomNode(XmlOptions options)
        { XmlCursor cur = newCursorForce(); try { return cur.newDomNode(makeInnerOptions(options)); } finally { cur.dispose(); } }

    public void save(ContentHandler ch, LexicalHandler lh, XmlOptions options) throws SAXException
        { XmlCursor cur = newCursorForce(); try { cur.save(ch, lh, makeInnerOptions(options)); } finally { cur.dispose(); } }

    public void save(File file, XmlOptions options) throws IOException
        { XmlCursor cur = newCursorForce(); try { cur.save(file, makeInnerOptions(options)); } finally { cur.dispose(); } }

    public void save(OutputStream os, XmlOptions options) throws IOException
        { XmlCursor cur = newCursorForce(); try { cur.save(os, makeInnerOptions(options)); } finally { cur.dispose(); } }

    public void save(Writer w, XmlOptions options) throws IOException
        { XmlCursor cur = newCursorForce(); try { cur.save(w, makeInnerOptions(options)); } finally { cur.dispose(); } }

    public void save(ContentHandler ch, LexicalHandler lh) throws SAXException
        { save( ch, lh, null ); }

    public void save(File file) throws IOException
        { save( file, null ); }

    public void save(OutputStream os) throws IOException
        { save( os, null ); }

    public void save(Writer w) throws IOException
        { save( w, null ); }

    public void dump()
        { XmlCursor cur = newCursorForce(); try { cur.dump(); } finally { cur.dispose(); } }

    public XmlCursor newCursorForce()
    {
        synchronized (monitor())
        {
            return ensureStore().newCursor();
        }
    }

    private XmlObject ensureStore()
    {
        if ((_flags & FLAG_STORE) != 0)
            return this;

        check_dated();

        String value =
            (_flags & FLAG_NIL) != 0
                ? ""
                : compute_text( has_store() ? get_store() : null );

        XmlOptions options = new XmlOptions().setDocumentType(schemaType());

        XmlObject x = XmlObject.Factory.newInstance( options );

        XmlCursor c = x.newCursor();
        c.toNextToken();
        c.insertChars( value );

        return x;
    }

    private static XmlOptions makeInnerOptions(XmlOptions options)
    {
        XmlOptions innerOptions = new XmlOptions( options );
        innerOptions.put( XmlOptions.SAVE_INNER );
        return innerOptions;
    }

    public XmlCursor newCursor()
    {
        if ((_flags & FLAG_STORE) == 0)
            throw new IllegalStateException("XML Value Objects cannot create cursors");

        check_orphaned();

        // Note that new_cursor does not really need sync ....

        XmlLocale l = getXmlLocale();

        if (l.noSync())         { l.enter(); try { return get_store().new_cursor(); } finally { l.exit(); } }
        else synchronized ( l ) { l.enter(); try { return get_store().new_cursor(); } finally { l.exit(); } }

    }

    public abstract SchemaType schemaType();

    public SchemaType instanceType()
        { synchronized (monitor()) { return isNil() ? null : schemaType(); } }

    private SchemaField schemaField() {
        SchemaType st = schemaType();
        SchemaField field;

        // First check if this field has an anonymous type
        field = st.getContainerField();

        if (field == null)
            field = get_store().get_schema_field();

        return field;
    }

    /**
     * Use _voorVc when you want to throw a ValueOutOfRangeException when
     * validating a simple type.
     */
    private static final class ValueOutOfRangeValidationContext implements ValidationContext
    {
        public void invalid(String message)
        {
            throw new XmlValueOutOfRangeException( message );
        }

        public void invalid(String code, Object[] args)
        {
            throw new XmlValueOutOfRangeException( code, args );
        }
    }

    /**
     * Used to supply validation context for the validate_value methods
     */
    private static final class ImmutableValueValidationContext implements ValidationContext
    {
        private XmlObject _loc;
        private Collection _coll;
        ImmutableValueValidationContext(Collection coll, XmlObject loc)
        {
            _coll = coll;
            _loc = loc;
        }
        public void invalid(String message)
        {
           _coll.add(XmlError.forObject(message, _loc));
        }
        public void invalid(String code, Object[] args)
        {
            _coll.add(XmlError.forObject(code, args, _loc));
        }
    }

    public static final ValidationContext _voorVc = new ValueOutOfRangeValidationContext();

    public boolean validate()
        { return validate(null); }

    public boolean validate(XmlOptions options)
    {
        if ((_flags & FLAG_STORE) == 0)
        {
            if ((_flags & FLAG_IMMUTABLE) != 0)
            {
                return validate_immutable(options);
            }

            throw new IllegalStateException(
                    "XML objects with no underlying store cannot be validated");
        }

        synchronized (monitor())
        {
            if ((_flags & FLAG_ORPHANED) != 0)
                throw new XmlValueDisconnectedException();

            SchemaField field = schemaField();
            SchemaType type = schemaType();

            TypeStore typeStore = get_store();

            Validator validator =
                new Validator(
                    type, field, typeStore.get_schematypeloader(), options, null);

            typeStore.validate( validator );

            return validator.isValid();
        }
    }

    private boolean validate_immutable(XmlOptions options)
    {
        Collection errorListener = options == null ? null : (Collection)options.get(XmlOptions.ERROR_LISTENER);
        XmlErrorWatcher watcher = new XmlErrorWatcher(errorListener);
        if (!(schemaType().isSimpleType() || options != null &&
                options.hasOption(XmlOptions.VALIDATE_TEXT_ONLY)))
        {
            // cannot have any required attributes or elements
            SchemaProperty[] properties = schemaType().getProperties();
            for (int i = 0; i < properties.length; i++)
            {
                if (properties[i].getMinOccurs().signum() > 0)
                {
                    // KHK: error code?
                    if (properties[i].isAttribute())
                        watcher.add(XmlError.forObject(XmlErrorCodes.ELEM_COMPLEX_TYPE_LOCALLY_VALID$MISSING_REQUIRED_ATTRIBUTE, new Object[]{QNameHelper.pretty(properties[i].getName()), }, this));
                    else
                        watcher.add(XmlError.forObject(XmlErrorCodes.ELEM_COMPLEX_TYPE_LOCALLY_VALID$MISSING_ELEMENT, new Object[]{properties[i].getMinOccurs(), QNameHelper.pretty(properties[i].getName()), }, this));
                }
            }

            if (schemaType().getContentType() != SchemaType.SIMPLE_CONTENT)
                return !watcher.hasError(); // don't validate non-simple-content
        }

        String text = (String)_textsource;
        if (text == null)
            text = "";
        validate_simpleval(text, new ImmutableValueValidationContext(watcher, this));
        return !watcher.hasError();
    }

    protected void validate_simpleval(String lexical, ValidationContext ctx)
    {
        return;
    }

    private static XmlObject[] _typedArray(XmlObject[] input)
    {
        if (input.length == 0)
            return input;
        SchemaType commonType = input[0].schemaType();
        if (commonType.equals(XmlObject.type) || commonType.isNoType())
            return input;
        for (int i = 1; i < input.length; i++)
        {
            if (input[i].schemaType().isNoType())
                return input;
            commonType = commonType.getCommonBaseType(input[i].schemaType());
            if (commonType.equals(XmlObject.type))
                return input;
        }
        Class desiredClass = commonType.getJavaClass();
        while (desiredClass == null)
        {
            commonType = commonType.getBaseType();
            if (XmlObject.type.equals(commonType))
                return input;
            desiredClass = commonType.getJavaClass();
        }

        XmlObject[] result = (XmlObject[])Array.newInstance(desiredClass, input.length);
        System.arraycopy(input, 0, result, 0, input.length);
        return result;
    }

    public XmlObject[] selectPath ( String path )
    {
        return selectPath( path, null );
    }

    public XmlObject[] selectPath ( String path, XmlOptions options )
    {
        XmlObject [] selections;

        // all user-level code; doesn't need to be synchronized

        XmlCursor c = newCursor();

        if (c == null)
            throw new XmlValueDisconnectedException();

        try
        {
            c.selectPath( path, options );

            if (!c.hasNextSelection())
                selections = EMPTY_RESULT;
            else
            {
                selections = new XmlObject [ c.getSelectionCount() ];

                for (int i = 0 ; c.toNextSelection() ; i++)
                {
                    if ((selections[ i ] = c.getObject()) == null)
                    {
                        if ( !c.toParent() || (selections[ i ] = c.getObject()) == null )
                        throw
                            new XmlRuntimeException(
                                "Path must select only elements " +
                                    "and attributes" );
                    }
                }
            }
        }
        finally
        {
            c.dispose();
        }

         return _typedArray(selections);
    }

    public XmlObject[] execQuery ( String path )
    {
        return execQuery( path, null );
    }

    public XmlObject[] execQuery ( String queryExpr, XmlOptions options )
    {
        synchronized (monitor())
        {
            TypeStore typeStore = get_store();

            if (typeStore == null)
            {
                throw
                    new XmlRuntimeException(
                        "Cannot do XQuery on XML Value Objects" );
            }

            try
            {
                return _typedArray(typeStore.exec_query( queryExpr, options ));
            }
            catch (XmlException e)
            {
                throw new XmlRuntimeException( e );
            }
        }
    }

    public XmlObject changeType(SchemaType type)
    {
        if (type == null)
            throw new IllegalArgumentException( "Invalid type (null)" );

        if ((_flags & FLAG_STORE) == 0)
        {
            throw
                new IllegalStateException(
                    "XML Value Objects cannot have thier type changed" );
        }

        synchronized (monitor())
        {
            check_orphaned();
            return (XmlObject) get_store().change_type( type );
        }
    }

    public XmlObject substitute(QName name, SchemaType type)
    {
        if (name == null)
            throw new IllegalArgumentException( "Invalid name (null)" );

        if (type == null)
            throw new IllegalArgumentException( "Invalid type (null)" );

        if ((_flags & FLAG_STORE) == 0)
        {
            throw
                new IllegalStateException(
                    "XML Value Objects cannot be used with substitution" );
        }

        synchronized (monitor())
        {
            check_orphaned();
            return (XmlObject) get_store().substitute( name, type );
        }
    }

    private int _flags;
    private Object _textsource;

    protected XmlObjectBase()
    {
        _flags = FLAG_NILLABLE | FLAG_NIL;
    }

    public void init_flags(SchemaProperty prop)
    {
        if (prop == null) return;

        if (prop.hasDefault() == SchemaProperty.VARIABLE ||
            prop.hasFixed() == SchemaProperty.VARIABLE ||
            prop.hasNillable() == SchemaProperty.VARIABLE)
            return;

        _flags &= ~FLAGS_ELEMENT;
        _flags |=
            (prop.hasDefault() == SchemaProperty.NEVER ? 0 : TypeStore.HASDEFAULT) |
            (prop.hasFixed() == SchemaProperty.NEVER ? 0 : TypeStore.FIXED) |
            (prop.hasNillable() == SchemaProperty.NEVER ? 0 : TypeStore.NILLABLE) |
            (FLAG_NOT_VARIABLE);
    }

    {
        assert TypeStore.NILLABLE   == 1;
        assert TypeStore.HASDEFAULT == 2;
        assert TypeStore.FIXED      == 4;
    }

    private static final int FLAG_NILLABLE        = TypeStore.NILLABLE;
    private static final int FLAG_HASDEFAULT      = TypeStore.HASDEFAULT;
    private static final int FLAG_FIXED           = TypeStore.FIXED;
    private static final int FLAG_ATTRIBUTE       =     8;
    private static final int FLAG_STORE           =    16;
    private static final int FLAG_VALUE_DATED     =    32;
    private static final int FLAG_NIL             =    64;
    private static final int FLAG_NIL_DATED       =   128;
    private static final int FLAG_ISDEFAULT       =   256;
    private static final int FLAG_ELEMENT_DATED   =   512;
    private static final int FLAG_SETTINGDEFAULT  =  1024;
    private static final int FLAG_ORPHANED        =  2048;
    private static final int FLAG_IMMUTABLE       =  4096;
    private static final int FLAG_COMPLEXTYPE     =  8192;
    private static final int FLAG_COMPLEXCONTENT  = 16384;
    private static final int FLAG_NOT_VARIABLE    = 32768;
    private static final int FLAG_VALIDATE_ON_SET = 65536;


    /**
     * The three dated flags are always stacked:
     *     FLAG_ELEMENT_DATED implies FLAG_NIL_DATED is set
     *     FLAG_NIL_DATED implies FLAG_TEXT_DATED is set.
     * checkers work on the flags from top to bottom.
     */
    private static final int FLAGS_DATED =
            FLAG_VALUE_DATED | FLAG_NIL_DATED | FLAG_ELEMENT_DATED;

    /**
     * The three element status flags have one interrlationshiop:
     *     FLAG_FIXED implies FLAG_HASDEFAULT is set.
     * These flags are used when setting nils, defaults, strings.
     * Since an initial get implies setting from text, they're
     * also used during getting.
     */
    private static final int FLAGS_ELEMENT =
            FLAG_NILLABLE | FLAG_FIXED | FLAG_HASDEFAULT;


    /**
     * Called by restriction subclasses within their constructors to enable
     * complex type support.
     */
    protected void initComplexType(boolean complexType, boolean complexContent)
    {
        _flags |= (complexType ? FLAG_COMPLEXTYPE : 0) |
                  (complexContent ? FLAG_COMPLEXCONTENT : 0);
    }

    protected boolean _isComplexType()
        { return (_flags & FLAG_COMPLEXTYPE) != 0; }

    protected boolean _isComplexContent()
        { return (_flags & FLAG_COMPLEXCONTENT) != 0; }

    public void setValidateOnSet() {
        _flags |= FLAG_VALIDATE_ON_SET;
    }

    protected boolean _validateOnSet()
        { return (_flags & FLAG_VALIDATE_ON_SET) != 0; }

    /**
     * True if the value is nilled.
     */
    public final boolean isNil()
    {
        synchronized (monitor())
        {
            check_dated();
            return ((_flags & FLAG_NIL) != 0);
        }
    }

    /**
     * True if the value is fixed.
     */
    public final boolean isFixed()
    {
        check_element_dated();
        return ((_flags & FLAG_FIXED) != 0);
    }

    /**
     * True if the value is allowed to be nil.
     */
    public final boolean isNillable()
    {
        check_element_dated();
        return ((_flags & FLAG_NILLABLE) != 0);
    }

    /**
     * True if the value is currently defaulted.
     */
    public final boolean isDefaultable()
    {
        check_element_dated();
        return ((_flags & FLAG_HASDEFAULT) != 0);
    }

    /**
     * True if the value is currently defaulted.
     */
    public final boolean isDefault()
    {
        check_dated();
        return ((_flags & FLAG_ISDEFAULT) != 0);
    }


    /**
     * Nils the value.
     */
    public final void setNil()
    {
        synchronized (monitor())
        {
            set_prepare();

            // if we're not nillable, throw exception on setNil(true)
            if ((_flags & FLAG_NILLABLE) == 0 &&
                (_flags & FLAG_VALIDATE_ON_SET) != 0)
                throw new XmlValueNotNillableException();

            // the implementation should zero the value to reflect nil
            set_nil();

            // set the nil flag
            _flags |= FLAG_NIL;

            // ordinary commit except no clearing of nil flag
            if ((_flags & FLAG_STORE) != 0)
            {
                get_store().invalidate_text();
                _flags &= ~FLAGS_DATED;
                get_store().invalidate_nil();
            }
            else
            {
                _textsource = null;
            }
        }
    }

    /**
     * Used for situations where these flags must be passed on to
     * chained values. (See XmlAnySimpleType (allSimpleValue), union
     * implementations).
     */
    protected int elementFlags()
    {
        check_element_dated();
        return (_flags & FLAGS_ELEMENT);
    }

    /**
     * Used to make a free-standing xml simple value instance immutable.
     * This is a one-way street, and it is illegal to attempt to make a
     * value that is embedded in an xml document immutable.
     *
     * Once a value is marked as immutable, it is illegal to call setters
     * of any kind.
     */
    public void setImmutable()
    {
        if ((_flags & (FLAG_IMMUTABLE | FLAG_STORE)) != 0)
            throw new IllegalStateException();

        _flags |= FLAG_IMMUTABLE;
    }

    /**
     * Is this instance an immutable value?
     */
    public boolean isImmutable()
    {
        return (_flags & FLAG_IMMUTABLE) != 0;
    }




    // TEXTUSER implementation

    /**
     * Called to initialize the TypeStore associated with this XmlObject
     * implementation. If not called, this is a free-floating value holder.
     *
     * When a value is first attached, it is put in a completely invalidated
     * state.
     */
    public final void attach_store(TypeStore store)
    {
        _textsource = store;
        if ((_flags & FLAG_IMMUTABLE) != 0)
            throw new IllegalStateException();
        _flags |= FLAG_STORE | FLAG_VALUE_DATED | FLAG_NIL_DATED | FLAG_ELEMENT_DATED;

        if (store.is_attribute())
            _flags |= FLAG_ATTRIBUTE;

        if (store.validate_on_set())
            _flags |= FLAG_VALIDATE_ON_SET;
    }

    /**
     * Called by a TypeStore to indicate that the text has been
     * invalidated and should be fetched next time the value is
     * needed.
     */
    public final void invalidate_value()
    {
        assert((_flags & FLAG_STORE) != 0);
        _flags |= FLAG_VALUE_DATED;
    }

    public final boolean uses_invalidate_value()
    {
        SchemaType type = schemaType();
        return type.isSimpleType() || type.getContentType() == SchemaType.SIMPLE_CONTENT;
    }

    /**
     * Called by a TypeStore to indicate that the xsi:nil attribute
     * on the containing element (and possibly the text) has been
     * invalidated and both should be consulted next time the value
     * is needed.
     */
    public final void invalidate_nilvalue()
    {
        assert((_flags & FLAG_STORE) != 0);
        _flags |= FLAG_VALUE_DATED | FLAG_NIL_DATED;
    }

    /**
     * Called by a TypeStore to indicate that the element's default
     * value, nillability, fixedness, etc, may have changed by
     * virtue of the element order changing (and xsi:nil and the
     * text may have changed too); so the store should be consulted
     * next time any setter or getter is called.
     */
    public final void invalidate_element_order()
    {
        assert((_flags & FLAG_STORE) != 0);
        _flags |= FLAG_VALUE_DATED | FLAG_NIL_DATED | FLAG_ELEMENT_DATED;
    }

    /**
     * Used by the ComplexTypeImpl subclass to get direct access
     * to the store.
     */
    public final TypeStore get_store()
    {
        assert((_flags & FLAG_STORE) != 0);
        return (TypeStore)_textsource;
    }

    public final XmlLocale getXmlLocale ( )
    {
        return get_store().get_locale();
    }

    protected final boolean has_store()
    {
        return (_flags & FLAG_STORE) != 0;
    }

    /**
     * Called by a TypeStore to pull out the most reasonable
     * text value from us. This is done after we have invalidated
     * the store (typically when our value has been set).
     */
    public final String build_text(NamespaceManager nsm)
    {
        assert((_flags & FLAG_STORE) != 0);
        assert((_flags & FLAG_VALUE_DATED) == 0);
        if ((_flags & (FLAG_NIL | FLAG_ISDEFAULT)) != 0)
            return "";
        return compute_text(
                    nsm == null ? has_store() ? get_store() : null : nsm);
    }

    /**
     * A store will call back on build_nil after we've called invalidate_nil
     * and it needs to know what the nil value is.
     */
    public boolean build_nil()
    {
        assert((_flags & FLAG_STORE) != 0);
        assert((_flags & FLAG_VALUE_DATED) == 0);
        return (_flags & FLAG_NIL) != 0;
    }

    /**
     * A store will call back on validate_now to force us to look at
     * the text if we're in an invalid state. We're allowed to throw
     * an exception if the text isn't valid for our type.
     */
    public void validate_now()
    {
        check_dated();
    }

    /**
     * A store calls back here in order to force a disconnect.
     * After this is done, the object should be considered invalid.
     * Any attempt to access or set a value should result in an
     * exception.
     *
     * Note that this is how we handle deletions and xsi:type changes.
     */
    public void disconnect_store()
    {
        assert((_flags & FLAG_STORE) != 0);
        _flags |= FLAGS_DATED | FLAG_ORPHANED;
        // do NOT null out _textsource, because we need it non-null for synchronization
    }

    /**
     * A typestore user can create a new TypeStoreUser instance for
     * a given element child name as long as you also pass the
     * qname contained by the xsi:type attribute, if any.
     *
     * Note that we will ignore the xsiType if it turns out to be invalid.
     *
     * Returns null if there is no strongly typed information for that
     * given element (which implies, recusively, no strongly typed information
     * downwards).
     */
    public TypeStoreUser create_element_user(QName eltName, QName xsiType)
    {
        return
            (TypeStoreUser)
                ((SchemaTypeImpl) schemaType()).createElementType(
                    eltName, xsiType, get_store().get_schematypeloader() );

        /*
        SchemaTypeImpl stype = (SchemaTypeImpl)schemaType().getElementType(eltName, xsiType, get_store().get_schematypeloader());
        if (stype == null)
            return null;
        return (TypeStoreUser)stype.createUnattachedNode();
        */
    }

    /**
     * A typestore user can create a new TypeStoreUser instance for
     * a given attribute child, based on the attribute name.
     *
     * Returns null if there is no strongly typed information for that
     * given attributes.
     */
    public TypeStoreUser create_attribute_user(QName attrName)
    {
        return (TypeStoreUser)((SchemaTypeImpl)schemaType()).createAttributeType(attrName, get_store().get_schematypeloader());
    }

    public SchemaType get_schema_type()
    {
        return schemaType();
    }

    public SchemaType get_element_type(QName eltName, QName xsiType)
    {
        return schemaType().getElementType(
            eltName, xsiType, get_store().get_schematypeloader() );
    }

    public SchemaType get_attribute_type(QName attrName)
    {
        return schemaType().getAttributeType(
            attrName, get_store().get_schematypeloader() );
    }

    /**
     * Returns the default element text, if it's consistent. If it's
     * not consistent, returns null, and requires a visitor walk.
     *
     * Also returns null if there is no default at all (although
     * that can also be discovered via get_elementflags without
     * doing a walk).
     */
    public String get_default_element_text(QName eltName)
    {
        assert(_isComplexContent());
        if (!_isComplexContent())
            throw new IllegalStateException();

        SchemaProperty prop = schemaType().getElementProperty(eltName);
        if (prop == null)
            return "";
        return prop.getDefaultText();
    }

    /**
     * Returns the default attribute text for the attribute with
     * the given name, or null if no default.
     */
    public String get_default_attribute_text(QName attrName)
    {
        assert(_isComplexType());
        if (!_isComplexType())
            throw new IllegalStateException();

        SchemaProperty prop = schemaType().getAttributeProperty(attrName);
        if (prop == null)
            return "";
        return prop.getDefaultText();
    }

    /**
     * Returns the elementflags, if they're consistent. If they're
     * not, returns -1, and requires a vistor walk.
     */
    public int get_elementflags(QName eltName)
    {
        if (!_isComplexContent())
            return 0;

        SchemaProperty prop = schemaType().getElementProperty(eltName);
        if (prop == null)
            return 0;
        if (prop.hasDefault() == SchemaProperty.VARIABLE ||
            prop.hasFixed() == SchemaProperty.VARIABLE ||
            prop.hasNillable() == SchemaProperty.VARIABLE)
            return -1;
        return
            (prop.hasDefault() == SchemaProperty.NEVER ? 0 : TypeStore.HASDEFAULT) |
            (prop.hasFixed() == SchemaProperty.NEVER ? 0 : TypeStore.FIXED) |
            (prop.hasNillable() == SchemaProperty.NEVER ? 0 : TypeStore.NILLABLE);
    }

    /**
     * Returns the flags for the given attribute.
     */
    public int get_attributeflags(QName attrName)
    {
        if (!_isComplexType())
            return 0;
        SchemaProperty prop = schemaType().getAttributeProperty(attrName);
        if (prop == null)
            return 0;
        return
            (prop.hasDefault() == SchemaProperty.NEVER ? 0 : TypeStore.HASDEFAULT) |
            (prop.hasFixed() == SchemaProperty.NEVER ? 0 : TypeStore.FIXED);
        // BUGBUG: todo: hook up required?
    }

    /**
     * Returns false if child elements are insensitive to order;
     * if it returns true, you're required to call invalidate_element_order
     * on children to the right of any child order rearrangement.
     */
    public boolean is_child_element_order_sensitive()
    {
        if (!_isComplexType())
            return false;
        return schemaType().isOrderSensitive();
    }

    /**
     * Inserting a new element is always unambiguous except in one
     * situation: when adding an element after the last one with
     * that name (or the first one if there are none).
     *
     * In that case, add the element at the first possible slot
     * BEFORE any element whose qname is contained in the QNameSet
     * given. (If the QNameSet is empty, that means add the new
     * element at the very end.)
     *
     * If the returned QNameSet is null, treat it as if the QNameSet
     * contained all QNames, i.e., add the new element at the very
     * first position possible (adjacent to the last element of the
     * same name, or at the very first slot if it is the first elt
     * with that name).
     */
    public final QNameSet get_element_ending_delimiters(QName eltname)
    {
        SchemaProperty prop = schemaType().getElementProperty(eltname);
        if (prop == null)
            return null;
        return prop.getJavaSetterDelimiter();
    }

    /**
     * A typestore user can return a visitor that is used to compute
     * default text and elementflags for an arbitrary element.
     */
    public TypeStoreVisitor new_visitor()
    {
        if (!_isComplexContent())
            return null;
        return new SchemaTypeVisitorImpl(schemaType().getContentModel());
    }

    public SchemaField get_attribute_field(QName attrName)
    {
        SchemaAttributeModel model = schemaType().getAttributeModel();
        if (model == null)
            return null;
        return model.getAttribute(attrName);
    }


    /**
     * Setting a string preserves any noncanonical literal
     * representation. This is done by storing the actual
     * string in the underlying store after checking it
     * against the primitive type for validity.
     */
    protected void set_String(String v)
    {
        if ((_flags & FLAG_IMMUTABLE) != 0)
            throw new IllegalStateException();

        boolean wasNilled = ((_flags & FLAG_NIL) != 0);

        // update the underlying value from the string
        String wscanon = apply_wscanon(v);
        update_from_wscanon_text(wscanon);

        // Now store the literal text immediately in the underlying
        if ((_flags & FLAG_STORE) != 0)
        {
            _flags &= ~FLAG_VALUE_DATED;
            if ((_flags & FLAG_SETTINGDEFAULT) == 0)
                get_store().store_text(v);
            if (wasNilled)
                get_store().invalidate_nil();
        }
        else
            _textsource = v;
    }

    /**
     * Update the value based on complex content.
     */
    protected void update_from_complex_content()
    {
        throw new XmlValueNotSupportedException("Complex content");
    }

    /**
     * Utility to update the value based on a string that
     * was passed either from the text store or from the user.
     * This function handles the cases where there is a default
     * that must be applied, and where the value must match
     * a fixed value.
     */
    private final void update_from_wscanon_text(String v)
    {
        // Whitespace is default if this type treats this space as defaultable
        if ((_flags & FLAG_HASDEFAULT) != 0 &&  (_flags & FLAG_SETTINGDEFAULT) == 0)
        {
            // This isn't quite correct since the .equals("") test should be
            // done on the actual text, not the wscanon text
            if ((_flags & FLAG_ATTRIBUTE) == 0 && v.equals(""))
            {
                String def = get_store().compute_default_text();
                if (def == null)
                    throw new XmlValueOutOfRangeException();

                // protect against recursion with this flag
                _flags |= FLAG_SETTINGDEFAULT;
                try { this.setStringValue(def); }
                finally { _flags &= ~FLAG_SETTINGDEFAULT; }
                _flags &= ~FLAG_NIL;
                _flags |= FLAG_ISDEFAULT;
                return;
            }
        }
        // If we haven't returned yet, the default doesn't apply.

        // Ask underlying impl to parse ordinary non-default text
        set_text(v);
        _flags &= ~(FLAG_NIL | FLAG_ISDEFAULT);
    }

    /**
     * Types should return false if they don't treat the given
     * whitespace as a default value.
     */
    protected boolean is_defaultable_ws(String v)
    {
        return true;
    }

    /**
     * Returns the whitespace rule that will be applied before
     * building a string to pass to get_text().
     *
     * Overridden by subclasses that don't need their text
     * for set_text canonicalized; perhaps they already implement
     * scanners that can deal with whitespace, and they know
     * they have no regex pattern restrictions.
     */
    protected int get_wscanon_rule()
    {
        return SchemaType.WS_COLLAPSE;
    }

    /**
     * Called to canonicalize whitespace before calling set_text.
     *
     * Tries to avoid allocation when the string is already canonical, but
     * otherwise this is not particularly efficient. Hopefully the common
     * case is that we pass our wscanon rule to the store via fetch_text
     * and it's canonicalized before we even see it as a string.
     */
    private final String apply_wscanon(String v)
    {
        return XmlWhitespace.collapse(v, get_wscanon_rule());
    }

    /**
     * Called before every set and get, to ensure that we have
     * a correct picture of whether we're nillable, fixed, or
     * if we have a default that can be applied.
     */
    private final void check_element_dated()
    {
        if ((_flags & FLAG_ELEMENT_DATED) != 0 &&
            (_flags & FLAG_NOT_VARIABLE) == 0)
        {
            if ((_flags & FLAG_ORPHANED) != 0)
                throw new XmlValueDisconnectedException();

            int eltflags = get_store().compute_flags();
            // int eltflags = 0;
            _flags &= ~(FLAGS_ELEMENT | FLAG_ELEMENT_DATED);
            _flags |= eltflags;
        }
        if ((_flags & FLAG_NOT_VARIABLE) != 0)
            _flags &= ~(FLAG_ELEMENT_DATED);
    }

    /**
     * Describes the orphaned status of this object.
     */
    protected final boolean is_orphaned()
    {
        return (_flags & FLAG_ORPHANED) != 0;
    }

    /**
     * Called before every getter and setter on the strongly
     * typed classes to ensure that the object has not been
     * orphaned.
     */
    protected final void check_orphaned()
    {
        if (is_orphaned())
            throw new XmlValueDisconnectedException();
    }

    /**
     * Called prior to every get operation, to ensure
     * that the value being read is valid. If the value
     * has been invalidated, it is re-read from the underlying
     * text store, and this may cause an out of range exception.
     *
     * This method deals with nils, nillability, defaults, etc.
     */
    public final void check_dated()
    {
        if ((_flags & FLAGS_DATED) != 0)
        {
            if ((_flags & FLAG_ORPHANED) != 0)
                throw new XmlValueDisconnectedException();

            assert((_flags & FLAG_STORE) != 0);

            check_element_dated();

            if ((_flags & FLAG_ELEMENT_DATED) != 0)
            {
                int eltflags = get_store().compute_flags();
                _flags &= ~(FLAGS_ELEMENT | FLAG_ELEMENT_DATED);
                _flags |= eltflags;
            }

            boolean nilled = false;

            if ((_flags & FLAG_NIL_DATED) != 0)
            {
                if (get_store().find_nil())
                {
                    if ((_flags & FLAG_NILLABLE) == 0 &&
                        (_flags & FLAG_VALIDATE_ON_SET) != 0)
                        throw new XmlValueOutOfRangeException(); // nil not allowed

                    // let the implementation know that we're nil now
                    set_nil();

                    _flags |= FLAG_NIL;
                    nilled = true;
                }
                else
                {
                    _flags &= ~FLAG_NIL;
                }
                _flags &= ~FLAG_NIL_DATED;
            }

            if (!nilled)
            {
                String text;

                if ((_flags & FLAG_COMPLEXCONTENT) != 0 || (text = get_wscanon_text()) == null)
                    update_from_complex_content();
                else
                {
                    NamespaceContext.push(new NamespaceContext(get_store()));
                    try { update_from_wscanon_text(text); }
                    finally { NamespaceContext.pop(); }
                }
            }

            _flags &= ~FLAG_VALUE_DATED;
        }
    }

    /**
     * Called before every set operation (except for the
     * special case of setting a string) to:
     * (1) get the nillable, fixed, etc flags
     * (2) throw an exception if it's fixed (not for strings)
     */
    private final void set_prepare()
    {
        check_element_dated();
        if ((_flags & FLAG_IMMUTABLE) != 0)
            throw new IllegalStateException();
    }

    /**
     * Called after every set operation to invalidate
     * the attached raw text. Also, if we were dated,
     * we make a note that we're now current, since the
     * latest set beats the previous invalidate. Also,
     * if we were nil, we're no longer.
     */
    private final void set_commit()
    {
        boolean wasNilled = ((_flags & FLAG_NIL) != 0);
          _flags &= ~(FLAG_NIL | FLAG_ISDEFAULT);

        if ((_flags & FLAG_STORE) != 0)
        {
            _flags &= ~(FLAGS_DATED);
            get_store().invalidate_text();
            if (wasNilled)
                get_store().invalidate_nil();
        }
        else
        {
            _textsource = null;
        }
    }

    /**
     * Grabs the undelying litral representation, applying the
     * implementation's wscanon rule.
     * Null if not simple content.
     */
    public final String get_wscanon_text()
    {
        if ((_flags & FLAG_STORE) == 0)
        {
            return apply_wscanon((String)_textsource);
        }
        else return get_store().fetch_text(get_wscanon_rule());
    }

    /**
     * This should set the value of the type from text,
     * or throw an XmlValueOutOfRangeException if it can't.
     */
    abstract protected void set_text(String text);

    /**
     * This should clear the value, and set it to whatever
     * is supposed to be returned when the value is nilled.
     */
    abstract protected void set_nil();

    /**
     * This should return the canonical string value of the primitive.
     * Only called when non-nil.
     */
    abstract protected String compute_text(NamespaceManager nsm);

    // SIMPLE VALUE ACCESSORS BELOW -------------------------------------------

    // numerics: fractional
    public float getFloatValue()
        { BigDecimal bd = getBigDecimalValue(); return bd == null ? 0.0f : bd.floatValue(); }
    public double getDoubleValue()
        { BigDecimal bd = getBigDecimalValue(); return bd == null ? 0.0 : bd.doubleValue(); }
    public BigDecimal getBigDecimalValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
                new Object[] {getPrimitiveTypeName(), "numeric"}); }

    // numerics: integral
    public BigInteger getBigIntegerValue()
        { BigDecimal bd = bigDecimalValue(); return bd == null ? null : bd.toBigInteger(); }

    public byte getByteValue()
    {
        long l = getIntValue();
        if (l > Byte.MAX_VALUE) throw new XmlValueOutOfRangeException();
        if (l < Byte.MIN_VALUE) throw new XmlValueOutOfRangeException();
        return (byte)l;
    }

    public short getShortValue()
    {
        long l = getIntValue();
        if (l > Short.MAX_VALUE) throw new XmlValueOutOfRangeException();
        if (l < Short.MIN_VALUE) throw new XmlValueOutOfRangeException();
        return (short)l;
    }

    public int getIntValue()
    {
        long l = getLongValue();
        if (l > Integer.MAX_VALUE) throw new XmlValueOutOfRangeException();
        if (l < Integer.MIN_VALUE) throw new XmlValueOutOfRangeException();
        return (int)l;
    }
    private static final BigInteger _max = BigInteger.valueOf(Long.MAX_VALUE);
    private static final BigInteger _min = BigInteger.valueOf(Long.MIN_VALUE);

    public long getLongValue()
    {
        BigInteger b = getBigIntegerValue();
        if (b == null) return 0L;
        if (b.compareTo(_max) >= 0) throw new XmlValueOutOfRangeException();
        if (b.compareTo(_min) <= 0) throw new XmlValueOutOfRangeException();
        return b.longValue();
    }

    private static final XmlOptions _toStringOptions =
        buildInnerPrettyOptions();

    static final XmlOptions buildInnerPrettyOptions()
    {
        XmlOptions options = new XmlOptions();
        options.put( XmlOptions.SAVE_INNER );
        options.put( XmlOptions.SAVE_PRETTY_PRINT );
        options.put( XmlOptions.SAVE_AGGRESSIVE_NAMESPACES );
        options.put( XmlOptions.SAVE_USE_DEFAULT_NAMESPACE );
        return options;
    }

    /*
    private static final void dumpStack ( String msg )
    {
        try
        {
            java.io.FileOutputStream fos = new java.io.FileOutputStream( "C:\\ee.txt", true );
            java.io.PrintStream ps = new java.io.PrintStream( fos );
            ps.println( "======================================" );
            ps.println( msg );
            new Exception().printStackTrace( ps );
            ps.close();
            fos.close();
        }
        catch ( Exception e )
        {
        }

    }
    */

    public final String toString( )
    {
        synchronized (monitor())
        {
            return ensureStore().xmlText(_toStringOptions);
        }
    }

    public String xmlText()
    {
        return xmlText(null);
    }

    public String xmlText (XmlOptions options)
    {
        XmlCursor cur = newCursorForce();

        try
        {
            return cur.xmlText(makeInnerOptions(options));
        }
        finally
        {
            cur.dispose();
        }
    }

    // enums
    public StringEnumAbstractBase getEnumValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
                new Object[] {getPrimitiveTypeName(), "enum"}); }

    // various
    public String getStringValue()
    {
        if (isImmutable())
        {
            if ((_flags & FLAG_NIL) != 0)
                return null;
            return compute_text(null);
        }
        // Since complex-content types don't have a "natural" string value, we
        // emit the deeply concatenated, tag-removed content of the tag.
        synchronized (monitor())
        {
            if (_isComplexContent())
                return get_store().fetch_text(TypeStore.WS_PRESERVE);

            check_dated();
            if ((_flags & FLAG_NIL) != 0)
                return null;
            return compute_text(has_store() ? get_store() : null);
        }
    }

    /** @deprecated replaced with {@link #getStringValue} */
    public String stringValue()
        { return getStringValue(); }
    /** @deprecated replaced with {@link #getBooleanValue} */
    public boolean booleanValue()
        { return getBooleanValue(); }
    /** @deprecated replaced with {@link #getByteValue} */
    public byte byteValue()
        { return getByteValue(); }
    /** @deprecated replaced with {@link #getShortValue} */
    public short shortValue()
        { return getShortValue(); }
    /** @deprecated replaced with {@link #getIntValue} */
    public int intValue()
        { return getIntValue(); }
    /** @deprecated replaced with {@link #getLongValue} */
    public long longValue()
        { return getLongValue(); }
    /** @deprecated replaced with {@link #getBigIntegerValue} */
    public BigInteger bigIntegerValue()
        { return getBigIntegerValue(); }
    /** @deprecated replaced with {@link #getBigDecimalValue} */
    public BigDecimal bigDecimalValue()
        { return getBigDecimalValue(); }
    /** @deprecated replaced with {@link #getFloatValue} */
    public float floatValue()
        { return getFloatValue(); }
    /** @deprecated replaced with {@link #getDoubleValue} */
    public double doubleValue()
        { return getDoubleValue(); }
    /** @deprecated replaced with {@link #getByteArrayValue} */
    public byte[] byteArrayValue()
        { return getByteArrayValue(); }
    /** @deprecated replaced with {@link #getEnumValue} */
    public StringEnumAbstractBase enumValue()
        { return getEnumValue(); }
    /** @deprecated replaced with {@link #getCalendarValue} */
    public Calendar calendarValue()
        { return getCalendarValue(); }
    /** @deprecated replaced with {@link #getDateValue} */
    public Date dateValue()
        { return getDateValue(); }
    /** @deprecated replaced with {@link #getGDateValue} */
    public GDate gDateValue()
        { return getGDateValue(); }
    /** @deprecated replaced with {@link #getGDurationValue} */
    public GDuration gDurationValue()
        { return getGDurationValue(); }
    /** @deprecated replaced with {@link #getQNameValue} */
    public QName qNameValue()
        { return getQNameValue(); }
    /** @deprecated replaced with {@link #xgetListValue} */
    public List xlistValue()
        { return xgetListValue(); }
    /** @deprecated replaced with {@link #getListValue} */
    public List listValue()
        { return getListValue(); }
    /** @deprecated replaced with {@link #getObjectValue} */
    public Object objectValue()
        { return getObjectValue(); }

    /** @deprecated replaced with {@link #setStringValue} */
    public void set(String obj)
        { setStringValue(obj); }
    /** @deprecated replaced with {@link #setBooleanValue} */
    public void set(boolean v)
        { setBooleanValue(v); }
    /** @deprecated replaced with {@link #setByteValue} */
    public void set(byte v)
        { setByteValue(v); }
    /** @deprecated replaced with {@link #setShortValue} */
    public void set(short v)
        { setShortValue(v); }
    /** @deprecated replaced with {@link #setIntValue} */
    public void set(int v)
        { setIntValue(v); }
    /** @deprecated replaced with {@link #setLongValue} */
    public void set(long v)
        { setLongValue(v); }
    /** @deprecated replaced with {@link #setBigIntegerValue} */
    public void set(BigInteger obj)
        { setBigIntegerValue(obj); }
    /** @deprecated replaced with {@link #setBigDecimalValue} */
    public void set(BigDecimal obj)
        { setBigDecimalValue(obj); }
    /** @deprecated replaced with {@link #setFloatValue} */
    public void set(float v)
        { setFloatValue(v); }
    /** @deprecated replaced with {@link #setDoubleValue} */
    public void set(double v)
        { setDoubleValue(v); }
    /** @deprecated replaced with {@link #setByteArrayValue} */
    public void set(byte[] obj)
        { setByteArrayValue(obj); }
    /** @deprecated replaced with {@link #setEnumValue} */
    public void set(StringEnumAbstractBase obj)
        { setEnumValue(obj); }
    /** @deprecated replaced with {@link #setCalendarValue} */
    public void set(Calendar obj)
        { setCalendarValue(obj); }
    /** @deprecated replaced with {@link #setDateValue} */
    public void set(Date obj)
        { setDateValue(obj); }
    /** @deprecated replaced with {@link #setGDateValue} */
    public void set(GDateSpecification obj)
        { setGDateValue(obj); }
    /** @deprecated replaced with {@link #setGDurationValue} */
    public void set(GDurationSpecification obj)
        { setGDurationValue(obj); }
    /** @deprecated replaced with {@link #setQNameValue} */
    public void set(QName obj)
        { setQNameValue(obj); }
    /** @deprecated replaced with {@link #setListValue} */
    public void set(List obj)
        { setListValue(obj); }
    /** @deprecated replaced with {@link #setObjectValue} */
    public void objectSet(Object obj)
        { setObjectValue(obj); }

    public byte[] getByteArrayValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "byte[]"}); }
    public boolean getBooleanValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "boolean"}); }
    public GDate getGDateValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "Date"}); }
    public Date getDateValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "Date"}); }
    public Calendar getCalendarValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "Calendar"}); }
    public GDuration getGDurationValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "Duration"}); }
    public QName getQNameValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "QName"}); }
    public List getListValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "List"}); }
    public List xgetListValue()
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_S2J,
            new Object[] {getPrimitiveTypeName(), "List"}); }
    public Object getObjectValue()
        { return java_value(this); }

    // set this value
    public final void setBooleanValue(boolean v)
        { synchronized (monitor()) { set_prepare(); set_boolean(v); set_commit(); } }
    public final void setByteValue(byte v)
        { synchronized (monitor()) { set_prepare(); set_byte(v); set_commit(); } }
    public final void setShortValue(short v)
        { synchronized (monitor()) { set_prepare(); set_short(v); set_commit(); } }
    public final void setIntValue(int v)
        { synchronized (monitor()) { set_prepare(); set_int(v); set_commit(); } }
    public final void setLongValue(long v)
        { synchronized (monitor()) { set_prepare(); set_long(v); set_commit(); } }
    public final void setFloatValue(float v)
        { synchronized (monitor()) { set_prepare(); set_float(v); set_commit(); } }
    public final void setDoubleValue(double v)
        { synchronized (monitor()) { set_prepare(); set_double(v); set_commit(); } }
    public final void setByteArrayValue(byte[] obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_ByteArray(obj); set_commit(); } } }
    public final void setEnumValue(StringEnumAbstractBase obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_enum(obj); set_commit(); } } }
    public final void setBigIntegerValue(BigInteger obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_BigInteger(obj); set_commit(); } } }
    public final void setBigDecimalValue(BigDecimal obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_BigDecimal(obj); set_commit(); } } }
    public final void setCalendarValue(Calendar obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_Calendar(obj); set_commit(); } } }
    public final void setDateValue(Date obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_Date(obj); set_commit(); } } }
    public final void setGDateValue(GDate obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_GDate(obj); set_commit(); } } }
    public final void setGDateValue(GDateSpecification obj)
    { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_GDate(obj); set_commit(); } } }
    public final void setGDurationValue(GDuration obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_GDuration(obj); set_commit(); } } }
    public final void setGDurationValue(GDurationSpecification obj)
    { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_GDuration(obj); set_commit(); } } }
    public final void setQNameValue(QName obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_QName(obj); set_commit(); } } }
    public final void setListValue(List obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_list(obj); set_commit(); } } }
    public final void setStringValue(String obj)
        { if (obj == null) setNil(); else { synchronized (monitor()) { set_prepare(); set_String(obj); /* strings are special, so set_String does its own commit.*/ } } }

    public void setObjectValue(Object o)
    {
        if (o == null)
        {
            setNil();
            return;
        }

        if (o instanceof XmlObject)
            set( (XmlObject) o );
        else if (o instanceof String)
            setStringValue( (String) o );
        else if (o instanceof StringEnumAbstractBase)
            setEnumValue( (StringEnumAbstractBase) o );
        else if (o instanceof BigInteger)
            setBigIntegerValue( (BigInteger) o );
        else if (o instanceof BigDecimal)
            setBigDecimalValue( (BigDecimal) o );
        else if (o instanceof Byte)
            setByteValue( ((Byte)o).byteValue() );
        else if (o instanceof Short)
            setShortValue( ((Short)o).shortValue() );
        else if (o instanceof Integer)
            setIntValue( ((Integer)o).intValue() );
        else if (o instanceof Long)
            setLongValue( ((Long)o).longValue() );
        else if (o instanceof Boolean)
            setBooleanValue( ((Boolean)o).booleanValue() );
        else if (o instanceof Float)
            setFloatValue( ((Float)o).floatValue() );
        else if (o instanceof Double)
            setDoubleValue( ((Double)o).doubleValue() );
        else if (o instanceof Calendar)
            setCalendarValue( ((Calendar)o) );
        else if (o instanceof Date)
            setDateValue( (Date) o );
        else if (o instanceof GDateSpecification)
            setGDateValue( (GDateSpecification) o );
        else if (o instanceof GDurationSpecification)
            setGDurationValue( (GDurationSpecification) o );
        else if (o instanceof QName)
            setQNameValue( (QName) o );
        else if (o instanceof List)
            setListValue( (List) o );
        else if (o instanceof byte[])
            setByteArrayValue( (byte[]) o );
        else
        {
            throw
                new XmlValueNotSupportedException(
                    "Can't set union object of class : " +
                        o.getClass().getName() );
        }
    }

    public final void set_newValue(XmlObject obj)
    {
        if (obj == null || obj.isNil())
        {
            setNil();
            return;
        }

        primitive:
        if (obj instanceof XmlAnySimpleType)
        {
            XmlAnySimpleType v = (XmlAnySimpleType)obj;
            SchemaType instanceType = ((SimpleValue)v).instanceType();
            assert(instanceType != null) : "Nil case should have been handled already";

            // handle lists
            if (instanceType.getSimpleVariety() == SchemaType.LIST)
            {
                synchronized (monitor())
                {
                    set_prepare();
                    set_list(((SimpleValue)v).xgetListValue());
                    set_commit();
                    return;
                }
            }

            // handle atomic types
            synchronized (monitor())
            {
                assert(instanceType.getSimpleVariety() == SchemaType.ATOMIC);
                switch (instanceType.getPrimitiveType().getBuiltinTypeCode())
                {
                    default:
                        assert(false) : "encountered nonprimitive type.";
                    // case SchemaType.BTC_ANY_SIMPLE:  This is handled below...
                    // but we eventually want to handle it with a treecopy, so
                    // eventually we should break here.
                        break primitive;

                    case SchemaType.BTC_BOOLEAN:
                    {
                        boolean bool = ((SimpleValue)v).getBooleanValue();
                        set_prepare();
                        set_boolean(bool);
                        break;
                    }
                    case SchemaType.BTC_BASE_64_BINARY:
                    {
                        byte[] byteArr = ((SimpleValue)v).getByteArrayValue();
                        set_prepare();
                        set_b64(byteArr);
                        break;
                    }
                    case SchemaType.BTC_HEX_BINARY:
                    {
                        byte[] byteArr = ((SimpleValue)v).getByteArrayValue();
                        set_prepare();
                        set_hex(byteArr);
                        break;
                    }
                    case SchemaType.BTC_QNAME:
                    {
                        QName name = ((SimpleValue)v).getQNameValue();
                        set_prepare();
                        set_QName(name);
                        break;
                    }
                    case SchemaType.BTC_FLOAT:
                    {
                        float f = ((SimpleValue)v).getFloatValue();
                        set_prepare();
                        set_float(f);
                        break;
                    }
                    case SchemaType.BTC_DOUBLE:
                    {
                        double d = ((SimpleValue)v).getDoubleValue();
                        set_prepare();
                        set_double(d);
                        break;
                    }
                    case SchemaType.BTC_DECIMAL:
                    {
                        switch (instanceType.getDecimalSize())
                        {
                            case SchemaType.SIZE_BYTE:
                            {
                                byte b = ((SimpleValue)v).getByteValue();
                                set_prepare();
                                set_byte(b);
                                break;
                            }
                            case SchemaType.SIZE_SHORT:
                            {
                                short s = ((SimpleValue)v).getShortValue();
                                set_prepare();
                                set_short(s);
                                break;
                            }
                            case SchemaType.SIZE_INT:
                            {
                                int i = ((SimpleValue)v).getIntValue();
                                set_prepare();
                                set_int(i);
                                break;
                            }
                            case SchemaType.SIZE_LONG:
                            {
                                long l = ((SimpleValue)v).getLongValue();
                                set_prepare();
                                set_long(l);
                                break;
                            }
                            case SchemaType.SIZE_BIG_INTEGER:
                            {
                                BigInteger bi = ((SimpleValue)v).getBigIntegerValue();
                                set_prepare();
                                set_BigInteger(bi);
                                break;
                            }
                            default:
                            {
                                assert(false) : "invalid numeric bit count";
                                // fallthrough
                            }
                            case SchemaType.SIZE_BIG_DECIMAL:
                            {
                                BigDecimal bd = ((SimpleValue)v).getBigDecimalValue();
                                set_prepare();
                                set_BigDecimal(bd);
                                break;
                            }
                        }
                        break;
                    }
                    case SchemaType.BTC_ANY_URI:
                    {
                        String uri = v.getStringValue();
                        set_prepare();
                        set_text(uri);
                        break;
                    }
                    case SchemaType.BTC_NOTATION:
                    {
                        String s = v.getStringValue();
                        set_prepare();
                        set_notation(s);
                        break;
                    }
                    case SchemaType.BTC_DURATION:
                    {
                        GDuration gd = ((SimpleValue)v).getGDurationValue();
                        set_prepare();
                        set_GDuration(gd);
                        break;
                    }
                    case SchemaType.BTC_DATE_TIME:
                    case SchemaType.BTC_TIME:
                    case SchemaType.BTC_DATE:
                    case SchemaType.BTC_G_YEAR_MONTH:
                    case SchemaType.BTC_G_YEAR:
                    case SchemaType.BTC_G_MONTH_DAY:
                    case SchemaType.BTC_G_DAY:
                    case SchemaType.BTC_G_MONTH:
                    {
                        GDate gd = ((SimpleValue)v).getGDateValue();
                        set_prepare();
                        set_GDate(gd);
                        break;
                    }
                    case SchemaType.BTC_STRING:
                    {
                        String s = v.getStringValue();
                        set_prepare();
                        set_String(s);
                        break;
                    }
                    case SchemaType.BTC_ANY_SIMPLE:
                        {
                            boolean pushed = false;
                            if (!v.isImmutable())
                            {
                                pushed = true;
                                NamespaceContext.push(new NamespaceContext(v));
                            }
                            try
                            {
                                set_prepare();
                                set_xmlanysimple(v);
                            }
                            finally
                            {
                                if (pushed)
                                    NamespaceContext.pop();
                            }
                            break;
                        }
                }
                set_commit();
                return; // primitive node tree copy handled.
            }
        }

        throw new IllegalStateException("Complex type unexpected");
    }

    private TypeStoreUser setterHelper ( XmlObjectBase src )
    {
        check_orphaned();

        src.check_orphaned();

        return
            get_store().copy_contents_from( src.get_store() ).
                get_store().change_type( src.schemaType() );
    }

    public final XmlObject set(XmlObject src)
    {
        if (isImmutable())
            throw new IllegalStateException("Cannot set the value of an immutable XmlObject");

        XmlObjectBase obj = underlying(src);

        TypeStoreUser newObj = this;

        if (obj == null)
        {
            setNil();
            return this;
        }

        if (obj.isImmutable())
            setStringValue(obj.getStringValue());
        else
        {
            boolean noSyncThis = preCheck();
            boolean noSyncObj  = obj.preCheck();

            if (monitor() == obj.monitor())             // both are in the same locale
            {
                if (noSyncThis)                         // the locale is not sync
                    newObj = setterHelper( obj );
                else                                    // the locale is sync
                {
                    synchronized (monitor()) {
                        newObj = setterHelper( obj );
                    }
                }
            }
            else                                        // on different locale's
            {
                if (noSyncThis)
                {
                    if (noSyncObj)                      // both unsync
                    {
                        newObj = setterHelper( obj );
                    }
                    else                                // only obj is sync
                    {
                        synchronized (obj.monitor()) {
                            newObj = setterHelper( obj );
                        }
                    }
                }
                else
                {
                    if (noSyncObj)                      // only this is sync
                    {
                        synchronized (monitor()) {
                            newObj = setterHelper( obj );
                        }
                    }
                    else                                // both are sync can't avoid the global lock
                    {
                        boolean acquired = false;

                        try
                        {
                            // about to grab two locks: don't deadlock ourselves
                            GlobalLock.acquire();
                            acquired = true;

                            synchronized (monitor())
                            {
                                synchronized (obj.monitor())
                                {
                                    GlobalLock.release();
                                    acquired = false;

                                    newObj = setterHelper( obj );
                                }
                            }
                        }
                        catch (InterruptedException e)
                        {
                            throw new XmlRuntimeException(e);
                        }
                        finally
                        {
                            if (acquired)
                                GlobalLock.release();
                        }
                    }
                }
            }
        }

        return (XmlObject) newObj;
    }

    public final XmlObject generatedSetterHelperImpl(XmlObject src, QName propName, int index,
        short kindSetterHelper)
    {

        XmlObjectBase srcObj = underlying(src);

        if (srcObj == null)
        {
            synchronized (monitor())
            {
                XmlObjectBase target = getTargetForSetter(propName, index, kindSetterHelper);
                target.setNil();
                return target;
            }
        }

        if (srcObj.isImmutable())
        {
            synchronized (monitor())
            {
                XmlObjectBase target = getTargetForSetter(propName, index, kindSetterHelper);
                target.setStringValue(srcObj.getStringValue());
                return (XmlObject) target;
            }
        }


        boolean noSyncThis = preCheck();
        boolean noSyncObj  = srcObj.preCheck();

        if (monitor() == srcObj.monitor())             // both are in the same locale
        {
            if (noSyncThis)                         // the locale is not sync
            {
                return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
            }
            else                                    // the locale is sync
            {
                synchronized (monitor())
                {
                    return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
                }
            }
        }

                                               // on different locale's
        if (noSyncThis)
        {
            if (noSyncObj)                      // both unsync
            {
                return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
            }
            else                                // only obj is sync
            {
                synchronized (srcObj.monitor())
                {
                    return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
                }
            }
        }
        else
        {
            if (noSyncObj)                      // only this is sync
            {
                synchronized (monitor())
                {
                    return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
                }
            }
            else                                // both are sync can't avoid the global lock
            {
                boolean acquired = false;

                try
                {
                    // about to grab two locks: don't deadlock ourselves
                    GlobalLock.acquire();
                    acquired = true;

                    synchronized (monitor())
                    {
                        synchronized (srcObj.monitor())
                        {
                            GlobalLock.release();
                            acquired = false;

                            return (XmlObject)objSetterHelper(srcObj, propName, index, kindSetterHelper);
                        }
                    }
                }
                catch (InterruptedException e)
                {
                    throw new XmlRuntimeException(e);
                }
                finally
                {
                    if (acquired)
                        GlobalLock.release();
                }
            }
        }
    }

    private TypeStoreUser objSetterHelper(XmlObjectBase srcObj, QName propName, int index, short kindSetterHelper)
    {
        XmlObjectBase target = getTargetForSetter(propName, index, kindSetterHelper);

        target.check_orphaned();
        srcObj.check_orphaned();

        return target.get_store().copy_contents_from( srcObj.get_store() ).
                get_store().change_type( srcObj.schemaType() );
    }

    private XmlObjectBase getTargetForSetter(QName propName, int index, short kindSetterHelper)
    {
        switch (kindSetterHelper)
        {
            case KIND_SETTERHELPER_SINGLETON:
            {
                check_orphaned();
                XmlObjectBase target = null;
                target = (XmlObjectBase)get_store().find_element_user(propName, index);
                if (target == null)
                {
                    target = (XmlObjectBase)get_store().add_element_user(propName);
                }

                if (target.isImmutable())
                    throw new IllegalStateException("Cannot set the value of an immutable XmlObject");

                return target;
            }

            case KIND_SETTERHELPER_ARRAYITEM:
            {
                check_orphaned();
                XmlObjectBase target = null;
                target = (XmlObjectBase)get_store().find_element_user(propName, index);
                if (target == null)
                {
                    throw new IndexOutOfBoundsException();
                }

                if (target.isImmutable())
                    throw new IllegalStateException("Cannot set the value of an immutable XmlObject");

                return target;
            }

            default:
                throw new IllegalArgumentException("Unknown kindSetterHelper: " + kindSetterHelper);
        }
    }

    /**
     * Same as set() but unsynchronized.
     * Warning: Using this method in mutithreaded environment can cause invalid states.
     */
    public final XmlObject _set(XmlObject src)
    {
        if (isImmutable())
            throw new IllegalStateException("Cannot set the value of an immutable XmlObject");

        XmlObjectBase obj = underlying(src);

        TypeStoreUser newObj = this;

        if (obj == null)
        {
            setNil();
            return this;
        }

        if (obj.isImmutable())
            set(obj.stringValue());
        else
        {
            check_orphaned();
            obj.check_orphaned();

            newObj = get_store().copy_contents_from( obj.get_store() ).
                get_store().change_type( obj.schemaType() );
        }
        return (XmlObject) newObj;
    }

    protected void set_list(List list)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"List", getPrimitiveTypeName() }); }
    protected void set_boolean(boolean v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"boolean", getPrimitiveTypeName() }); }
    protected void set_byte(byte v)
        { set_int((int) v); }
    protected void set_short(short v)
        { set_int((int) v); }
    protected void set_int(int v)
        { set_long((long) v); }
    protected void set_long(long v)
        { set_BigInteger(BigInteger.valueOf(v)); }
    protected void set_char(char v)
        { set_String(Character.toString(v)); }
    protected void set_float(float v)
        { set_BigDecimal(new BigDecimal(v)); }
    protected void set_double(double v)
        { set_BigDecimal(new BigDecimal(v)); }

    protected void set_enum(StringEnumAbstractBase e)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"enum", getPrimitiveTypeName() }); }

    protected void set_ByteArray(byte[] b)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"byte[]", getPrimitiveTypeName() }); }
    protected void set_b64(byte[] b)
        { set_ByteArray(b); }
    protected void set_hex(byte[] b)
        { set_ByteArray(b); }
    protected void set_BigInteger(BigInteger v)
        { set_BigDecimal(new BigDecimal(v)); }
    protected void set_BigDecimal(BigDecimal v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"numeric", getPrimitiveTypeName() }); }
    protected void set_Date(Date v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"Date", getPrimitiveTypeName() }); }
    protected void set_Calendar(Calendar v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"Calendar", getPrimitiveTypeName() }); }
    protected void set_GDate(GDateSpecification v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"Date", getPrimitiveTypeName() }); }
    protected void set_GDuration(GDurationSpecification v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"Duration", getPrimitiveTypeName() }); }
    protected void set_ComplexXml(XmlObject v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"complex content", getPrimitiveTypeName() }); }
    protected void set_QName(QName v)
        { throw new XmlValueNotSupportedException(XmlErrorCodes.EXCEPTION_VALUE_NOT_SUPPORTED_J2S,
            new Object[] {"QName", getPrimitiveTypeName() }); }

    protected void set_notation(String v)
        { throw new XmlValueNotSupportedException(); }

    protected void set_xmlanysimple(XmlAnySimpleType v)
        { set_String(v.getStringValue()); }

    private final String getPrimitiveTypeName()
    {
        SchemaType type = schemaType();
        if (type.isNoType())
            return "unknown";
        SchemaType t = type.getPrimitiveType();
        if (t == null)
            return "complex";
        else
            return t.getName().getLocalPart();
    }

    private final boolean comparable_value_spaces(SchemaType t1, SchemaType t2)
    {
        assert(t1.getSimpleVariety() != SchemaType.UNION && t2.getSimpleVariety() != SchemaType.UNION);

        if (!t1.isSimpleType() && !t2.isSimpleType())
            return (t1.getContentType() == t2.getContentType());

        if (!t1.isSimpleType() || !t2.isSimpleType())
            return false;

        if (t1.getSimpleVariety() == SchemaType.LIST && t2.getSimpleVariety() == SchemaType.LIST)
            return true;

        if (t1.getSimpleVariety() == SchemaType.LIST || t2.getSimpleVariety() == SchemaType.LIST)
            return false;

        return (t1.getPrimitiveType().equals(t2.getPrimitiveType()));
    }

    private final boolean valueEqualsImpl(XmlObject xmlobj)
    {
        check_dated();

        SchemaType typethis = instanceType();
        SchemaType typeother = ((SimpleValue)xmlobj).instanceType();

        if (typethis == null && typeother == null) // detects nil
            return true;

        if (typethis == null || typeother == null)
            return false;

        if (!comparable_value_spaces(typethis, typeother))
            return false;

        if (xmlobj.schemaType().getSimpleVariety() == SchemaType.UNION)
            return (underlying(xmlobj)).equal_to(this);

        return equal_to(xmlobj);
    }

    public final boolean valueEquals(XmlObject xmlobj)
    {
        boolean acquired = false;
        try
        {
            if (isImmutable())
            {
                if (xmlobj.isImmutable())
                {
                    return valueEqualsImpl(xmlobj);
                }
                else
                {
                    synchronized (xmlobj.monitor())
                    {
                        return valueEqualsImpl(xmlobj);
                    }
                }
            }
            else
            {
                if (xmlobj.isImmutable() || monitor() == xmlobj.monitor())
                {
                    synchronized (monitor())
                    {
                        return valueEqualsImpl(xmlobj);
                    }
                }
                else
                {
                    GlobalLock.acquire();
                    acquired = true;
                    synchronized (monitor())
                    {
                        synchronized (xmlobj.monitor())
                        {
                            GlobalLock.release();
                            acquired = false;
                            return valueEqualsImpl(xmlobj);
                        }
                    }
                }
            }

        }
        catch (InterruptedException e)
        {
            throw new XmlRuntimeException(e);
        }
        finally
        {
            if (acquired)
                GlobalLock.release();
        }
    }

    /**
     * Implements Comparable. This compareTo is inconsistent with
     * equals unless isImmutable() is true.
     */
    public final int compareTo(Object obj)
    {
        int result = compareValue((XmlObject)obj); // can throw ClassCast
        if (result == 2)
            throw new ClassCastException();
        return result;
    }

    /**
     * Allowed to return 2 for incomparable.
     */
    private final int compareValueImpl(XmlObject xmlobj)
    {
        SchemaType type1, type2;

        try
        {
            type1 = instanceType();
            type2 = ((SimpleValue)xmlobj).instanceType();
        }
        catch (XmlValueOutOfRangeException e)
        {
            return 2;
        }

        if (type1 == null && type2 == null)
            return 0;
        if (type1 == null || type2 == null)
            return 2;

        if (!type1.isSimpleType() || type1.isURType())
            return 2;

        if (!type2.isSimpleType() || type2.isURType())
            return 2;

        type1 = type1.getPrimitiveType();
        type2 = type2.getPrimitiveType();

        // Different value spaces: different
        if (type1.getBuiltinTypeCode() != type2.getBuiltinTypeCode())
            return 2;

        // now we'll depend on our impl class to do the work
        return compare_to(xmlobj);
    }

    public final int compareValue(XmlObject xmlobj)
    {
        if (xmlobj == null)
            return 2;

        boolean acquired = false;
        try
        {
            if (isImmutable())
            {
                if (xmlobj.isImmutable())
                {
                    return compareValueImpl(xmlobj);
                }
                else
                {
                    synchronized (xmlobj.monitor())
                    {
                        return compareValueImpl(xmlobj);
                    }
                }
            }
            else
            {
                if (xmlobj.isImmutable() || monitor() == xmlobj.monitor())
                {
                    synchronized (monitor())
                    {
                        return compareValueImpl(xmlobj);
                    }
                }
                else
                {
                    GlobalLock.acquire();
                    acquired = true;
                    synchronized (monitor())
                    {
                        synchronized (xmlobj.monitor())
                        {
                            GlobalLock.release();
                            acquired = false;
                            return compareValueImpl(xmlobj);
                        }
                    }
                }
            }

        }
        catch (InterruptedException e)
        {
            throw new XmlRuntimeException(e);
        }
        finally
        {
            if (acquired)
                GlobalLock.release();
        }
    }
    /**
     * This implementation of compare_to is allowed to do two
     * unusual things:
     * (1) it can assume that the xmlobj passed has a primitive
     *     type underlying the instance type that matches the
     *     current instance, and that neither is nil.
     * (2) it is allowed to return 2 for "incomparable";
     *     it should not throw an exception.
     */
    protected int compare_to(XmlObject xmlobj)
    {
        if (equal_to(xmlobj))
            return 0;
        return 2;
    }

    protected abstract boolean equal_to(XmlObject xmlobj);

    protected abstract int value_hash_code();

    public int valueHashCode()
    {
        synchronized (monitor())
        {
            return value_hash_code();
        }
    }


    public boolean isInstanceOf(SchemaType type)
    {
        SchemaType myType;

        if (type.getSimpleVariety() != SchemaType.UNION)
        {
            for (myType = instanceType(); myType != null; myType = myType.getBaseType())
                if (type == myType)
                    return true;
            return false;
        }
        else
        {
            Set ctypes = new HashSet(Arrays.asList(type.getUnionConstituentTypes()));
            for (myType = instanceType(); myType != null; myType = myType.getBaseType())
                if (ctypes.contains(myType))
                    return true;
            return false;
        }
    }

    public final boolean equals(Object obj)
    {
        if (!isImmutable())
            return super.equals(obj);

        if (!(obj instanceof XmlObject))
            return false;

        XmlObject xmlobj = (XmlObject)obj;
        if (!xmlobj.isImmutable())
            return false;

        return valueEquals(xmlobj);
    }

    public final int hashCode()
    {
        if (!isImmutable())
            return super.hashCode();

        synchronized (monitor())
        {
            if (isNil())
                return 0;

            return value_hash_code();
        }
    }

    private static final XmlObject[] EMPTY_RESULT = new XmlObject[0];

    /**
     * Selects the contents of the children elements with the given name.
     */
    public XmlObject[] selectChildren(QName elementName)
    {
        XmlCursor xc = this.newCursor();
        try
        {
            if (!xc.isContainer())
                return EMPTY_RESULT;

            List result = new ArrayList();

            if (xc.toChild(elementName))
            {
                // look for elements
                do
                {
                    result.add(xc.getObject());
                }
                while (xc.toNextSibling(elementName));
            }
            if (result.size() == 0)
                return EMPTY_RESULT;
            else
                return (XmlObject[]) result.toArray(EMPTY_RESULT);
        }
        finally
        {
            xc.dispose();
        }
    }

    /**
     * Selects the contents of the children elements with the given name.
     */
    public XmlObject[] selectChildren(String elementUri, String elementLocalName)
    {
        return selectChildren(new QName(elementUri, elementLocalName));
    }

    /**
     * Selects the contents of the children elements that are contained in the elementNameSet.
     */
    public XmlObject[] selectChildren(QNameSet elementNameSet)
    {
        if (elementNameSet==null)
            throw new IllegalArgumentException();

        XmlCursor xc = this.newCursor();
        try
        {
            if (!xc.isContainer())
                return EMPTY_RESULT;

            List result = new ArrayList();

            if (xc.toFirstChild())
            {
                // look for elements
                do
                {
                    assert xc.isContainer();
                    if (elementNameSet.contains(xc.getName()))
                    {
                        result.add(xc.getObject());
                    }
                }
                while (xc.toNextSibling());
            }
            if (result.size() == 0)
                return EMPTY_RESULT;
            else
                return (XmlObject[]) result.toArray(EMPTY_RESULT);
        }
        finally
        {
            xc.dispose();
        }
    }

    /**
     * Selects the content of the attribute with the given name.
     */
    public XmlObject selectAttribute(QName attributeName)
    {
        XmlCursor xc = this.newCursor();

        try
        {
            if (!xc.isContainer())
                return null;

            if (xc.toFirstAttribute())
            {
                //look for attributes
                do
                {
                    if (xc.getName().equals(attributeName))
                    {
                        return xc.getObject();
                    }
                }
                while (xc.toNextAttribute());
            }
            return null;
        }
        finally
        {
            xc.dispose();
        }
    }

    /**
     * Selects the content of the attribute with the given name.
     */
    public XmlObject selectAttribute(String attributeUri, String attributeLocalName)
    {
        return selectAttribute(new QName(attributeUri, attributeLocalName));
    }

    /**
     * Selects the contents of the attributes that are contained in the elementNameSet.
     */
    public XmlObject[] selectAttributes(QNameSet attributeNameSet)
    {
        if (attributeNameSet==null)
            throw new IllegalArgumentException();

        XmlCursor xc = this.newCursor();
        try
        {
            if (!xc.isContainer())
                return EMPTY_RESULT;

            List result = new ArrayList();

            if (xc.toFirstAttribute())
            {
                //look for attributes
                do
                {
                    if (attributeNameSet.contains(xc.getName()))
                    {
                        result.add(xc.getObject());
                    }
                }
                while (xc.toNextAttribute());
            }

            if (result.size() == 0)
                return EMPTY_RESULT;
            else
                return (XmlObject[]) result.toArray(EMPTY_RESULT);
        }
        finally
        {
            xc.dispose();
        }
    }

    /**
     * This method can writeReplace either an unwrapped XmlObjectBase
     * or an XBean proxy.  A "true" argument means unwrapped.
     *
     * The serialization strategy for XmlObjects is this:
     *
     * (1) Only the root XmlObject for a document actually gets
     *     fully serialized; it is serialized as a SerializedRootObject,
     *     which simply saves itself as XML text.
     *
     * (2) Interior XmlObjects get serialized as a reference to the
     *     root XmlObject for their document, plus an integer which
     *     indicates the position of the XmlObject within the owner
     *     document. This pair is stored as a SerializedInteriorObject.
     *
     * Both objects can be maked as wrapped or unwrapped. If wrapped,
     * then the proxy is returned when deserializing; if unwrapped, then
     * the proxy is stripped when deserializing.
     */
    public Object writeReplace()
    {
        synchronized (monitor())
        {
            if (isRootXmlObject())
                return new SerializedRootObject(this);

            return new SerializedInteriorObject(this, getRootXmlObject());
        }
    }

    /**
     * True if the object is at the root of the document.
     */
    private boolean isRootXmlObject()
    {
        XmlCursor cur = newCursor();
        if (cur == null)
            return false;

        boolean result = !cur.toParent();
        cur.dispose();
        return result;
    }

    /**
     * Gets the root XmlObject for this document.
     */
    private XmlObject getRootXmlObject()
    {
        XmlCursor cur = newCursor();
        if (cur == null)
            return this;
        cur.toStartDoc();
        XmlObject result = cur.getObject();
        cur.dispose();
        return result;
    }

    /**
     * Serializable rewrite object that knows how to resolve
     * to an XmlObjectBase or a proxy for the root object of
     * a document.
     */
    private static class SerializedRootObject implements Serializable
    {
        private static final long serialVersionUID = 1;

        transient Class _xbeanClass;
        transient XmlObject _impl;

        private SerializedRootObject()
        {
        }

        private SerializedRootObject(XmlObject impl)
        {
            _xbeanClass = impl.schemaType().getJavaClass();
            _impl = impl;
        }

        private void writeObject(ObjectOutputStream out) throws IOException
        {
            out.writeObject(_xbeanClass);
            // the first short is written out for backwards compatibility
            // it will always be zero for objects written with
            // this code, but it used to be the first 2 bytes of the
            // writeUTF() method
            out.writeShort((short)0);
            out.writeShort(MAJOR_VERSION_NUMBER);
            out.writeShort(MINOR_VERSION_NUMBER);
            // CR122401 - need to use writeObject instead of writeUTF
            // for xmlText as writeUTF has a length limitation of
            // 65535 bytes
            String xmlText = _impl.xmlText();
            out.writeObject(xmlText);
            out.writeBoolean(false);
        }

        private void readObject(ObjectInputStream in) throws IOException
        {
            try
            {
                // read class object first - this is
                // first just for historical reasons - really
                // it would be better to have the version numbers
                // first
                _xbeanClass = (Class)in.readObject();

                int utfBytes = in.readUnsignedShort();

                // determine version numbers
                // if utfBytes is non-zero then we default to 0.0
                // otherwise expect major and minor version numbers
                // to be next entries in stream
                int majorVersionNum = 0;
                int minorVersionNum = 0;
                if (utfBytes == 0)
                {
                    majorVersionNum = in.readUnsignedShort();
                    minorVersionNum = in.readUnsignedShort();
                }

                String xmlText = null;
                switch (majorVersionNum)
                {
                    case 0: // original, unnumbered version
                            // minorVersionNum is always zero
                        xmlText = readObjectV0(in, utfBytes);
                        in.readBoolean(); // ignored
                        break;

                    case 1:
                        switch (minorVersionNum)
                        {
                            case 1:
                                xmlText = (String)in.readObject();
                                in.readBoolean(); // ignored
                                break;

                            default:
                                throw new IOException("Deserialization error: " +
                                        "version number " + majorVersionNum + "." +
                                        minorVersionNum + " not supported.");
                        }
                        break;

                    default:
                        throw new IOException("Deserialization error: " +
                                "version number " + majorVersionNum + "." +
                                minorVersionNum + " not supported.");
                }

                XmlOptions opts = new XmlOptions().setDocumentType(XmlBeans.typeForClass(_xbeanClass));
                _impl = XmlBeans.getContextTypeLoader().parse(xmlText, null, opts);
            }
            catch (Exception e)
            {
                throw (IOException)(new IOException(e.getMessage()).initCause(e));
            }
        }

        // this method is for reading the UTF-8 String that used to be
        // written out for a serialized XmlObject according to the
        // original format before this fix, i.e. it expects it
        // to have been written using the following algorithm:
        //
        // writeObject(Class object)
        // writeUTF(xmlText of object as String)
        // writeBoolean()
        //
        // this method is passed the original input stream positioned as though
        // it had just read the class object plus the next 2 bytes. Those 2
        // bytes are interpreted as an unsigned short saying how many more
        // bytes there are representing the bytes of the UTF-8-formatted String;
        // this value is passed in as the argument utfBytes
        private String readObjectV0(ObjectInputStream in, int utfBytes)
                throws IOException
        {
            // allow an extra 2 bytes up front for the unsigned short
            byte[] bArray = new byte[utfBytes+2];

            // for format of these first 2 bytes see
            // Java API docs - DataOutputStream.writeShort()
            bArray[0] = (byte)( 0xff & (utfBytes >> 8) );
            bArray[1] = (byte)( 0xff & utfBytes );

            // read the next numBytes bytes from the input stream
            // into the byte array starting at offset 2; this may
            // take multiple calls to read()
            int totalBytesRead = 0;
            int numRead;
            while (totalBytesRead < utfBytes)
            {
                numRead =
                    in.read(bArray, 2+totalBytesRead, utfBytes-totalBytesRead);
                if (numRead == -1) // reached end of stream
                    break;

                totalBytesRead += numRead;
            }

            if (totalBytesRead != utfBytes)
            {
                throw new IOException("Error reading backwards compatible " +
                        "XmlObject: number of bytes read (" + totalBytesRead +
                        ") != number expected (" + utfBytes + ")" );
            }

            // now set up a DataInputStream to read those
            // bytes as a UTF-8 String i.e. as though we'd never
            // read the first 2 bytes from the original stream
            DataInputStream dis = null;
            String str = null;
            try
            {
                dis = new DataInputStream(new ByteArrayInputStream(bArray));
                str = dis.readUTF();
            }
            finally
            {
                if (dis != null)
                    dis.close();
            }

            return str;
        }

        private Object readResolve() throws ObjectStreamException
        {
            return _impl;
        }
    }

    /**
     * Serializable rewrite object that knows how to resolve
     * to an XmlObjectBase or a proxy for an interior position
     * within a document.
     */
    private static class SerializedInteriorObject implements Serializable
    {
        private static final long serialVersionUID = 1;

        transient XmlObject _impl;
        transient XmlObject _root;

        private SerializedInteriorObject()
        {
        }

        private SerializedInteriorObject(XmlObject impl, XmlObject root)
        {
            _impl = impl;
            _root = root;
        }

        private void writeObject(ObjectOutputStream out) throws IOException
        {
            out.writeObject(_root);
            out.writeBoolean(false);
            out.writeInt(distanceToRoot());
        }

        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
        {
            _root = (XmlObject)in.readObject();
            in.readBoolean();
            _impl = objectAtDistance(in.readInt());
        }

        private Object readResolve() throws ObjectStreamException
        {
            return _impl;
        }

        private int distanceToRoot()
        {
            XmlCursor cur = _impl.newCursor();
            int count = 0;
            while (!cur.toPrevToken().isNone())
            {
                if (!cur.currentTokenType().isNamespace())
                {
                    count += 1;
                    // System.out.println("Count: " + count + " " + cur.currentTokenType().toString() + " " + QName.pretty(cur.getName()));
                }
            }
            cur.dispose();
            return count;
        }

        private XmlObject objectAtDistance(int count)
        {
            XmlCursor cur = _root.newCursor();
            while (count > 0)
            {
                cur.toNextToken();
                if (!cur.currentTokenType().isNamespace())
                {
                    count -= 1;
                    // System.out.println("Count: " + count + " " + cur.currentTokenType().toString() + " " + QName.pretty(cur.getName()));
                }
            }
            XmlObject result = cur.getObject();
            cur.dispose();
            return result;
        }
    }

    protected static Object java_value(XmlObject obj)
    {
        if (obj.isNil())
            return null;

        if (!(obj instanceof XmlAnySimpleType))
            return obj;

        SchemaType instanceType = ((SimpleValue)obj).instanceType();
        assert(instanceType != null) : "Nil case should have been handled above";

        // handle lists
        if (instanceType.getSimpleVariety() == SchemaType.LIST)
            return ((SimpleValue)obj).getListValue();

        SimpleValue base = (SimpleValue)obj;

        switch (instanceType.getPrimitiveType().getBuiltinTypeCode())
        {
            case SchemaType.BTC_BOOLEAN:
                return base.getBooleanValue() ? Boolean.TRUE : Boolean.FALSE;

            case SchemaType.BTC_BASE_64_BINARY:
            case SchemaType.BTC_HEX_BINARY:
                return base.getByteArrayValue();

            case SchemaType.BTC_QNAME:
                return base.getQNameValue();

            case SchemaType.BTC_FLOAT:
                return new Float(base.getFloatValue());

            case SchemaType.BTC_DOUBLE:
                return new Double(base.getDoubleValue());

            case SchemaType.BTC_DECIMAL:
            {
                switch (instanceType.getDecimalSize())
                {
                    case SchemaType.SIZE_BYTE:
                        return new Byte(base.getByteValue());

                    case SchemaType.SIZE_SHORT:
                        return new Short(base.getShortValue());

                    case SchemaType.SIZE_INT:
                        return new Integer(base.getIntValue());

                    case SchemaType.SIZE_LONG:
                        return new Long(base.getLongValue());

                    case SchemaType.SIZE_BIG_INTEGER:
                        return base.getBigIntegerValue();

                    default:
                        assert(false) : "invalid numeric bit count";
                        // fallthrough
                    case SchemaType.SIZE_BIG_DECIMAL:
                        return base.getBigDecimalValue();
                }
            }
            case SchemaType.BTC_ANY_URI:
                return base.getStringValue();

            case SchemaType.BTC_DURATION:
                return base.getGDurationValue();

            case SchemaType.BTC_DATE_TIME:
            case SchemaType.BTC_TIME:
            case SchemaType.BTC_DATE:
            case SchemaType.BTC_G_YEAR_MONTH:
            case SchemaType.BTC_G_YEAR:
            case SchemaType.BTC_G_MONTH_DAY:
            case SchemaType.BTC_G_DAY:
            case SchemaType.BTC_G_MONTH:
                return base.getCalendarValue();

            default:
                assert(false) : "encountered nonprimitive type.";
                // fallthrough

            // NB: for string enums we just do java.lang.String
            // when in the context of unions. It's easier on users.
            case SchemaType.BTC_NOTATION:
            case SchemaType.BTC_STRING:
            case SchemaType.BTC_ANY_SIMPLE:
                // return base.getStringValue();
            return base.getStringValue();
        }
    }

    /**
     * Called by code generated code to get the default attribute value
     * for a given attribute name, or null if none.
     */
    protected XmlAnySimpleType get_default_attribute_value(QName name)
    {
        SchemaType sType = schemaType();
        SchemaAttributeModel aModel = sType.getAttributeModel();
        if (aModel == null)
            return null;
        SchemaLocalAttribute sAttr = aModel.getAttribute(name);
        if (sAttr == null)
            return null;
        return sAttr.getDefaultValue();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy