Package org.jgroups.blocks

Source Code of org.jgroups.blocks.RpcDispatcher$MarshallerAdapter

package org.jgroups.blocks;


import org.jgroups.*;
import org.jgroups.util.*;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;


/**
* This class allows a programmer to invoke remote methods in all (or single)
* group members and optionally wait for the return value(s).
* An application will typically create a channel and layer the
* RpcDispatcher building block on top of it, which allows it to
* dispatch remote methods (client role) and at the same time be
* called by other members (server role).
* This class is derived from MessageDispatcher.
*  Is the equivalent of RpcProtocol on the application rather than protocol level.
* @author Bela Ban
*/
public class RpcDispatcher extends MessageDispatcher implements ChannelListener {
    protected Object        server_obj=null;
    /** Marshaller to marshall requests at the caller and unmarshal requests at the receiver(s) */
    protected Marshaller2   req_marshaller=null;

    /** Marshaller to marshal responses at the receiver(s) and unmarshal responses at the caller */
    protected Marshaller2   rsp_marshaller=null;
    protected final List<ChannelListener> additionalChannelListeners=new ArrayList<ChannelListener>();
    protected MethodLookup  method_lookup=null;


    public RpcDispatcher() {
    }


    public RpcDispatcher(Channel channel, MessageListener l, MembershipListener l2, Object server_obj) {
        super(channel, l, l2);
        channel.addChannelListener(this);
        this.server_obj=server_obj;
    }


    @Deprecated
    public RpcDispatcher(Channel channel, MessageListener l, MembershipListener l2, Object server_obj,
                         boolean deadlock_detection) {
        super(channel, l, l2);
        channel.addChannelListener(this);
        this.server_obj=server_obj;
    }

    @Deprecated
    public RpcDispatcher(Channel channel, MessageListener l, MembershipListener l2, Object server_obj,
                         boolean deadlock_detection, boolean concurrent_processing) {
        super(channel, l, l2, false, concurrent_processing);
        channel.addChannelListener(this);
        this.server_obj=server_obj;
    }


    @Deprecated
    public RpcDispatcher(PullPushAdapter adapter, Serializable id,
                         MessageListener l, MembershipListener l2, Object server_obj) {
        super(adapter, id, l, l2);

        // Fixes bug #804956
        // channel.setChannelListener(this);
        if(this.adapter != null) {
            Transport t=this.adapter.getTransport();
            if(t != null && t instanceof Channel) {
                ((Channel)t).addChannelListener(this);
            }
        }

        this.server_obj=server_obj;
    }


    public interface Marshaller {
        byte[] objectToByteBuffer(Object obj) throws Exception;
        Object objectFromByteBuffer(byte[] buf) throws Exception;
    }


    public interface Marshaller2 extends Marshaller {
        /**
         * Marshals the object into a byte[] buffer and returns a Buffer with a ref to the underlying byte[] buffer,
         * offset and length.<br/>
         * <em>
         * Note that the underlying byte[] buffer must not be changed as this would change the buffer of a message which
         * potentially can get retransmitted, and such a retransmission would then carry a ref to a changed byte[] buffer !
         * </em>
         * @param obj
         * @return
         * @throws Exception
         */
        Buffer objectToBuffer(Object obj) throws Exception;

        Object objectFromByteBuffer(byte[] buf, int offset, int length) throws Exception;
    }


    /** Used to provide a Marshaller2 interface to a Marshaller. This class is for internal use only, and will be
     * removed in 3.0 when Marshaller and Marshaller2 get merged. Do not use, but provide an implementation of
     * Marshaller directly, e.g. in setRequestMarshaller().
     */
    public static class MarshallerAdapter implements Marshaller2 {
        private final Marshaller marshaller;

        public MarshallerAdapter(Marshaller marshaller) {
            this.marshaller=marshaller;
        }

        public byte[] objectToByteBuffer(Object obj) throws Exception {
            return marshaller.objectToByteBuffer(obj);
        }

        public Object objectFromByteBuffer(byte[] buf) throws Exception {
            return buf == null? null : marshaller.objectFromByteBuffer(buf);
        }

        public Buffer objectToBuffer(Object obj) throws Exception {
            byte[] buf=marshaller.objectToByteBuffer(obj);
            return new Buffer(buf, 0, buf.length);
        }

        public Object objectFromByteBuffer(byte[] buf, int offset, int length) throws Exception {
            if(buf == null || (offset == 0 && length == buf.length))
                return marshaller.objectFromByteBuffer(buf);
            byte[] tmp=new byte[length];
            System.arraycopy(buf, offset, tmp, 0, length);
            return marshaller.objectFromByteBuffer(tmp);
        }

    }


    public static String getName() {return "RpcDispatcher";}

    public Marshaller getRequestMarshaller()             {return req_marshaller;}

    public void setRequestMarshaller(Marshaller m) {
        if(m == null)
            this.req_marshaller=null;
        else if(m instanceof Marshaller2)
            this.req_marshaller=(Marshaller2)m;
        else
            this.req_marshaller=new MarshallerAdapter(m);
    }

    public Marshaller getResponseMarshaller()             {return rsp_marshaller;}

    public void setResponseMarshaller(Marshaller m) {
        if(m == null)
            this.rsp_marshaller=null;
        else if(m instanceof Marshaller2)
            this.rsp_marshaller=(Marshaller2)m;
        else
            this.rsp_marshaller=new MarshallerAdapter(m);

        if(corr != null)
            corr.setMarshaller(this.rsp_marshaller);
    }

    public Marshaller getMarshaller() {return req_marshaller;}
   
    public void setMarshaller(Marshaller m) {setRequestMarshaller(m);}

    public Object getServerObject() {return server_obj;}

    public void setServerObject(Object server_obj) {
        this.server_obj=server_obj;
    }

    public MethodLookup getMethodLookup() {
        return method_lookup;
    }

    public void setMethodLookup(MethodLookup method_lookup) {
        this.method_lookup=method_lookup;
    }


    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, String method_name, Object[] args,
                                     Class[] types, int mode, long timeout) {
        return callRemoteMethods(dests, method_name, args, types, mode, timeout, false);
    }


    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, String method_name, Object[] args,
                                     Class[] types, int mode, long timeout, boolean use_anycasting) {
        return callRemoteMethods(dests, method_name, args, types, mode, timeout, use_anycasting, null);
    }

    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, String method_name, Object[] args,
                                     Class[] types, int mode, long timeout, boolean use_anycasting, RspFilter filter) {
        MethodCall method_call=new MethodCall(method_name, args, types);
        return callRemoteMethods(dests, method_call,
                                 new RequestOptions(mode, timeout, use_anycasting, filter, (byte)0));
    }

    public RspList callRemoteMethods(Collection<Address> dests, String method_name, Object[] args,
                                     Class[] types, RequestOptions options) {
        MethodCall method_call=new MethodCall(method_name, args, types);
        return callRemoteMethods(dests, method_call, options);
    }

    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, String method_name, Object[] args,
                                     String[] signature, int mode, long timeout) {
        return callRemoteMethods(dests, method_name, args, signature, mode, timeout, false);
    }

    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, String method_name, Object[] args,
                                     String[] signature, int mode, long timeout, boolean use_anycasting) {
        MethodCall method_call=new MethodCall(method_name, args, signature);
        return callRemoteMethods(dests, method_call, new RequestOptions(mode, timeout, use_anycasting, null, (byte)0));
    }

    @Deprecated
    public RspList callRemoteMethods(Vector<Address> dests, MethodCall method_call, int mode, long timeout) {
        return callRemoteMethods(dests, method_call,  new RequestOptions().setMode(mode).setTimeout(timeout));
    }


    /**
     * Invokes a method in all members contained in dests (or all members if dests is null).
     * @param dests A list of addresses. If null, the method will be invoked on all cluster members
     * @param method_call The method (plus args) to be invoked
     * @param options A collection of call options, e.g. sync versus async, timeout etc
     * @return RspList A list of return values and flags (suspected, not received) per member
     * @since 2.9
     */
    public RspList callRemoteMethods(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
        if(dests != null && dests.isEmpty()) { // don't send if dest list is empty
            if(log.isTraceEnabled())
                log.trace(new StringBuilder("destination list of ").append(method_call.getName()).
                        append("() is empty: no need to send message"));
            return RspList.EMPTY_RSP_LIST;
        }

        if(log.isTraceEnabled())
            log.trace(new StringBuilder("dests=").append(dests).append(", method_call=").append(method_call).
                    append(", options=").append(options));

        Object buf;
        try {
            buf=req_marshaller != null? req_marshaller.objectToBuffer(method_call) : Util.objectToByteBuffer(method_call);
        }
        catch(Exception e) {
            // if(log.isErrorEnabled()) log.error("exception", e);
            // we will change this in 3.0 to add the exception to the signature
            // (see http://jira.jboss.com/jira/browse/JGRP-193). The reason for a RTE is that we cannot change the
            // signature in 2.3, otherwise 2.3 would be *not* API compatible to prev releases
            throw new RuntimeException("failure to marshal argument(s)", e);
        }

        Message msg=new Message();
        if(buf instanceof Buffer)
            msg.setBuffer((Buffer)buf);
        else
            msg.setBuffer((byte[])buf);

        msg.setFlag(options.getFlags());
        if(options.getScope() > 0)
            msg.setScope(options.getScope());

        RspList retval=super.castMessage(dests, msg, options);
        if(log.isTraceEnabled()) log.trace("responses: " + retval);
        return retval;
    }

    @Deprecated
    public NotifyingFuture<RspList> callRemoteMethodsWithFuture(Vector<Address> dests, MethodCall method_call, int mode, long timeout,
                                                       boolean use_anycasting, boolean oob, RspFilter filter) {
        RequestOptions options=new RequestOptions(mode, timeout, use_anycasting, filter);
        if(oob) options.setFlags(Message.OOB);
        return callRemoteMethodsWithFuture(dests, method_call, options);
    }

    @Deprecated
    public NotifyingFuture<RspList> callRemoteMethodsWithFuture(Vector<Address> dests, MethodCall method_call) {
        return callRemoteMethodsWithFuture(dests, method_call, new RequestOptions());
    }

    public NotifyingFuture<RspList> callRemoteMethodsWithFuture(Collection<Address> dests, MethodCall method_call, RequestOptions options) {
        if(dests != null && dests.isEmpty()) { // don't send if dest list is empty
            if(log.isTraceEnabled())
                log.trace(new StringBuilder("destination list of ").append(method_call.getName()).
                        append("() is empty: no need to send message"));
            return new NullFuture<RspList>(RspList.EMPTY_RSP_LIST);
        }

        if(log.isTraceEnabled())
            log.trace(new StringBuilder("dests=").append(dests).append(", method_call=").append(method_call).
                    append(", options=").append(options));

        Object buf;
        try {
            buf=req_marshaller != null? req_marshaller.objectToBuffer(method_call) : Util.objectToByteBuffer(method_call);
        }
        catch(Exception e) {
            // if(log.isErrorEnabled()) log.error("exception", e);
            // we will change this in 2.4 to add the exception to the signature
            // (see http://jira.jboss.com/jira/browse/JGRP-193). The reason for a RTE is that we cannot change the
            // signature in 2.3, otherwise 2.3 would be *not* API compatible to prev releases
            throw new RuntimeException("failure to marshal argument(s)", e);
        }

        Message msg=new Message();
        if(buf instanceof Buffer)
            msg.setBuffer((Buffer)buf);
        else
            msg.setBuffer((byte[])buf);
        msg.setFlag(options.getFlags());
        if(options.getScope() > 0)
            msg.setScope(options.getScope());
       
        NotifyingFuture<RspList>  retval=super.castMessageWithFuture(dests, msg, options);
        if(log.isTraceEnabled()) log.trace("responses: " + retval);
        return retval;
    }


    @Deprecated
    public Object callRemoteMethod(Address dest, String method_name, Object[] args,
                                   Class[] types, int mode, long timeout) throws Throwable {
        MethodCall method_call=new MethodCall(method_name, args, types);
        return callRemoteMethod(dest, method_call, mode, timeout);
    }

    public Object callRemoteMethod(Address dest, String method_name, Object[] args,
                                   Class[] types, RequestOptions options) throws Throwable {
        MethodCall method_call=new MethodCall(method_name, args, types);
        return callRemoteMethod(dest, method_call, options);
    }

    @Deprecated
    public Object callRemoteMethod(Address dest, String method_name, Object[] args,
                                   String[] signature, int mode, long timeout) throws Throwable {
        MethodCall method_call=new MethodCall(method_name, args, signature);
        return callRemoteMethod(dest, method_call, mode, timeout);
    }

    @Deprecated
    public Object callRemoteMethod(Address dest, MethodCall method_call, int mode, long timeout) throws Throwable {
        return callRemoteMethod(dest, method_call, mode, timeout, false);
    }

    @Deprecated
    public Object callRemoteMethod(Address dest, MethodCall method_call, int mode, long timeout, boolean oob) throws Throwable {
        RequestOptions options=new RequestOptions(mode, timeout, false, null);
        if(oob) options.setFlags(Message.OOB);
        return callRemoteMethod(dest, method_call, options);
    }

    @Deprecated
    public Object callRemoteMethod(Address dest, MethodCall call) throws Throwable {
        return callRemoteMethod(dest, call, new RequestOptions());
    }

    public Object callRemoteMethod(Address dest, MethodCall call, RequestOptions options) throws Throwable {
        if(log.isTraceEnabled())
            log.trace("dest=" + dest + ", method_call=" + call + ", options=" + options);

        Object buf=req_marshaller != null? req_marshaller.objectToBuffer(call) : Util.objectToByteBuffer(call);
        Message msg=new Message(dest, null, null);
        if(buf instanceof Buffer)
            msg.setBuffer((Buffer)buf);
        else
            msg.setBuffer((byte[])buf);
        msg.setFlag(options.getFlags());
        if(options.getScope() > 0)
            msg.setScope(options.getScope());

        Object retval=super.sendMessage(msg, options);
        if(log.isTraceEnabled()) log.trace("retval: " + retval);
        if(retval instanceof Throwable)
            throw (Throwable)retval;
        return retval;
    }

    @Deprecated
    public <T> NotifyingFuture<T> callRemoteMethodWithFuture(Address dest, MethodCall method_call, int mode, long timeout, boolean oob) throws Throwable {
        RequestOptions options=new RequestOptions(mode, timeout, false, null);
        if(oob) options.setFlags(Message.OOB);
        return callRemoteMethodWithFuture(dest, method_call, options);
    }

    @Deprecated
    public <T> NotifyingFuture<T> callRemoteMethodWithFuture(Address dest, MethodCall call) throws Throwable {
        return callRemoteMethodWithFuture(dest, call, new RequestOptions());
    }

    public <T> NotifyingFuture<T> callRemoteMethodWithFuture(Address dest, MethodCall call, RequestOptions options) throws Throwable {
        if(log.isTraceEnabled())
            log.trace("dest=" + dest + ", method_call=" + call + ", options=" + options);

        Object buf=req_marshaller != null? req_marshaller.objectToBuffer(call) : Util.objectToByteBuffer(call);
        Message msg=new Message(dest, null, null);
        if(buf instanceof Buffer)
            msg.setBuffer((Buffer)buf);
        else
            msg.setBuffer((byte[])buf);
        msg.setFlag(options.getFlags());
        if(options.getScope() > 0)
            msg.setScope(options.getScope());
        return super.sendMessageWithFuture(msg, options);
    }


    protected void correlatorStarted() {
        if(corr != null)
           corr.setMarshaller(rsp_marshaller);
    }


    /**
     * Message contains MethodCall. Execute it against *this* object and return result.
     * Use MethodCall.invoke() to do this. Return result.
     */
    public Object handle(Message req) {
        Object      body;
        MethodCall  method_call;

        if(server_obj == null) {
            if(log.isErrorEnabled()) log.error("no method handler is registered. Discarding request.");
            return null;
        }

        if(req == null || req.getLength() == 0) {
            if(log.isErrorEnabled()) log.error("message or message buffer is null");
            return null;
        }

        try {
            body=req_marshaller != null?
                    req_marshaller.objectFromByteBuffer(req.getBuffer(), req.getOffset(), req.getLength())
                    : req.getObject();
        }
        catch(Throwable e) {
            if(log.isErrorEnabled()) log.error("exception marshalling object", e);
            return e;
        }

        if(!(body instanceof MethodCall)) {
            if(log.isErrorEnabled()) log.error("message does not contain a MethodCall object");
           
            // create an exception to represent this and return it
            return  new IllegalArgumentException("message does not contain a MethodCall object") ;
        }

        method_call=(MethodCall)body;

        try {
            if(log.isTraceEnabled())
                log.trace("[sender=" + req.getSrc() + "], method_call: " + method_call);

            if(method_call.getMode() == MethodCall.ID) {
                if(method_lookup == null)
                    throw new Exception("MethodCall uses ID=" + method_call.getId() + ", but method_lookup has not been set");
                Method m=method_lookup.findMethod(method_call.getId());
                if(m == null)
                    throw new Exception("no method found for " + method_call.getId());
                method_call.setMethod(m);
            }
           
            return method_call.invoke(server_obj);
        }
        catch(Throwable x) {
            return x;
        }
    }

    /**
     * Add a new channel listener to be notified on the channel's state change.
     *
     * @return true if the listener was added or false if the listener was already in the list.
     */
    public boolean addChannelListener(ChannelListener l) {
        synchronized(additionalChannelListeners) {
            if (additionalChannelListeners.contains(l)) {
               return false;
            }
            additionalChannelListeners.add(l);
            return true;
        }
    }


    /**
     *
     * @return true if the channel was removed indeed.
     */
    public boolean removeChannelListener(ChannelListener l) {

        synchronized(additionalChannelListeners) {
            return additionalChannelListeners.remove(l);
        }
    }



    /* --------------------- Interface ChannelListener ---------------------- */

    public void channelConnected(Channel channel) {

        synchronized(additionalChannelListeners) {
            for(Iterator i = additionalChannelListeners.iterator(); i.hasNext(); ) {
                ChannelListener l = (ChannelListener)i.next();
                try {
                    l.channelConnected(channel);
                }
                catch(Throwable t) {
                    log.warn("channel listener failed", t);
                }
            }
        }
    }

    public void channelDisconnected(Channel channel) {

        stop();

        synchronized(additionalChannelListeners) {
            for(Iterator i = additionalChannelListeners.iterator(); i.hasNext(); ) {
                ChannelListener l = (ChannelListener)i.next();
                try {
                    l.channelDisconnected(channel);
                }
                catch(Throwable t) {
                    log.warn("channel listener failed", t);
                }
            }
        }
    }

    public void channelClosed(Channel channel) {

        stop();

        synchronized(additionalChannelListeners) {
            for(Iterator i = additionalChannelListeners.iterator(); i.hasNext(); ) {
                ChannelListener l = (ChannelListener)i.next();
                try {
                    l.channelClosed(channel);
                }
                catch(Throwable t) {
                    log.warn("channel listener failed", t);
                }
            }
        }
    }

    public void channelShunned() {
    }

    public void channelReconnected(Address new_addr) {
    }
    /* ----------------------------------------------------------------------- */

TOP

Related Classes of org.jgroups.blocks.RpcDispatcher$MarshallerAdapter

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.