天天看點

RMI執行個體—RMI分布式議程服務—分布式實驗—西工大

原文連結:https://blog.csdn.net/Sardar_/article/details/78887586

在原文的代碼基礎上

  1. 優化了異常檢測。

  2. 增加了線程安全,用vector替代了arraylist

  3. 優化了代碼結構

也就是加強版,無BUG版本

題目簡介:

主要功能

1) 使用Java RMI建立一個分布式議程共享服務。不同的使用者可以使用這個共享議程服務執行查詢、添加和删除會議的操作。伺服器支援會議的登記和清除等功能;

2) 議程共享服務包括以下功能:使用者注冊、添加會議、查詢會議、删除會議、清除會議;

3) 使用者注冊

新使用者注冊需要填寫使用者名和密碼,如果使用者名已經存在,則注冊失敗并列印提示資訊,否則注冊成功并列印成功提示。使用如下指令進行使用者注冊:

4) 添加會議

已注冊的使用者可以添加會議。會議必須涉及到兩個已注冊的使用者,一個隻涉及單個使用者的會議無法被建立。會議的資訊包括開始時間、結束時間、會議标題、會議參與者。當一個會議被添加之後,它必須出現在建立會議的使用者和參加會議的使用者的議程中。如果一個使用者的新會議與已經存在的會議出現時間重疊,則無法建立會議。最終,使用者收到會議添加結果的提示。使用如下指令進行會議的添加:

5) 查詢會議

已注冊的使用者通過給出特定時間區間(給出開始時間和結束時間)在議程中查詢到所有符合條件的會議記錄。傳回的結果清單按時間排序。在清單中,包括開始時間、結束時間、會議标題、會議參與者等資訊。使用如下指令進行會議的查詢:

6) 删除會議

已注冊的使用者可以根據會議的資訊删除由該使用者建立的會議。使用如下指令進行删除會議操作:

7) 清除會議

已注冊的使用者可以清除所有由該使用者建立的會議。使用如下指令進行清除操作:

使用方法:

1.啟動RMISever

2.啟動RMIClient,輸入指令

項目結構:

RMI執行個體—RMI分布式議程服務—分布式實驗—西工大
package ssd8.rmi.bean;

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;
    }
}
           
package ssd8.rmi.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;

public class User implements Serializable {
    private String name;
    private String password;
    private Vector<Meeting> schedule;

    public User(String name, String password) {
        super();
        this.name = name;
        this.password = password;
        this.schedule = new Vector<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 Vector<Meeting> getSchedule() {
        return schedule;
    }
}
           
package ssd8.rmi.interface_rmi;

import java.rmi.Remote;
import java.text.ParseException;

/**
 * 遠端接口必須擴充接口java.rmi.Remote
 * @author Sarda
 */
public interface RMIInterface 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  會議的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;
}
           
package ssd8.rmi.service_rmi;
import ssd8.rmi.bean.Meeting;
import ssd8.rmi.bean.User;
import ssd8.rmi.interface_rmi.RMIInterface;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;

/**
 * 擴充UnicastRemoteObject類,并實作遠端接口RMIInterface
 *
 * @author The Great Ke
 *
 */
public class RMIService extends UnicastRemoteObject implements RMIInterface {
    /**
     *
     */
    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 Vector<User> userVector = new Vector<>();   // 保證線程安全。  hash_table,con

    // private List<Meeting> meetingList = new ArrayList<Meeting>();  棄用,線程不安全的。
    private Vector<Meeting> meetingVector = new Vector<>();// 保證線程安全。  hash_table,con

    /**
     * 必須定義構造方法,即使是預設構造方法,也必須把它明确地寫出來,因為它必須抛出出RemoteException異常
     */
    public RMIService() throws RemoteException {
    }

    /**
     * 遠端接口方法的實作
     */

    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;
        }
        userVector.add(new User(name, password));

        return true;
    }
    /**
     * 檢查使用者是否已注冊
     * @param name
     * @return
     */
    private boolean exist(String name) {
        for (User u : userVector) {
            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++);
        meetingVector.add(meeting);
        sponsor.getSchedule().add(meeting);
        otheruser.getSchedule().add(meeting);
        return 1;
    }
    /**
     * 檢查時間是否與已經存在的會議出現時間重疊
     * @param user
     * @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>();
        Vector<Meeting> list = new Vector<>();
        for (Meeting meeting : meetingVector) {
            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(Vector<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 < meetingVector.size(); i++) {
            if(meetingVector.get(i).getSponsor().equals(user) && meetingVector.get(i).getId() == id) {
                meetingVector.get(i).getSponsor().getSchedule().remove(meetingVector.get(i));
                meetingVector.get(i).getOtheruser().getSchedule().remove(meetingVector.get(i));
                meetingVector.remove(meetingVector.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);
        Vector<Meeting> m = new Vector<Meeting>();
        for (Meeting meeting : meetingVector) {
            if(meeting.getSponsor().equals(user)) {
                m.add(meeting);
            }
        }
        for (Meeting meeting : m) {
            meetingVector.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 : userVector) {
            if(u.getName().equals(name))
                return u;
        }
        return null;
    }
    /**
     * 檢查使用者輸入的賬号密碼是否正确
     * @param name
     * @param password
     * @return
     */
    private boolean checkUser(String name, String password) {
        for (User u : userVector) {
            if(u.getName().equals(name)&&u.getPassword().equals(password))
                return true;
        }
        return false;
    }
}

           
package ssd8.rmi;

import ssd8.rmi.interface_rmi.RMIInterface;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class RMIClient {
    public static void main(String[] argv) throws RemoteException, NotBoundException, MalformedURLException {
        BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
            RMIInterface rmi_interface = (RMIInterface) Naming.lookup("HelloRMI");

            // 如果要從另一台啟動了RMI注冊服務的機器上查找hello執行個體
            // HelloInterface hello =
            // (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello");

            //控制台輸入提示
            System.out.println("RMI Menu:");
            System.out.println("\t1. register");
            System.out.println("\t2. add");
            System.out.println("\t3. query");
            System.out.println("\t4. delete");
            System.out.println("\t5. clear");

            while(true){
                try {

                    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(rmi_interface.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 = rmi_interface.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 = rmi_interface.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(rmi_interface.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(rmi_interface.clear(name, password)) {
                        System.out.println("清除成功!");
                    }else {
                        System.out.println("清除失敗!");
                    }
                }else{
                    System.out.println("bad request!");
                }

                }
                catch (Exception e) {
                System.out.println("RMIClient exception: " + e + "請糾錯後重新輸入");
            }

            }

    }
}
           
package ssd8.rmi;

import ssd8.rmi.interface_rmi.RMIInterface;
import ssd8.rmi.service_rmi.RMIService;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

/**
 * RMI Hello Server
 *
 * @author The Great Ke
 *
 */
public class RMIServer {

    /**
     * 啟動 RMI 注冊服務并進行對象注冊
     */
    public static void main(String[] args) {
        try {
            // 啟動RMI注冊服務,指定端口為1099 (1099為預設端口)
            // 也可以通過指令 $java_home/bin/rmiregistry 1099啟動
            // 這裡用這種方式避免了再打開一個DOS視窗
            // 而且用指令rmiregistry啟動注冊服務還必須事先用RMIC生成一個stub類為它所用
            LocateRegistry.createRegistry(1099);

            // 建立遠端對象的一個或多個執行個體,下面是hello對象
            // 可以用不同名字注冊不同的執行個體
            RMIInterface hello_rmi = new RMIService();

            // 把hello注冊到RMI注冊伺服器上,命名為Hello
            Naming.rebind("HelloRMI", hello_rmi);

            // 如果要把hello執行個體注冊到另一台啟動了RMI注冊服務的機器上
            // Naming.rebind("//192.168.1.105:1099/Hello",hello_rmi);
            System.out.println("Hello_rmi Server is ready.");

        } catch (Exception e) {
            System.out.println("Hello_rmi Server failed: " + e);
        }
    }

}
           

運作測試輸入截圖:

RMI執行個體—RMI分布式議程服務—分布式實驗—西工大
RMI執行個體—RMI分布式議程服務—分布式實驗—西工大

輸入部分: 可直接粘接輸入

add

zhouke,123,1999-05-09 14:00:00,1999-05-09 16:00:00,title,afei

zhouke,123,1999-05-09 15:00:00,1999-05-09 15:30:00,title_02,afei              //沖突

zhouke,123,1999-05-09 17:00:00,1999-05-09 17:30:00,title_03,afei           //不沖突

query

zhouke,123,1999-05-09 12:00:00,1999-05-09 19:30:00

afei,123,1999-05-09 12:00:00,1999-05-09 19:30:00

delete

zhouke,123,0            //成功  會議的建立者才有權限删除這個會議

afei,123,0                 //失敗,afei是參與者沒權限

clear

zhouke,123

繼續閱讀