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

net.sf.lipermi.handler.ConnectionHandler Maven / Gradle / Ivy

There is a newer version: 1.0.3
Show newest version
/*
 * LipeRMI - a light weight Internet approach for remote method invocation
 * Copyright (C) 2006  Felipe Santos Andrade
 * 
 * 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * 
 * For more information, see http://lipermi.sourceforge.net/license.php
 * You can also contact author through [email protected]
 */
package net.sf.lipermi.handler;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import net.sf.lipermi.call.IRemoteMessage;
import net.sf.lipermi.call.RemoteCall;
import net.sf.lipermi.call.RemoteInstance;
import net.sf.lipermi.call.RemoteReturn;
import net.sf.lipermi.exception.LipeRMIException;
import net.sf.lipermi.handler.filter.IProtocolFilter;

/**
 * A ConnectionHandler is object which can call remote
 * methods, receive remote calls and dispatch its returns.
 *
 * @author lipe
 * date 05/10/2006
 *
 * @see	net.sf.lipermi.handler.CallHandler
 * @see	net.sf.lipermi.call.RemoteInstance
 * @see	net.sf.lipermi.call.RemoteCall
 * @see	net.sf.lipermi.call.RemoteReturn
 * @see	net.sf.lipermi.net.Client
 * @see	net.sf.lipermi.net.Server
 * @see	net.sf.lipermi.handler.filter.DefaultFilter
 */
public class ConnectionHandler implements Runnable {

    public static ConnectionHandler createConnectionHandler(Socket socket, CallHandler callHandler,
            IProtocolFilter filter) {
        ConnectionHandler connectionHandler = new ConnectionHandler(socket, callHandler, filter);

        String threadName = String.format("ConnectionHandler (%s:%d)", socket.getInetAddress().getHostAddress(), socket
                .getPort()); //$NON-NLS-1$
        Thread connectionHandlerThread = new Thread(connectionHandler, threadName);
        connectionHandlerThread.setDaemon(true);
        connectionHandlerThread.start();

        return connectionHandler;
    }

    public static ConnectionHandler createConnectionHandler(Socket socket, CallHandler callHandler,
            IProtocolFilter filter, IConnectionHandlerListener listener) {
        ConnectionHandler connectionHandler = createConnectionHandler(socket, callHandler, filter);
        connectionHandler.addConnectionHandlerListener(listener);
        return connectionHandler;
    }

    private final CallHandler callHandler;

    private final Socket socket;

    private ObjectOutputStream output;

    private static final AtomicLong callId = new AtomicLong(0L);

    private final IProtocolFilter filter;

    private final List listeners = new LinkedList<>();

    private final Map remoteInstanceProxys = new HashMap<>();

    private final List remoteReturns = new LinkedList<>();

    public void addConnectionHandlerListener(IConnectionHandlerListener listener) {
        listeners.add(listener);
    }

    public void removeConnectionHandlerListener(IConnectionHandlerListener listener) {
        listeners.remove(listener);
    }

    private ConnectionHandler(Socket socket, CallHandler callHandler, IProtocolFilter filter) {
        this.callHandler = callHandler;
        this.socket = socket;
        this.filter = filter;
    }

    @Override
    public void run() {
        ObjectInputStream input;

        try {
            input = new ObjectInputStream(socket.getInputStream());

            while (socket.isConnected()) {
                Object objFromStream = input.readUnshared();

                IRemoteMessage remoteMessage = filter.readObject(objFromStream);

                if (remoteMessage instanceof RemoteCall) {

                    final RemoteCall remoteCall = (RemoteCall) remoteMessage;
                    if (remoteCall.getArgs() != null) {
                        for (int n = 0; n < remoteCall.getArgs().length; n++) {
                            Object arg = remoteCall.getArgs()[n];
                            if (arg instanceof RemoteInstance) {
                                RemoteInstance remoteInstance = (RemoteInstance) arg;
                                remoteCall.getArgs()[n] = getProxyFromRemoteInstance(remoteInstance);
                            }
                        }
                    }

                    Thread delegator = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            CallLookup.handlingMe(ConnectionHandler.this);

                            RemoteReturn remoteReturn;
                            try {
//								System.out.println("remoteCall: " + remoteCall.getCallId() + " - " + remoteCall.getRemoteInstance().getInstanceId());
//								System.out.println("(" + remoteCall.getCallId() + ") " + remoteCall.getArgs()[0]);
                                remoteReturn = callHandler.delegateCall(remoteCall);
//								System.out.println("(" + remoteCall.getCallId() + ") " + remoteReturn.getRet());
                                sendMessage(remoteReturn);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                            CallLookup.forgetMe();
                        }
                    }, "Delegator"); //$NON-NLS-1$
                    delegator.setDaemon(true);
                    delegator.start();
                } else if (remoteMessage instanceof RemoteReturn) {
                    RemoteReturn remoteReturn = (RemoteReturn) remoteMessage;
                    synchronized (remoteReturns) {
                        remoteReturns.add(remoteReturn);
                        remoteReturns.notifyAll();
                    }
                } else {
                    throw new LipeRMIException("Unknown IRemoteMessage type"); //$NON-NLS-1$
                }
            }
        } catch (IOException | ClassNotFoundException | LipeRMIException e) {
            try {
                socket.close();
            } catch (IOException e1) {
            }

            synchronized (remoteReturns) {
                remoteReturns.notifyAll();
            }

            for (IConnectionHandlerListener listener : listeners) {
                listener.connectionClosed();
            }
        }
    }

    private synchronized void sendMessage(IRemoteMessage remoteMessage) throws IOException {
        if (output == null) {
            output = new ObjectOutputStream(socket.getOutputStream());
        }

        Object objToWrite = filter.prepareWrite(remoteMessage);
        output.reset();
        output.writeUnshared(objToWrite);
        output.flush();
    }

    final synchronized Object remoteInvocation(final Object proxy, final Method method, final Object[] args)
            throws Throwable {
        final Long id = callId.getAndIncrement();

        RemoteInstance remoteInstance;
        remoteInstance = getRemoteInstanceFromProxy(proxy);
        if (remoteInstance == null) {
            remoteInstance = new RemoteInstance(null, proxy.getClass().getInterfaces()[0].getName());
        }

        if (args != null) {
            for (int n = 0; n < args.length; n++) {
                RemoteInstance remoteRef = callHandler.getRemoteReference(args[n]);
                if (remoteRef != null) {
                    args[n] = remoteRef;
                }
            }
        }

        String methodId = method.toString().substring(15);

        IRemoteMessage remoteCall = new RemoteCall(remoteInstance, methodId, args, id);
        sendMessage(remoteCall);

        RemoteReturn remoteReturn = null;

        boolean bReturned = false;
        do {
            synchronized (remoteReturns) {
                for (RemoteReturn ret : remoteReturns) {
                    if (ret.getCallId().equals(id)) {
                        bReturned = true;
                        remoteReturn = ret;
                        break;
                    }
                }
                if (bReturned) {
                    remoteReturns.remove(remoteReturn);
                } else {
                    try {
                        remoteReturns.wait();
                    } catch (InterruptedException ie) {
                    }
                }
            }
        } while (socket.isConnected() && !bReturned);

        if (!socket.isConnected() && !bReturned) {
            throw new LipeRMIException("Connection aborted"); //$NON-NLS-1$
        }
        if (remoteReturn.isThrowing() && remoteReturn.getRet() instanceof Throwable) {
            throw ((Throwable) remoteReturn.getRet()).getCause();
        }

        if (remoteReturn.getRet() instanceof RemoteInstance) {
            RemoteInstance remoteInstanceReturn = (RemoteInstance) remoteReturn.getRet();
            Object proxyReturn = remoteInstanceProxys.get(remoteInstanceReturn);
            if (proxyReturn == null) {
                proxyReturn = CallProxy.buildProxy(remoteInstanceReturn, this);
                remoteInstanceProxys.put(remoteInstanceReturn, proxyReturn);
            }
            return proxyReturn;
        }

        return remoteReturn.getRet();
    }

    private Object getProxyFromRemoteInstance(RemoteInstance remoteInstance) {
        Object proxy = remoteInstanceProxys.get(remoteInstance);
        if (proxy == null) {
            try {
                proxy = CallProxy.buildProxy(remoteInstance, this);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            remoteInstanceProxys.put(remoteInstance, proxy);
        }
        return proxy;
    }

    private RemoteInstance getRemoteInstanceFromProxy(Object proxy) {
        for (RemoteInstance remoteInstance : remoteInstanceProxys.keySet()) {
            if (remoteInstanceProxys.get(remoteInstance) == proxy) {
                return remoteInstance;
            }
        }
        return null;
    }

    public Socket getSocket() {
        return socket;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy