All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.ws.security.message.stream.LazyStreamBasedMessage Maven / Gradle / Ivy

There is a newer version: 4.0.4
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package com.sun.xml.ws.security.message.stream;

import com.sun.xml.ws.message.stream.*;
import com.sun.xml.ws.spi.db.XMLBridge;
import com.sun.xml.stream.buffer.MutableXMLStreamBuffer;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.ws.api.pipe.StreamSOAPCodec;
import java.io.IOException;
import jakarta.xml.soap.SOAPException;
import jakarta.xml.soap.SOAPMessage;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamReader;
import com.sun.istack.NotNull;
import com.sun.istack.Nullable;
import org.glassfish.jaxb.runtime.api.Bridge;
import com.sun.xml.ws.api.message.AttachmentSet;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.wss.jaxws.impl.logging.LogDomainConstants;
import java.util.logging.Logger;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
/**
 *
 * @author [email protected]
 */
public class LazyStreamBasedMessage extends Message{
    protected static final Logger logger =
            Logger.getLogger(
            LogDomainConstants.WSS_JAXWS_IMPL_DOMAIN,
            LogDomainConstants.WSS_JAXWS_IMPL_DOMAIN_BUNDLE);
    private StreamSOAPCodec codec = null;
    private boolean readMessage = false;
    private XMLStreamReader reader = null;
    private Message message = null;
    AttachmentSet as = null;
    private MutableXMLStreamBuffer buffer = null;
    
    private static final boolean MTOM_LARGEDATA;
    
    static {
        MTOM_LARGEDATA= Boolean.getBoolean("MTOM_LARGEDATA");
    }
    /** Creates a new instance of StreamMessage */
    public LazyStreamBasedMessage(XMLStreamReader message,StreamSOAPCodec codec) {
        this.reader = message;
        this.codec = codec;
    }
    
    public LazyStreamBasedMessage(XMLStreamReader message,StreamSOAPCodec codec, AttachmentSet as) {
        this.reader = message;
        this.codec = codec;
        this.as = as;
    }
    
    public StreamSOAPCodec getCodec(){
        return codec;
    }
    
    private synchronized void cacheMessage(){
        if(!readMessage){
            if(as == null){
                message = codec.decode(reader);
            } else {
                message = codec.decode(reader, as);
            }
            readMessage = true;
        }
    }
    
    
    
    /**
     * Returns true if headers are present in the message.
     *
     * @return
     *      true if headers are present.
     */
    public boolean hasHeaders(){
        if(!readMessage){
            cacheMessage();
        }
        return message.hasHeaders();
    }
    
    /**
     * Gets all the headers of this message.
     *
     * 

Implementation Note

*

* {@link Message} implementation is allowed to defer * the construction of {@link HeaderList} object. So * if you only want to check for the existence of any header * element, use {@link #hasHeaders()}. * * @return * always return the same non-null object. */ public HeaderList getHeaders(){ if(!readMessage){ cacheMessage(); } // FIXME: RJE -- remove cast once Message.getHeaders is updated to return MessageHeaders return (HeaderList) message.getHeaders(); } /** * Gets the attachments of this message * (attachments live outside a message.) */ public @NotNull AttachmentSet getAttachments() { if(!readMessage){ cacheMessage(); } return message.getAttachments(); } /** * Returns true if this message is a request message for a * one way operation according to the given WSDL. False otherwise. * *

* This method is functionally equivalent as doing * {@code getOperation(port).getOperation().isOneWay()} * (with proper null check and all.) But this method * can sometimes work faster than that (for example, * on the client side when used with SEI.) * * @param port * {@link Message}s are always created under the context of * one {@link WSDLPort} and they never go outside that context. * Pass in that "governing" {@link WSDLPort} object here. * We chose to receive this as a parameter instead of * keeping {@link WSDLPort} in a message, just to save the storage. * *

* The implementation of this method involves caching the return * value, so the behavior is undefined if multiple callers provide * different {@link WSDLPort} objects, which is a bug of the caller. */ public boolean isOneWay(@NotNull WSDLPort port) { if(!readMessage){ cacheMessage(); } return message.isOneWay(port); } /** * Gets the local name of the payload element. * * @return * null if a {@link Message} doesn't have any payload. */ public @Nullable String getPayloadLocalPart(){ if(!readMessage){ cacheMessage(); } return message.getPayloadLocalPart(); } /** * Gets the namespace URI of the payload element. * * @return * null if a {@link Message} doesn't have any payload. */ public String getPayloadNamespaceURI(){ if(!readMessage){ cacheMessage(); } return message.getPayloadNamespaceURI(); } // I'm not putting @Nullable on it because doing null check on getPayloadLocalPart() should be suffice /** * Returns true if a {@link Message} has a payload. * *

* A message without a payload is a SOAP message that looks like: *


     * <S:Envelope>
     *   <S:Header>
     *     ...
     *   </S:Header>
     *   <S:Body />
     * </S:Envelope>
     * 
*/ public boolean hasPayload(){ if(!readMessage){ cacheMessage(); } return message.hasPayload(); } /** * Consumes this message including the envelope. * returns it as a {@link Source} object. */ public Source readEnvelopeAsSource(){ if(!readMessage){ cacheMessage(); } return message.readEnvelopeAsSource(); } /** * Returns the payload as a {@link Source} object. * * This consumes the message. * * @return * if there's no payload, this method returns null. */ public Source readPayloadAsSource(){ if(!readMessage){ cacheMessage(); } return message.readPayloadAsSource(); } /** * Creates the equivalent {@link SOAPMessage} from this message. * * This consumes the message. * * @throws SOAPException * if there's any error while creating a {@link SOAPMessage}. */ public SOAPMessage readAsSOAPMessage() throws SOAPException{ if(!readMessage){ cacheMessage(); } return message.readAsSOAPMessage(); } /** * Reads the payload as a JAXB object by using the given unmarshaller. * * This consumes the message. * * @throws JAXBException * If JAXB reports an error during the processing. */ public T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException{ if(!readMessage){ cacheMessage(); } throw new UnsupportedOperationException(); } /** * Reads the payload as a JAXB object according to the given {@link Bridge}. * * This consumes the message. * * @throws JAXBException * If JAXB reports an error during the processing. */ public T readPayloadAsJAXB(Bridge bridge) throws JAXBException{ if(!readMessage){ cacheMessage(); } return message.readPayloadAsJAXB((Unmarshaller) bridge); } /** * Reads the payload as a {@link XMLStreamReader} * * This consumes the message. * * @return * If there's no payload, this method returns null. * Otherwise always non-null valid {@link XMLStreamReader} that points to * the payload tag name. */ public XMLStreamReader readPayload() throws XMLStreamException{ if(!readMessage){ cacheMessage(); } return message.readPayload(); } /** * Writes the payload to StAX. * * This method writes just the payload of the message to the writer. * This consumes the message. * The implementation will not write * {@link XMLStreamWriter#writeStartDocument()} * nor * {@link XMLStreamWriter#writeEndDocument()} * *

* If there's no payload, this method is no-op. * * @throws XMLStreamException * If the {@link XMLStreamWriter} reports an error, * or some other errors happen during the processing. */ public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException{ if(!readMessage){ cacheMessage(); } message.writePayloadTo(sw); } /** * Writes the whole SOAP message (but not attachments) * to the given writer. * * This consumes the message. * * @throws XMLStreamException * If the {@link XMLStreamWriter} reports an error, * or some other errors happen during the processing. */ public void writeTo(XMLStreamWriter sw) throws XMLStreamException{ if(!readMessage){ cacheMessage(); } message.writeTo(sw); } /** * Writes the whole SOAP envelope as SAX events. * *

* This consumes the message. * * @param contentHandler * must not be nulll. * @param errorHandler * must not be null. * any error encountered during the SAX event production must be * first reported to this error handler. Fatal errors can be then * thrown as {@link SAXParseException}. {@link SAXException}s thrown * from {@link ErrorHandler} should propagate directly through this method. */ public void writeTo( ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException{ if(!readMessage){ cacheMessage(); } message.writeTo(contentHandler,errorHandler); } // TODO: do we need a method that reads payload as a fault? // do we want a separte streaming representation of fault? // or would SOAPFault in SAAJ do? /** * Creates a copy of a {@link Message}. * *

* This method creates a new {@link Message} whose header/payload/attachments/properties * are identical to this {@link Message}. Once created, the created {@link Message} * and the original {@link Message} behaves independently --- adding header/ * attachment to one {@link Message} doesn't affect another {@link Message} * at all. * *

* This method does NOT consume a message. * *

* To enable efficient copy operations, there's a few restrictions on * how copied message can be used. * *

    *
  1. The original and the copy may not be * used concurrently by two threads (this allows two {@link Message}s * to share some internal resources, such as JAXB marshallers.) * Note that it's OK for the original and the copy to be processed * by two threads, as long as they are not concurrent. * *
  2. The copy has the same 'life scope' * as the original (this allows shallower copy, such as * JAXB beans wrapped in {@link JAXBMessage}.) *
* *

* A 'life scope' of a message created during a message processing * in a pipeline is until a pipeline processes the next message. * A message cannot be kept beyond its life scope. * * (This experimental design is to allow message objects to be reused * --- feedback appreciated.) * * * *

Design Rationale

*

* Since a {@link Message} body is read-once, sometimes * (such as when you do fail-over, or WS-RM) you need to * create an idential copy of a {@link Message}. * *

* The actual copy operation depends on the layout * of the data in memory, hence it's best to be done by * the {@link Message} implementation itself. * *

* The restrictions placed on the use of copied {@link Message} can be * relaxed if necessary, but it will make the copy method more expensive. */ // TODO: update the class javadoc with 'lifescope' // and move the discussion about life scope there. public Message copy(){ if(!readMessage){ cacheMessage(); } return message.copy(); } public XMLStreamReader readMessage(){ if (!readMessage) { return reader; } if (buffer == null) { try { buffer = new com.sun.xml.stream.buffer.MutableXMLStreamBuffer(); javax.xml.stream.XMLStreamWriter writer = buffer.createFromXMLStreamWriter(); message.writeTo(writer); } catch (javax.xml.stream.XMLStreamException ex) { logger.log(java.util.logging.Level.SEVERE,LogStringsMessages.WSSMSG_0001_PROBLEM_CACHING(),ex); } } try { reader = buffer.readAsXMLStreamReader(); return reader; } catch (XMLStreamException ex) { logger.log(java.util.logging.Level.SEVERE,LogStringsMessages.WSSMSG_0002_ERROR_READING_BUFFER(),ex); } return null; } public void print() throws XMLStreamException{ if(readMessage){ try { message.readAsSOAPMessage().writeTo(java.lang.System.out); return; } catch (SOAPException ex) { logger.log(java.util.logging.Level.SEVERE, LogStringsMessages.WSSMSG_0003_ERROR_PRINT(),ex); } catch (IOException ex) { logger.log(java.util.logging.Level.SEVERE, LogStringsMessages.WSSMSG_0003_ERROR_PRINT(),ex); } } if(buffer == null){ buffer = new MutableXMLStreamBuffer(); buffer.createFromXMLStreamReader(reader); reader = buffer.readAsXMLStreamReader(); } XMLOutputFactory xof = XMLOutputFactory.newInstance(); buffer.writeToXMLStreamWriter(xof.createXMLStreamWriter(System.out)); } public T readPayloadAsJAXB(XMLBridge bridge) throws JAXBException { if(!readMessage){ cacheMessage(); } return message.readPayloadAsJAXB(bridge); } /** * Since the StreamMessage is leaving out the white spaces around message payload, * it must be handled specially to allow message signature verification * @return white space prolog of the SOAP message body */ public String getBodyEpilogue() { return message instanceof StreamMessage ? ((StreamMessage) message).getBodyEpilogue(): null; } /** * Since the StreamMessage is leaving out the white spaces around message payload, * it must be handled specially to allow message signature verification * @return white space epilog of the SOAP message body */ public String getBodyPrologue() { return message instanceof StreamMessage ? ((StreamMessage) message).getBodyPrologue() : null; } public static boolean mtomLargeData() { return MTOM_LARGEDATA; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy