javarmirmiregistry

Cannot send (Service) object from RMI server to Client


I have been killing my brain trying to figure out the problem, i am pretty sure the server connection is established neatly. i have even put some system prints to make sure the object is sent and received. let me post my code first.

RemoteService.java (interface):

package testrmi;

import java.rmi.*;
import javax.swing.JPanel;

public interface RemoteService extends Remote {

    public Object[] getServiceList() throws RemoteException;
    public Service getService(Object SvcKey) throws RemoteException;

}

Service.java (interface) used by Services offered by server:

package testrmi;

import javax.swing.*;
import java.io.*;
import java.rmi.Remote;

public interface Service extends Serializable {

    public JPanel getGuiPanel();

}

RSimpl.java (RemoteService interface implementer)

package testrmi;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;

public class RSimpl implements RemoteService {

    HashMap<String, Service> map;

    public RSimpl() throws RemoteException
    {
        //super();
        setUpServices();
    }

    public void setUpServices()
    {
        map = new HashMap<String, Service>();
        map.put("Dice Roll Service", new DiceRoll());
        map.put("Calculator Service", new Calculator());
        map.put("Clock Service", new DigitalClock1());
        // Keep Adding Services On The Go!
    }

    public Object[] getServiceList()
    {
        return map.keySet().toArray();
    }

    public Service getService(Object SvcKey)
    {
        System.out.println(SvcKey + " request has been recieved");
        Service theService = map.get(SvcKey);
        return theService;
    }
}

Client.java (The client, this looks dirty :p )

package testrmi;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class Client {

    JFrame frame;
    JPanel mainPanel;
    JComboBox<Object> comboBox;
    RemoteService server;
    int i = 0;
    Object[] error = {"Cannot Load Services"};

    public void buildGUI()
    {
        frame = new JFrame("Service Browser");
        mainPanel = new JPanel();

        attemptConnect();

        frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
        frame.getContentPane().add(BorderLayout.NORTH, comboBox);
        frame.setVisible(true);
        frame.setSize(300, 150);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        //centerFrame();
    }

    public void attemptConnect()
    {
        if(i==0)
        {
            i++;
            Object[] services = getServiceList();
            try {
                comboBox = new JComboBox<Object>(services);
                if (!services.toString().equalsIgnoreCase("Cannot Load Services"))
                comboBox.addActionListener(new MyListListener());
            }
            catch(Exception ex) {
                System.out.println("Cannot Establish Connection");
            }
        }
    }

    public void centerFrame()
    {
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (int) (d.getWidth()-frame.getWidth() / 2);
        int y = (int) (d.getHeight()-frame.getHeight() / 2);
        frame.setLocation(x, y);
    }

    public Object[] getServiceList()
    {
        boolean connectionsuccess = false;
        Object[] objList = null;
        try {
            Registry rs = LocateRegistry.getRegistry("127.0.0.1", 9797); //CHANGE TO 192.168.1.97
            server = (RemoteService) rs.lookup("RService");
            connectionsuccess = true;
        }
        catch(Exception ex) {
            Object[] options = {"Retry","Cancel"};
            int o = JOptionPane.showOptionDialog(frame, "Cannot Establish Connection To The Server. \n Do You Want To Retry?", "Connection Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
            if(o==0)
            {
                i=0;
                attemptConnect();
            }
            else
            {
                i=1;
                return error;
            }
        }
        if(connectionsuccess) {
            try {
                objList = server.getServiceList();
            }
            catch(Exception ex) {
                Object[] options = {"Retry","Cancel"};
                int o = JOptionPane.showOptionDialog(frame, "Cannot Fetch Services List From The Server. \n Do You Want To Retry?", "Fetch Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
                if(o==0)
                {
                    i=0;
                    attemptConnect();
                }
                else
                {
                    i=1;
                    return error;
                }
            }
        }
        return objList;
    }

    public void loadService(Object SvcKey)
    {
        try {
            System.out.println(" I am going to send key: " + SvcKey);
            Service svc = (Service) server.getService(SvcKey); //THIS IS CAUSING THE ERROR!
            System.out.println("i am yet working"); //THIS LINE IS NOT WORKING
            mainPanel.removeAll();
            //frame.setContentPane(svc.getGuiPanel());
            mainPanel.add(svc.getGuiPanel());
            mainPanel.validate();
            mainPanel.repaint();
            frame.pack();
            frame.setMinimumSize(new Dimension(300,150));
        }
        catch(Exception ex) {
            Object[] options = {"Retry","Cancel"};
            int o = JOptionPane.showOptionDialog(frame, "Cannot Load The Service From The Server. \n Do You Want To Retry?", "Connection Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[0]);
            if(o==0)
            {
                new MyListListener();
            }
            else
            {
                i=1;
                frame.repaint();
            }
        }
    }

    public class MyListListener implements ActionListener
    {
        public void actionPerformed(ActionEvent ev)
        {
            Object selection = comboBox.getSelectedItem();
            System.out.println(comboBox.getSelectedItem()); //DO NOT FORGET TO TEST THIS!
            loadService(selection);
        }
    }

    public static void main(String[] args)
    {
        Client cl = new Client();
        cl.buildGUI();
    }
}

StartServer.java (instantiates RSimpl object and starts server)

package testrmi;

import java.net.InetAddress;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class StartServer {

    public static void main(String[] args)
    {
        try {
            RSimpl obj = new RSimpl();
            RemoteService stub = (RemoteService) UnicastRemoteObject.exportObject(obj, 0);
            System.setProperty("java.rmi.server.hostname","192.168.1.97");
            //RemoteService rs = new RSimpl();
            Registry r = LocateRegistry.getRegistry(9797);
            r.rebind("RService", stub);
            System.out.println("Remote Service Is Running");
            System.out.println(""+ InetAddress.getLocalHost().getHostAddress());
        }
        catch (Exception ex) {
            ex.printStackTrace();
            System.out.println("Sorry, Cannot Start Remote Service");
        }
    }   

}

Calculator.java (Calculator Service, no need to check this)

package testrmi;

import javax.script.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;

public class Calculator implements Service, Serializable {

    JPanel mainPanel;

    public JPanel getGuiPanel()
    {
        mainPanel = new JPanel();
        mainPanel.setLayout(new BorderLayout());

        //JPanel p1 = new JPanel();
        //p1.setLayout(new GridLayout(4,4));

        JPanel p1 = new JPanel();
        JPanel p2 = new JPanel();
        JPanel p3 = new JPanel();
        JPanel p4 = new JPanel();

        final JTextField t = new JTextField(10);
        t.setEditable(false);
        t.setBackground(Color.green);
        t.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
        Font myFont = new Font("MS Sans Serif", Font.BOLD, 24);
        t.setFont(myFont);

        mainPanel.add(t,BorderLayout.NORTH);

        final JButton n1 =  new JButton("1");
        n1.setFocusable(false);
        n1.setFont(myFont);
        n1.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n1.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);
            }
        });

        final JButton  n2 =  new JButton("2");
        n2.setFocusable(false);
        n2.setFont(myFont);
        n2.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n2.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);    
            }
        });

        final JButton  n3 =  new JButton("3");
        n3.setFocusable(false);
        n3.setFont(myFont);
        n3.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n3.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);
            }
        });

        final JButton  n4 =  new JButton("4");
        n4.setFocusable(false);
        n4.setFont(myFont);
        n4.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n4.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);
            }
        });

        final JButton  n5 =  new JButton("5");
        n5.setFocusable(false);
        n5.setFont(myFont);
        n5.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n5.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global); 
            }
        });

        final JButton  n6 =  new JButton("6");
        n6.setFocusable(false);
        n6.setFont(myFont);
        n6.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n6.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);
            }
        });

        final JButton  n7 =  new JButton("7");
        n7.setFocusable(false);
        n7.setFont(myFont);
        n7.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n7.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);  
            }
        }); 

        final JButton  n8 =  new JButton("8");
        n8.setFocusable(false);
        n8.setFont(myFont);
        n8.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n8.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);  
            }
        }); 

        final JButton  n9 =  new JButton("9");
        n9.setFocusable(false);
        n9.setFont(myFont);
        n9.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n9.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);  
            }
        });


        final JButton  n10 =  new JButton("0");
        n10.setFocusable(false);
        n10.setFont(myFont);
        n10.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n10.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);
            }
        });

        final JButton  n11 =  new JButton("+");
        n11.setFocusable(false);
        n11.setFont(myFont);
        n11.setForeground(Color.MAGENTA);
        n11.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n11.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);  
            }   
        });


        final JButton  n12 =  new JButton("-");
        n12.setFocusable(false);
        n12.setFont(myFont);
        n12.setForeground(Color.MAGENTA);
        n12.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n12.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global); 
            }
        });

        final JButton  n13 =  new JButton("*");
        n13.setFocusable(false);
        n13.setFont(myFont);
        n13.setForeground(Color.MAGENTA);
        n13.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n13.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global); 
            }           
        });

        final  JButton  n14 =  new JButton("/");
        n14.setFocusable(false);
        n14.setFont(myFont);
        n14.setForeground(Color.MAGENTA);
        n14.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                String num1 = n14.getText();
                String global = t.getText();
                global = global.concat(num1);
                t.setText(global);  
            }
        });

        final JButton  n15 =  new JButton("=");
        n15.setFocusable(false);
        n15.setFont(myFont);
        n15.setForeground(Color.BLUE);
        n15.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                //String num1 = n15.getText();
                String global = t.getText();
                //global = global.concat(num1);

                ScriptEngineManager mgr = new ScriptEngineManager();
                ScriptEngine engine = mgr.getEngineByName("JavaScript");
                try {
                    String s = engine.eval(global).toString();
                    t.setText(s); 
                } 
                catch (ScriptException e1) {
                    e1.printStackTrace();
                }  
            }
        });

        final  JButton  n16 =  new JButton("C");
        n16.setFocusable(false);
        n16.setFont(myFont);
        n16.setForeground(Color.RED);
        n16.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                //String num1 = n16.getText();
                String global = t.getText();
                global = null;
                t.setText(global);
            }
        });

        p1.add(n1);
        p1.add(n2);
        p1.add(n3);
        p1.add(n4);
        p2.add(n5);
        p2.add(n6);
        p2.add(n7);
        p2.add(n8);
        p3.add(n9);
        p3.add(n10);
        p3.add(n11);
        p3.add(n12);
        p4.add(n13);
        p4.add(n14);
        p4.add(n15);
        p4.add(n16);

        JPanel pPanel = new JPanel();
        pPanel.setLayout(new BoxLayout(pPanel, BoxLayout.Y_AXIS));
        pPanel.add(p1);
        pPanel.add(p2);
        pPanel.add(p3);
        pPanel.add(p4);

        mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        mainPanel.add(pPanel);
        return mainPanel;
    }
}

DiceRoll.java (DiceRoll Service, no need to check this)

package testrmi;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class DiceRoll implements Service {

    int i = 0;
    int h = 0;
    JPanel mainPanel;
    JButton roll;
    MyDrawPanel drawPanel;

    public JPanel getGuiPanel()
    {
        mainPanel = new JPanel();
        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));

        roll = new JButton("Roll The Dice!");
        roll.setFont(new Font("Comic Sans Ms", Font.BOLD, 16));
        roll.setFocusable(false);
        roll.setAlignmentX(Component.CENTER_ALIGNMENT);
        roll.addActionListener(new rollListener());

        drawPanel = new MyDrawPanel();
        drawPanel.setPreferredSize(new Dimension(150,150));

        mainPanel.add(roll);
        mainPanel.add(Box.createRigidArea(new Dimension(0,10)));
        mainPanel.add(drawPanel);
        mainPanel.setBorder(BorderFactory.createEmptyBorder(5,0,5,0));
        return mainPanel;
    }

    public int roll()
    {
        while (i==0 || i==h)
        {
            i = (int) (Math.random()*7);
        }
        h = i;
        return i;
    }

    public class rollListener implements ActionListener
    {
        public void actionPerformed(ActionEvent ev)
        {
            int x = roll();
            drawPanel.sendNum(x);
            drawPanel.repaint();
        }
    }

    public class MyDrawPanel extends JPanel
    {
        Graphics g;
        int least = 0, x;
        int fx=0, fy=0, fw=150, fh=150;
        int dw=100, dh=100;
        int dx=((fw-dw)/2), dy=((fh-dh)/2);
        int dxc,dyc,dx1,dy1,dx2,dy2,dx3,dy3,dx4,dy4,dx5,dy5,dx6,dy6;

        public void paintComponent(Graphics gn)
        {
            g = gn;
            super.paintComponent(g);
            g.setColor(Color.LIGHT_GRAY);
            g.fillRect(fx, fy, fw, fh);
            g.setColor(Color.WHITE);
            g.fillRoundRect(dx, dy, dw, dh, 30, 30);
            g.setColor(Color.BLACK); // set black for dots and border
            g.drawRoundRect(dx, dy, dw, dh, 30, 30);
            if(least>=1)
            {
                if(x==1)
                {
                    g.fillOval(dxc, dyc, 20, 20);
                }
                else if(x==2)
                {
                    g.fillOval(dx1, dy1, 20, 20);
                    g.fillOval(dx6, dy6, 20, 20);
                }
                else if(x==3)
                {
                    g.fillOval(dx1, dy1, 20, 20);
                    g.fillOval(dxc, dyc, 20, 20);
                    g.fillOval(dx6, dy6, 20, 20);
                }
                else if(x==4)
                {
                    g.fillOval(dx1, dy1, 20, 20);
                    g.fillOval(dx2, dy2, 20, 20);
                    g.fillOval(dx5, dy5, 20, 20);
                    g.fillOval(dx6, dy6, 20, 20);
                }
                else if(x==5)
                {
                    g.fillOval(dx1, dy1, 20, 20);
                    g.fillOval(dx2, dy2, 20, 20);
                    g.fillOval(dxc, dyc, 20, 20);
                    g.fillOval(dx5, dy5, 20, 20);
                    g.fillOval(dx6, dy6, 20, 20);
                }
                else if(x==6)
                {
                    g.fillOval(dx1, dy1, 20, 20);
                    g.fillOval(dx2, dy2, 20, 20);
                    g.fillOval(dx3, dy3, 20, 20);
                    g.fillOval(dx4, dy4, 20, 20);
                    g.fillOval(dx5, dy5, 20, 20);
                    g.fillOval(dx6, dy6, 20, 20);
                }
            }
        }

        public void sendNum(int xx)
        {
            least = 1;
            x = xx;
            // REMEMBER: dx+40=CENTER_X and dy+40=CENTER_Y because dice size 100, dot size 20
            dxc=dx+40;
            dyc=dy+40;
            dx1=dx+10;
            dy1=dy+10;
            dx2=dx+70;
            dy2=dy+10;
            dx3=dx+10;
            dy3=dy+40;
            dx4=dx+70;
            dy4=dy+40;
            dx5=dx+10;
            dy5=dy+70;
            dx6=dx+70;
            dy6=dy+70;
        }
    } // close class MyDrawPanel
}

DigitalClock1.java (no need to check -- these are only for compilation purposes)

package testrmi;

import java.awt.*; 
import java.util.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.awt.event.ActionEvent;

public class DigitalClock1 implements Service
{
        public JPanel getGuiPanel()
        {
            SimpleDigitalClock clock1 = new SimpleDigitalClock();
            return clock1;
        }
        static class SimpleDigitalClock extends JPanel
        { 
            String stringTime;
            int hour, minute, second;
            String aHour = "";
            String bMinute = "";
            String cSecond = ""; 
            public void setStringTime(String abc)
            {
                this.stringTime = abc;
            } 
            public int Number(int a, int b)
            {
                return (a <= b) ? a : b;
            } 
            SimpleDigitalClock()
            { 
                Timer t = new Timer(1000, new ActionListener()
                { 
                    public void actionPerformed(ActionEvent e)
                    {
                        repaint();
                    }
                });
                t.start();
            }
            @Override 
            public void paintComponent(Graphics v)
            {
                super.paintComponent(v);
                Calendar rite = Calendar.getInstance();
                hour = rite.get(Calendar.HOUR_OF_DAY);
                minute = rite.get(Calendar.MINUTE);
                second = rite.get(Calendar.SECOND);
                if (hour < 10)
                {
                    this.aHour = "0"; 
                } 
                if (hour >= 10)
                {
                    this.aHour = "";
                } 
                if (minute < 10)
                {
                    this.bMinute = "0";
                } 
                if (minute >= 10)
                {
                    this.bMinute = "";
                }
                if (second < 10)
                {
                    this.cSecond = "0";
                }
                if (second >= 10)
                {
                    this.cSecond = "";
                } 
                setStringTime(aHour + hour + ":" + bMinute+ minute + ":" + cSecond + second);
                v.setColor(Color.BLACK);
                int length = Number(this.getWidth(),this.getHeight());
                Font Font1 = new Font("Comic Sans MS", Font.PLAIN, length / 5);
                v.setFont(Font1);
                v.drawString(stringTime, (int) length/6, length/2);
            } 
            @Override 
            public Dimension getPreferredSize()
            {
                return new Dimension(200, 200);
            }
        }
}

I am running start rmiregistry 9797 from the directory in which the testrmi directory(package) is also placed. Then I run java testrmi.StartServer from the same directory. I get the server is running message, then I run the client from another directory but with same package name, which only contains Client.class, RemoteService.class and Service.class; the client starts fine, displays all three services, but when I select from the list, I get the exception error 'Cannot load service, retry?'.

NOTE: The client loads the services properly if I copy the services (calculator.class, diceroll.class and digitalclock1.class) in the client package directory. I don't want the services to be accessible to the clients directly without connecting to server.


Solution

  • If you want to be able to return serializable objects to the client that aren't in the client's classpath, you need to use the RMI codebase feature, which among other things requires you to deploy a codebase server, and use a SecurityManager at the client.