Well, perhaps not corrupted as such.
So, a little background. I've recently moved my Red5 powered game from a windows build of red5 to one running on Debian Squeeze. I have a game lobby which uses a shared object to maintain a list of the various available games.
A single game is stored as a HashMap[String, Object] against it's game_id in said SharedObject. A couple of the properties of the HashMap are ArrayLists, specifically players (an ArrayList[Integer] of connected player id's) and votes (another ArrayList[Integer] of players who have submitted a vote)
Whenever I make a change to either of these ArrayLists, something, somewhere goes wrong and I can no long write the HashMap to the SharedObject (setAttribute returns false)
Creating a new game (server side):
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);
This executes without problem, and success returns true.
Later I retrieve the player array and make amendments:
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);
here success always returns false. If a create a new HashMap for the game and copy across each property from the old one but omitting players and votes it is fine, but what ever try, I cannot get it to maintain an array. I've also tried this with List and Vector with the same results. This is my first contact with Java, I've been careful to only add class instances of Integer and not the primitive int but for all my efforts I have run out of ideas.
When on Windows it ran perfectly, my original implementation used ArrayList[String] instead of ArrayList[Integer]
Environment: Debian Squeeze 6.0.6 jre 1.7 Red5 1.0RC2
Any help or suggestions would be greatly appreciated!
Based on your red5 version info, this is the implementation of the method "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;
}
I guess value is != null (but I could be wrong). But in my opinion it would forward that call to its parent class with the "super.setAttribute" call, this is the implementation of the parent/super class:
/**
* 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;
}
The important line here (IMHO):
return (previous == null || !value.equals(previous));
=> "previous" cannot be found, and then it returns false.
The issue is I think: This cast that you are doing:
HashMap<String, Object> game = (HashMap<String, Object>)this.gamesSO.getMapAttribute(Integer.toString(game_id));
I don't think that "this.gamesSO.getMapAttribute(Integer.toString(game_id));" will return HashMap, I think I can remember that Red5 has its own Map type.
If you simply debug and add a:
System.out.println(this.gamesSO.getMapAttribute(Integer.toString(game_id)));
and/or add some debug breakpoint and verify what type exactly this is. And then cast to this one really.
I think you should also specify the Map more detailed. Something like:
HashMap<String, MyPlayerBean>
And create a class MyPlayerBean, with the attributes you really need. Making those Map/List objects might be handy to get started quickly but it can get quite ugly if your application starts to grow.
Sebastian