Package org.apache.tuscany.sca.implementation.java.invocation

Source Code of org.apache.tuscany.sca.implementation.java.invocation.ResponseDispatchImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.tuscany.sca.implementation.java.invocation;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.tuscany.sca.assembly.EndpointReference;
import org.apache.tuscany.sca.context.CompositeContext;
import org.apache.tuscany.sca.context.ThreadMessageContext;
import org.apache.tuscany.sca.core.ExtensionPointRegistry;
import org.apache.tuscany.sca.core.FactoryExtensionPoint;
import org.apache.tuscany.sca.core.factory.ObjectFactory;
import org.apache.tuscany.sca.core.invocation.AsyncFaultWrapper;
import org.apache.tuscany.sca.core.invocation.AsyncResponseHandler;
import org.apache.tuscany.sca.core.invocation.CallbackReferenceObjectFactory;
import org.apache.tuscany.sca.core.invocation.ExtensibleProxyFactory;
import org.apache.tuscany.sca.core.invocation.ProxyFactory;
import org.apache.tuscany.sca.invocation.Message;
import org.apache.tuscany.sca.invocation.MessageFactory;
import org.apache.tuscany.sca.runtime.RuntimeEndpointReference;
import org.oasisopen.sca.ResponseDispatch;
import org.oasisopen.sca.ServiceReference;

/**
* Implementation of the ResponseDispatch interface of the OASIS SCA Java API
*
* This is used for invocations of asynchronous services, where it is passed as a parameter on async service operations
* and it provides the path by which the service implementation returns the response to the request, or a Fault
*
* Note that this class is serializable and can be serialized, stored and deserialized by the service implementation
*
* @param <T> - type of the response message
*/
public class ResponseDispatchImpl<T> implements ResponseDispatch<T>, Serializable {

  /**
   * Generated serialVersionUID value
   */
  private static final long serialVersionUID = 300158355992568592L;
    private static String WS_MESSAGE_ID = "WS_MESSAGE_ID";
    private static String MESSAGE_ID = "MESSAGE_ID";
 
  // A latch used to ensure that the sendResponse() and sendFault() operations are used at most once
  // The latch is initialized with the value "false"
  private AtomicBoolean latch = new AtomicBoolean();
 
  private final Lock lock = new ReentrantLock();
    private final Condition completed  = lock.newCondition();
 
  // The result
  private volatile T response = null;
  private volatile Throwable fault = null;
 
  private ExtensionPointRegistry registry;
 
  // Service Reference used for the callback
  private ServiceReference<AsyncResponseHandler<?>> callbackRef;
  private String callbackAddress;
  private String messageID;
 
  public ResponseDispatchImpl( Message msg ) {
    super();
    callbackRef = getAsyncCallbackRef( msg );
     
    callbackAddress = msg.getFrom().getCallbackEndpoint().getURI();
   
    // TODO - why is WS stuff bleeding into general code?
      messageID = (String) msg.getHeaders().get(MESSAGE_ID);
      if (messageID == null){
          messageID = (String) msg.getHeaders().get(WS_MESSAGE_ID);
      }
     
  } // end constructor
 
  public static <T> ResponseDispatchImpl<T> newInstance( Class<T> type, Message msg ) {
    return new ResponseDispatchImpl<T>( msg );
  }
 
  /**
   * Provide Context data for this ResponseDispatch that the service implementation can use
   */
  public Map<String, Object> getContext() {
    return null;
  }

  /**
   * Send a Fault.  Must only be invoked once for this ResponseDispatch object
   * @param e - the Fault to send
   * @throws IllegalStateException if either the sendResponse method or the sendFault method have been called previously
   */
  public void sendFault(Throwable e) {
    if( sendOK() ) {
      lock.lock();
      try {
        fault = e;
        completed.signalAll();
      } finally {
        lock.unlock();
      } // end try
    } else {
      throw new IllegalStateException("sendResponse() or sendFault() has been called previously");
    } // end if
    // Now dispatch the response to the callback...
    AsyncResponseHandler<T> handler = (AsyncResponseHandler<T>) callbackRef.getService();
    setResponseHeaders();
    handler.setFault(new AsyncFaultWrapper(e));
  } // end method sendFault

  /**
   * Send the response message.  Must only be invoked once for this ResponseDispatch object
   * @throws IllegalStateException if either the sendResponse method or the sendFault method have been called previously
   * @param res - the response message, which is of type T
   */
  public void sendResponse(T res) {
    if( sendOK() ) {
      lock.lock();
      try {
        response = res;
        completed.signalAll();
      } finally {
        lock.unlock();
      } // end try
    } else {
      throw new IllegalStateException("sendResponse() or sendFault() has been called previously");
    } // end if
    // Now dispatch the response to the callback...
    AsyncResponseHandler<T> handler = (AsyncResponseHandler<T>) callbackRef.getService();
    setResponseHeaders();
    handler.setResponse(res);
  } // end method sendResponse
 
  public T get(long timeout, TimeUnit unit) throws Throwable {
    lock.lock();
    try {
      // wait for result to be available
      if( response == null && fault == null ) completed.await( timeout, unit);
      if( response != null ) return response;
      if( fault != null ) throw fault;
    } finally {
      lock.unlock();
    } // end try

    return null;
  } // end method get

  /**
   * Indicates that sending a response is OK - this is a transactional
   * query in that it also updates the state of this ResponseDispatch, so
   * that it will return true once and once only
   * @return - true if it is OK to send the response, false otherwise
   */
  private boolean sendOK() {
    return latch.compareAndSet(false, true);
  }
 
  /**
   * Creates a service reference for the async callback, based on information contained in the supplied message
   * @param msg - the incoming message
   * @return - a CallBackServiceReference
   */
  @SuppressWarnings("unchecked")
  private ServiceReference<AsyncResponseHandler<?>> getAsyncCallbackRef( Message msg ) {
      RuntimeEndpointReference callbackEPR = (RuntimeEndpointReference) msg.getHeaders().get("ASYNC_CALLBACK");
      if( callbackEPR == null ) return null;
     
      CompositeContext compositeContext = callbackEPR.getCompositeContext();
        registry = compositeContext.getExtensionPointRegistry();
      ProxyFactory proxyFactory = ExtensibleProxyFactory.getInstance(registry);
      List<EndpointReference> eprList = new ArrayList<EndpointReference>();
      eprList.add(callbackEPR);
      ObjectFactory<?> factory = new CallbackReferenceObjectFactory(AsyncResponseHandler.class, proxyFactory, eprList);
     
      return (ServiceReference<AsyncResponseHandler<?>>) factory.getInstance();
     
    } // end method getAsyncCallbackEPR
 
  /**
   * Sets the values of various headers in the response message
   */
  private void setResponseHeaders() {
    // Is there an existing message context?
    Message msgContext = ThreadMessageContext.getMessageContext();
    if( msgContext == null ) {
      // Create a message context
      msgContext = getMessageFactory().createMessage();
    } // end if
   
    // Add in the header for the RelatesTo Message ID
    msgContext.getHeaders().put(WS_MESSAGE_ID, messageID);
    msgContext.getHeaders().put(MESSAGE_ID, messageID);
   
    ThreadMessageContext.setMessageContext(msgContext);
  } // end method setResponseHeaders
 
  private MessageFactory getMessageFactory() {
        FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class);
        return modelFactories.getFactory(MessageFactory.class);
  } // end method getMessageFactory
}
TOP

Related Classes of org.apache.tuscany.sca.implementation.java.invocation.ResponseDispatchImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.