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

ClientOutboundSequence

public class ClientOutboundSequence extends com.sun.xml.ws.rm.jaxws.runtime.OutboundSequence implements com.sun.xml.ws.api.rm.client.ClientSequence
ClientOutboundSequence represents the set of all messages from a single BindingProvider instance. It includes methods that connect and disconnect to a remote RMDestination using a client for a WebService that uses CreateSequence and TerminateSequence as its request messages.

Fields Summary
private static final Logger
logger
protected int
receiveBufferSize
Current value of receive buffer read from incoming SequenceAcknowledgement messages if RM Destination implements properietary Indigo Flow Control feature.
protected ProtocolMessageSender
protocolMessageSender
The helper class used to send protocol messages CreateSequenceElement CreateSequenceResponseElement LastMessage AckRequestedElement
private com.sun.xml.ws.api.SOAPVersion
version
private boolean
secureReliableMessaging
Flag to indicate if secureReliableMessaging is on
private JAXBElement
str
The SecurityTokenReference to pass to CreateSequence
private boolean
isAnonymous
Indicates whether the sequence uses anonymous acksTo
private boolean
isActive
private long
resendDeadline
Time after which resend of messages in sequences is attempted at next opportunity.
private long
ackRequestDeadline
Time after which Ack is requested at next opportunity.
private com.sun.xml.ws.api.rm.AcknowledgementListener
ackListener
Can be registered to listen for sequence acknowledgements.
private Service
service
Service using this sequence (if known)
private static boolean
sendHeartbeats
This field is used only as a hack to test Server-side timeout functionality. It is not intended to be used for any other purpose.
Constructors Summary
public ClientOutboundSequence(com.sun.xml.ws.rm.jaxws.runtime.SequenceConfig config)


    
       
        this.config = config;

        //for now
        this.version = config.getSoapVersion();
        this.ackHandler = new AcknowledgementHandler(config);
        this.rmConstants = config.getRMConstants();
        this.bufferRemaining = config.getBufferSize();

    
Methods Summary
public synchronized voidacknowledge(int i)
Implementation of acknowledge defers discarding stored messages when the AcksTo endpoint is anonymous and the message is a two-way request. In this case, the actual work usually done by acknowledge() needs to wait until the response is received. The RMClientPipe invokes acknowledgeResponse at that time.

param
i The index to acknowledge
throws
InvalidMessageNumberException

        
        Message mess = get(i);
        if (isAnonymous() && mess.isTwoWayRequest) {
            return;
        } else {
            super.acknowledge(i);
                    
            if (ackListener != null) {
                ackListener.notify(this, i);
            }
            //if this acknowledgement is not on the protocol
            //response for the one-way message (endpoint behaved
            //unkindly, or possibly dropped the request), the sending
            //thread is waiting in the resend loop in RMClientPipe.
            mess.resume();
        }
    
public synchronized voidacknowledgeResponse(int i)
Acknowledges that a response to a two-way operation has been received. See Javadoc for acknowledge

param
i The index to acknowledge
throws
InvalidMessageNumberException

            
        super.acknowledge(i);
        if (ackListener != null) {
                ackListener.notify(this, i);
        }
    
public voidconnect(java.net.URI destination, java.net.URI acksTo, boolean twoWay)
Connects to remote RM Destination by sending request through the proxy stored in the port field.

param
destination Destination URI for RM Destination
param
acksTo reply to EPR for protocol responses. The null value indicates use of the WS-Addressing anonymous EPR
throws
RMException wrapper for all exceptions thrown during execution of method.

        try {

            this.destination = destination;
            this.acksTo = acksTo;

            String anonymous = rmConstants.getAnonymousURI().toString();
            String acksToString;

            if (acksTo == null) {
                acksToString = anonymous;
            } else {
                acksToString = acksTo.toString();

            }

            this.isAnonymous = acksToString.equals(anonymous);


            CreateSequenceElement cs = new CreateSequenceElement();

            /**
             * ADDRESSING_FIXME
             * This needs to be fixed commenting temporarily to get the compilation
             * problems fixed
             */
            /*if (RMConstants.getAddressingVersion() == AddressingVersion.W3C){
                cs.setAcksTo(new W3CAcksToImpl(new URI(acksToString)));
            }    else {
                cs.setAcksTo(new MemberSubmissionAcksToImpl(new URI(acksToString)));
                
            }*/
            W3CEndpointReference endpointReference = null;
            AddressingVersion addressingVersion = rmConstants.getAddressingVersion();
            if ( addressingVersion == AddressingVersion.W3C){
                  //WSEndpointReference wsepr = new WSEndpointReference(getClass().getResourceAsStream("w3c-anonymous-acksTo.xml"), addressingVersion);
                  WSEndpointReference epr = AddressingVersion.W3C.anonymousEpr;
                  Source s = epr.asSource("AcksTo");
                  endpointReference = new W3CEndpointReference(s);
            }/*else {
                  WSEndpointReference wsepr = new WSEndpointReference(getClass().getResourceAsStream("member-anonymous-acksTo.xml"), addressingVersion);
                  Source s = wsepr.asSource("AcksTo");
                  endpointReference = new MemberSubmissionEndpointReference(s);
            }*/
            cs.setAcksTo(endpointReference);

            String incomingID = "uuid:" + UUID.randomUUID();

            if (twoWay) {
                Identifier id = new Identifier();
                id.setValue(incomingID);
                OfferType offer = new OfferType();
                offer.setIdentifier(id);

                cs.setOffer(offer);
            }

            if (secureReliableMessaging) {
                JAXBElement<SecurityTokenReferenceType> str = getSecurityTokenReference();
                if (str != null) {
                    cs.setSecurityTokenReference(str.getValue());
                }   else {
                    throw new RMException("SecurityTokenReference is null");
                }
            }

            CreateSequenceResponseElement csr = protocolMessageSender.sendCreateSequence(cs,destination,
                    acksTo,version);
           
            
            if (csr != null ) {
                Identifier idOutbound = csr.getIdentifier();
                this.id = idOutbound.getValue();
                
                AcceptType accept = csr.getAccept();
                
                if (accept != null) {
                    /**
                     * ADDRESSING_FIXME Needs to be fixes once
                     * AcksTO issue is resolved
                     */
                   /* URI uriAccept = accept.getAcksTo();*/
                   URI uriAccept = null;

                    inboundSequence = new ClientInboundSequence(this,
                            incomingID,
                            uriAccept);
                } else {
                    inboundSequence = new ClientInboundSequence(this,
                            incomingID, null);
                }
                
                //start the inactivity clock
                resetLastActivityTime();

            } else {
                //maybe a non-anonymous AcksTo
                //Handle CreateSequenceRefused fault
            }
        } catch (Exception e) {
            throw new RMException(e);
        }
    
public voiddisconnect()
Disconnect from the RMDestination by invoking TerminateSequence on the proxy stored in the port field. State of sequence is set to inactive.

throws
RMException wrapper for all exceptions thrown during execution of method.

        disconnect(false);
    
public voiddisconnect(boolean keepAlive)
Disconnect from the RMDestination by invoking TerminateSequence on the proxy stored in the port field.

param
keepAlive If true, state of sequence is kept in active atate allowing the reuse of the sequence.
throws
RMException wrapper for all exceptions thrown during execution of method.


        //FIXME - find another check for connectiveness.. want to get rid of
        //unnecessary InboundSequences.
        if (inboundSequence == null) {
            throw new IllegalStateException("Not connected.");
        }
        
        isActive = keepAlive;
 
        //TODO 
        //Move this after waitForAcks to obviate  problems caused by
        //the LastMessage Protocol message being processed concurrently with
        //application messages.  At the moment, this may cause problems in
        //Glassfish container with ordered delivery configured.  This will
        //probably no longer be the case when the Tube/Fibre architecture
        //is used.
        sendLast();
         
        //this will block until all messages are complete
        waitForAcks();
                 
        TerminateSequenceElement ts = new TerminateSequenceElement();
        Identifier idTerminate = new Identifier();
        idTerminate.setValue(id);
        ts.setIdentifier(idTerminate);
        protocolMessageSender.sendTerminateSequence(ts,this,version);

    
public synchronized voiddoMaintenanceTasks()
Handler periodically invoked by RMSource.MaintenanceThread. Has two duties:

  • Resend incomplete messages.
  • Send AckRequested message down the pipeline if Inactivity timeout is approaching.

throws
RMException

         
        if (storedMessages > 0 && isResendDue()) {
            int top = getNextIndex();
            for (int i = 1; i < top; i++) {
                Message mess = get(i);
                if (mess != null && !mess.isComplete()) {
                    logger.fine("resending "  + getId() + ":" + i);
                    resend(i);
                }
            }
        } else {
            //check whether we need to prime the pump
            if (isGettingClose(System.currentTimeMillis() - getLastActivityTime(),
                                config.getInactivityTimeout())) { 
                //send an AckRequested down the pipe.  Need to use a background
                //Thread.  This is being called by the RMSource maintenance thread
                //whose health we have to be very careful with.  If the heartbeat
                //message takes inordinately long to process, the maintenance thread
                //could miss many assignments.
                new AckRequestedSender(this).start();
            }
        }
    
private longgetAckRequestInterval()

        //send an ackRequest at every opportunity under these conditions
        //1. Sequence has been terminated
        //2. Number of stored messages exceeds 1/2 available space.
        //3. Number of stored messages at endpoint exceeds 1/2
        //   available space.
        if (!isActive || 
            storedMessages > (getTransferWindowSize() / 2) ||
            getReceiveBufferSize() > (config.getBufferSize() / 2)) {
            return 0;
        }
        return config.getAckRequestInterval();
    
public com.sun.xml.ws.api.rm.AcknowledgementListenergetAcknowledgementListener()
Accessor for the AcknowledgementListener field.

return
The AcknowledgementListener.

        return ackListener;
    
public intgetReceiveBufferSize()
Accessor for the receiveBufferSize field.

return
The value for the field.

        return receiveBufferSize;
    
private longgetResendInterval()

        
        //do a resend at every opportunity under these conditions
        //1. Sequence has been terminated
        //2. Number of stored messages exceeds 1/2 available space.
        
        if (!isActive || 
            storedMessages > (getTransferWindowSize() / 2) ) {
            return 0;
        }
        return config.getResendInterval();
    
public javax.xml.bind.JAXBElementgetSecurityTokenReference()

        return str;
    
public com.sun.xml.ws.rm.jaxws.runtime.SequenceConfiggetSequenceConfig()
Accessor for the sequenceConfig field

return
The value of the field.

        return config;
    
public com.sun.xml.ws.api.rm.SequenceSettingsgetSequenceSettings()
Implementation of the getSequenceSettings method in com.sun.xml.ws.rm.api.client.ClientSequence. Need to populate the sequence ids in the returned SequenceSettings object, since in general, they will not be set in the underlying SequenceConfig object.

        
        SequenceSettings settings = getSequenceConfig();
        settings.sequenceId = getId();
        
        InboundSequence iseq = getInboundSequence();
        
        settings.companionSequenceId = (iseq != null) ?
                                       iseq.getId() :
                                       null;
        return settings;
    
public javax.xml.ws.ServicegetService()
Accessor for the service field.

returns
The value of the service field. May be null if not known.

        return service;
    
public intgetTransferWindowSize()
Return the hoped-for limit to number of stored messages. Currently the limit is not enforced, but as the number of stored messages approaches the limit, resends and ackRequests occur more frequently.

       //Use server size receive buffer size for now.  Might
       //want to make this configurable.
       return config.getBufferSize();
    
protected synchronized booleanisAckRequested()
Checks whether an ack should be requested. Currently checks whether the The algorithm checks whether the ackRequest deadline has elapsed. The ackRequestDeadline is determined by the ackRequestInterval in the SequenceConfig member for this sequence.

      
        long time = System.currentTimeMillis();
        if (time > ackRequestDeadline) {
            //reset the clock
            ackRequestDeadline = time + getAckRequestInterval();
            return true;
        } else {
            return false;
        }
    
public booleanisAnonymous()
Return value is determined by whether the destination endpoint is the anonymous URI.

return
true if the destination is the anonymous URI. false otherwise.

        return isAnonymous;
    
public synchronized booleanisResendDue()
Checks whether a resend should happen. The algorithm checks whether the resendDeadline has elapsed. The resendDeadline is determined by the resendInterval in the SequenceConfig member for this sequence.

        long time = System.currentTimeMillis();
        if (time > resendDeadline) {
            //reset the clock
            resendDeadline = time + getResendInterval();
            return true;
        } else {
            return false;
        }
    
public booleanisSecureReliableMessaging()

        return secureReliableMessaging;
    
public booleanisTransferWindowFull()
Returns true if TransferWindow is full. In this case, we hold off on sending messages.

        return getTransferWindowSize() == storedMessages;
    
public voidregisterProtocolMessageSender(ProtocolMessageSender pms)

        this.protocolMessageSender = pms;

    
public synchronized voidrequestAck()
Forces an ack request on next message

        ackRequestDeadline = System.currentTimeMillis();
    
public voidresend(int messageNumber)
Causes the specified message number to be resent.

param
messageNumber The message number to resend

        Message mess = get(messageNumber);
        mess.resume();
    
private voidsendLast()

        protocolMessageSender.sendLast(this,version);
    
public voidsetAcknowledgementListener(com.sun.xml.ws.api.rm.AcknowledgementListener listener)
Registers a AcknowledgementListener for this sequence

param
listener The AcknowledgementListener

        this.ackListener = listener;
    
public voidsetReceiveBufferSize(int receiveBufferSize)
Mutator for the receiveBufferSize field.

param
receiveBufferSize The new value for the field.

        this.receiveBufferSize = receiveBufferSize;
    
public voidsetSecureReliableMessaging(boolean secureReliableMessaging)

        this.secureReliableMessaging = secureReliableMessaging;
    
public voidsetSecurityTokenReference(javax.xml.bind.JAXBElement str)

        this.str = str;
    
public voidsetService(javax.xml.ws.Service service)
Sets the value of the service field.

param
service The service using the sequence.

        this.service = service;