JAVA技巧(客戶訪問限制管理器)

字號:

前段時間開發(fā)短信收發(fā)系統(tǒng),遇到一個問題,就是有n個對象都可以通過Mobile對象發(fā)短信,但同一時刻只允許一個對象進(jìn)行操作。所以設(shè)計了一個客戶限制管理器的對象來解決,但由于種種原因沒有用到實際系統(tǒng)中。后來經(jīng)過仔細(xì)考慮,發(fā)現(xiàn)它不僅可以用于端口的管理,還可用于其他需要針對客戶訪問數(shù)量進(jìn)行限制的各種服務(wù)中去。----這里的“客戶”是指要操作該管理器的對象
    /**
    * 客戶限制管理器的抽象類
    * 此抽象類實現(xiàn)了對客戶訪問的限制,當(dāng)一個客戶訪問該服務(wù)時,可以通過halt(long guestid)方法阻止其他客戶進(jìn)行
    * 訪問,防止多個客戶同時訪問產(chǎn)生的沖突。例如:對通訊端口的訪問等。
    */
    public abstract class GuestManager {
    /**
    * 時間:一分鐘
    */
    protected static final long ONE_MINUTE = 60L * 1000L;
    /**
    * 時間:一小時
    */
    protected static final long ONE_HOUR = 60L * ONE_MINUTE;
    /**
    * 自動清理客戶記錄的間隔時間
    */
    private long cleanInterval;
    /**
    * 客戶記錄<客戶標(biāo)識,最近訪問時間>
    */
    private Hashtable guests;
    /**
    * 當(dāng)前限制的客戶
    */
    private long limitGuest;
    /**
    * 自動清除過期客戶的線程
    */
    private Thread autoCleanThread;
    /**
    * 客戶注冊
    *
    * @return 返回分配給客戶端的標(biāo)識,如果注冊失敗,返回-1
    */
    public long login() {
    long guestid = -1L;
    // 增加客戶記錄
    Hashtable guests = getGuests();
    if (guests != null) {
    guestid = System.currentTimeMillis();
    guests.put("" + guestid, "" + guestid);
    update(guestid);
    // if (guests.size() == 1)
    // connect();
    }
    return guestid;
    }
    /**
    * 檢查客戶是否已經(jīng)注冊
    *
    * @param guestid
    * 客戶標(biāo)識
    * @return 如果客戶已經(jīng)注冊返回true,否則返回false
    */
    public boolean isLogin(long guestid) {
    boolean flag = false;
    if (guestid > 0) {
    Hashtable guests = getGuests();
    if (guests != null)
    flag = guests.containsKey("" + guestid);
    if (flag)
    update(guestid);
    }// end if (guestid > 0)
    return flag;
    }
    /**
    * 注銷客戶
    * 如果仍有其他客戶在使用此對象,則僅僅注銷guestid客戶,否則調(diào)用disconnect()方法關(guān)閉連接。
    *
    * @param guestid
    * 客戶標(biāo)識
    * @return 返回是否成功注銷
    */
    public void logout(long guestid) {
    Hashtable guests = getGuests();
    if (guests != null) {
    if (guestid > 0 && guests.containsKey("" + guestid)) {
    guests.remove("" + guestid);
    }// end if (guestid > 0 && getGuests().containsKey("" +
    // guestid))
    }// end if (guests != null)
    }
    /**
    * 限制
    * 如果某一客戶調(diào)用了該方法,那么其他客戶將無法訪問,直至該客戶調(diào)用resume()釋放。
    *
    * @param guestid
    * 中斷標(biāo)識
    * @return 返回是否成功中斷
    */
    public boolean limit(long guestid) {
    boolean flag = false;
    if (isLogin(guestid)) {
    update(guestid);
    if (isLimit(guestid))
    return flag;
    limitGuest = guestid;
    flag = true;
    }// end if (isLogin(guestid))
    return flag;
    }
    /**
    * 釋放
    *
    * @param guestid
    * 客戶標(biāo)識
    * @return 返回是否釋放成功
    */
    public boolean resume(long guestid) {
    boolean flag = false;
    if (isLogin(guestid)) {
    update(guestid);
    if (limitGuest == guestid) {
    limitGuest = -1L;
    }// end if(haltGuest == guestid)
    flag = !isLimit();
    }
    return flag;
    }
    /**
    * 是否限制其他客戶調(diào)用
    *
    * @return 返回是否限制其他客戶調(diào)用
    */
    protected boolean isLimit() {
    boolean flag = false;
    if (limitGuest > 0) {
    long lasttime = Long.parseLong((getGuests().get(
    "" + limitGuest)));
    if (lasttime > 0) {
    // 如果10分鐘內(nèi)無響應(yīng),則注釋放該客戶的中斷
    long time = System.currentTimeMillis() - 10L
    * ONE_MINUTE;
    if (time < lasttime)
    flag = true;
    else
    limitGuest = -1;
    }
    }// end if(this.id <= 0)
    return flag;
    }
    /**
    * 該客戶是否被限制訪問
    *
    * @param haltId
    * 客戶標(biāo)識
    * @return 返回true表示禁止訪問,false表示可以訪問
    */ public boolean isLimit(long guestid) {
    boolean flag = true;
    if (isLogin(guestid)) {
    update(guestid);
    flag = isLimit();
    if (flag) {
    if (guestid > 0 && limitGuest == guestid)
    flag = false;
    }// end if(flag)
    }
    return flag;
    }
    /**
    * 取得當(dāng)前限制客戶的標(biāo)識(該標(biāo)識是該管理器為客戶分配的一個標(biāo)識)
    *
    * @return 返回當(dāng)前限制客戶的標(biāo)識
    */
    protected long getLimitGuest() {
    return limitGuest;
    }
    /**
    * 更新客戶最近使用時間
    *
    * @param guestid
    * 客戶標(biāo)識
    */
    protected void update(long guestid) {
    runThread();
    Hashtable guests = getGuests();
    if (guests != null && guests.containsKey("" + guestid))
    guests.put("" + guestid, ""
    + System.currentTimeMillis());
    }
    /**
    * 運行監(jiān)聽線程
    */
    protected void runThread() {
    // 客戶自動清理線程
    if (autoCleanThread != null && !autoCleanThread.isAlive())
    autoCleanThread = null;
    if (autoCleanThread == null) {
    autoCleanThread = new AutoCleanThread();
    autoCleanThread.start();
    }// end if (autoCleanThread == null)
    }
    /**
    * 設(shè)置自動清理客戶記錄的間隔時間
    *
    * @param time
    * 間隔時間(毫秒)
    */
    public void setCleanInterval(long time) {
    if (time > 0)
    cleanInterval = time;
    }
    /**
    * 取得自動清理客戶記錄的間隔時間
    *
    * @return 返回自動清理客戶記錄的間隔時間(毫秒)
    */
    public long getCleanInterval() {
    return cleanInterval;
    }
    /**
    * 取得客戶記錄
    *
    * @return 返回客戶記錄。格式為<客戶標(biāo)識,最近訪問時間>
    */
    protected Hashtable getGuests() {
    if (guests == null)
    guests = new Hashtable();
    return guests;
    }
    /**
    * 輸出錯誤信息
    *
    * @param err
    */
    public abstract void trace(String err);
    /**
    * 自動清除超時的客戶端的線程
    *
    */
    private class AutoCleanThread extends Thread {
    public void run() {
    trace("AutoCleanThread thread start runing...");
    long interval = ONE_HOUR / 4L;
    if (getCleanInterval() > 0)
    interval = getCleanInterval();
    while (autoCleanThread == this && getGuests().size() > 0) {
    long time = System.currentTimeMillis()
    - ONE_HOUR / 2L;
    Enumeration keys = getGuests().keys();
    while (keys.hasMoreElements()) {
    String key = (String) keys.nextElement();
    if (key != null) {
    long lasttime = Long.parseLong(getGuests()
    .get(key));
    if (time > lasttime)
    // 超時
    getGuests().remove(key);
    }// end if (key != null)
    }// end while (keys.hasMoreElements())
    try {
    Thread.sleep(interval);
    } catch (InterruptedException e) {
    e.printStackTrace();
    trace("error - " + e.toString());
    }
    }// end while (mobiles != null && mobiles.size() > 0)
    trace("AutoCleanThread thread end...");
    }
    }
    }
    /**
    * 通訊端口的客戶端限制管理器的抽象類
    * 該類繼承自GuestManager類,增加了connect()、disconnect()等方法
    *
    * @author none
    *
    */
    public abstract class PortGuestManager extends GuestManager {
    /**
    * 連接
    *
    * @return 返回是否連接成功
    */
    protected abstract boolean connect();
    /**
    * 斷開
    *
    * @return 返回是否斷開成功
    */
    protected abstract boolean disconnect();
    /**
    * 是否已經(jīng)連接
    *
    * @return 返回端口是否已經(jīng)連接
    */
    protected abstract boolean isConnected();
    public long login() {
    long guestid = -1L;
    if (!isConnected())
    connect();
    if (isConnected())
    guestid = super.login();
    return guestid;
    }
    public boolean limit(long guestid) {
    boolean flag = false;
    if (isConnected())
    flag = super.limit(guestid);
    return flag;
    }
    public void logout(long guestid) {
    super.logout(guestid);
    Hashtable guests = getGuests();
    if (guests != null)
    if (guests.size() <= 0)
    disconnect();
    }
    public boolean isLimit(long guestid) {
    boolean flag = true;
    if (isConnected())
    flag = super.isLimit(guestid);
    return flag;
    }
    }