===== Chat GUI =====
Készítsünk egy csoportos Chat vastag kliens alkalmazást. Alkalmazzuk a Java-RMI technológiát.
Hozzunk létre két projektet az eclipse-ben a kliens és a szerver számára. Az alábbi interakciós diagramm bemutatja az elvi működést.
sequenceDiagram
participant U as User
participant UI as ChatUI
participant CC as ChatClient
participant CS as ChatServer
participant IC as IChatClient
participant IS as IChatServer
U->>UI: Starts Application
UI->>CC: Creates ChatClient
CC->>IS: Tries to connect
IS->>CS: Login request
CS->>IC: Checks if client can connect
IC->>CC: Connection successful
CC->>UI: Update UI (Connected)
UI->>U: Show connected status
U->>UI: Enter message
UI->>CC: Send message
CC->>IS: Publish message
IS->>CS: Publish message to all clients
CS->>IC: Iterate over clients
IC->>CC: Display message
CC->>UI: Update UI with new message
UI->>U: Show new message
U->>UI: Disconnect
UI->>CC: Disconnect from server
CC->>IS: Logout request
IS->>CS: Remove client from list
CS-->>IC: Update client list
IC->>CC: Acknowledge disconnect
CC->>UI: Update UI (Disconnected)
UI->>U: Show disconnected status
Készíthetünk egy másik diagrammot is a működés bemutatásásra:
* **ChatUI** a felhasználói interfész, amely közvetlenül kommunikál a ChatClient-tel.
* **ChatClient** a kliens oldali logika, amely megvalósítja az IChatClient interfészt.
* **Java RMI Registry** a szolgáltatások nevének feloldására szolgál, amit a ChatClient használ a IChatServer interfész elérésére.
* **IChatServer** az interfész, amelyen keresztül a ChatClient kommunikál a ChatServer-rel.
* **ChatServer** a szerver oldali logika, amely megvalósítja az IChatServer interfészt.
* **Client List** a csatlakoztatott kliensek listája a szerveren.
* **User Interface** ábrázolja a felhasználói felület komponenseit, amelyek interakcióban állnak a felhasználóval.
E
z a diagram bemutatja a rendszer összetevőinek kapcsolódási és kommunikációs struktúráját, beleértve a kliens és szerver közötti interakciókat.
graph TD
A[ChatUI] --> B[ChatClient]
B --> C{Java RMI Registry}
B -->|lookup| D[IChatServer]
D --> E[ChatServer]
E --> F[IChatClient]
F --> B
D -.-> G[Client List]
E --> G
A -.-> H[User Interface]
H --> A
C -.->|registers| E
style A fill:#f9f,stroke:#333,stroke-width:4px
style B fill:#bbf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style C fill:#fea,stroke:#333,stroke-width:2px
style D fill:#bbf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style E fill:#f99,stroke:#333,stroke-width:4px
style F fill:#bbf,stroke:#f66,stroke-width:2px,stroke-dasharray: 5, 5
style G fill:#dff,stroke:#333,stroke-width:2px
style H fill:#fff,stroke:#333,stroke-width:2px
==== Project 1: ChatServer ====
1.) IChatClient
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IChatClient extends Remote {
public void tell(String name) throws RemoteException;
public String getName() throws RemoteException;
}
2.) IChatServer
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;
public interface IChatServer extends Remote {
public boolean login(IChatClient client) throws RemoteException;
public void publish(String s) throws RemoteException;
public ArrayList getConnected() throws RemoteException;
}
3.) ChatServer
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
public class ChatServer extends UnicastRemoteObject implements IChatServer {
private static final long serialVersionUID = 4705993250126188735L;
private ArrayList v = new ArrayList();
public ChatServer() throws RemoteException {
}
public boolean login(IChatClient client) throws RemoteException {
System.out.println(client.getName() + " got connected....");
client.tell("client connected");
publish(client.getName() + " connected.");
v.add(client);
return true;
}
public void publish(String s) throws RemoteException {
System.out.println(s);
for (int i = 0; i < v.size(); i++) {
try {
IChatClient tmp = (IChatClient) v.get(i);
tmp.tell(s);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public ArrayList getConnected() throws RemoteException {
return v;
}
}
4.) StartServer
import java.rmi.Naming;
public class StartServer {
public static void main(String[] args) {
try {
// System.setSecurityManager(new RMISecurityManager());
java.rmi.registry.LocateRegistry.createRegistry(1099);
IChatServer server = new ChatServer();
Naming.rebind("rmi://localhost:1099/chatserver", server);
System.out.println("server ready.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
===== Client Side =====
==== Project 2: ChatClient ====
1.) ChatClient
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class ChatClient extends UnicastRemoteObject implements IChatClient {
private String name;
private ChatUI ui;
public ChatClient(String n) throws RemoteException {
name = n;
}
public void tell(String st) throws RemoteException {
System.out.println(st);
ui.writeMsg(st);
}
public String getName() throws RemoteException {
return name;
}
public void setGUI(ChatUI t) {
ui = t;
}
}
2.) ChatUI
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.Naming;
import java.util.ArrayList;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class ChatUI {
private ChatClient client;
private IChatServer server;
public void doConnect() {
if (connect.getText().equals("Connect")) {
if (name.getText().length() < 2) {
JOptionPane
.showMessageDialog(frame, "You need to type a name.");
return;
}
if (ip.getText().length() < 2) {
JOptionPane.showMessageDialog(frame, "You need to type an IP.");
return;
}
try {
client = new ChatClient(name.getText());
client.setGUI(this);
server = (IChatServer) Naming.lookup("rmi://localhost/chatserver");
server.login(client);
updateUsers(server.getConnected());
connect.setText("Disconnect");
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(frame,
"ERROR, we wouldn't connect....");
}
} else {
updateUsers(null);
connect.setText("Connect");
}
}
public void sendText() {
if (connect.getText().equals("Connect")) {
JOptionPane.showMessageDialog(frame, "You need to connect first.");
return;
}
String st = tf.getText();
st = "[" + name.getText() + "] " + st;
tf.setText("");
// Remove if you are going to implement for remote invocation
try {
server.publish(st);
} catch (Exception e) {
e.printStackTrace();
}
}
public void writeMsg(String st) {
tx.setText(tx.getText() + "\n" + st);
}
public void updateUsers(ArrayList users) {
DefaultListModel listModel = new DefaultListModel();
if (users != null)
for (int i = 0; i < users.size(); i++) {
try {
String tmp = ((IChatClient) users.get(i)).getName();
listModel.addElement(tmp);
} catch (Exception e) {
e.printStackTrace();
}
}
list.setModel(listModel);
}
public static void main(String[] args) {
System.out.println("Hello World !");
ChatUI c = new ChatUI();
}
// User Interface code.
public ChatUI() {
frame = new JFrame("Group Chat");
JPanel main = new JPanel();
JPanel top = new JPanel();
JPanel cn = new JPanel();
JPanel bottom = new JPanel();
ip = new JTextField();
tf = new JTextField();
name = new JTextField();
tx = new JTextArea();
connect = new JButton("Connect");
JButton bt = new JButton("Send");
list = new JList();
main.setLayout(new BorderLayout(5, 5));
top.setLayout(new GridLayout(1, 0, 5, 5));
cn.setLayout(new BorderLayout(5, 5));
bottom.setLayout(new BorderLayout(5, 5));
top.add(new JLabel("Your name: "));
top.add(name);
top.add(new JLabel("Server Address: "));
top.add(ip);
top.add(connect);
cn.add(new JScrollPane(tx), BorderLayout.CENTER);
cn.add(list, BorderLayout.EAST);
bottom.add(tf, BorderLayout.CENTER);
bottom.add(bt, BorderLayout.EAST);
main.add(top, BorderLayout.NORTH);
main.add(cn, BorderLayout.CENTER);
main.add(bottom, BorderLayout.SOUTH);
main.setBorder(new EmptyBorder(10, 10, 10, 10));
// Events
connect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
doConnect();
}
});
bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sendText();
}
});
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sendText();
}
});
frame.setContentPane(main);
frame.setSize(600, 600);
frame.setVisible(true);
}
JTextArea tx;
JTextField tf, ip, name;
JButton connect;
JList list;
JFrame frame;
}
**Feladat 1.**: implementáljuk, hogy új kliensek belépése esetén, a régiek is megkapják az új belépő nevét.
**Feladat 2.**: implementáljuk továbbá, hogy kilépés esetén a felhasználók törlődjenek.