因为课内作业第一次接触到了Java RMI的使用,感觉是一个很棒的工具,所以在此记录一下用法,方便以后再用。
这里以在线的会议管理为例,为了看起来简洁所以随便删了一部分不是很重要的代码;
众所周知,RMI是面向对象的分布式调用,所以对象的概念尤为重要,所以第一个包就是定义用得到的对象类:
User类
为了简单只要name和password两个属性;
这里要注意的是,因为要在网络上引用这个对象,所以传输的时候一定要能够串行化,否则难以传输,这里继承了Serializable 就是这个目的。
package ssd8.rmi.bean;
import java.io.Serializable;
/**
* @author ly
*/
public class User implements Serializable {
private String name;
private String password;
public User(String name, String password) {
super();
this.name = name;
this.password = password;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
if (!name.equals(user.name)) return false;
return password != null ? password.equals(user.password) : user.password == null;
}
//get或者set操作
}
再来一个Meeting类:
package ssd8.rmi.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
/**
* @author ly
*/
public class Meeting implements Serializable{
/**
* the id for meeting
*/
private int meetingID;
/**
* the title for meeting
*/
private String title;
/**
* the time for the meeting
*/
private Date startTime;
private Date endTime;
/**
* the sponsor and the joiner
*/
private User launchUser;
private ArrayList<User> otherUsers;
/**
*
* @param meetingID
* @param title
* @param startTime
* @param endTime
* @param launchUser
* @param otherUsers
*/
public Meeting(int meetingID, String title, Date startTime, Date endTime, User launchUser, ArrayList<User> otherUsers) {
this.meetingID = meetingID;
this.title = title;
this.startTime = startTime;
this.endTime = endTime;
this.launchUser = launchUser;
this.otherUsers = otherUsers;
}
//get set equal toString操作
}
类实体定义完了,接下来就是为了统一协调收发端(服务器和客户端)而特意定义的接口MeetingInterface接口:
这里要注意的是
1、因为是定义接口,所以用interface extends Remote由此继承Remote接口的特性;
2、所有的方法都必须抛出RemoteException异常类型,否则运行时会出错;
package ssd8.rmi.rface;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;
/**
* @author ly
*/
public interface MeetingInterface extends Remote {
/**
* register
*
* @param username
* @param password
* @return true if register successfully
* @throws RemoteException
*/
public boolean registerUser(String username, String password) throws RemoteException;
/**
* add meeting
*
* @param username
* @param password
* @param otherusers
* @param start
* @param end
* @param title
* @return the result information
* @throws RemoteException
*/
public String addMeeting(String username, String password, String[] otherUsers,
String start, String end, String title) throws RemoteException;
/**
* query meeting
*
* @param username
* @param password
* @param start
* @param end
* @return
* @throws RemoteException
*/
public String queryMeeting(String username, String password, String start, String end) throws RemoteException;
/**
* delete meeting
*
* @param username
* @param password
* @param meetingID
* @return true if delete successfully
* @throws RemoteException
*/
public boolean deleteMeeting(String username, String password, int meetingID) throws RemoteException;
/**
* clear meeting
*
* @param username
* @param password
* @return true if clear
* @throws RemoteException
*/
public boolean clearMeeting(String username, String password) throws RemoteException;
}
定义好接口以后,就是接口的实现;
MeetingInstance:
这里不要忘记前面的接口要继承过来,而且同时还要继承UnicastRemoteObject类
package ssd8.rmi.server;
import ssd8.rmi.bean.Meeting;
import ssd8.rmi.bean.User;
import ssd8.rmi.rface.MeetingInterface;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
/**
* @author ly
*/
public class MeetingInstance extends UnicastRemoteObject implements MeetingInterface {
private ArrayList<User> users = new ArrayList<>();
private ArrayList<Meeting> meetings = new ArrayList<>();
private static int meetingID = 0;
private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
public MeetingInstance() throws RemoteException {
super();
}
@Override
public boolean registerUser(String username, String password) throws RemoteException {
for (User user : users) {
if (isUserExist(username)) {
System.out.println(userRegisterFailure);
return false;
}
}
User user = new User(username, password);
users.add(user);
System.out.println(user.toString() + userRgisterSuccessfully);
return true;
}
@Override
public String addMeeting(String username, String password, String[] otherUserNames, String start, String end, String title) throws RemoteException {
String info = null;
ArrayList<User> otherUsers = new ArrayList<>();
User launchUser = new User(username, password);
Date startTime = null;
Date endTime = null;
/*
* judge if the format is correct
*/
try {
startTime = dateFormat.parse(start);
endTime = dateFormat.parse(end);
} catch (ParseException e) {
info = timeFormatInvalid;
e.printStackTrace();
return info;
}
/*
* judge if the time overlap
*/
if (isOverlap(startTime, endTime)||isReversed(startTime, endTime)) {
info = wrongTime;
return info;
}
/*
* judge if the user exist
*/
if (!isUserExist(launchUser)) {
info = unregisterUser;
return info;
}
/*
* judge if the other user exist and the number is correct
*/
if (otherUserNames.length < 1 || !isUsersExist(otherUserNames)) {
info = unregisterUser;
return info;
}else {
for (String temp : otherUserNames){
for (User user : users){
if (user.getName().equals(temp)){
otherUsers.add(user);
}
}
}
}
/*
* add meeting
*/
Meeting meeting = new Meeting(meetingID++, title, startTime, endTime, launchUser, otherUsers);
meetings.add(meeting);
info = addMeetingSuccessfully;
return info;
}
/**
*
* @param startTime
* @param endTime
* @return whether overlap
*/
private boolean isOverlap(Date startTime, Date endTime) {
boolean isOverlap = false;
for (Meeting meeting : meetings) {
if (isOverlap(meeting.getStartTime(), meeting.getEndTime(), startTime, endTime)) {
isOverlap = true;
return isOverlap;
}
}
return isOverlap;
}
/**
* judge if the time reverse
*
* @param former
* @param latter
* @return
*/
private boolean isReversed(Date former, Date latter){
return former.after(latter);
}
/**
* judge if [st1 et1] overlap [st2 et2]
*
* @param st1
* @param et1
* @param st2
* @param et2
* @return whether overlap
*/
private boolean isOverlap(Date st1, Date et1, Date st2, Date et2) {
boolean isOverlap = isBetween(st2, st1, et1) || isBetween(et2, st1, et1) || isBetween(st1, st2, et2) ||
st1.equals(st2) || et1.equals(et2);
return isOverlap;
}
/**
* judge if the date in range [former latter]
*
* @param date
* @param former
* @param latter
* @return
*/
private boolean isBetween(Date date, Date former, Date latter) {
boolean isBetween = (date.after(former) && date.before(latter))
|| date.equals(former) && date.equals(latter);
return isBetween;
}
/**
*
* @param usernames
* @return
*/
private boolean isUsersExist(String[] usernames) {
boolean isAllExist = true;
for (String username : usernames) {
if (!isUserExist(username)) {
isAllExist = false;
break;
}
}
return isAllExist;
}
/**
* judge if the user exist
*
* @param username
* @return whether exist or not
*/
private boolean isUserExist(String username) {
boolean isExist = false;
for (User user : users) {
if (user.getName().equals(username)) {
isExist = true;
break;
}
}
return isExist;
}
/**
* judge if the user exist
*
* @param user
* @return exist or not
*/
private boolean isUserExist(User user) {
boolean isExist = false;
for (User temp : users) {
if (temp.equals(user)) {
isExist = true;
break;
}
}
return isExist;
}
}
最后就是客户端和服务器的实现:
首先说服务器RMIServer
package ssd8.rmi.server;
import ssd8.rmi.rface.MeetingInterface;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
/**
* RMI 服务器
*
* @author ly
*/
public class RMIServer {
/**
* 启动 RMI 注册服务并进行对象注册
*/
public static void main(String[] args) {
try {
// 启动RMI注册服务,指定端口为1099 (1099为默认端口)
// 也可以通过命令 $java_home/bin/rmiregistry 1099启动
// 这里用这种方式避免了再打开一个DOS窗口
// 而且用命令rmi registry启动注册服务还必须事先用RMIC生成一个stub类为它所用
LocateRegistry.createRegistry(1099);
// 创建远程对象的一个或多个实例,下面是MeetingInterfaceImpl对象
// 可以用不同名字注册不同的实例
MeetingInterface meetingInterface = new MeetingInstance();
// 把hello注册到RMI注册服务器上,命名为Hello
Naming.rebind("Meeting", meetingInterface);
// 如果要把hello实例注册到另一台启动了RMI注册服务的机器上
// Naming.rebind("//192.168.1.105:1099/Hello",hello);
System.out.println("Meeting Server is ready.");
} catch (Exception e) {
System.out.println("Meeting Server failed: " + e);
}
}
}
最后就是客户端RMIClient:
package ssd8.rmi.client;
import ssd8.rmi.rface.MeetingInterface;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.Arrays;
/**
*
*
* @author ly
*
*/
public class RMIClient {
private static final String inputWrongParameter = "wrong parameter!";
private static final String operateSuccess = "operate successfully!";
private static final String operateFailure = "operate failed!";
private static final String timeFormat = "time format:yyyy-MM-dd-HH:mm";
private static BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
/**
*
*/
private static String username = null;
private static String password = null;
public static MeetingInterface rmi;
public static void main(String[] args) {
/**
* get the console command
*/
try {
if (args.length < 3) {
System.err.println(inputWrongParameter);
System.exit(0);
}
String host = args[0];
String port = args[1];
/*
* connect the server according to the ip and port 这里就是根据主机端口号寻找名字服务器
*/
rmi = (MeetingInterface) Naming.lookup("//" + host + ":" + port + "/Meeting");
/**
* check the register mainloop
*/
if (args[2].equals("register")) {
if (args.length != 5) {
System.err.println(inputWrongParameter);
System.exit(0);
}
boolean flag = rmi.registerUser(args[3], args[4]);
if (!flag) {
System.err.println(operateFailure);
} else {
username = args[3];
password = args[4];
System.out.println("register "+username+" " + operateSuccess);
}
} else {
//other mainloop
username = args[3];
password = args[4];
String[] cmds = Arrays.copyOfRange(args, 5, args.length);
mainloop(cmds);
}
/**
* the help menu
*/
helpMenu();
/**
* other mainloop
*/
while (true) {
System.out.println("Input an operation: ");
String operation = bufferedReader.readLine();
String[] cmds = operation.split(" ");
mainloop(cmds);
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* deal with the command
*
* @param cmds
*
*/
private static void mainloop(String[] cmds) throws RemoteException {
if (cmds[0].equals("add")) {
dealAdd(cmds);
} else if (cmds[0].equals("delete")) {
dealDelete(cmds);
} else if (cmds[0].equals("clear")) {
dealClear();
} else if (cmds[0].equals("query")) {
dealQuery(cmds);
} else if (cmds[0].equals("help")) {
helpMenu();
} else if (cmds[0].equals("quit")) {
System.exit(0);
} else if (cmds[0].equals("register")) {
boolean flag = rmi.registerUser(cmds[1], cmds[2]);
if (!flag) {
System.err.println(operateFailure);
} else {
username = cmds[1];
password = cmds[2];
System.out.println("register "+username+" " + operateSuccess);
}
}else
System.err.println(inputWrongParameter);
}
/**
* add the meeting according to the command
*
* @param cmds
*
* @throws RemoteException
*/
private static void dealAdd(String[] cmds) throws RemoteException {
String info;
if (cmds.length < 5) {
info = inputWrongParameter;
System.err.println(info);
} else {
String[] otherUserNames = Arrays.copyOfRange(cmds, 1, cmds.length - 3);
info = rmi.addMeeting(username, password, otherUserNames, cmds[cmds.length - 3], cmds[cmds.length - 2],
cmds[cmds.length - 1]);
System.out.println(info);
}
}
/**
* delete the meeting according to the command
*
* @param cmds
*
* @throws RemoteException
*/
private static void dealDelete(String[] cmds) throws RemoteException {
if (cmds.length != 2) {
System.err.println(inputWrongParameter);
} else {
boolean flag = rmi.deleteMeeting(username, password, Integer.parseInt(cmds[1]));
if (flag) {
System.out.println(operateSuccess);
} else
System.err.println(operateFailure);
}
}
/**
* clear the meeting according to the command
*
* @throws RemoteException
*/
private static void dealClear() throws RemoteException {
boolean flag = rmi.clearMeeting(username, password);
if (flag) {
System.out.println(operateSuccess);
} else
System.err.println(operateFailure);
}
/**
* query the meeting according to the command
*
* @param cmds
*
* @throws RemoteException
*/
private static void dealQuery(String[] cmds) throws RemoteException {
if (cmds.length != 3) {
System.err.println(inputWrongParameter);
} else {
String info = rmi.queryMeeting(username, password, cmds[1], cmds[2]);
System.out.println(info);
}
}
}
/*
* 2018-12-28-12:00 2018-12-28-13:00
*
* test case:
* register a a
* add a 2018-12-28-12:00 2018-12-28-13:00 test
* query 2018-12-28-11:00 2018-12-28-14:00
* delete 0
* query 2018-12-28-11:00 2018-12-28-14:00
* add a 2018-12-28-12:00 2018-12-28-13:00 test
* query 2018-12-28-11:00 2018-12-28-14:00
* clear
* query 2018-12-28-11:00 2018-12-28-14:00
*
* restart:
* register a a
* register c c
* add a c b 2018-12-28-12:00 2018-12-28-13:00 test
* add a c 2018-12-28-12:00 2018-12-28-13:00 test1
*/