1 /*
2  * Copyright (c) 1997, 2013, 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.message.stream;
27 
28 import com.sun.istack.internal.FinalArrayList;
29 import com.sun.istack.internal.NotNull;
30 import com.sun.xml.internal.stream.buffer.XMLStreamBuffer;
31 import com.sun.xml.internal.stream.buffer.XMLStreamBufferSource;
32 import com.sun.xml.internal.ws.api.SOAPVersion;
33 import com.sun.xml.internal.ws.api.addressing.AddressingVersion;
34 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
35 import com.sun.xml.internal.ws.api.message.Header;
36 import com.sun.xml.internal.ws.message.AbstractHeaderImpl;
37 import com.sun.xml.internal.ws.util.xml.XmlUtil;
38 import org.w3c.dom.Node;
39 import org.xml.sax.ContentHandler;
40 import org.xml.sax.ErrorHandler;
41 import org.xml.sax.SAXException;
42 
43 import javax.xml.soap.SOAPException;
44 import javax.xml.soap.SOAPHeader;
45 import javax.xml.soap.SOAPMessage;
46 import javax.xml.stream.XMLStreamException;
47 import javax.xml.stream.XMLStreamReader;
48 import javax.xml.stream.XMLStreamWriter;
49 import javax.xml.transform.Transformer;
50 import javax.xml.transform.TransformerFactory;
51 import javax.xml.transform.dom.DOMResult;
52 import java.util.List;
53 import java.util.Set;
54 
55 /**
56  * {@link Header} whose physical data representation is an XMLStreamBuffer.
57  *
58  * @author Paul.Sandoz@Sun.Com
59  */
60 public 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 
Attribute(String nsUri, String localName, String value)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      */
StreamHeader(XMLStreamReader reader, XMLStreamBuffer mark)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      */
StreamHeader(XMLStreamReader reader)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 
isIgnorable(@otNull SOAPVersion soapVersion, @NotNull Set<String> roles)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 
getRole(@otNull SOAPVersion soapVersion)150     public @NotNull String getRole(@NotNull SOAPVersion soapVersion) {
151         assert _role!=null;
152         return _role;
153     }
154 
isRelay()155     public boolean isRelay() {
156         return _isRelay;
157     }
158 
getNamespaceURI()159     public @NotNull String getNamespaceURI() {
160         return _namespaceURI;
161     }
162 
getLocalPart()163     public @NotNull String getLocalPart() {
164         return _localName;
165     }
166 
getAttribute(String nsUri, String localName)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      */
readHeader()181     public XMLStreamReader readHeader() throws XMLStreamException {
182         return _mark.readAsXMLStreamReader();
183     }
184 
writeTo(XMLStreamWriter w)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 
writeTo(SOAPMessage saaj)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();
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 
writeTo(ContentHandler contentHandler, ErrorHandler errorHandler)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
readAsEPR(AddressingVersion expected)226     public WSEndpointReference readAsEPR(AddressingVersion expected) throws XMLStreamException {
227         return new WSEndpointReference(_mark,expected);
228     }
229 
processHeaderAttributes(XMLStreamReader reader)230     protected abstract FinalArrayList<Attribute> processHeaderAttributes(XMLStreamReader reader);
231 
232     /**
233      * Convert null to "".
234      */
fixNull(String s)235     private static String fixNull(String s) {
236         if(s==null) return "";
237         else        return s;
238     }
239 }
240