[Red5commits] [1601] Shared objects package documenting is complete. Some minor code improvements.
mklishin
luke at codegent.com
Wed Jan 24 11:03:47 EST 2007
Shared objects package documenting is complete. Some minor code improvements.
Timestamp: 12/24/06 22:15:19 EST (1 month ago)
Change: 1601
Author: mklishin
Files (see diff or trac for details):
java/server/trunk/src/org/red5/server/messaging/AbstractMessage.java
java/server/trunk/src/org/red5/server/so/ClientSharedObject.java
java/server/trunk/src/org/red5/server/so/ISharedObjectMessage.java
java/server/trunk/src/org/red5/server/so/SharedObject.java
java/server/trunk/src/org/red5/server/so/SharedObjectEvent.java
java/server/trunk/src/org/red5/server/so/SharedObjectMessage.java
java/server/trunk/src/org/red5/server/so/SharedObjectScope.java
java/server/trunk/src/org/red5/server/so/SharedObjectService.java
Trac: http://mirror1.cvsdude.com/trac/osflash/red5/changeset/1601
Index: /java/server/trunk/src/org/red5/server/so/SharedObjectEvent.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/SharedObjectEvent.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/SharedObjectEvent.java (revision 1601)
@@ -20,12 +20,24 @@
*/
+/**
+ * {@inheritDoc}
+ */
public class SharedObjectEvent implements ISharedObjectEvent {
-
+ /**
+ * Event type
+ */
private Type type;
-
+ /**
+ * Changed pair key
+ */
private String key;
-
+ /**
+ * Changed pair value
+ */
private Object value;
+ /**
+ * {@inheritDoc}
+ */
public SharedObjectEvent(Type type, String key, Object value) {
this.type = type;
Index: /java/server/trunk/src/org/red5/server/so/SharedObjectMessage.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/SharedObjectMessage.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/SharedObjectMessage.java (revision 1601)
@@ -20,27 +20,55 @@
*/
+import org.red5.server.api.event.IEventListener;
+import org.red5.server.net.rtmp.event.BaseEvent;
+
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import org.red5.server.api.event.IEventListener;
-import org.red5.server.net.rtmp.event.BaseEvent;
-
+/**
+ * Shared object event
+ */
public class SharedObjectMessage extends BaseEvent implements
ISharedObjectMessage {
- private String name;
+ /**
+ * SO event name
+ */
+ private String name;
- private LinkedList<ISharedObjectEvent> events = new LinkedList<ISharedObjectEvent>();
+ /**
+ * SO events chain
+ */
+ private LinkedList<ISharedObjectEvent> events = new LinkedList<ISharedObjectEvent>();
+ /**
+ * SO version, used for synchronization purposes
+ */
+ private int version;
+ /**
+ * Whether SO persistent
+ */
+ private boolean persistent;
- private int version = 0;
-
- private boolean persistent = false;
-
- public SharedObjectMessage(String name, int version, boolean persistent) {
+ /**
+ * Creates Shared Object event with given name, version and persistence flag
+ *
+ * @param name Event name
+ * @param version SO version
+ * @param persistent SO persistence flag
+ */
+ public SharedObjectMessage(String name, int version, boolean persistent) {
this(null, name, version, persistent);
}
- public SharedObjectMessage(IEventListener source, String name, int version,
+ /**
+ * Creates Shared Object event with given listener, name, SO version and persistence flag
+ *
+ * @param source Event listener
+ * @param name Event name
+ * @param version SO version
+ * @param persistent SO persistence flag
+ */
+ public SharedObjectMessage(IEventListener source, String name, int version,
boolean persistent) {
super(Type.SHARED_OBJECT, source);
@@ -62,7 +90,7 @@
/**
- * Setter for property 'version'.
+ * Setter for version
*
- * @param version Value to set for property 'version'.
+ * @param version New version
*/
protected void setVersion(int version) {
@@ -76,7 +104,7 @@
/**
- * Setter for property 'name'.
+ * Setter for name
*
- * @param name Value to set for property 'name'.
+ * @param name Event name
*/
protected void setName(String name) {
@@ -90,7 +118,7 @@
/**
- * Setter for property 'isPersistent'.
+ * Setter for persistence flag
*
- * @param persistent Value to set for property 'isPersistent'.
+ * @param persistent Persistence flag
*/
protected void setIsPersistent(boolean persistent) {
Index: /java/server/trunk/src/org/red5/server/so/SharedObjectScope.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/SharedObjectScope.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/SharedObjectScope.java (revision 1601)
@@ -20,14 +20,4 @@
*/
-import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -44,16 +34,40 @@
import org.red5.server.service.ServiceUtils;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Special scope for shared objects
+ */
public class SharedObjectScope extends BasicScope implements ISharedObject {
-
+ /**
+ *
+ */
private Log log = LogFactory.getLog(SharedObjectScope.class.getName());
-
+ /**
+ * Lock to synchronize shared object updates from multiple threads
+ */
private final ReentrantLock lock = new ReentrantLock();
-
+ /**
+ * Server-side listeners
+ */
private HashSet<ISharedObjectListener> serverListeners = new HashSet<ISharedObjectListener>();
-
+ /**
+ * Event handlers
+ */
private HashMap<String, Object> handlers = new HashMap<String, Object>();
-
+ /**
+ * Scoped shared object
+ */
protected SharedObject so;
+ /**
+ * Creates shared object with given parent scope, name, persistence flag state and store object
+ * @param parent Parent scope
+ * @param name Name
+ * @param persistent Persistence flag state
+ * @param store Persistence store
+ */
public SharedObjectScope(IScope parent, String name, boolean persistent,
IPersistenceStore store) {
@@ -65,11 +79,14 @@
path = '/' + path;
}
- so = (SharedObject) store.load(TYPE + path + '/' + name);
- if (so == null) {
+ // Load SO
+ so = (SharedObject) store.load(TYPE + path + '/' + name);
+ // Create if it doesn't exist
+ if (so == null) {
so = new SharedObject(attributes, name, path, persistent, store);
-
+ // Save
store.save(so);
} else {
- so.setName(name);
+ // Rename and set path
+ so.setName(name);
so.setPath(parent.getContextPath());
}
@@ -77,7 +94,7 @@
/**
- * Setter for property 'persistenceClass'.
+ * Setter for persistence class.
*
- * @param persistenceClass Value to set for property 'persistenceClass'.
+ * @param persistenceClass Persistence class.
*/
public void setPersistenceClass(String persistenceClass) {
@@ -136,14 +153,18 @@
/** {@inheritDoc} */
public synchronized void beginUpdate(IEventListener listener) {
- if (!lock.isHeldByCurrentThread()) {
+ // If lock is not held by current thread then lock it
+ if (!lock.isHeldByCurrentThread()) {
lock.lock();
}
- so.beginUpdate(listener);
+ // Begin updating SO with this listener
+ so.beginUpdate(listener);
}
/** {@inheritDoc} */
public synchronized void endUpdate() {
- so.endUpdate();
- if (so.updateCounter == 0) {
+ // End update of SO
+ so.endUpdate();
+ // Release lock
+ if (so.updateCounter == 0) {
lock.unlock();
}
@@ -208,10 +229,8 @@
// Notify server listeners
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectSend(this, handler, arguments);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectSend(this, handler, arguments);
+ }
+ }
/** {@inheritDoc} */
@@ -223,10 +242,8 @@
if (success) {
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectDelete(this, name);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectDelete(this, name);
+ }
+ }
return success;
}
@@ -239,10 +256,8 @@
endUpdate();
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectClear(this);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectClear(this);
+ }
+ }
/** {@inheritDoc} */
@@ -252,10 +267,8 @@
so.register(listener);
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener soListener = it.next();
- soListener.onSharedObjectConnect(this);
- }
- }
+ for (ISharedObjectListener soListener : serverListeners) {
+ soListener.onSharedObjectConnect(this);
+ }
+ }
/** {@inheritDoc} */
@@ -268,10 +281,8 @@
}
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener soListener = it.next();
- soListener.onSharedObjectDisconnect(this);
- }
- }
+ for (ISharedObjectListener soListener : serverListeners) {
+ soListener.onSharedObjectDisconnect(this);
+ }
+ }
/** {@inheritDoc} */
@@ -361,10 +372,8 @@
if (success) {
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectUpdate(this, name, value);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectUpdate(this, name, value);
+ }
+ }
return success;
}
@@ -377,10 +386,8 @@
endUpdate();
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectUpdate(this, values);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectUpdate(this, values);
+ }
+ }
/** {@inheritDoc} */
@@ -391,10 +398,8 @@
endUpdate();
- Iterator<ISharedObjectListener> it = serverListeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectUpdate(this, values);
- }
- }
+ for (ISharedObjectListener listener : serverListeners) {
+ listener.onSharedObjectUpdate(this, values);
+ }
+ }
/** {@inheritDoc} */
Index: /java/server/trunk/src/org/red5/server/so/ISharedObjectMessage.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/ISharedObjectMessage.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/ISharedObjectMessage.java (revision 1601)
@@ -20,8 +20,11 @@
*/
+import org.red5.server.net.rtmp.event.IRTMPEvent;
+
import java.util.List;
-import org.red5.server.net.rtmp.event.IRTMPEvent;
-
+/**
+ * Shared object message
+ */
public interface ISharedObjectMessage extends IRTMPEvent {
@@ -56,14 +59,27 @@
public List<ISharedObjectEvent> getEvents();
- public void addEvent(ISharedObjectEvent.Type type, String key, Object value);
+ /**
+ * Addition event handler
+ * @param type Event type
+ * @param key Handler key
+ * @param value Event value (like arguments)
+ */
+ public void addEvent(ISharedObjectEvent.Type type, String key, Object value);
+ /**
+ * Add event handler
+ * @param event SO event
+ */
public void addEvent(ISharedObjectEvent event);
- public void clear();
+ /**
+ * Clear shared object
+ */
+ public void clear();
/**
- * Getter for property 'empty'.
+ * Is empty?
*
- * @return Value for property 'empty'.
+ * @return <code>true</code> if shared object is empty, <code>false</code> otherwise
*/
public boolean isEmpty();
Index: /java/server/trunk/src/org/red5/server/so/ClientSharedObject.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/ClientSharedObject.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/ClientSharedObject.java (revision 1601)
@@ -20,13 +20,4 @@
*/
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -41,15 +32,40 @@
import org.red5.server.so.ISharedObjectEvent.Type;
+import java.util.*;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Works with client-side shared object
+ */
public class ClientSharedObject extends SharedObject implements
IClientSharedObject, IEventDispatcher {
- protected static Log log = LogFactory.getLog(ClientSharedObject.class.getName());
-
- private boolean initialSyncReceived = false;
- private final ReentrantLock lock = new ReentrantLock();
- private HashSet<ISharedObjectListener> listeners = new HashSet<ISharedObjectListener>();
- private HashMap<String, Object> handlers = new HashMap<String, Object>();
-
- public ClientSharedObject(String name, boolean persistent) {
+ /**
+ * Logger
+ */
+ protected static Log log = LogFactory.getLog(ClientSharedObject.class.getName());
+ /**
+ * Initial synchronization flag
+ */
+ private boolean initialSyncReceived;
+ /**
+ * Synchronization lock
+ */
+ private final ReentrantLock lock = new ReentrantLock();
+ /**
+ * Set of listeners
+ */
+ private HashSet<ISharedObjectListener> listeners = new HashSet<ISharedObjectListener>();
+ /**
+ * Set of event handlers
+ */
+ private HashMap<String, Object> handlers = new HashMap<String, Object>();
+
+ /**
+ * Create new client SO with
+ * @param name Shared Object name
+ * @param persistent Persistence flag
+ */
+ public ClientSharedObject(String name, boolean persistent) {
super();
this.name = name;
@@ -60,5 +76,5 @@
* Connect the shared object using the passed connection.
*
- * @param conn
+ * @param conn Attach SO to given connection
*/
public void connect(IConnection conn) {
@@ -77,5 +93,5 @@
/**
- * Disconnect the shared object.
+ * Disconnect shared object.
*/
public void disconnect() {
@@ -156,29 +172,39 @@
}
- protected void notifyConnect() {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectConnect(this);
- }
- }
-
- protected void notifyDisconnect() {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectDisconnect(this);
- }
- }
-
- protected void notifyUpdate(String key, Object value) {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectUpdate(this, key, value);
- }
- }
-
- protected void notifyUpdate(String key, Map<String, Object> value) {
+ /**
+ * Notify listeners on event
+ */
+ protected void notifyConnect() {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectConnect(this);
+ }
+ }
+
+ /**
+ * Notify listeners on disconnect
+ */
+ protected void notifyDisconnect() {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectDisconnect(this);
+ }
+ }
+
+ /**
+ * Notify listeners on update
+ * @param key Updated attribute key
+ * @param value Updated attribute value
+ */
+ protected void notifyUpdate(String key, Object value) {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectUpdate(this, key, value);
+ }
+ }
+
+ /**
+ * Notify listeners on map attribute update
+ * @param key Updated attribute key
+ * @param value Updated attribute value
+ */
+ protected void notifyUpdate(String key, Map<String, Object> value) {
if (value.size() == 1) {
Map.Entry<String, Object> entry = value.entrySet().iterator().next();
@@ -186,34 +212,38 @@
return;
}
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectUpdate(this, key, value);
- }
- }
-
- protected void notifyDelete(String key) {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectDelete(this, key);
- }
- }
-
- protected void notifyClear() {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectClear(this);
- }
- }
-
- protected void notifySendMessage(String method, List params) {
- Iterator<ISharedObjectListener> it = listeners.iterator();
- while (it.hasNext()) {
- ISharedObjectListener listener = it.next();
- listener.onSharedObjectSend(this, method, params);
- }
- }
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectUpdate(this, key, value);
+ }
+ }
+
+ /**
+ * Notify listeners on attribute delete
+ * @param key Attribute name
+ */
+ protected void notifyDelete(String key) {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectDelete(this, key);
+ }
+ }
+
+ /**
+ * Notify listeners on clear
+ */
+ protected void notifyClear() {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectClear(this);
+ }
+ }
+
+ /**
+ * Broadcast send event to listeners
+ * @param method Method name
+ * @param params Params
+ */
+ protected void notifySendMessage(String method, List params) {
+ for (ISharedObjectListener listener : listeners) {
+ listener.onSharedObjectSend(this, method, params);
+ }
+ }
/** {@inheritDoc} */
@@ -245,10 +275,8 @@
// TODO: there must be a direct way to clear the SO on the client
// side...
- Iterator keys = data.keySet().iterator();
- while (keys.hasNext()) {
- String key = (String) keys.next();
- ownerMessage.addEvent(Type.SERVER_DELETE_ATTRIBUTE, key, null);
- }
- notifyModified();
+ for (String key : data.keySet()) {
+ ownerMessage.addEvent(Type.SERVER_DELETE_ATTRIBUTE, key, null);
+ }
+ notifyModified();
}
@@ -377,5 +405,5 @@
/** {@inheritDoc} */
- synchronized public Object getAttribute(String name, Object defaultValue) {
+ public synchronized Object getAttribute(String name, Object defaultValue) {
if (!hasAttribute(name)) {
setAttribute(name, defaultValue);
Index: /java/server/trunk/src/org/red5/server/so/SharedObject.java
===================================================================
--- /java/server/trunk/src/org/red5/server/so/SharedObject.java (revision 1597)
+++ /java/server/trunk/src/org/red5/server/so/SharedObject.java (revision 1601)
@@ -20,17 +20,4 @@
*/
-import static org.red5.server.api.so.ISharedObject.TYPE;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -43,4 +30,5 @@
import org.red5.server.api.persistence.IPersistable;
import org.red5.server.api.persistence.IPersistenceStore;
+import static org.red5.server.api.so.ISharedObject.TYPE;
import org.red5.server.net.rtmp.Channel;
import org.red5.server.net.rtmp.RTMPConnection;
@@ -48,71 +36,167 @@
import org.red5.server.so.ISharedObjectEvent.Type;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Represents shared object on server-side. Shared Objects in Flash are like cookies that are stored
+ * on client side. In Red5 and Flash Media Server there's one more special type of SOs : remote Shared Objects.
+ *
+ * These are shared by multiple clients and synchronized between them automatically on each data change. This is done
+ * asynchronously, used as events handling and is widely used in multiplayer Flash online games.
+ *
+ * Shared object can be persistent or transient. The difference is that first are saved to the disk and can be
+ * accessed later on next connection, transient objects are not saved and get lost each time they last client
+ * disconnects from it.
+ *
+ * Shared Objects has name identifiers and path on server's HD (if persistent). On deeper level server-side
+ * Shared Object in this implementation actually uses IPersistenceStore to delegate all (de)serialization work.
+ *
+ * SOs store data as simple map, that is, "name-value" pairs. Each value in turn can be complex object or map.
+ */
public class SharedObject implements IPersistable, Constants {
-
+ /**
+ * Logger
+ */
protected static Log log = LogFactory.getLog(SharedObject.class.getName());
- protected String name = "";
-
- protected String path = "";
-
- // true if the SharedObject was stored by the persistence framework
- protected boolean persistent = false;
-
- // true if the client / server created the SO to be persistent
- protected boolean persistentSO = false;
-
- protected IPersistenceStore storage = null;
-
- protected int version = 1;
-
- protected Map<String, Object> data = null;
-
- protected Map<String, Integer> hashes = new HashMap<String, Integer>();
-
- protected int updateCounter = 0;
-
- protected boolean modified = false;
-
- protected long lastModified = -1;
-
- protected SharedObjectMessage ownerMessage;
-
- protected LinkedList<ISharedObjectEvent> syncEvents = new LinkedList<ISharedObjectEvent>();
-
- protected HashSet<IEventListener> listeners = new HashSet<IEventListener>();
-
- protected IEventListener source = null;
+ /**
+ * Shared Object name (identifier)
+ */
+ protected String name = "";
+
+ /**
+ * SO path
+ */
+ protected String path = "";
+
+ /**
+ * true if the SharedObject was stored by the persistence framework (NOT in database,
+ * just plain serialization to the disk) and can be used later on reconnection
+ */
+
+ protected boolean persistent;
+
+ /**
+ * true if the client / server created the SO to be persistent
+ */
+ protected boolean persistentSO;
+
+ /**
+ * Object that is delegated with all storage work for persistent SOs
+ */
+ protected IPersistenceStore storage;
+
+ /**
+ * Version. Used on synchronization purposes.
+ */
+ protected int version = 1;
+
+ /**
+ * SO data
+ */
+ protected Map<String, Object> data;
+
+ /**
+ * SO hashes
+ */
+ protected Map<String, Integer> hashes = new HashMap<String, Integer>();
+
+ /**
+ * Number of pending update operations
+ */
+ protected int updateCounter;
+
+ /**
+ * Has changes? flag
+ */
+ protected boolean modified;
+
+ /**
+ * Last modified timestamp
+ */
+ protected long lastModified = -1;
+
+ /**
+ * Owner event
+ */
+ protected SharedObjectMessage ownerMessage;
+
+ /**
+ * Synchronization events
+ */
+ protected LinkedList<ISharedObjectEvent> syncEvents = new LinkedList<ISharedObjectEvent>();
+
+ /**
+ * Liste
Note:
Diffs are chopped if more than 25k.
This is to get past the limit on the mailing list.
More information about the Red5commits
mailing list