001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.api.addressing;
038:
039: import com.sun.istack.FinalArrayList;
040: import com.sun.istack.NotNull;
041: import com.sun.xml.stream.buffer.XMLStreamBuffer;
042: import com.sun.xml.stream.buffer.XMLStreamBufferException;
043: import com.sun.xml.ws.api.message.Header;
044: import com.sun.xml.ws.message.AbstractHeaderImpl;
045: import com.sun.xml.ws.util.xml.XMLStreamWriterFilter;
046: import org.w3c.dom.Element;
047: import org.xml.sax.Attributes;
048: import org.xml.sax.ContentHandler;
049: import org.xml.sax.ErrorHandler;
050: import org.xml.sax.SAXException;
051: import org.xml.sax.helpers.AttributesImpl;
052: import org.xml.sax.helpers.XMLFilterImpl;
053:
054: import javax.xml.namespace.QName;
055: import javax.xml.soap.SOAPException;
056: import javax.xml.soap.SOAPMessage;
057: import javax.xml.stream.XMLStreamException;
058: import javax.xml.stream.XMLStreamReader;
059: import javax.xml.stream.XMLStreamWriter;
060: import javax.xml.stream.util.StreamReaderDelegate;
061: import javax.xml.ws.WebServiceException;
062:
063: /**
064: * Used to represent outbound header created from {@link WSEndpointReference}'s
065: * referenec parameters.
066: *
067: * <p>
068: * This is optimized for outbound use, so it implements some of the methods lazily,
069: * in a slow way.
070: *
071: * <p>
072: * This header adds "wsa:IsReferenceParameter" and thus only used for the W3C version.
073: *
074: * @author Kohsuke Kawaguchi
075: */
076: final class OutboundReferenceParameterHeader extends AbstractHeaderImpl {
077: private final XMLStreamBuffer infoset;
078: private final String nsUri, localName;
079:
080: /**
081: * The attributes on the header element.
082: * Lazily parsed.
083: * Null if not parsed yet.
084: */
085: private FinalArrayList<Attribute> attributes;
086:
087: OutboundReferenceParameterHeader(XMLStreamBuffer infoset,
088: String nsUri, String localName) {
089: this .infoset = infoset;
090: this .nsUri = nsUri;
091: this .localName = localName;
092: }
093:
094: public @NotNull
095: String getNamespaceURI() {
096: return nsUri;
097: }
098:
099: public @NotNull
100: String getLocalPart() {
101: return localName;
102: }
103:
104: public String getAttribute(String nsUri, String localName) {
105: if (attributes == null)
106: parseAttributes();
107: for (int i = attributes.size() - 1; i >= 0; i--) {
108: Attribute a = attributes.get(i);
109: if (a.localName.equals(localName) && a.nsUri.equals(nsUri))
110: return a.value;
111: }
112: return null;
113: }
114:
115: /**
116: * We don't really expect this to be used, but just to satisfy
117: * the {@link Header} contract.
118: *
119: * So this is rather slow.
120: */
121: private void parseAttributes() {
122: try {
123: XMLStreamReader reader = readHeader();
124: reader.nextTag(); // move to the first element, which is the header element
125:
126: attributes = new FinalArrayList<Attribute>();
127:
128: for (int i = 0; i < reader.getAttributeCount(); i++) {
129: final String localName = reader
130: .getAttributeLocalName(i);
131: final String namespaceURI = reader
132: .getAttributeNamespace(i);
133: final String value = reader.getAttributeValue(i);
134:
135: attributes.add(new Attribute(namespaceURI, localName,
136: value));
137: }
138:
139: // we are adding one more attribute "wsa:IsReferenceParameter"
140: attributes.add(new Attribute(AddressingVersion.W3C.nsUri,
141: IS_REFERENCE_PARAMETER, TRUE_VALUE));
142: } catch (XMLStreamException e) {
143: throw new WebServiceException(
144: "Unable to read the attributes for {" + nsUri + "}"
145: + localName + " header", e);
146: }
147: }
148:
149: public XMLStreamReader readHeader() throws XMLStreamException {
150: return new StreamReaderDelegate(infoset.readAsXMLStreamReader()) {
151: int state = 0; /* 0:expecting root, 1:in root, 2:past root */
152:
153: public int next() throws XMLStreamException {
154: return check(super .next());
155: }
156:
157: public int nextTag() throws XMLStreamException {
158: return check(super .nextTag());
159: }
160:
161: private int check(int type) {
162: switch (state) {
163: case 0:
164: if (type == START_ELEMENT)
165: state = 1;
166: break;
167: case 1:
168: state = 2;
169: }
170:
171: return type;
172: }
173:
174: public int getAttributeCount() {
175: if (state == 1)
176: return super .getAttributeCount() + 1;
177: else
178: return super .getAttributeCount();
179: }
180:
181: public String getAttributeLocalName(int index) {
182: if (state == 1 && index == super .getAttributeCount())
183: return IS_REFERENCE_PARAMETER;
184: else
185: return super .getAttributeLocalName(index);
186: }
187:
188: public String getAttributeNamespace(int index) {
189: if (state == 1 && index == super .getAttributeCount())
190: return AddressingVersion.W3C.nsUri;
191: else
192: return super .getAttributeNamespace(index);
193: }
194:
195: public String getAttributePrefix(int index) {
196: if (state == 1 && index == super .getAttributeCount())
197: return "wsa";
198: else
199: return super .getAttributePrefix(index);
200: }
201:
202: public String getAttributeType(int index) {
203: if (state == 1 && index == super .getAttributeCount())
204: return "CDATA";
205: else
206: return super .getAttributeType(index);
207: }
208:
209: public String getAttributeValue(int index) {
210: if (state == 1 && index == super .getAttributeCount())
211: return TRUE_VALUE;
212: else
213: return super .getAttributeValue(index);
214: }
215:
216: public QName getAttributeName(int index) {
217: if (state == 1 && index == super .getAttributeCount())
218: return new QName(AddressingVersion.W3C.nsUri,
219: IS_REFERENCE_PARAMETER, "wsa");
220: else
221: return super .getAttributeName(index);
222: }
223:
224: public String getAttributeValue(String namespaceUri,
225: String localName) {
226: if (state == 1
227: && localName.equals(IS_REFERENCE_PARAMETER)
228: && namespaceUri
229: .equals(AddressingVersion.W3C.nsUri))
230: return TRUE_VALUE;
231: else
232: return super .getAttributeValue(namespaceUri,
233: localName);
234: }
235: };
236: }
237:
238: public void writeTo(XMLStreamWriter w) throws XMLStreamException {
239: infoset.writeToXMLStreamWriter(new XMLStreamWriterFilter(w) {
240: private boolean root = true;
241:
242: public void writeStartElement(String localName)
243: throws XMLStreamException {
244: super .writeStartElement(localName);
245: writeAddedAttribute();
246: }
247:
248: private void writeAddedAttribute()
249: throws XMLStreamException {
250: if (!root)
251: return;
252: root = false;
253: writeNamespace("wsa", AddressingVersion.W3C.nsUri);
254: super .writeAttribute("wsa",
255: AddressingVersion.W3C.nsUri,
256: IS_REFERENCE_PARAMETER, TRUE_VALUE);
257: }
258:
259: public void writeStartElement(String namespaceURI,
260: String localName) throws XMLStreamException {
261: super .writeStartElement(namespaceURI, localName);
262: writeAddedAttribute();
263: }
264:
265: public void writeStartElement(String prefix,
266: String localName, String namespaceURI)
267: throws XMLStreamException {
268: //TODO: Verify with KK later
269: //check if prefix is declared before writing start element.
270: boolean prefixDeclared = isPrefixDeclared(prefix,
271: namespaceURI);
272: super
273: .writeStartElement(prefix, localName,
274: namespaceURI);
275: if (!prefixDeclared && !prefix.equals(""))
276: super .writeNamespace(prefix, namespaceURI);
277: writeAddedAttribute();
278: }
279:
280: public void writeNamespace(String prefix,
281: String namespaceURI) throws XMLStreamException {
282: //TODO: Verify with KK later
283: if (isPrefixDeclared(prefix, namespaceURI)) {
284: //Dont write it again , as its already in NamespaceContext
285: return;
286: } else
287: super .writeNamespace(prefix, namespaceURI);
288: }
289:
290: private boolean isPrefixDeclared(String prefix,
291: String namespaceURI) {
292: return namespaceURI.equals(getNamespaceContext()
293: .getNamespaceURI(prefix));
294: }
295: }, true);
296: }
297:
298: public void writeTo(SOAPMessage saaj) throws SOAPException {
299: //TODO: SAAJ returns null instead of throwing SOAPException,
300: // when there is no SOAPHeader in the message,
301: // which leads to NPE.
302: try {
303: Element node = (Element) infoset.writeTo(saaj
304: .getSOAPHeader());
305: node.setAttributeNS(AddressingVersion.W3C.nsUri,
306: AddressingVersion.W3C.getPrefix() + ":"
307: + IS_REFERENCE_PARAMETER, TRUE_VALUE);
308: } catch (XMLStreamBufferException e) {
309: throw new SOAPException(e);
310: }
311: }
312:
313: public void writeTo(ContentHandler contentHandler,
314: ErrorHandler errorHandler) throws SAXException {
315: class Filter extends XMLFilterImpl {
316: Filter(ContentHandler ch) {
317: setContentHandler(ch);
318: }
319:
320: private int depth = 0;
321:
322: public void startElement(String uri, String localName,
323: String qName, Attributes atts) throws SAXException {
324: if (depth++ == 0) {
325: // add one more attribute
326: super .startPrefixMapping("wsa",
327: AddressingVersion.W3C.nsUri);
328: AttributesImpl atts2 = new AttributesImpl(atts);
329: atts2.addAttribute(AddressingVersion.W3C.nsUri,
330: IS_REFERENCE_PARAMETER,
331: "wsa:IsReferenceParameter", "CDATA",
332: TRUE_VALUE);
333: atts = atts2;
334: }
335:
336: super .startElement(uri, localName, qName, atts);
337: }
338:
339: public void endElement(String uri, String localName,
340: String qName) throws SAXException {
341: super .endElement(uri, localName, qName);
342: if (--depth == 0)
343: super .endPrefixMapping("wsa");
344: }
345: }
346:
347: infoset.writeTo(new Filter(contentHandler), errorHandler);
348: }
349:
350: /**
351: * Keep the information about an attribute on the header element.
352: */
353: static final class Attribute {
354: /**
355: * Can be empty but never null.
356: */
357: final String nsUri;
358: final String localName;
359: final String value;
360:
361: public Attribute(String nsUri, String localName, String value) {
362: this .nsUri = fixNull(nsUri);
363: this .localName = localName;
364: this .value = value;
365: }
366:
367: /**
368: * Convert null to "".
369: */
370: private static String fixNull(String s) {
371: if (s == null)
372: return "";
373: else
374: return s;
375: }
376: }
377:
378: /**
379: * We the performance paranoid people in the JAX-WS RI thinks
380: * saving three bytes is worth while...
381: */
382: private static final String TRUE_VALUE = "1";
383: private static final String IS_REFERENCE_PARAMETER = "IsReferenceParameter";
384: }
|