FileDocCategorySizeDatePackage
ProtocolMessageSender.javaAPI DocExample15780Tue May 29 16:56:42 BST 2007com.sun.xml.ws.rm.jaxws.runtime.client

ProtocolMessageSender.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * ProtocolMessageSender.java
 *
 * @author Mike Grogan
 * Created on January 30, 2006, 12:12 PM
 *
 */

package com.sun.xml.ws.rm.jaxws.runtime.client;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.api.message.*;
import com.sun.xml.ws.api.message.Messages;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.ws.api.pipe.Pipe;
import com.sun.xml.ws.rm.*;
import com.sun.xml.ws.rm.jaxws.runtime.InboundMessageProcessor;
import com.sun.xml.ws.rm.jaxws.runtime.OutboundSequence;
import com.sun.xml.ws.rm.protocol.*;

import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.net.URI;

/**
 * Helper class used to send protocol message addressed to the endpoint.
 * The messages belong to the following types:
 * <ul>
 * <li>CreateSequence. A message with a CreateSequence element in its body is sent.  The
 * response message contains a CreateSequenceResponse element in its body</li>
 * <li>Last. A message with empty body, and a Sequence header with Last child
 * is sent.  The headers on the body are processed.</li>
 * <li>AckRequensted. A message with empty body, and a Sequence header with Last child
 * is sent.  The headers on the body are processed.</li>
 * <li>TerminateSequence A message with a TerminateSequence element in its body is sent.</li>
 * </ul>
 *
 */
public class ProtocolMessageSender {

    /**
     * Helper to process InboundMessages.
     */
    private InboundMessageProcessor processor;

    /**
     * The next client pipe in the pipeline.  Used to propogate the messages.
     */
    private Pipe nextPipe;

    /**
     * The marshaller to write the messages
     */
    private  Marshaller marshaller;
    /**
     * The unmarshaller to read the messages
     */
    private  Unmarshaller unmarshaller;


    private RMConstants constants;

    /**
     * Properties like the BindingProvider to associate with the
     * request and response context
     * contentNegotiation etc can be obtained from
     * the packet
     */
    private Packet packet;

    /*
     * WSDLPort for use by addressing module when assigning headers.
     */
    private WSDLPort port;

    /*
     * WSBinding for use by addressing module when assigning headers.
     */
    private WSBinding binding;

    /**
     * Public ctor.  Initialize the fields
     */
    public ProtocolMessageSender(InboundMessageProcessor processor,
                                 Marshaller marshaller,
                                 Unmarshaller unmarshaller,
                                 WSDLPort port,
                                 WSBinding binding,
                                 Pipe nextPipe,
                                 Packet packet) {

        this.processor = processor;
        this.nextPipe = nextPipe;
        this.port = port;
        this.binding = binding;
        this.marshaller = marshaller;
        this.unmarshaller = unmarshaller;
        this.constants =  RMConstants.getRMConstants(binding.getAddressingVersion());
        this.packet = packet;

    }

    public CreateSequenceResponseElement sendCreateSequence(CreateSequenceElement cs,
                                                            URI destination,
                                                            URI acksTo,
                                                            SOAPVersion version) throws RMException {

        //Used from com.sun.xml.ws.jaxws.runtime.client.ClientOutboundSequence.connect, where
        //CreateSequence object is constructed and resulting CreateSequenceResponse object is
        //processed.
        CreateSequenceResponseElement csrElem = null;

        //1. Initialize  message adding CreateSequence to body
        if (cs != null) {
            Message request = Messages.create(constants.getJAXBContext(),cs,version);


            //Addressing Headers are added by configuring the following property
            //on the packet

            Packet requestPacket = new Packet(request);
            requestPacket.proxy = packet.proxy;
            requestPacket.contentNegotiation = packet.contentNegotiation;
            requestPacket.setEndPointAddressString(destination.toString());

            addAddressingHeaders (requestPacket, Constants.CREATE_SEQUENCE_ACTION,
                    destination , acksTo, false);

            String messageId = null ;/*= ADDRESSING_FIXME - initialize with mesageID
                                   assigned by addAddressingHeaders for use in
                                   correlating non-anonymous acksTo response*/



            Packet responsePacket = nextPipe.process(requestPacket);

            if (acksTo.equals(constants.getAnonymousURI())) {

                Message response = responsePacket.getMessage();
               if (response.isFault()){
                    throw new CreateSequenceException("CreateSequence was refused by the RMDestination \n ",response);
                }

                //unmarshall CreateSequenceResponse object from body of response.
                //need the null check because this might be a non-anonymous ackto and
                //CSR will be processed on another connection.
                if (response != null) {
                    csrElem = unmarshallCreateSequenceResponse(response);
                }
            } else {

                csrElem = ProtocolMessageReceiver.getCreateSequenceResponse(messageId);
            }
        }

        return csrElem;
    }

    public void sendTerminateSequence(TerminateSequenceElement ts,
                                      OutboundSequence seq,
                                      SOAPVersion version) throws RMException {

        //Used from com.sun.xml.ws.jaxws.runtime.client.ClientOutboundSequence.disconnect, where the
        //TerminateSequence message is initialzied.

        Message request = Messages.create(constants.getJAXBContext(),ts,version);

        //piggyback an acknowledgement if one is pending
        seq.processAcknowledgement(new com.sun.xml.ws.rm.Message(request), marshaller);

        Packet requestPacket = new Packet(request);
        requestPacket.proxy = packet.proxy;
        requestPacket.contentNegotiation = packet.contentNegotiation;
        addAddressingHeaders (requestPacket,Constants.TERMINATE_SEQUENCE_ACTION,seq.getDestination(),seq.getAcksTo(),/*true*/ false);
        requestPacket.setEndPointAddressString(seq.getDestination().toString());
        Packet responsePacket = nextPipe.process(requestPacket);
        Message response = responsePacket.getMessage();
        if (response != null && response.isFault()){
                throw new TerminateSequenceException("There was an error trying to terminate the sequence " ,response);
        }


        //What to do with response?
        //TODO
        //It may have a TerminateSequence for reverse sequence on it as well as
        //ack headers
        //Process these.

    }

    /**
     * Send Message with empty body and a single SequenceElement (with Last child) down the pipe.  Process the response,
     * which may contain a SequenceAcknowledgementElement.
     *
     * @param seq Outbound sequence to which SequenceHeaderElement will belong.
     *
     */
    public void sendLast(OutboundSequence seq, SOAPVersion version) throws RMException {

        Message request = createEmptyMessage(version);
        SequenceElement el = createLastHeader(seq);
        //request.getHeaders().add(Headers.create(version,marshaller,el));
        request.getHeaders().add(createHeader(el));

        seq.setLast();

        Packet requestPacket = new Packet(request);
        requestPacket.proxy = packet.proxy;
        //requestPacket.proxy = new ProxyWrapper(packet.proxy);
        requestPacket.setEndPointAddressString(seq.getDestination().toString());
        requestPacket.contentNegotiation = packet.contentNegotiation;
        addAddressingHeaders(requestPacket, constants.getLastAction(),seq.getDestination(),
                seq.getAcksTo(), /*true*/ false);

       

        Packet responsePacket = nextPipe.process(requestPacket);
        Message response = responsePacket.getMessage();

        com.sun.xml.ws.rm.Message msg = new com.sun.xml.ws.rm.Message(response);
        if (response != null && response.isFault()){
                throw new RMException(response);
        }

        processor.processMessage(msg, marshaller, unmarshaller);

    }


    /**
     * Send Message with empty body and a AckRequestedElement (with Last child) down the pipe.  Process the response,
     * which may contain a SequenceAcknowledgementElement.
     *
     * @param seq Outbound sequence to which SequenceHeaderElement will belong.
     *
     */
    public void sendAckRequested(OutboundSequence seq, SOAPVersion version) throws RMException {

        try {
            Message request = createEmptyMessage(version);
            AckRequestedElement el = createAckRequestedElement(seq);
            //request.getHeaders().add(Headers.create(version,marshaller,el));
            request.getHeaders().add(createHeader(el));


            Packet requestPacket = new Packet(request);
            requestPacket.proxy = packet.proxy;
            requestPacket.contentNegotiation = packet.contentNegotiation;

            addAddressingHeaders (requestPacket, Constants.ACK_REQUESTED_ACTION,
                    seq.getDestination(),seq.getAcksTo(), /*true*/ false);

            requestPacket.setEndPointAddressString(seq.getDestination().toString());

            Packet responsePacket = nextPipe.process(requestPacket);
            Message response = responsePacket.getMessage();
            if (response != null && response.isFault()){
                    //reset alarm
                    ((ClientOutboundSequence)seq).resetLastActivityTime();
                    throw new RMException(response);
            }

            com.sun.xml.ws.rm.Message msg = new com.sun.xml.ws.rm.Message(response);
            processor.processMessage(msg, marshaller, unmarshaller);
        } finally {
            //Make sure that alarm is reset.
            ((ClientOutboundSequence)seq).resetLastActivityTime();
        }

    }

    /**
     * Initialize an AddressingProperties object using the arguments.  Put the AddressingProperties
     * object in the RequestContext obtained from getMessageProperties.
     */
    private Packet addAddressingHeaders(Packet requestPacket,
                                        String action,
                                        URI destination,
                                        URI acksTo,
                                        boolean oneWay) throws RMException {
       
        /*ADDRESSING FIX_ME

        Current API does not allow assignment of non-anon reply to, if we
           need to support non-anon acksTo.
         */
        Message message = requestPacket.getMessage();
        HeaderList list = message.getHeaders();
        if (oneWay) {
            message.assertOneWay(true);
        } else {
            message.assertOneWay(false);
        }
        //list.fillRequestAddressingHeaders(port, binding, requestPacket, action);
        requestPacket.setEndPointAddressString(destination.toString());
        list.fillRequestAddressingHeaders(requestPacket,constants.getAddressingVersion(),binding.getSOAPVersion(),oneWay,action);

        return requestPacket;
       
   }

    /**
     * Create an empty message using correct SOAPVersion
     */
    private Message createEmptyMessage(SOAPVersion version) {
        return Messages.createEmpty(version);
    }



    private CreateSequenceResponseElement unmarshallCreateSequenceResponse(Message response) throws RMException{
        CreateSequenceResponseElement csrElement = null;
        try {
            csrElement = response.readPayloadAsJAXB(unmarshaller);
        } catch (JAXBException e) {
            throw new RMException (e);
        }
        return csrElement;
    }



     /**
     * Return a <code>SequenceElement.LastMessage</code>
     */
    private SequenceElement createLastHeader(OutboundSequence seq
                                                  ) {
        SequenceElement sequenceElement = new SequenceElement();
        sequenceElement.setId(seq.getId());
        sequenceElement.setNumber(seq.getNextIndex());
        sequenceElement.setLastMessage(new SequenceElement.LastMessage());
        return sequenceElement;
    }

    /**
     * Return a <code>AckReqesutedElement</code> whose Sequence ID matches the specified
     * <code>OutboundSequence</code> and whose MessageNumber is the
     * highest <MessageNumber> sent within a Sequence
     * sequence.
     */
    private AckRequestedElement createAckRequestedElement(OutboundSequence seq
                                                          ) {
        AckRequestedElement ackRequestedElement = new AckRequestedElement();
        ackRequestedElement.setId(seq.getId());
        ackRequestedElement.setMaxMessageNumber(seq.getNextIndex()-1);
        return ackRequestedElement;
    }

    public RMConstants getConstants() {
        return constants;
    }
    
    private com.sun.xml.ws.api.message.Header createHeader(Object obj) {
        return com.sun.xml.ws.api.message.Headers.create(constants.getJAXBRIContextHeaders(), obj);
    }

    
}