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

org.ow2.frascati.tinfi.oasis.ServiceReferenceImpl Maven / Gradle / Ivy

The newest version!
/***
 * OW2 FraSCAti Tinfi
 * Copyright (C) 2007-2018 Inria, Univ. Lille
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Contact: [email protected]
 *
 * Author: Lionel Seinturier
 */

package org.ow2.frascati.tinfi.oasis;

import org.oasisopen.sca.ServiceReference;
import org.osoa.sca.ConversationEndedException;
import org.osoa.sca.NoRegisteredCallbackException;
import org.osoa.sca.annotations.Conversational;
import org.ow2.frascati.tinfi.CallbackManager;
import org.ow2.frascati.tinfi.TinfiComponentOutInterface;
import org.ow2.frascati.tinfi.osoa.ConversationImpl;
import org.ow2.frascati.tinfi.osoa.ConversationManager;
import org.ow2.frascati.tinfi.osoa.ConversationState;

/**
 * Implementation of a service reference.
 * 
 * @author Lionel Seinturier 
 * @author Romain Rouvoy 
 */
public class ServiceReferenceImpl implements ServiceReference {
    
    /*
     * Since version 1.4.2 all methods in this class are prefixed with
     * underscore to avoid conflicts when generating proxy classes for
     * interfaces with method names that collapse with these methods. The
     * case was encountered by Nicolas Petitprez who needed to generate code for
     * services implementing the existing javax.persistence.EntityManager
     * interface. This type contains a getDelegate() method that was conflicting
     * with the existing getDelegate() method defined in this class.
     */
    
    private static final long serialVersionUID = -6320574328183281789L;

    private Class businessInterface;
    protected B service;

    public ServiceReferenceImpl( Class businessInterface, B service ) {
        this.businessInterface = businessInterface;
        this.service = service;        
        this.conversationAnnotation =
            businessInterface.getAnnotation(Conversational.class);
    }
    
    
    // ----------------------------------------------------------------------
    // Management of the ServiceReferenceImpl chain.
    //
    // This chain is used by the CallbackManager. Prior to 1.4.5 I was using a
    // Stack in CallbackManager but Romain suggested this smarter
    // implementation.
    // ----------------------------------------------------------------------

    /** @since 1.4.5 */
    private ServiceReferenceImpl previous;
    
    /** @since 1.4.5 */
    public void setPrevious( ServiceReferenceImpl previous ) {
        this.previous = previous;
    }
    
    /** @since 1.4.5 */
    public ServiceReferenceImpl getPrevious() { return previous; }
    
    
    // ----------------------------------------------------------------------
    // Callback retated methods
    // ----------------------------------------------------------------------
    
    private Object callback;
    
    protected Object _getCallback() {
        if( callback == null ) {
            throw new NoRegisteredCallbackException();
        }
        return callback;
    }

    protected Object _getCallbackID() {
        return callbackID;
    }

    protected void _setCallback( Object callback ) {
        this.callback = callback;
    }

    protected void _setCallbackID( Object callbackID ) {
        this.callbackID = callbackID;
    }
    
    /** @since 1.4.5 */
    protected void _pushCallback( ServiceReferenceImpl sr ) {
        CallbackManager cm = CallbackManager.get();
        cm.push(sr);
    }

    /** @since 1.4.5 */
    protected void _popCallback() {
        CallbackManager cm = CallbackManager.get();
        cm.pop();
    }

    
    // ----------------------------------------------------------------------
    // Conversation related methods
    // ----------------------------------------------------------------------
    
    private Conversational conversationAnnotation;
    private Object callbackID;
    
    /** The conversation associated with the current reference. */
    private ThreadLocal conversation;

    protected boolean _isConversational() {
        return (conversationAnnotation != null);
    }

    protected ConversationImpl _getConversation() throws IllegalStateException {
        if( ! _isConversational() ) {
            String msg = "This reference is not conversational";
            throw new IllegalStateException(msg);
        }
        if( conversation == null ) {
            conversation = new ThreadLocal();
        }
        ConversationImpl conv = conversation.get();
        if( conv == null ) {
            conv = new ConversationImpl();
            conversation.set(conv);
        }
        return conv;
    }

    protected Object _getConversationID() {
        if( ! _isConversational() ) {
            String msg = "This reference is not conversational";
            throw new IllegalStateException(msg);
        }        
        return _getConversation().getConversationID();
    }

    /**
     * Set the id to associate with any conversation started through this
     * reference. If the value supplied is null then the id will be
     * generated by the implementation.
     *
     * @param conversationId
     *      the user-defined id to associated with a conversation
     * @throws IllegalStateException
     *      if a conversation is currently associated with this reference
     */
    protected void _setConversationID( Object conversationId )
    throws IllegalStateException {
        
        if( ! _isConversational() ) {
            String msg = "This reference is not conversational";
            throw new IllegalStateException(msg);
        }        
        if( _getConversation().getConversationID() != null ) {
            String msg =
                "A conversion has already been associated with this service "+
                "reference";
            throw new IllegalStateException(msg);
        }
        
        if( conversationId == null ) {
            conversationId = Math.random();
        }
        
        _getConversation().setConversationID(conversationId);
    }

    
    // ----------------------------------------------------------------------
    // Implementation of the ServiceReference interface
    // ----------------------------------------------------------------------
    
    public Class getBusinessInterface() {
        return businessInterface;
    }

    public B getService() {
        
        /*
         * Up until Tinfi 1.3.1 included, this method was returning
         * "this.service".
         * 
         * Since 1.4, we changed to the following piece of code. The idea is
         * that the object returned by this method must implement the business
         * interface while yet being able to execute the control logic (such as
         * pushing conversations on the conversation stack) when invoked. This
         * control logic is implemented by the generated subclasses of
         * ServiceReferenceImpl. A typical usage scenario which motivated this
         * change came from a mail discussion in August 2010 with David Feliot
         * from ScalAgent:
         * 
         *        ServiceReference actionRef =
         *            componentContext.getServiceReference(Action.class,"action");
         *        actionRef.getService().someAction(actionOccurrence);
         *
         * When invoking method someAction on the reference returned by
         * getService, the control logic must be executed. 
         */
        
        @SuppressWarnings("unchecked")
        TinfiComponentOutInterface tco =
            (TinfiComponentOutInterface) this.service;
        ServiceReference sr = tco.getServiceReference();
        
        @SuppressWarnings("unchecked")
        B service = (B) sr;
        return service;
    }

    
    // ----------------------------------------------------------------------
    // Implementation specific
    // ----------------------------------------------------------------------
    
    /**
     * Return the reference this callable reference delegates to. This method is
     * invoked by methods setReferenceValue and unsetReferenceValue in {@link
     * org.ow2.frascati.tinfi.control.content.SCAContentControllerMixin} to
     * manage reference injection for collection interfaces.
     * 
     * @since 1.4
     */
    public B _getDelegate() {
        return service;
    }
    
    
    // ----------------------------------------------------------------------
    // Methods used by generated subclasses
    // ----------------------------------------------------------------------
    
    /**
     * @since 1.1.1
     */
    protected void _pushConversation( ConversationImpl conv )
    throws ConversationEndedException {
        
        ConversationState convstate = conv.getFcState();
        if( convstate.equals(ConversationState.STOPPED) ) {
          throw new ConversationEndedException();
        }
        
        if( convstate.equals(ConversationState.CREATED) ) {
          String conversationId =
              Thread.currentThread().toString()+':'+getService().toString();
          conv.setConversationID(conversationId);
          conv.start();
        }
        
        ConversationManager cm = ConversationManager.get();
        cm.push(conv);        
    }
    
    /**
     * @since 1.1.1
     */
    protected ConversationImpl _popConversation() {
        ConversationManager cm = ConversationManager.get();
        ConversationImpl conv = cm.pop();
        return conv;
    }

    
    /**
     * @since 1.4
     */
    protected ConversationImpl _peekConversation() {
        ConversationManager cm = ConversationManager.get();
        ConversationImpl conv = cm.peek();
        return conv;
    }
}