主要功能
1) 使用Java RMI创建一个分布式议程共享服务。不同的用户可以使用这个共享议程服务执行查询、添加和删除会议的操作。服务器支持会议的登记和清除等功能;
2) 议程共享服务包括以下功能:用户注册、添加会议、查询会议、删除会议、清除会议;
3) 用户注册
新用户注册需要填写用户名和密码,如果用户名已经存在,则注册失败并打印提示信息,否则注册成功并打印成功提示。使用如下命令进行用户注册:
4) 添加会议
已注册的用户可以添加会议。会议必须涉及到两个已注册的用户,一个只涉及单个用户的会议无法被创建。会议的信息包括开始时间、结束时间、会议标题、会议参与者。当一个会议被添加之后,它必须出现在创建会议的用户和参加会议的用户的议程中。如果一个用户的新会议与已经存在的会议出现时间重叠,则无法创建会议。最终,用户收到会议添加结果的提示。使用如下命令进行会议的添加:
5) 查询会议
已注册的用户通过给出特定时间区间(给出开始时间和结束时间)在议程中查询到所有符合条件的会议记录。返回的结果列表按时间排序。在列表中,包括开始时间、结束时间、会议标题、会议参与者等信息。使用如下命令进行会议的查询:
6) 删除会议
已注册的用户可以根据会议的信息删除由该用户创建的会议。使用如下命令进行删除会议操作:
7) 清除会议
已注册的用户可以清除所有由该用户创建的会议。使用如下命令进行清除操作:
具体代码实现
启动 RMI 注册服务并进行对象注册
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
import ssd8.rmi.rface.HelloInterface;
/**
* RMI Hello Server
*
* @author Sardar
*
*/
public class HelloServer {
/**
* 启动 RMI 注册服务并进行对象注册
*/
public static void main(String[] args) {
try {
// 启动RMI注册服务,指定端口为1099 (1099为默认端口)
// 也可以通过命令 $java_home/bin/rmiregistry 1099启动
// 这里用这种方式避免了再打开一个DOS窗口
// 而且用命令rmiregistry启动注册服务还必须事先用RMIC生成一个stub类为它所用
LocateRegistry.createRegistry(1099);
// 创建远程对象的一个或多个实例,下面是hello对象
// 可以用不同名字注册不同的实例
HelloInterface hello = new Hello();
// 把hello注册到RMI注册服务器上,命名为Hello
Naming.rebind("Hello", hello);
// 如果要把hello实例注册到另一台启动了RMI注册服务的机器上
// Naming.rebind("//192.168.1.105:1099/Hello",hello);
System.out.println("Hello Server is ready.");
} catch (Exception e) {
System.out.println("Hello Server failed: " + e);
}
}
}
创建远程接口,此接口必须扩展接口java.rmi.Remote
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.text.ParseException;
import java.util.ArrayList;
import ssd8.rmi.bean.Meeting;
import ssd8.rmi.bean.User;
/**
* 远程接口必须扩展接口java.rmi.Remote
* @author Sarda
*/
public interface HelloInterface extends Remote {
/**
* 注册用户
* 如果用户名存在,返回false,否则注册新用户,返回true
*/
public boolean register(String name, String password)throws java.rmi.RemoteException;
/**
* 添加新会议
* 账号密码不正确,返回0
* 会议发起者和参与者是同一个用户,返回-1
* 会议参与者没有注册,返回-2
* 会议时间与发起者时间冲突,返回-3
* 会议时间与参与者时间冲突,返回-4
* 添加成功,返回1
* @throws ParseException
*/
public int addMeeting(String name, String password, String start, String end, String title, String otherusername)throws java.rmi.RemoteException, ParseException;
/**
* 查询相应时间段内是否有会议
* 账号密码不正确,返回null
* 查询成功,返回查询内容
* @throws ParseException
*/
public String[][] search(String name, String password, String start, String end)throws java.rmi.RemoteException, ParseException;
/**
* 删除用户发起的某一个会议
* @param name
* @param password
* @param id
* @return 账号密码错误返回false,添加成功,返回true
* @throws java.rmi.RemoteException
*/
public boolean delete(String name, String password, int id)throws java.rmi.RemoteException;
/**
* 清楚用户发起的所有会议
* @param name
* @param password
* @return 账号密码错误返回false,清除成功,返回true
* @throws java.rmi.RemoteException
*/
public boolean clear(String name, String password)throws java.rmi.RemoteException;
}
创建远程方法,扩展UnicastRemoteObject类,并实现远程接口HelloInterface
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import ssd8.rmi.bean.Meeting;
import ssd8.rmi.bean.User;
import ssd8.rmi.rface.HelloInterface;
/**
* 扩展UnicastRemoteObject类,并实现远程接口HelloInterface
*
* @author wben
*
*/
public class Hello extends UnicastRemoteObject implements HelloInterface {
/**
*
*/
private static final long serialVersionUID = 1L;
private String status = "0000";
private int id = 0;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private List<User> userList = new ArrayList<User>();
private List<Meeting> meetingList = new ArrayList<Meeting>();
/**
* 必须定义构造方法,即使是默认构造方法,也必须把它明确地写出来,因为它必须抛出出RemoteException异常
*/
public Hello() throws RemoteException {
// userList.add(new User("peter","peter"));
}
/**
* 远程接口方法的实现
*/
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public boolean register(String name, String password) throws RemoteException {
if(exist(name)){
return false;
}
userList.add(new User(name, password));
return true;
}
/**
* 检查用户是否已注册
* @param name
* @return
*/
private boolean exist(String name) {
for (User u : userList) {
if(u.getName().equals(name)) {
return true;
}
}
return false;
}
@Override
public int addMeeting(String name, String password, String startTime, String endTime,
String title, String otherusername)
throws RemoteException, ParseException {
User sponsor = findUser(name);
User otheruser = findUser(otherusername);
Date start = sdf.parse(startTime);
Date end = sdf.parse(endTime);
if(!checkUser(name, password)) return 0;
if(name == otherusername) return -1;
if(!exist(otherusername)) return -2;
if(overlap(sponsor, start, end)) return -3;
if(overlap(otheruser, start, end)) return -4;
Meeting meeting = new Meeting(sponsor, otheruser, start, end, title);
meeting.setId(id++);
meetingList.add(meeting);
sponsor.getSchedule().add(meeting);
otheruser.getSchedule().add(meeting);
return 1;
}
/**
* 检查时间是否与已经存在的会议出现时间重叠
* @param name
* @param start
* @param end
* @return
*/
private boolean overlap(User user, Date start, Date end) {
if(user.getSchedule().size()==0) {
return false;
}
for (Meeting meeting : user.getSchedule())
if(max(meeting.getStart(),start).compareTo(min(meeting.getEnd(),end))<=0)
return true;
return false;
}
private Date max(Date start, Date start2) {
if(start.after(start2)) {
return start;
}else {
return start2;
}
}
private Date min(Date end, Date end2) {
if(end.before(end2)) {
return end;
}else {
return end2;
}
}
@Override
public String[][] search(String name, String password, String startTime, String endTime)
throws RemoteException, ParseException {
if(!checkUser(name, password)) return null;
User user = findUser(name);
Date start = sdf.parse(startTime);
Date end = sdf.parse(endTime);
ArrayList<Meeting> list = new ArrayList<Meeting>();
for (Meeting meeting : meetingList) {
if(meeting.getStart().compareTo(start)>=0&&meeting.getStart().before(end)) {
list.add(meeting);
}
}
sort(list);
int n = list==null?0:list.size();
String[][] s = new String[n][5];
for(int j=0; j<list.size(); j++) {
s[j][0] = String.valueOf(list.get(j).getId());
s[j][1] = sdf.format(list.get(j).getStart());
s[j][2] = sdf.format(list.get(j).getEnd());
s[j][3] = list.get(j).getTitle();
s[j][4] = list.get(j).getSponsor().getName() + ", " + list.get(j).getOtheruser().getName();
}
return s;
}
/**
* 会议按开始时间升序排序
* @param list
*/
private void sort(ArrayList<Meeting> list) {
for(int i=0; i<list.size(); i++) {
for(int j=i; j<list.size(); j++) {
if(list.get(j).getStart().before(list.get(i).getStart())) {
swap(list.get(j),list.get(i));
}
}
}
}
/**
* 交换两个会议内容
* @param m1
* @param m2
*/
private void swap(Meeting m1, Meeting m2) {
User user = m1.getSponsor();
m1.setSponsor(m2.getSponsor());
m2.setSponsor(user);
user = m1.getOtheruser();
m1.setOtheruser(m2.getOtheruser());
m2.setOtheruser(user);
Date date = m1.getStart();
m1.setStart(m2.getStart());
m2.setStart(date);
date = m1.getEnd();
m1.setEnd(m2.getEnd());
m2.setEnd(date);
String title = m1.getTitle();
m1.setTitle(m2.getTitle());
m2.setTitle(title);
}
@Override
public boolean delete(String name, String password, int id) throws RemoteException {
if(!checkUser(name, password)) return false;
User user = findUser(name);
for (int i = 0; i < meetingList.size(); i++) {
if(meetingList.get(i).getSponsor().equals(user) && meetingList.get(i).getId() == id) {
meetingList.get(i).getSponsor().getSchedule().remove(meetingList.get(i));
meetingList.get(i).getOtheruser().getSchedule().remove(meetingList.get(i));
meetingList.remove(meetingList.get(i));
return true;
}
}
return false;
}
@Override
public boolean clear(String name, String password) throws RemoteException {
if(!checkUser(name, password)) return false;
int flag = 0;
User user = findUser(name);
List<Meeting> m = new ArrayList<Meeting>();
for (Meeting meeting : meetingList) {
if(meeting.getSponsor().equals(user)) {
m.add(meeting);
}
}
for (Meeting meeting : m) {
meetingList.remove(meeting);
flag = 1;
}
if(flag == 0) {
return false;
}else {
return true;
}
}
/**
* 按用户名查找用户
* @param name
* @return
* @throws RemoteException
*/
public User findUser(String name) throws RemoteException {
for (User u : userList) {
if(u.getName().equals(name))
return u;
}
return null;
}
/**
* 检查用户输入的账号密码是否正确
* @param name
* @param password
* @return
*/
private boolean checkUser(String name, String password) {
for (User u : userList) {
if(u.getName().equals(name)&&u.getPassword().equals(password))
return true;
}
return false;
}
}
创建Client 远程调用hello实例的方法
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.rmi.Naming;
import java.util.List;
import ssd8.rmi.rface.HelloInterface;
public class HelloClient {
public static void main(String[] argv) {
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
try {
HelloInterface hello = (HelloInterface) Naming.lookup("Hello");
// 如果要从另一台启动了RMI注册服务的机器上查找hello实例
// HelloInterface hello =
// (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello");
//控制台输入提示
System.out.println("请选择操作");
System.out.println("register");
System.out.println("add");
System.out.println("query");
System.out.println("delete");
System.out.println("clear");
while(true){
String request = keyboard.readLine();
//注册用户
if(request.startsWith("regist")){
System.out.println("请输入用户名和密码(用逗号隔开)");
String r = keyboard.readLine();
String[] s = r.split(",", 2);
String name = s[0];
String password = s[1];
if(hello.register(name, password)) {
System.out.println("注册成功!");
}else {
System.out.println("注册失败!");
}
//添加会议
}else if(request.startsWith("add")){
System.out.println("请输入用户名,密码,会议开始时间,会议结束时间,会议标题,会议参与者姓名(用逗号隔开)");
String r = keyboard.readLine();
String[] s = r.split(",", 6);
String name = s[0];
String password = s[1];
String start = s[2];
String end = s[3];
String title = s[4];
String otherusername = s[5];
int i = hello.addMeeting(name, password, start, end, title, otherusername);
switch (i) {
case 0:
System.out.println("用户名或密码错误!");
break;
case -1:
System.out.println("用户名未注册!");
break;
case -2:
System.out.println("会议参与者未注册!");
break;
case -3:
System.out.println("用户时间冲突!");
break;
case -4:
System.out.println("会议参与者时间冲突!");
break;
case 1:
System.out.println("添加会议成功!");
break;
default:
break;
}
//查询会议
}else if(request.startsWith("query")){
System.out.println("请输入用户名,密码,开始时间,结束时间(用逗号隔开)");
String r = keyboard.readLine();
String[] s = r.split(",", 4);
String name = s[0];
String password = s[1];
String start = s[2];
String end = s[3];
String[][] list = hello.search(name, password, start, end);
if(list != null) {
for (String[] i : list) {
System.out.print("ID: "+ i[0] + " ");
System.out.print("开始时间: "+ i[1] + " ");
System.out.print("结束时间: "+ i[2] + " ");
System.out.print("标题: "+ i[3] + " ");
System.out.print("参与者: "+ i[4] + " ");
System.out.println();
}
}else {
System.out.println("查询失败!");
}
//删除会议
}else if(request.startsWith("delete")){
System.out.println("请输入用户名,密码,id(用逗号隔开)");
String r = keyboard.readLine();
String[] s = r.split(",", 3);
String name = s[0];
String password = s[1];
int id = Integer.parseInt(s[2]);
if(hello.delete(name, password, id)) {
System.out.println("删除成功!");
}else {
System.out.println("删除失败!");
}
//清除会议
}else if(request.startsWith("clear")){
System.out.println("请输入用户名,密码(用逗号隔开)");
String r = keyboard.readLine();
String[] s = r.split(",", 2);
String name = s[0];
String password = s[1];
if(hello.clear(name, password)) {
System.out.println("清除成功!");
}else {
System.out.println("清除失败!");
}
}else{
System.out.println("bad request!");
}
}
} catch (Exception e) {
System.out.println("HelloClient exception: " + e);
}
}
}
自定义User对象
import java.io.Serializable;
import java.util.ArrayList;
public class User implements Serializable{
private String name;
private String password;
private ArrayList<Meeting> schedule;
public User(String name, String password) {
super();
this.name = name;
this.password = password;
this.schedule = new ArrayList<Meeting>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public ArrayList<Meeting> getSchedule() {
return schedule;
}
}
自定义Meeting对象
import java.util.Date;
public class Meeting {
private User sponsor;
private User otheruser;
private Date start;
private Date end;
private String title;
private int id;
public Meeting(User sponsor, User otheruser, Date start, Date end, String title) {
super();
this.sponsor = sponsor;
this.otheruser = otheruser;
this.start = start;
this.end = end;
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public User getSponsor() {
return sponsor;
}
public void setSponsor(User sponsor) {
this.sponsor = sponsor;
}
public User getOtheruser() {
return otheruser;
}
public void setOtheruser(User otheruser) {
this.otheruser = otheruser;
}
public Date getStart() {
return start;
}
public void setStart(Date start) {
this.start = start;
}
public Date getEnd() {
return end;
}
public void setEnd(Date end) {
this.end = end;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
运行示例
先运行HelloServer注册RMI实例,接着运行HelloClient远程调用Hello定义的方法
先注册两个用户,添加三个会议,其中前两个分别是每个用户发起的会议,第三个是时间冲突的会议
再启动一个HelloClient客户端,完成删除和清除操作。