Pass by reference problem in RMI? [duplicate]
can somebody please tell me where i m wrong why this RMI chat application not working,the goal is to achieve decoupleing between client, server and logic by remote objects or serialized objects.
import javax.swing.*;
import java.awt.event.*;
import java.rmi.*;
import java.rmi.server.*;
public class ChatClient1 implements ICallback {
JFrame frame = new JFrame("Chat Client");
private JTextArea myText;
private static JTextArea TAUinDispMsg;
private JScrollPane myTextScroll;
private JScrollPane TAUinDispMsgScroll;
private String textString = "";
private boolean firstMessage = true;
private static String name = null;
private static final int HOR_SIZE = 400;
private static final int VER_SIZE = 150;
protected static ServerServices chatServer;
MessageImpl remomsg ;
public ChatClient1() throws RemoteException {
super();
try {
this.chatServer = (ServerServices) Naming.lookup("rmi://localhost"
+ "/ChatServer");
UnicastRemoteObject.exportObject(this);
chatServer.register(this);
} catch (Exception e) {
System.err.println("RemoteException: " + e.getMessage());
System.exit(0);
}
;
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
initComponents();
}
});
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
try {
if (name != null) {
// chatServer.leave(displayChat, name);
}
} catch (Exception ex) {
TAUinDispMsg.append("Exit failed.");
}
System.exit(0);
}
});
}
private void initComponents() {
myText = new JTextArea();
myTextScroll = new JScrollPane(myText);
myTextScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
myTextScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
myTextScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myTextScroll
.setPreferredSize(new java.awt.Dimension(HOR_SIZE, VER_SIZE));
myText.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
textTyped(evt);
}
});
frame.getContentPane().add(myTextScroll, java.awt.BorderLayout.NORTH);
TAUinDispMsg = new JTextArea();
TAUinDispMsgScroll = new JScrollPane(TAUinDispMsg);
TAUinDispMsg.setBackground(new java.awt.Color(200, 200, 200));
TAUinDispMsgScroll
.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
TAUinDispMsgScroll
.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
TAUinDispMsgScroll.setMaximumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setMinimumSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsgScroll.setPreferredSize(new java.awt.Dimension(HOR_SIZE,
VER_SIZE));
TAUinDispMsg.setEditable(false);
frame.getContentPane().add(TAUinDispMsgScroll,
java.awt.BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
private void textTyped(java.awt.event.KeyEvent evt) {
try {
remomsg = new MessageImpl();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
char c = evt.getKeyChar();
if (c == '\n') {
try {
if (firstMessage) {
name = textString;
// .join(name);
firstMessage = false;
} else {
remomsg.sendMessage(name, textString);
}
} catch (RemoteException ie) {
TAUinDispMsg.append("Failed to send message.");
System.err.println(ie.getMessage());
}
textString = "";
} else {
textString = textString + c;
}
}
@Override
public void updateClients(final String msg) throws RemoteException {
// TODO Auto-generated method stub
System.out.println("Recived Message: " + msg);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TAUinDispMsg.append(name + " says: " + msg + "\n");
}
});
}
public static void main(String args[]) throws RemoteException {
ChatClient1 ch = null;
try {
ch = new ChatClient1();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
**ICallback.java: interface for callbacks from server to client**
import java.rmi.*;
public interface ICallback extends Remote {
void updateClients(String msg) throws RemoteException;
}
The object which i want to serve as business logic (gamelogic).
import java.rmi.*;
public interface Message extends Remote {
public void sendMessage(String name, String message) throws RemoteException;
public void updateClients() throws RemoteException;
}
Its implementation:
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class MessageImpl extends UnicastRemoteObject implements Message {
private String name;
private String message;
public MessageImpl() throws RemoteException {
super();
}
public MessageImpl(ArrayList clients2) throws RemoteException {
// TODO Auto-generated constructor stub
this.clients = clients2;
}
static ServerServicesImpl si;
// static ArrayListDemo az;
private List<ICallback> clients = new ArrayList<ICallback>();
// private List<ICallback> clients;
private ServerEngine serverEngine = new ServerEngine();
// Notice this one not called remotely
public void setName(String name) throws RemoteException {
this.name = name;
}
public String getName() {
return name;
}
public void setServerList(ServerEngine serverList2) throws RemoteException {
this.serverEngine = serverList2;
}
public void setClientList(List<ICallback> aclients) throws RemoteException {
this.clients = (ArrayList<ICallback>) aclients;
System.err.println("in setClientlist");
}
public ServerEngine getServerList() {
return serverEngine;
}
// Notice this one not called remotely
public void setMessage(String message) throws RemoteException {
this.message = message;
}
public String getMessage() {
return message;
}
public void updateClients() throws RemoteException {
si = new ServerServicesImpl();
ArrayList j = si.getClientNames();
System.out.println(j.size());
if (clients != null) {
System.out.println(clients.size());
for (ICallback aClient : clients) {
aClient.updateClients(message);
}
} else
System.err.println("Clientlist is empty");
if (clients != null) {
System.out.println(j.size());
} else
System.err.println("Clientlist is empty");
}
public void sendMessage(String name, String message1)
throws RemoteException {
setName(name);
setMessage(message1);
updateClients();
}
}
class for managaing client threads
import java.lang.*;
import java.util.*;
class ServerEngine {
private Collection<ICallback> threadList =
new ArrayList<ICallback>();
private int counter = 0;
// Get the lock on threadList, and wait until the counter is zero - that
//is, no reads are taking place. Then it's safe to add the thread.
public synchronized void add(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.add(item);
}
catch (InterruptedException e) {
System.out.println("Addition interrupted.");
}
finally{
notifyAll();
}
}
// Similarly for removal.
public synchronized void remove(ICallback item) {
try {
while (counter > 0) {
wait();
}
threadList.remove(item);
}
catch (InterruptedException e) {
System.out.println("Removal interrupted.");
}
finally {
notifyAll();
}
}
// Similarly for changing counter
public synchronized void incCounter() {
counter++;
notifyAll();
}
public synchronized void decCounter() {
counter--;
notifyAll();
}
//This is because it would be too much effort to make this class implement
//Collection,开发者_如何学运维 return it's own Iterator etc. etc...\
//Note it is *not* a bug that it isn't synchronized
public Collection getCollection() {
return threadList;
}
}
Service.java: server the object which will be register and will bind to.
import java.rmi.*;
import java.util.ArrayList;
public interface ServerServices extends Remote {
// added so client can register self with server for callbacks
public void register(ICallback newClient) throws RemoteException;
public ArrayList getClients() throws RemoteException;
}
ServerServicesImpl.java: implementation side of server
import java.io.Serializable;
import java.rmi.*;
import java.rmi.server.*;
import java.util.*;
class ServerServicesImpl extends UnicastRemoteObject implements ServerServices,
Serializable {
String message;
MessageImpl msgimpl;
static Vector data = new Vector();
private static ArrayList Aclients = new ArrayList<ICallback>();
private static ArrayList testlist;
public ServerServicesImpl() throws RemoteException {
super();
testlist = new ArrayList();
}
public synchronized void register(ICallback newClient)
throws RemoteException {
data.addElement(newClient);
Aclients.add(newClient);
// //serverEngine.add(newClient);
testlist.add("testing");
System.out.println("testlist size =" + testlist.size());
System.out.println(Aclients.size());
setClientList(Aclients);
}
ArrayList getClientNames() {
// Aclients.add(ic);
System.out.println("vector size =" + data.size());
System.out.println("testlist size =" + testlist.size());
System.out.println(" Aclientlist size =" + Aclients.size());
return Aclients;
}
public void setClientList(ArrayList aclients2) {
this.Aclients = aclients2;
}
}
// the server which will publish the above remote object
import java.net.MalformedURLException;
import java.rmi.*;
public class ServiceLoader
{
public static void main(String[] args)
{
try
{
// Install a security manager
System.setSecurityManager(new RMISecurityManager());
ServerServicesImpl obj = new ServerServicesImpl();
Naming.rebind("ChatServer", obj);
System.out.println("ServiceLoader running.");
}
catch (MalformedURLException e)
{
System.err.println(e.getMessage());
}
catch (RemoteException e)
{
System.err.println(e.getMessage());
}
}
}
Change
private List<TTTClientRemote> serverList;
To:
private List<TTTClientRemote> serverList = new ArrayList<TTTClientRemote>();
Or initialize it somewhere before the for() in updateClients();
your question is not clear enough but:
debug your code, or put some logs (simply System.out.println) before the line that you are getting NPE. maybe you List is still null.
public void updateClients() throws RemoteException {
**if (serverList != null) {**
for (TTTClientRemote aClient : serverList) {
aClient.updateClients("slam");
}
}
}
As answered by Ernest Friedman-Hill at link texthttp://www.coderanch.com/t/508960/java/java/pass-reference:
The root of problem was the fact that RMI doesn't support pass by reference , so making the message class serializable and creating the remote instance of ServerServices in that serializable class can make this application work
OR
creating the remote instance of Message class in client class and publishing that from RMI registry can also work.
In this code the local references were used instead of remote, so it was getting the 0 elements in the list from Serverservices class.
thanks again to: Ernest Friedman-Hill.
精彩评论