如何使用Java RMI实现Observer模式?

时间:2009-07-27 12:06:19

标签: java rmi observer-pattern

我有一个客户端在服务器上启动一个长时间运行的进程。我会定期向用户展示后台正在发生的事情。最简单的方法是轮询服务器,但我想知道是否没有办法为此实现Observer模式。不幸的是,我正在使用RMI与服务器通信,我担心我必须将我的客户端变为RMI服务器。

我还有另一种方法吗?

4 个答案:

答案 0 :(得分:5)

答案 1 :(得分:3)

RMI通常可以支持双向通信。 (是的,RMI是一个PITA来建立,并做任何其他事情。)

但是,通过CGI脚本(!)工作的HTTP传输不支持它。

答案 2 :(得分:2)

在这里整合所有答案,我在客户端和服务器之间实现了双向RMI,服务器使用Registry公开其存根

  1. 客户端从rmi registry
  2. 获取服务器的存根
  3. 然后客户端将其存根作为Observer放入服务器的addObserver方法
  4. 服务器使用此存根通知客户端
  5. 以下代码将提供更好的主意

    import java.rmi.*;
    import java.rmi.registry.*;
    import java.rmi.server.*;
    import java.util.Observable;
    import java.util.Observer;
    import java.net.*;
    
    import javax.rmi.ssl.SslRMIClientSocketFactory;
    import javax.rmi.ssl.SslRMIServerSocketFactory;
    
    interface ReceiveMessageInterface extends Remote
    {
        /**
         * @param x
         * @throws RemoteException
         */
        void receiveMessage(String x) throws RemoteException;
    
        /**
         * @param observer
         * @throws RemoteException
         */
        void addObserver(Remote observer) throws RemoteException;
    }
    
    /**
     * 
     */
    class RmiClient extends UnicastRemoteObject
    {
        /**
         * @param args
         */
        static public void main(String args[])
        {
            ReceiveMessageInterface rmiServer;
            Registry registry;
            String serverAddress = args[0];
            String serverPort = args[1];
            String text = args[2];
            System.out.println("sending " + text + " to " + serverAddress + ":" + serverPort);
            try
            { // Get the server's stub
                registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue());
                rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer"));
    
                // RMI client will give a stub of itself to the server
                Remote aRemoteObj = (Remote) UnicastRemoteObject.exportObject(new RmiClient(), 0);
                rmiServer.addObserver(aRemoteObj);
    
                // call the remote method
                rmiServer.receiveMessage(text);
                // update method will be notified
            }
            catch (RemoteException e)
            {
                e.printStackTrace();
            }
            catch (NotBoundException e)
            {
                System.err.println(e);
            }
        }
    
        public void update(String a) throws RemoteException
        {
            // update should take some serializable object as param NOT Observable
            // and Object
            // Server callsbacks here
        }
    }
    
    /**
     * 
     */
    class RmiServer extends Observable implements ReceiveMessageInterface
    {
        String address;
        Registry registry;
    
        /**
         * {@inheritDoc}
         */
        public void receiveMessage(String x) throws RemoteException
        {
            System.out.println(x);
            setChanged();
            notifyObservers(x + "invoked me");
        }
    
        /**
         * {@inheritDoc}
         */
        public void addObserver(final Remote observer) throws RemoteException
        {
            // This is where you plug in client's stub
            super.addObserver(new Observer()
            {
                @Override
                public void update(Observable o,
                    Object arg)
                {
                    try
                    {
                        ((RmiClient) observer).update((String) arg);
                    }
                    catch (RemoteException e)
                    {
    
                    }
                }
            });
        }
    
        /**
         * @throws RemoteException
         */
        public RmiServer() throws RemoteException
        {
            try
            {
                address = (InetAddress.getLocalHost()).toString();
            }
            catch (Exception e)
            {
                System.out.println("can't get inet address.");
            }
            int port = 3232;
            System.out.println("this address=" + address + ",port=" + port);
            try
            {
                registry = LocateRegistry.createRegistry(port);
                registry.rebind("rmiServer", this);
            }
            catch (RemoteException e)
            {
                System.out.println("remote exception" + e);
            }
        }
    
        /**
         * 
         * @param args
         */
        static public void main(String args[])
        {
            try
            {
                RmiServer server = new RmiServer();
            }
            catch (Exception e)
            {
                e.printStackTrace();
                System.exit(1);
            }
        }
    }
    

答案 3 :(得分:1)

我认为你没有遗漏任何东西。唯一的两种方法是定期调用服务器并检查状态(轮询)或注册服务器定期调用的回调(客户端必须公开方法)。 IMO,民意调查是解决这个问题的一种非常合理的方法。

相关问题