001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the License). You may not use this file except in
005: * compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://glassfish.dev.java.net/public/CDDLv1.0.html.
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * Header Notice in each file and include the License file
014: * at https://glassfish.dev.java.net/public/CDDLv1.0.html.
015: * If applicable, add the following below the CDDL Header,
016: * with the fields enclosed by brackets [] replaced by
017: * you own identifying information:
018: * "Portions Copyrighted [year] [name of copyright owner]"
019: *
020: * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
021: */
022:
023: package com.sun.xml.ws.security.opt.impl.message;
024:
025: import com.sun.xml.ws.security.opt.api.SecurityElement;
026: import com.sun.istack.NotNull;
027: import com.sun.xml.bind.api.Bridge;
028: import com.sun.xml.ws.api.model.wsdl.WSDLPort;
029: import com.sun.xml.ws.api.message.AttachmentSet;
030: import com.sun.xml.ws.api.message.HeaderList;
031: import java.util.List;
032: import org.xml.sax.ContentHandler;
033: import org.xml.sax.ErrorHandler;
034: import org.xml.sax.SAXException;
035: import com.sun.xml.stream.buffer.MutableXMLStreamBuffer;
036: import javax.xml.bind.JAXBException;
037: import javax.xml.bind.Unmarshaller;
038: import javax.xml.soap.SOAPException;
039: import javax.xml.soap.SOAPMessage;
040: import javax.xml.stream.XMLStreamException;
041: import javax.xml.stream.XMLStreamReader;
042: import javax.xml.stream.XMLStreamWriter;
043: import javax.xml.transform.Source;
044:
045: /**
046: *
047: * @author K.Venugopal@sun.com
048: */
049: public class MessageWrapper extends com.sun.xml.ws.api.message.Message {
050: private boolean isOneWay = false;
051: private SecuredMessage sm;
052: private List headers;
053: private HeaderList hl = new HeaderList();
054: private MutableXMLStreamBuffer bufferedMsg = null;
055:
056: public MessageWrapper(SecuredMessage sm, boolean oneWay) {
057: this .sm = sm;
058: this .isOneWay = oneWay;
059: this .headers = sm.getHeaders();
060: for (int i = 0; i < headers.size(); i++) {
061: Object obj = headers.get(i);
062: if (obj instanceof com.sun.xml.ws.api.message.Header) {
063: hl.add((com.sun.xml.ws.api.message.Header) obj);
064: } else {
065: hl.add(new HeaderWrapper((SecurityElement) obj));
066: }
067: }
068: }
069:
070: public MessageWrapper(MutableXMLStreamBuffer msg, boolean oneWay,
071: HeaderList hdrs, SecuredMessage sm) {
072: this .bufferedMsg = msg;
073: this .sm = sm;
074: this .hl = hdrs;
075: this .isOneWay = oneWay;
076: }
077:
078: /**
079: * Returns true if headers are present in the message.
080: *
081: * @return
082: * true if headers are present.
083: */
084: public boolean hasHeaders() {
085: return (hl.size() > 0);
086: }
087:
088: /**
089: * Gets all the headers of this message.
090: *
091: * <h3>Implementation Note</h3>
092: * <p>
093: * {@link Message} implementation is allowed to defer
094: * the construction of {@link HeaderList} object. So
095: * if you only want to check for the existence of any header
096: * element, use {@link #hasHeaders()}.
097: *
098: * @return
099: * always return the same non-null object.
100: */
101: public HeaderList getHeaders() {
102: return hl;
103: }
104:
105: /**
106: * Gets the attachments of this message
107: * (attachments live outside a message.)
108: */
109: public AttachmentSet getAttachments() {
110: return sm.getAttachments();
111: }
112:
113: /**
114: * Optimization hint for the derived class to check
115: * if we may have some attachments.
116: */
117: protected boolean hasAttachments() {
118: return sm.getAttachments() != null;
119: }
120:
121: /**
122: * Returns true if this message is a request message for a
123: * one way operation according to the given WSDL. False otherwise.
124: *
125: * <p>
126: * This method is functionally equivalent as doing
127: * {@code getOperation(port).getOperation().isOneWay()}
128: * (with proper null check and all.) But this method
129: * can sometimes work faster than that (for example,
130: * on the client side when used with SEI.)
131: *
132: * @param port
133: * {@link Message}s are always created under the context of
134: * one {@link WSDLPort} and they never go outside that context.
135: * Pass in that "governing" {@link WSDLPort} object here.
136: * We chose to receive this as a parameter instead of
137: * keeping {@link WSDLPort} in a message, just to save the storage.
138: *
139: * <p>
140: * The implementation of this method involves caching the return
141: * value, so the behavior is undefined if multiple callers provide
142: * different {@link WSDLPort} objects, which is a bug of the caller.
143: */
144: public boolean isOneWay(@NotNull
145: WSDLPort port) {
146: return isOneWay;
147: }
148:
149: /**
150: * Gets the local name of the payload element.
151: *
152: * @return
153: * null if a {@link Message} doesn't have any payload.
154: */
155: public String getPayloadLocalPart() {
156: return sm.getPayloadLocalPart();
157: }
158:
159: /**
160: * Gets the namespace URI of the payload element.
161: *
162: * @return
163: * null if a {@link Message} doesn't have any payload.
164: */
165: public String getPayloadNamespaceURI() {
166: return sm.getPayloadNamespaceURI();
167: }
168:
169: // I'm not putting @Nullable on it because doing null check on getPayloadLocalPart() should be suffice
170:
171: /**
172: * Returns true if a {@link Message} has a payload.
173: *
174: * <p>
175: * A message without a payload is a SOAP message that looks like:
176: * <pre><xmp>
177: * <S:Envelope>
178: * <S:Header>
179: * ...
180: * </S:Header>
181: * <S:Body />
182: * </S:Envelope>
183: * </xmp></pre>
184: */
185: public boolean hasPayload() {
186: return true;
187: }
188:
189: /**
190: * Returns true if this message is a fault.
191: *
192: * <p>
193: * Just a convenience method built on {@link #getPayloadNamespaceURI()}
194: * and {@link #getPayloadLocalPart()}.
195: */
196: public boolean isFault() {
197: return false;
198: }
199:
200: /**
201: * Consumes this message including the envelope.
202: * returns it as a {@link Source} object.
203: */
204: public Source readEnvelopeAsSource() {
205: throw new UnsupportedOperationException();
206: }
207:
208: /**
209: * Returns the payload as a {@link Source} object.
210: *
211: * This consumes the message.
212: *
213: * @return
214: * if there's no payload, this method returns null.
215: */
216: public Source readPayloadAsSource() {
217: throw new UnsupportedOperationException();
218: }
219:
220: /**
221: * Creates the equivalent {@link SOAPMessage} from this message.
222: *
223: * This consumes the message.
224: *
225: * @throws SOAPException
226: * if there's any error while creating a {@link SOAPMessage}.
227: */
228: public SOAPMessage readAsSOAPMessage() throws SOAPException {
229: throw new UnsupportedOperationException();
230: }
231:
232: /**
233: * Reads the payload as a JAXB object by using the given unmarshaller.
234: *
235: * This consumes the message.
236: *
237: * @throws JAXBException
238: * If JAXB reports an error during the processing.
239: */
240: public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller)
241: throws JAXBException {
242: throw new UnsupportedOperationException();
243: }
244:
245: /**
246: * Reads the payload as a JAXB object according to the given {@link Bridge}.
247: *
248: * This consumes the message.
249: *
250: * @throws JAXBException
251: * If JAXB reports an error during the processing.
252: */
253: public <T> T readPayloadAsJAXB(Bridge<T> bridge)
254: throws JAXBException {
255: throw new UnsupportedOperationException();
256: }
257:
258: /**
259: * Reads the payload as a {@link XMLStreamReader}
260: *
261: * This consumes the message.
262: *
263: * @return
264: * If there's no payload, this method returns null.
265: * Otherwise always non-null valid {@link XMLStreamReader} that points to
266: * the payload tag name.
267: */
268: public XMLStreamReader readPayload() throws XMLStreamException {
269: _check();
270: return sm.readPayload();
271: }
272:
273: /**
274: * Writes the payload to StAX.
275: *
276: * This method writes just the payload of the message to the writer.
277: * This consumes the message.
278: * The implementation will not write
279: * {@link XMLStreamWriter#writeStartDocument()}
280: * nor
281: * {@link XMLStreamWriter#writeEndDocument()}
282: *
283: * <p>
284: * If there's no payload, this method is no-op.
285: *
286: * @throws XMLStreamException
287: * If the {@link XMLStreamWriter} reports an error,
288: * or some other errors happen during the processing.
289: */
290: public void writePayloadTo(XMLStreamWriter sw)
291: throws XMLStreamException {
292: _check();
293: sm.writePayloadTo(sw);
294: }
295:
296: /**
297: * Writes the whole SOAP message (but not attachments)
298: * to the given writer.
299: *
300: * This consumes the message.
301: *
302: * @throws XMLStreamException
303: * If the {@link XMLStreamWriter} reports an error,
304: * or some other errors happen during the processing.
305: */
306: public void writeTo(XMLStreamWriter sw) throws XMLStreamException {
307: if (bufferedMsg != null) {
308: bufferedMsg.writeToXMLStreamWriter(sw);
309: return;
310: }
311: sm.writeTo(sw);
312: }
313:
314: /**
315: * Writes the whole SOAP envelope as SAX events.
316: *
317: * <p>
318: * This consumes the message.
319: *
320: * @param contentHandler
321: * must not be nulll.
322: * @param errorHandler
323: * must not be null.
324: * any error encountered during the SAX event production must be
325: * first reported to this error handler. Fatal errors can be then
326: * thrown as {@link SAXParseException}. {@link SAXException}s thrown
327: * from {@link ErrorHandler} should propagate directly through this method.
328: */
329: public void writeTo(ContentHandler contentHandler,
330: ErrorHandler errorHandler) throws SAXException {
331: throw new UnsupportedOperationException();
332: }
333:
334: // TODO: do we need a method that reads payload as a fault?
335: // do we want a separte streaming representation of fault?
336: // or would SOAPFault in SAAJ do?
337:
338: /**
339: * Creates a copy of a {@link Message}.
340: *
341: * <p>
342: * This method creates a new {@link Message} whose header/payload/attachments/properties
343: * are identical to this {@link Message}. Once created, the created {@link Message}
344: * and the original {@link Message} behaves independently --- adding header/
345: * attachment to one {@link Message} doesn't affect another {@link Message}
346: * at all.
347: *
348: * <p>
349: * This method does <b>NOT</b> consume a message.
350: *
351: * <p>
352: * To enable efficient copy operations, there's a few restrictions on
353: * how copied message can be used.
354: *
355: * <ol>
356: * <li>The original and the copy may not be
357: * used concurrently by two threads (this allows two {@link Message}s
358: * to share some internal resources, such as JAXB marshallers.)
359: * Note that it's OK for the original and the copy to be processed
360: * by two threads, as long as they are not concurrent.
361: *
362: * <li>The copy has the same 'life scope'
363: * as the original (this allows shallower copy, such as
364: * JAXB beans wrapped in {@link JAXBMessage}.)
365: * </ol>
366: *
367: * <p>
368: * A 'life scope' of a message created during a message processing
369: * in a pipeline is until a pipeline processes the next message.
370: * A message cannot be kept beyond its life scope.
371: *
372: * (This experimental design is to allow message objects to be reused
373: * --- feedback appreciated.)
374: *
375: *
376: *
377: * <h3>Design Rationale</h3>
378: * <p>
379: * Since a {@link Message} body is read-once, sometimes
380: * (such as when you do fail-over, or WS-RM) you need to
381: * create an idential copy of a {@link Message}.
382: *
383: * <p>
384: * The actual copy operation depends on the layout
385: * of the data in memory, hence it's best to be done by
386: * the {@link Message} implementation itself.
387: *
388: * <p>
389: * The restrictions placed on the use of copied {@link Message} can be
390: * relaxed if necessary, but it will make the copy method more expensive.
391: */
392: // TODO: update the class javadoc with 'lifescope'
393: // and move the discussion about life scope there.
394: public MessageWrapper copy() {
395: return this ;
396: // if(bufferedMsg == null){
397: // try{
398: // bufferedMsg = new com.sun.xml.stream.buffer.MutableXMLStreamBuffer();
399: // javax.xml.stream.XMLStreamWriter writer = bufferedMsg.createFromXMLStreamWriter();
400: // sm.writeTo(writer);
401: // } catch (XMLStreamException ex) {
402: // java.util.logging.Logger.getLogger("global").log(java.util.logging.Level.SEVERE,
403: // ex.getMessage(),
404: // ex);
405: // }
406: // }
407: // return new MessageWrapper(bufferedMsg,this.isOneWay,this.hl,this.sm);
408: }
409:
410: private void _check() {
411: if (bufferedMsg != null) {
412: throw new UnsupportedOperationException(
413: "Message is buffered , only writeTo method is supported");
414: }
415: }
416: }
|