src/share/jaxws_classes/com/sun/xml/internal/txw2/StartTag.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.xml.internal.txw2;
    28 import javax.xml.namespace.QName;
    31 /**
    32  * Start tag.
    33  *
    34  * <p>
    35  * This object implements {@link NamespaceResolver} for attribute values.
    36  *
    37  * @author Kohsuke Kawaguchi
    38  */
    39 class StartTag extends Content implements NamespaceResolver {
    40     /**
    41      * Tag name of the element.
    42      *
    43      * <p>
    44      * This field is also used as a flag to indicate
    45      * whether the start tag has been written.
    46      * This field is initially set to non-null, and
    47      * then reset to null when it's written.
    48      */
    49     private String uri;
    50     // but we keep the local name non-null so that
    51     // we can diagnose an error
    52     private final String localName;
    54     private Attribute firstAtt;
    55     private Attribute lastAtt;
    57     /**
    58      * If this {@link StartTag} has the parent {@link ContainerElement},
    59      * that value. Otherwise null.
    60      */
    61     private ContainerElement owner;
    63     /**
    64      * Explicitly given namespace declarations on this element.
    65      *
    66      * <p>
    67      * Additional namespace declarations might be necessary to
    68      * generate child {@link QName}s and attributes.
    69      */
    70     private NamespaceDecl firstNs;
    71     private NamespaceDecl lastNs;
    73     final Document document;
    75     public StartTag(ContainerElement owner, String uri, String localName) {
    76         this(owner.document,uri,localName);
    77         this.owner = owner;
    78     }
    80     public StartTag(Document document, String uri, String localName) {
    81         assert uri!=null;
    82         assert localName!=null;
    84         this.uri = uri;
    85         this.localName = localName;
    86         this.document = document;
    88         // TODO: think about a better way to maintain namespace decls.
    89         // this requires at least one NamespaceDecl per start tag,
    90         // which is rather expensive.
    91         addNamespaceDecl(uri,null,false);
    92     }
    94     public void addAttribute(String nsUri, String localName, Object arg) {
    95         checkWritable();
    97         // look for the existing ones
    98         Attribute a;
    99         for(a=firstAtt; a!=null; a=a.next) {
   100             if(a.hasName(nsUri,localName)) {
   101                 break;
   102             }
   103         }
   105         // if not found, declare a new one
   106         if(a==null) {
   107             a = new Attribute(nsUri,localName);
   108             if(lastAtt==null) {
   109                 assert firstAtt==null;
   110                 firstAtt = lastAtt = a;
   111             } else {
   112                 assert firstAtt!=null;
   113                 lastAtt.next = a;
   114                 lastAtt = a;
   115             }
   116             if(nsUri.length()>0)
   117                 addNamespaceDecl(nsUri,null,true);
   118         }
   120         document.writeValue(arg,this,a.value);
   121     }
   123     /**
   124      * Declares a new namespace URI on this tag.
   125      *
   126      * @param uri
   127      *      namespace URI to be bound. Can be empty, but must not be null.
   128      * @param prefix
   129      *      If non-null and non-empty, this prefix is bound to the URI
   130      *      on this element. If empty, then the runtime will still try to
   131      *      use the URI as the default namespace, but it may fail to do so
   132      *      because of the constraints in the XML.
   133      *      <p>
   134      *      If this parameter is null, the runtime will allocate an unique prefix.
   135      * @param requirePrefix
   136      *      Used only when the prefix parameter is null. If true, this indicates
   137      *      that the non-empty prefix must be assigned to this URI. If false,
   138      *      then this URI might be used as the default namespace.
   139      *      <p>
   140      *      Normally you just need to set it to false.
   141      */
   142     public NamespaceDecl addNamespaceDecl(String uri, String prefix,boolean requirePrefix) {
   143         checkWritable();
   145         if(uri==null)
   146             throw new IllegalArgumentException();
   147         if(uri.length()==0) {
   148             if(requirePrefix)
   149                 throw new IllegalArgumentException("The empty namespace cannot have a non-empty prefix");
   150             if(prefix!=null && prefix.length()>0)
   151                 throw new IllegalArgumentException("The empty namespace can be only bound to the empty prefix");
   152             prefix = "";
   153         }
   155         // check for the duplicate
   156         for(NamespaceDecl n=firstNs; n!=null; n=n.next) {
   157             if(uri.equals(n.uri)) {
   158                 if(prefix==null) {
   159                     // reuse this binding
   160                     n.requirePrefix |= requirePrefix;
   161                     return n;
   162                 }
   163                 if(n.prefix==null) {
   164                     // reuse this binding
   165                     n.prefix = prefix;
   166                     n.requirePrefix |= requirePrefix;
   167                     return n;
   168                 }
   169                 if(prefix.equals(n.prefix)) {
   170                     // reuse this binding
   171                     n.requirePrefix |= requirePrefix;
   172                     return n;
   173                 }
   174             }
   175             if(prefix!=null && n.prefix!=null && n.prefix.equals(prefix))
   176                 throw new IllegalArgumentException(
   177                     "Prefix '"+prefix+"' is already bound to '"+n.uri+'\'');
   178         }
   180         NamespaceDecl ns = new NamespaceDecl(document.assignNewId(),uri,prefix,requirePrefix);
   181         if(lastNs==null) {
   182             assert firstNs==null;
   183             firstNs = lastNs = ns;
   184         } else {
   185             assert firstNs!=null;
   186             lastNs.next = ns;
   187             lastNs = ns;
   188         }
   189         return ns;
   190     }
   192     /**
   193      * Throws an error if the start tag has already been committed.
   194      */
   195     private void checkWritable() {
   196         if(isWritten())
   197             throw new IllegalStateException(
   198                 "The start tag of "+this.localName+" has already been written. " +
   199                 "If you need out of order writing, see the TypedXmlWriter.block method");
   200     }
   202     /**
   203      * Returns true if this start tag has already been written.
   204      */
   205     boolean isWritten() {
   206         return uri==null;
   207     }
   209     /**
   210      * A {@link StartTag} can be only written after
   211      * we are sure that all the necessary namespace declarations are given.
   212      */
   213     boolean isReadyToCommit() {
   214         if(owner!=null && owner.isBlocked())
   215             return false;
   217         for( Content c=getNext(); c!=null; c=c.getNext() )
   218             if(c.concludesPendingStartTag())
   219                 return true;
   221         return false;
   222     }
   224     public void written() {
   225         firstAtt = lastAtt = null;
   226         uri = null;
   227         if(owner!=null) {
   228             assert owner.startTag==this;
   229             owner.startTag = null;
   230         }
   231     }
   233     boolean concludesPendingStartTag() {
   234         return true;
   235     }
   237     void accept(ContentVisitor visitor) {
   238         visitor.onStartTag(uri,localName,firstAtt,firstNs);
   239     }
   241     public String getPrefix(String nsUri) {
   242         NamespaceDecl ns = addNamespaceDecl(nsUri,null,false);
   243         if(ns.prefix!=null)
   244             // if the prefix has already been declared, use it.
   245             return ns.prefix;
   246         return ns.dummyPrefix;
   247     }
   248 }

mercurial