1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/txw2/StartTag.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,248 @@ 1.4 +/* 1.5 + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.txw2; 1.30 + 1.31 +import javax.xml.namespace.QName; 1.32 + 1.33 + 1.34 +/** 1.35 + * Start tag. 1.36 + * 1.37 + * <p> 1.38 + * This object implements {@link NamespaceResolver} for attribute values. 1.39 + * 1.40 + * @author Kohsuke Kawaguchi 1.41 + */ 1.42 +class StartTag extends Content implements NamespaceResolver { 1.43 + /** 1.44 + * Tag name of the element. 1.45 + * 1.46 + * <p> 1.47 + * This field is also used as a flag to indicate 1.48 + * whether the start tag has been written. 1.49 + * This field is initially set to non-null, and 1.50 + * then reset to null when it's written. 1.51 + */ 1.52 + private String uri; 1.53 + // but we keep the local name non-null so that 1.54 + // we can diagnose an error 1.55 + private final String localName; 1.56 + 1.57 + private Attribute firstAtt; 1.58 + private Attribute lastAtt; 1.59 + 1.60 + /** 1.61 + * If this {@link StartTag} has the parent {@link ContainerElement}, 1.62 + * that value. Otherwise null. 1.63 + */ 1.64 + private ContainerElement owner; 1.65 + 1.66 + /** 1.67 + * Explicitly given namespace declarations on this element. 1.68 + * 1.69 + * <p> 1.70 + * Additional namespace declarations might be necessary to 1.71 + * generate child {@link QName}s and attributes. 1.72 + */ 1.73 + private NamespaceDecl firstNs; 1.74 + private NamespaceDecl lastNs; 1.75 + 1.76 + final Document document; 1.77 + 1.78 + public StartTag(ContainerElement owner, String uri, String localName) { 1.79 + this(owner.document,uri,localName); 1.80 + this.owner = owner; 1.81 + } 1.82 + 1.83 + public StartTag(Document document, String uri, String localName) { 1.84 + assert uri!=null; 1.85 + assert localName!=null; 1.86 + 1.87 + this.uri = uri; 1.88 + this.localName = localName; 1.89 + this.document = document; 1.90 + 1.91 + // TODO: think about a better way to maintain namespace decls. 1.92 + // this requires at least one NamespaceDecl per start tag, 1.93 + // which is rather expensive. 1.94 + addNamespaceDecl(uri,null,false); 1.95 + } 1.96 + 1.97 + public void addAttribute(String nsUri, String localName, Object arg) { 1.98 + checkWritable(); 1.99 + 1.100 + // look for the existing ones 1.101 + Attribute a; 1.102 + for(a=firstAtt; a!=null; a=a.next) { 1.103 + if(a.hasName(nsUri,localName)) { 1.104 + break; 1.105 + } 1.106 + } 1.107 + 1.108 + // if not found, declare a new one 1.109 + if(a==null) { 1.110 + a = new Attribute(nsUri,localName); 1.111 + if(lastAtt==null) { 1.112 + assert firstAtt==null; 1.113 + firstAtt = lastAtt = a; 1.114 + } else { 1.115 + assert firstAtt!=null; 1.116 + lastAtt.next = a; 1.117 + lastAtt = a; 1.118 + } 1.119 + if(nsUri.length()>0) 1.120 + addNamespaceDecl(nsUri,null,true); 1.121 + } 1.122 + 1.123 + document.writeValue(arg,this,a.value); 1.124 + } 1.125 + 1.126 + /** 1.127 + * Declares a new namespace URI on this tag. 1.128 + * 1.129 + * @param uri 1.130 + * namespace URI to be bound. Can be empty, but must not be null. 1.131 + * @param prefix 1.132 + * If non-null and non-empty, this prefix is bound to the URI 1.133 + * on this element. If empty, then the runtime will still try to 1.134 + * use the URI as the default namespace, but it may fail to do so 1.135 + * because of the constraints in the XML. 1.136 + * <p> 1.137 + * If this parameter is null, the runtime will allocate an unique prefix. 1.138 + * @param requirePrefix 1.139 + * Used only when the prefix parameter is null. If true, this indicates 1.140 + * that the non-empty prefix must be assigned to this URI. If false, 1.141 + * then this URI might be used as the default namespace. 1.142 + * <p> 1.143 + * Normally you just need to set it to false. 1.144 + */ 1.145 + public NamespaceDecl addNamespaceDecl(String uri, String prefix,boolean requirePrefix) { 1.146 + checkWritable(); 1.147 + 1.148 + if(uri==null) 1.149 + throw new IllegalArgumentException(); 1.150 + if(uri.length()==0) { 1.151 + if(requirePrefix) 1.152 + throw new IllegalArgumentException("The empty namespace cannot have a non-empty prefix"); 1.153 + if(prefix!=null && prefix.length()>0) 1.154 + throw new IllegalArgumentException("The empty namespace can be only bound to the empty prefix"); 1.155 + prefix = ""; 1.156 + } 1.157 + 1.158 + // check for the duplicate 1.159 + for(NamespaceDecl n=firstNs; n!=null; n=n.next) { 1.160 + if(uri.equals(n.uri)) { 1.161 + if(prefix==null) { 1.162 + // reuse this binding 1.163 + n.requirePrefix |= requirePrefix; 1.164 + return n; 1.165 + } 1.166 + if(n.prefix==null) { 1.167 + // reuse this binding 1.168 + n.prefix = prefix; 1.169 + n.requirePrefix |= requirePrefix; 1.170 + return n; 1.171 + } 1.172 + if(prefix.equals(n.prefix)) { 1.173 + // reuse this binding 1.174 + n.requirePrefix |= requirePrefix; 1.175 + return n; 1.176 + } 1.177 + } 1.178 + if(prefix!=null && n.prefix!=null && n.prefix.equals(prefix)) 1.179 + throw new IllegalArgumentException( 1.180 + "Prefix '"+prefix+"' is already bound to '"+n.uri+'\''); 1.181 + } 1.182 + 1.183 + NamespaceDecl ns = new NamespaceDecl(document.assignNewId(),uri,prefix,requirePrefix); 1.184 + if(lastNs==null) { 1.185 + assert firstNs==null; 1.186 + firstNs = lastNs = ns; 1.187 + } else { 1.188 + assert firstNs!=null; 1.189 + lastNs.next = ns; 1.190 + lastNs = ns; 1.191 + } 1.192 + return ns; 1.193 + } 1.194 + 1.195 + /** 1.196 + * Throws an error if the start tag has already been committed. 1.197 + */ 1.198 + private void checkWritable() { 1.199 + if(isWritten()) 1.200 + throw new IllegalStateException( 1.201 + "The start tag of "+this.localName+" has already been written. " + 1.202 + "If you need out of order writing, see the TypedXmlWriter.block method"); 1.203 + } 1.204 + 1.205 + /** 1.206 + * Returns true if this start tag has already been written. 1.207 + */ 1.208 + boolean isWritten() { 1.209 + return uri==null; 1.210 + } 1.211 + 1.212 + /** 1.213 + * A {@link StartTag} can be only written after 1.214 + * we are sure that all the necessary namespace declarations are given. 1.215 + */ 1.216 + boolean isReadyToCommit() { 1.217 + if(owner!=null && owner.isBlocked()) 1.218 + return false; 1.219 + 1.220 + for( Content c=getNext(); c!=null; c=c.getNext() ) 1.221 + if(c.concludesPendingStartTag()) 1.222 + return true; 1.223 + 1.224 + return false; 1.225 + } 1.226 + 1.227 + public void written() { 1.228 + firstAtt = lastAtt = null; 1.229 + uri = null; 1.230 + if(owner!=null) { 1.231 + assert owner.startTag==this; 1.232 + owner.startTag = null; 1.233 + } 1.234 + } 1.235 + 1.236 + boolean concludesPendingStartTag() { 1.237 + return true; 1.238 + } 1.239 + 1.240 + void accept(ContentVisitor visitor) { 1.241 + visitor.onStartTag(uri,localName,firstAtt,firstNs); 1.242 + } 1.243 + 1.244 + public String getPrefix(String nsUri) { 1.245 + NamespaceDecl ns = addNamespaceDecl(nsUri,null,false); 1.246 + if(ns.prefix!=null) 1.247 + // if the prefix has already been declared, use it. 1.248 + return ns.prefix; 1.249 + return ns.dummyPrefix; 1.250 + } 1.251 +}