--- old/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/runtime/output/NamespaceContextImpl.java 2018-01-30 20:33:40.000000000 -0500 +++ /dev/null 2018-01-30 20:33:40.000000000 -0500 @@ -1,559 +0,0 @@ -/* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.xml.internal.bind.v2.runtime.output; - -import java.io.IOException; -import java.util.Collections; -import java.util.Iterator; - -import javax.xml.XMLConstants; -import javax.xml.stream.XMLStreamException; - -import com.sun.istack.internal.NotNull; -import com.sun.istack.internal.Nullable; -import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper; -import com.sun.xml.internal.bind.v2.WellKnownNamespace; -import com.sun.xml.internal.bind.v2.runtime.Name; -import com.sun.xml.internal.bind.v2.runtime.NamespaceContext2; -import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; - -import org.xml.sax.SAXException; - -/** - * Keeps track of in-scope namespace bindings for the marshaller. - * - *

- * This class is also used to keep track of tag names for each element - * for the marshaller (for the performance reason.) - * - * @author Kohsuke Kawaguchi - */ -public final class NamespaceContextImpl implements NamespaceContext2 { - private final XMLSerializer owner; - - private String[] prefixes = new String[4]; - private String[] nsUris = new String[4]; -// /** -// * True if the correponding namespace declaration is an authentic one that should be printed. -// * -// * False if it's a re-discovered in-scope namespace binding available at the ancestor elements -// * outside this marhsalling. The false value is used to incorporate the in-scope namespace binding -// * information from {@link #inscopeNamespaceContext}. When false, such a declaration does not need -// * to be printed, as it's already available in ancestors. -// */ -// private boolean[] visible = new boolean[4]; -// -// /** -// * {@link NamespaceContext} that informs this {@link XMLSerializer} about the -// * in-scope namespace bindings of the ancestor elements outside this marshalling. -// * -// *

-// * This is used when the marshaller is marshalling into a subtree that has ancestor -// * elements created outside the JAXB marshaller. -// * -// * Its {@link NamespaceContext#getPrefix(String)} is used to discover in-scope namespace -// * binding, -// */ -// private final NamespaceContext inscopeNamespaceContext; - - /** - * Number of URIs declared. Identifies the valid portion of - * the {@link #prefixes} and {@link #nsUris} arrays. - */ - private int size; - - private Element current; - - /** - * This is the {@link Element} whose prev==null. - * This element is used to hold the contextual namespace bindings - * that are assumed to be outside of the document we are marshalling. - * Specifically the xml prefix and any other user-specified bindings. - * - * @see NamespacePrefixMapper#getPreDeclaredNamespaceUris() - */ - private final Element top; - - /** - * Never null. - */ - private NamespacePrefixMapper prefixMapper = defaultNamespacePrefixMapper; - - /** - * True to allow new URIs to be declared. False otherwise. - */ - public boolean collectionMode; - - - public NamespaceContextImpl(XMLSerializer owner) { - this.owner = owner; - - current = top = new Element(this,null); - // register namespace URIs that are implicitly bound - put(XMLConstants.XML_NS_URI,XMLConstants.XML_NS_PREFIX); - } - - public void setPrefixMapper( NamespacePrefixMapper mapper ) { - if(mapper==null) - mapper = defaultNamespacePrefixMapper; - this.prefixMapper = mapper; - } - - public NamespacePrefixMapper getPrefixMapper() { - return prefixMapper; - } - - public void reset() { - current = top; - size = 1; - collectionMode = false; - } - - /** - * Returns the prefix index to the specified URI. - * This method allocates a new URI if necessary. - */ - public int declareNsUri( String uri, String preferedPrefix, boolean requirePrefix ) { - preferedPrefix = prefixMapper.getPreferredPrefix(uri,preferedPrefix,requirePrefix); - - if(uri.length()==0) { - for( int i=size-1; i>=0; i-- ) { - if(nsUris[i].length()==0) - return i; // already declared - if(prefixes[i].length()==0) { - // the default prefix is already taken. - // move that URI to another prefix, then assign "" to the default prefix. - assert current.defaultPrefixIndex==-1 && current.oldDefaultNamespaceUriIndex==-1; - - String oldUri = nsUris[i]; - String[] knownURIs = owner.nameList.namespaceURIs; - - if(current.baseIndex<=i) { - // this default prefix is declared in this context. just reassign it - - nsUris[i] = ""; - - int subst = put(oldUri,null); - - // update uri->prefix table if necessary - for( int j=knownURIs.length-1; j>=0; j-- ) { - if(knownURIs[j].equals(oldUri)) { - owner.knownUri2prefixIndexMap[j] = subst; - break; - } - } - if (current.elementLocalName != null) { - current.setTagName(subst, current.elementLocalName, current.getOuterPeer()); - } - return i; - } else { - // first, if the previous URI assigned to "" is - // a "known URI", remember what we've reallocated - // so that we can fix it when this context pops. - for( int j=knownURIs.length-1; j>=0; j-- ) { - if(knownURIs[j].equals(oldUri)) { - current.defaultPrefixIndex = i; - current.oldDefaultNamespaceUriIndex = j; - // assert commented out; too strict/not valid any more - // assert owner.knownUri2prefixIndexMap[j]==current.defaultPrefixIndex; - // update the table to point to the prefix we'll declare - owner.knownUri2prefixIndexMap[j] = size; - break; - } - } - if (current.elementLocalName!=null) { - current.setTagName(size, current.elementLocalName, current.getOuterPeer()); - } - - put(nsUris[i],null); - return put("", ""); - } - } - } - - // "" isn't in use - return put("", ""); - } else { - // check for the existing binding - for( int i=size-1; i>=0; i-- ) { - String p = prefixes[i]; - if(nsUris[i].equals(uri)) { - if (!requirePrefix || p.length()>0) - return i; - // declared but this URI is bound to empty. Look further - } - if(p.equals(preferedPrefix)) { - // the suggested prefix is already taken. can't use it - preferedPrefix = null; - } - } - - if(preferedPrefix==null && requirePrefix) - // we know we can't bind to "", but we don't have any possible name at hand. - // generate it here to avoid this namespace to be bound to "". - preferedPrefix = makeUniquePrefix(); - - // haven't been declared. allocate a new one - // if the preferred prefix is already in use, it should have been set to null by this time - return put(uri, preferedPrefix); - } - } - - public int force(@NotNull String uri, @NotNull String prefix) { - // check for the existing binding - - for( int i=size-1; i>=0; i-- ) { - if(prefixes[i].equals(prefix)) { - if(nsUris[i].equals(uri)) - return i; // found duplicate - else - // the prefix is used for another namespace. we need to declare it - break; - } - } - - return put(uri, prefix); - } - - /** - * Puts this new binding into the declared prefixes list - * without doing any duplicate check. - * - * This can be used to forcibly set namespace declarations. - * - *

- * Most of the time {@link #declareNamespace(String, String, boolean)} shall be used. - * - * @return - * the index of this new binding. - */ - public int put(@NotNull String uri, @Nullable String prefix) { - if(size==nsUris.length) { - // reallocate - String[] u = new String[nsUris.length*2]; - String[] p = new String[prefixes.length*2]; - System.arraycopy(nsUris,0,u,0,nsUris.length); - System.arraycopy(prefixes,0,p,0,prefixes.length); - nsUris = u; - prefixes = p; - } - if(prefix==null) { - if(size==1) - prefix = ""; // if this is the first user namespace URI we see, use "". - else { - // otherwise make up an unique name - prefix = makeUniquePrefix(); - } - } - nsUris[size] = uri; - prefixes[size] = prefix; - - return size++; - } - - private String makeUniquePrefix() { - String prefix; - prefix = new StringBuilder(5).append("ns").append(size).toString(); - while(getNamespaceURI(prefix)!=null) { - prefix += '_'; // under a rare circumstance there might be existing 'nsNNN', so rename them - } - return prefix; - } - - - public Element getCurrent() { - return current; - } - - /** - * Returns the prefix index of the specified URI. - * It is an error if the URI is not declared. - */ - public int getPrefixIndex( String uri ) { - for( int i=size-1; i>=0; i-- ) { - if(nsUris[i].equals(uri)) - return i; - } - throw new IllegalStateException(); - } - - /** - * Gets the prefix from a prefix index. - * - * The behavior is undefined if the index is out of range. - */ - public String getPrefix(int prefixIndex) { - return prefixes[prefixIndex]; - } - - public String getNamespaceURI(int prefixIndex) { - return nsUris[prefixIndex]; - } - - /** - * Gets the namespace URI that is bound to the specified prefix. - * - * @return null - * if the prefix is unbound. - */ - public String getNamespaceURI(String prefix) { - for( int i=size-1; i>=0; i-- ) - if(prefixes[i].equals(prefix)) - return nsUris[i]; - return null; - } - - /** - * Returns the prefix of the specified URI, - * or null if none exists. - */ - public String getPrefix( String uri ) { - if(collectionMode) { - return declareNamespace(uri,null,false); - } else { - for( int i=size-1; i>=0; i-- ) - if(nsUris[i].equals(uri)) - return prefixes[i]; - return null; - } - } - - public Iterator getPrefixes(String uri) { - String prefix = getPrefix(uri); - if(prefix==null) - return Collections.emptySet().iterator(); - else - return Collections.singleton(uri).iterator(); - } - - public String declareNamespace(String namespaceUri, String preferedPrefix, boolean requirePrefix) { - int idx = declareNsUri(namespaceUri,preferedPrefix,requirePrefix); - return getPrefix(idx); - } - - /** - * Number of total bindings declared. - */ - public int count() { - return size; - } - - - /** - * This model of namespace declarations maintain the following invariants. - * - *

- */ - public final class Element { - - public final NamespaceContextImpl context; - - /** - * {@link Element}s form a doubly-linked list. - */ - private final Element prev; - private Element next; - - private int oldDefaultNamespaceUriIndex; - private int defaultPrefixIndex; - - - /** - * The numbe of prefixes declared by ancestor {@link Element}s. - */ - private int baseIndex; - - /** - * The depth of the {@link Element}. - * - * This value is equivalent as the result of the following computation. - * - *
-         * int depth() {
-         *   int i=-1;
-         *   for(Element e=this; e!=null;e=e.prev)
-         *     i++;
-         *   return i;
-         * }
-         * 
- */ - private final int depth; - - - - private int elementNamePrefix; - private String elementLocalName; - - /** - * Tag name of this element. - * Either this field is used or the {@link #elementNamePrefix} and {@link #elementLocalName} pair. - */ - private Name elementName; - - /** - * Used for the binder. The JAXB object that corresponds to this element. - */ - private Object outerPeer; - private Object innerPeer; - - - private Element(NamespaceContextImpl context,Element prev) { - this.context = context; - this.prev = prev; - this.depth = (prev==null) ? 0 : prev.depth+1; - } - - /** - * Returns true if this {@link Element} represents the root element that - * we are marshalling. - */ - public boolean isRootElement() { - return depth==1; - } - - public Element push() { - if(next==null) - next = new Element(context,this); - next.onPushed(); - return next; - } - - public Element pop() { - if(oldDefaultNamespaceUriIndex>=0) { - // restore the old default namespace URI binding - context.owner.knownUri2prefixIndexMap[oldDefaultNamespaceUriIndex] = defaultPrefixIndex; - } - context.size = baseIndex; - context.current = prev; - // release references to user objects - outerPeer = innerPeer = null; - return prev; - } - - private void onPushed() { - oldDefaultNamespaceUriIndex = defaultPrefixIndex = -1; - baseIndex = context.size; - context.current = this; - } - - public void setTagName( int prefix, String localName, Object outerPeer ) { - assert localName!=null; - this.elementNamePrefix = prefix; - this.elementLocalName = localName; - this.elementName = null; - this.outerPeer = outerPeer; - } - - public void setTagName( Name tagName, Object outerPeer ) { - assert tagName!=null; - this.elementName = tagName; - this.outerPeer = outerPeer; - } - - public void startElement(XmlOutput out, Object innerPeer) throws IOException, XMLStreamException { - this.innerPeer = innerPeer; - if(elementName!=null) { - out.beginStartTag(elementName); - } else { - out.beginStartTag(elementNamePrefix,elementLocalName); - } - } - - public void endElement(XmlOutput out) throws IOException, SAXException, XMLStreamException { - if(elementName!=null) { - out.endTag(elementName); - elementName = null; - } else { - out.endTag(elementNamePrefix,elementLocalName); - } - } - - /** - * Gets the number of bindings declared on this element. - */ - public final int count() { - return context.size-baseIndex; - } - - /** - * Gets the prefix declared in this context. - * - * @param idx - * between 0 and {@link #count()} - */ - public final String getPrefix(int idx) { - return context.prefixes[baseIndex+idx]; - } - - /** - * Gets the namespace URI declared in this context. - * - * @param idx - * between 0 and {@link #count()} - */ - public final String getNsUri(int idx) { - return context.nsUris[baseIndex+idx]; - } - - public int getBase() { - return baseIndex; - } - - public Object getOuterPeer() { - return outerPeer; - } - - public Object getInnerPeer() { - return innerPeer; - } - - /** - * Gets the parent {@link Element}. - */ - public Element getParent() { - return prev; - } - } - - - /** - * Default {@link NamespacePrefixMapper} implementation used when - * it is not specified by the user. - */ - private static final NamespacePrefixMapper defaultNamespacePrefixMapper = new NamespacePrefixMapper() { - public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { - if( namespaceUri.equals(WellKnownNamespace.XML_SCHEMA_INSTANCE) ) - return "xsi"; - if( namespaceUri.equals(WellKnownNamespace.XML_SCHEMA) ) - return "xs"; - if( namespaceUri.equals(WellKnownNamespace.XML_MIME_URI) ) - return "xmime"; - return suggestion; - } - }; -}