1/* 2 * Copyright (c) 1997, 2015, 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 26package com.sun.xml.internal.ws.message.stream; 27 28import com.sun.istack.internal.FinalArrayList; 29import com.sun.istack.internal.NotNull; 30import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; 31import com.sun.xml.internal.stream.buffer.XMLStreamBufferSource; 32import com.sun.xml.internal.ws.api.SOAPVersion; 33import com.sun.xml.internal.ws.api.addressing.AddressingVersion; 34import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; 35import com.sun.xml.internal.ws.api.message.Header; 36import com.sun.xml.internal.ws.message.AbstractHeaderImpl; 37import com.sun.xml.internal.ws.util.xml.XmlUtil; 38import org.w3c.dom.Node; 39import org.xml.sax.ContentHandler; 40import org.xml.sax.ErrorHandler; 41import org.xml.sax.SAXException; 42 43import javax.xml.soap.SOAPException; 44import javax.xml.soap.SOAPHeader; 45import javax.xml.soap.SOAPMessage; 46import javax.xml.stream.XMLStreamException; 47import javax.xml.stream.XMLStreamReader; 48import javax.xml.stream.XMLStreamWriter; 49import javax.xml.transform.Transformer; 50import javax.xml.transform.TransformerFactory; 51import javax.xml.transform.dom.DOMResult; 52import java.util.List; 53import java.util.Set; 54 55/** 56 * {@link Header} whose physical data representation is an XMLStreamBuffer. 57 * 58 * @author Paul.Sandoz@Sun.Com 59 */ 60public abstract class StreamHeader extends AbstractHeaderImpl { 61 protected final XMLStreamBuffer _mark; 62 63 protected boolean _isMustUnderstand; 64 65 /** 66 * Role or actor value. 67 */ 68 protected @NotNull String _role; 69 70 protected boolean _isRelay; 71 72 protected String _localName; 73 74 protected String _namespaceURI; 75 76 /** 77 * Keep the information about an attribute on the header element. 78 * 79 * TODO: this whole attribute handling could be done better, I think. 80 */ 81 protected static final class Attribute { 82 /** 83 * Can be empty but never null. 84 */ 85 final String nsUri; 86 final String localName; 87 final String value; 88 89 public Attribute(String nsUri, String localName, String value) { 90 this.nsUri = fixNull(nsUri); 91 this.localName = localName; 92 this.value = value; 93 } 94 } 95 96 /** 97 * The attributes on the header element. 98 * We expect there to be only a small number of them, 99 * so the use of {@link List} would be justified. 100 * 101 * Null if no attribute is present. 102 */ 103 private final FinalArrayList<Attribute> attributes; 104 105 /** 106 * Creates a {@link StreamHeader}. 107 * 108 * @param reader 109 * The parser pointing at the start of the mark. 110 * Technically this information is redundant, 111 * but it achieves a better performance. 112 * @param mark 113 * The start of the buffered header content. 114 */ 115 protected StreamHeader(XMLStreamReader reader, XMLStreamBuffer mark) { 116 assert reader!=null && mark!=null; 117 _mark = mark; 118 _localName = reader.getLocalName(); 119 _namespaceURI = reader.getNamespaceURI(); 120 attributes = processHeaderAttributes(reader); 121 } 122 123 /** 124 * Creates a {@link StreamHeader}. 125 * 126 * @param reader 127 * The parser that points to the start tag of the header. 128 * By the end of this method, the parser will point at 129 * the end tag of this element. 130 */ 131 protected StreamHeader(XMLStreamReader reader) throws XMLStreamException { 132 _localName = reader.getLocalName(); 133 _namespaceURI = reader.getNamespaceURI(); 134 attributes = processHeaderAttributes(reader); 135 // cache the body 136 _mark = XMLStreamBuffer.createNewBufferFromXMLStreamReader(reader); 137 } 138 139 public final boolean isIgnorable(@NotNull SOAPVersion soapVersion, @NotNull Set<String> roles) { 140 // check mustUnderstand 141 if(!_isMustUnderstand) return true; 142 143 if (roles == null) 144 return true; 145 146 // now role 147 return !roles.contains(_role); 148 } 149 150 public @NotNull String getRole(@NotNull SOAPVersion soapVersion) { 151 assert _role!=null; 152 return _role; 153 } 154 155 public boolean isRelay() { 156 return _isRelay; 157 } 158 159 public @NotNull String getNamespaceURI() { 160 return _namespaceURI; 161 } 162 163 public @NotNull String getLocalPart() { 164 return _localName; 165 } 166 167 public String getAttribute(String nsUri, String localName) { 168 if(attributes!=null) { 169 for(int i=attributes.size()-1; i>=0; i-- ) { 170 Attribute a = attributes.get(i); 171 if(a.localName.equals(localName) && a.nsUri.equals(nsUri)) 172 return a.value; 173 } 174 } 175 return null; 176 } 177 178 /** 179 * Reads the header as a {@link XMLStreamReader} 180 */ 181 public XMLStreamReader readHeader() throws XMLStreamException { 182 return _mark.readAsXMLStreamReader(); 183 } 184 185 public void writeTo(XMLStreamWriter w) throws XMLStreamException { 186 if(_mark.getInscopeNamespaces().size() > 0) 187 _mark.writeToXMLStreamWriter(w,true); 188 else 189 _mark.writeToXMLStreamWriter(w); 190 } 191 192 public void writeTo(SOAPMessage saaj) throws SOAPException { 193 try { 194 // TODO what about in-scope namespaces 195 // Not very efficient consider implementing a stream buffer 196 // processor that produces a DOM node from the buffer. 197 TransformerFactory tf = XmlUtil.newTransformerFactory(true); 198 Transformer t = tf.newTransformer(); 199 XMLStreamBufferSource source = new XMLStreamBufferSource(_mark); 200 DOMResult result = new DOMResult(); 201 t.transform(source, result); 202 Node d = result.getNode(); 203 if(d.getNodeType() == Node.DOCUMENT_NODE) 204 d = d.getFirstChild(); 205 SOAPHeader header = saaj.getSOAPHeader(); 206 if(header == null) 207 header = saaj.getSOAPPart().getEnvelope().addHeader(); 208 Node node = header.getOwnerDocument().importNode(d, true); 209 header.appendChild(node); 210 } catch (Exception e) { 211 throw new SOAPException(e); 212 } 213 } 214 215 public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException { 216 _mark.writeTo(contentHandler); 217 } 218 219 /** 220 * Creates an EPR without copying infoset. 221 * 222 * This is the most common implementation on which {@link Header#readAsEPR(AddressingVersion)} 223 * is invoked on. 224 */ 225 @Override @NotNull 226 public WSEndpointReference readAsEPR(AddressingVersion expected) throws XMLStreamException { 227 return new WSEndpointReference(_mark,expected); 228 } 229 230 protected abstract FinalArrayList<Attribute> processHeaderAttributes(XMLStreamReader reader); 231 232 /** 233 * Convert null to "". 234 */ 235 private static String fixNull(String s) { 236 if(s==null) return ""; 237 else return s; 238 } 239} 240