2012-10-15 79 views
3

好吧,也許不會像這樣損壞。Red5 - SharedObject中的ArrayList被破壞

所以,一點背景。我最近將Red5動力遊戲從red5的Windows版本移到了Debian Squeeze上。我有一個遊戲大廳,它使用共享對象來維護各種可用遊戲的列表。

單個遊戲在所述SharedObject中作爲HashMap [String,Object]存儲爲它的game_id。一對夫婦HashMap中的屬性是的ArrayList,特別是玩家(一個ArrayList [整數]連接的玩家ID的)和(另一個ArrayList的[整數]的球員誰已經提交表決)

每當我做出改變到這些的ArrayList的,什麼東西,什麼地方出了問題,我可以沒有長寫HashMap中的共享對象(的setAttribute返回false)

創建一個新的遊戲(服務器端):

HashMap<String, Object> game = new HashMap<String, Object>(); 
game.put("id", PendingGameManager.GAME_IDX); 
game.put("difficulty", difficulty); 
game.put("type", type); 
game.put("description", this.getDescription(type, difficulty)); 
game.put("players", new ArrayList<Integer>()); 
game.put("coords", coords); 
game.put("created", Calendar.getInstance().getTimeInMillis()); 
game.put("votes", new ArrayList<Integer>()); 
boolean success = this.gamesSO.setAttribute(Integer.toString(PendingGameManager.GAME_IDX), game); 

這個執行s沒有問題,成功返回true。

後來,我檢索玩家陣列和作出修正:

HashMap<String, Object> game = (HashMap<String, Object>)this.gamesSO.getMapAttribute(Integer.toString(game_id)); 
ArrayList<Integer> players = (ArrayList<Integer>) game.get("players"); 
players.add(new Integer(Integer.parseInt((user_id)))); 
boolean success = this.gamesSO.setAttribute(Integer.toString(game_id), game); 

這裏成功總是返回false。如果爲遊戲創建一個新的HashMap並複製每個屬性從舊的,但省略玩家投票這是好的,但什麼嘗試,我不能讓它維護一個數組。我也嘗試過使用List和Vector來獲得相同的結果。這是我與Java的第一次接觸,我一直小心只添加Integer的類實例,而不是原始的int,但是我已經用盡了所有的想法。

在Windows上它跑完美,我使用ArrayList的[字符串]原執行的,而不是ArrayList的[整數]

環境: Debian的擠壓6.0.6 JRE 1.7 Red5的1.0RC2

任何幫助或建議將不勝感激!

+3

什麼是'gamesSO'? –

+0

gamesSO是[SharedObject]的一個實例(http://dl.fancycode.com/red5/api/org/red5/server/so/SharedObject.html) – milks

回答

2

根據您的RED5版本信息,這是方法「的setAttribute」的實施:

@Override 
public boolean setAttribute(String name, Object value) { 
    log.debug("setAttribute - name: {} value: {}", name, value); 
    boolean result = true; 
    ownerMessage.addEvent(Type.CLIENT_UPDATE_ATTRIBUTE, name, null); 
    if (value == null && super.removeAttribute(name)) { 
     // Setting a null value removes the attribute 
     modified = true; 
     syncEvents.add(new SharedObjectEvent(Type.CLIENT_DELETE_DATA, name, null)); 
     deleteStats.incrementAndGet(); 
    } else if (value != null && super.setAttribute(name, value)) { 
     // only sync if the attribute changed 
     modified = true; 
     syncEvents.add(new SharedObjectEvent(Type.CLIENT_UPDATE_DATA, name, value)); 
     changeStats.incrementAndGet(); 
    } else { 
     result = false; 
    } 
    notifyModified(); 
    return result; 
} 

我估計值= NULL(但我可能是錯的!)。但在我看來,這將是呼叫轉移到它的父類與「super.setAttribute」號召, 這是父/超類的實現:

/** 
* Set an attribute on this object. 
* 
* @param name the name of the attribute to change 
* @param value the new value of the attribute 
* @return true if the attribute value was added or changed, otherwise false 
*/ 
public boolean setAttribute(String name, Object value) { 
    if (name != null) { 
     if (value != null) { 
      // update with new value 
      Object previous = attributes.put(name, value); 
      // previous will be null if the attribute didn't exist 
      return (previous == null || !value.equals(previous)); 
     } 
    } 
    return false; 
} 

這裏最重要的線(恕我直言):

return (previous == null || !value.equals(previous)); 

=>「previous」找不到,然後返回false。

的問題是,我認爲:這鑄你正在做的:

HashMap<String, Object> game = (HashMap<String, Object>)this.gamesSO.getMapAttribute(Integer.toString(game_id)); 

我不認爲 「this.gamesSO.getMapAttribute(Integer.toString(game_id));」將返回HashMap,我想我可以記得Red5有它自己的Map類型。

如果你簡單地調試,並添加:

System.out.println(this.gamesSO.getMapAttribute(Integer.toString(game_id))); 

和/或添加一些調試斷點和準確地確定這是哪種類型。 然後真的投給了這個。

我想你還應該指定更詳細的地圖。 喜歡的東西:

HashMap<String, MyPlayerBean> 

,並創建一個類MyPlayerBean,你真正需要的屬性。 使這些Map/List對象可以很方便地快速入門,但如果您的應用程序開始增長,它可能會變得非常難看。

塞巴斯蒂安

+0

嘿,謝謝你的信息。能夠看到一些源代碼已經非常有用,並且通過一些進一步的調查,我確定了我已經確定了這個問題。您標識的代碼行:return(previous == null ||!value)。等於(前面));似乎是原因,但它是聲明的第二部分,因爲我在修改對SO中存儲的映射的引用之前_always_等於 – milks

+0

之後如果我在編輯之前克隆映射,之前仍然等於之後地圖與數組列表共享相同的引用,並且java似乎也考慮地圖的哈希碼以便比較內容。我想我將不得不在克隆地圖和數組之前進行更改或克隆地圖並維護_changeCount_屬性。這一切似乎都很笨拙,如果只有某種方式來強制它更新/同步。 – milks

+0

我會投你的答案,但我沒有足夠的聲譽...對不起:/ – milks

0

所以我應該給我的調查結果作爲澄清的答案。

由於我抓取存儲在SharedObject中的HashMap(是一種複雜的數據類型而不是基元)的引用,所做的任何更改都會反映在該槽的當前值中,以便當它然後再次設置,Red5無法發現差異。

new_val.equals(old_val); // returns true since they both reference the same instance of HashMap 

如果我克隆HashMap的更改包含在HashMap中一個ArrayList之前,因爲該ArrayList是存儲在當前插槽和Java也考慮每個對象的hashCode相同的實例上面的語句還是評估爲真()(實際上,比較兩個HashMaps的內容)

因此,我必須在之前克隆HashMap和ArrayList 進行更改,以便檢測更改並與客戶端同步。或可替代(如我最終實現)克隆HashMap中,進行更改,還更新基本屬性,在我的情況INT changeCount

這將是巨大的,如果Red5的有一個機制來強制這種情況下同步(如在客戶端ActionScript使用使用setDirty代替的setProperty

0

更新這是一個ArrayList一個共享對象屬性,當我有類似的問題。我結束了刪除該屬性,然後再次設置它。

ArrayList<String> userlist = (ArrayList<String>) so.getAttribute("userlist"); 
userlist.remove(username); 
so.beginUpdate(); 
so.removeAttribute("userlist"); 
so.setAttribute("userlist", userlist); 
so.endUpdate();