1 /* 2 * Copyright (c) 1997, 2012, 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 */ 25 26 package com.sun.xml.internal.ws.encoding; 27 28 import org.xml.sax.helpers.AttributesImpl; 29 import org.xml.sax.ContentHandler; 30 import org.xml.sax.SAXException; 31 32 import javax.xml.stream.XMLStreamReader; 33 import javax.xml.stream.XMLStreamWriter; 34 import javax.xml.stream.XMLStreamException; 35 36 import com.sun.xml.internal.ws.message.stream.StreamMessage; 37 import com.sun.xml.internal.ws.encoding.StreamSOAPCodec; 38 import com.sun.istack.internal.Nullable; 39 import com.sun.istack.internal.NotNull; 40 41 /** 42 * Complete infoset about a start tag. 43 * 44 * <p> 45 * This is used between {@link StreamMessage} and {@link StreamSOAPCodec} 46 * to capture the infoset of the s:Envelope, s:Header, and s:Body elements. 47 * 48 * 49 * <h3>Design Note</h3> 50 * <p> 51 * Since StAX and SAX uses different null vs empty string convention, one has 52 * to choose which format we store things. It can go either way, but I'm assuming 53 * that we'll be using StAX more in JAX-WS, so things are kept in the StAX style 54 * in this class. 55 * 56 * @author Kohsuke Kawaguchi 57 */ 58 public final class TagInfoset { 59 /** 60 * Namespace declarations on this tag. Read-only. 61 * 62 * This is an array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }. 63 * 64 * URIs/prefixes can be null (StAX-style) 65 */ 66 public final @NotNull String[] ns; 67 /** 68 * Attributes on this tag. Read-only. 69 */ 70 public final @NotNull AttributesImpl atts; 71 72 /** 73 * Prefix of the start tag in stax-style. 74 */ 75 public final @Nullable String prefix; 76 77 /** 78 * Namespace URI of the start tag in stax-style. 79 */ 80 public final @Nullable String nsUri; 81 82 /** 83 * Local name of the start tag. 84 */ 85 public final @NotNull String localName; 86 87 /** 88 * Lazily computed QName (i.e., "foo:bar") 89 */ 90 private @Nullable String qname; 91 92 public TagInfoset(String nsUri, String localName, String prefix, AttributesImpl atts, String... ns) { 93 this.nsUri = nsUri; 94 this.prefix = prefix; 95 this.localName = localName; 96 this.atts = atts; 97 this.ns = ns; 98 } 99 100 /** 101 * Fills a {@link TagInfoset} object by the current element 102 * that the reader points to. 103 */ 104 public TagInfoset(XMLStreamReader reader) { 105 prefix = reader.getPrefix(); 106 nsUri = reader.getNamespaceURI(); 107 localName = reader.getLocalName(); 108 109 int nsc = reader.getNamespaceCount(); 110 if(nsc>0) { 111 ns = new String[nsc*2]; 112 for(int i=0; i<nsc; i++){ 113 ns[i*2 ] = fixNull(reader.getNamespacePrefix(i)); 114 ns[i*2+1] = fixNull(reader.getNamespaceURI(i)); 115 } 116 } else { 117 ns = EMPTY_ARRAY; 118 } 119 120 int ac = reader.getAttributeCount(); 121 if(ac>0) { 122 atts = new AttributesImpl(); 123 StringBuilder sb = new StringBuilder(); 124 for(int i=0; i< ac;i++){ 125 sb.setLength(0); 126 String prefix = reader.getAttributePrefix(i); 127 String localName = reader.getAttributeLocalName(i); 128 129 String qname; 130 if(prefix != null && prefix.length()!=0){ 131 sb.append(prefix); 132 sb.append(":"); 133 sb.append(localName); 134 qname = sb.toString(); 135 } else { 136 qname = localName; 137 } 138 139 atts.addAttribute( 140 fixNull(reader.getAttributeNamespace(i)), 141 localName, 142 qname, 143 reader.getAttributeType(i), 144 reader.getAttributeValue(i)); 145 } 146 } else { 147 atts = EMPTY_ATTRIBUTES; 148 } 149 } 150 151 /** 152 * Writes the start element event. 153 */ 154 public void writeStart(ContentHandler contentHandler) throws SAXException { 155 for( int i=0; i<ns.length; i+=2 ) 156 contentHandler.startPrefixMapping(fixNull(ns[i]),fixNull(ns[i+1])); 157 contentHandler.startElement(fixNull(nsUri), localName ,getQName(), atts); 158 } 159 160 /** 161 * Writes the end element event. 162 */ 163 public void writeEnd(ContentHandler contentHandler) throws SAXException{ 164 contentHandler.endElement(fixNull(nsUri),localName,getQName()); 165 for( int i=ns.length-2; i>=0; i-=2 ) { 166 contentHandler.endPrefixMapping(fixNull(ns[i])); 167 } 168 } 169 170 /** 171 * Writes the start element event. 172 */ 173 public void writeStart(XMLStreamWriter w) throws XMLStreamException { 174 // write start tag. 175 if(prefix==null) { 176 if(nsUri==null) 177 w.writeStartElement(localName); 178 else { 179 //fix Null prefix. otherwise throws XMLStreamException, 180 // if the namespace URI has not been bound to a prefix 181 w.writeStartElement("",localName,nsUri); 182 } 183 } else { 184 w.writeStartElement(prefix,localName,nsUri); 185 } 186 187 for( int i=0; i<ns.length; i+=2 ) { 188 w.writeNamespace(ns[i],ns[i+1]); 189 } 190 191 for( int i=0; i<atts.getLength(); i++ ) { 192 String nsUri = atts.getURI(i); 193 if(nsUri==null || nsUri.length() ==0) { 194 w.writeAttribute(atts.getLocalName(i),atts.getValue(i)); 195 } else { 196 String rawName = atts.getQName(i); 197 String prefix = rawName.substring(0,rawName.indexOf(':')); 198 w.writeAttribute(prefix,nsUri,atts.getLocalName(i),atts.getValue(i)); 199 } 200 } 201 } 202 203 private String getQName() { 204 if(qname!=null) return qname; 205 206 StringBuilder sb = new StringBuilder(); 207 if(prefix!=null){ 208 sb.append(prefix); 209 sb.append(':'); 210 sb.append(localName); 211 qname = sb.toString(); 212 } else { 213 qname = localName; 214 } 215 return qname; 216 } 217 private static String fixNull(String s) { 218 if(s==null) return ""; 219 else return s; 220 } 221 222 private static final String[] EMPTY_ARRAY = new String[0]; 223 private static final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl(); 224 }