Class OortObject<T>
- java.lang.Object
-
- org.eclipse.jetty.util.component.AbstractLifeCycle
-
- org.cometd.oort.OortObject<T>
-
- Type Parameters:
T
- the type of value object stored in this oort object
- All Implemented Interfaces:
java.lang.Iterable<OortObject.Info<T>>
,java.util.EventListener
,ConfigurableServerChannel.Initializer
,Oort.CometListener
,org.eclipse.jetty.util.component.Dumpable
,org.eclipse.jetty.util.component.LifeCycle
- Direct Known Subclasses:
OortContainer
public class OortObject<T> extends org.eclipse.jetty.util.component.AbstractLifeCycle implements ConfigurableServerChannel.Initializer, Oort.CometListener, java.lang.Iterable<OortObject.Info<T>>, org.eclipse.jetty.util.component.Dumpable
An
OortObject
represents a named composite entity that is distributed in an Oort cluster.A typical example is an oort object that stores the number of users connected to an Oort node. The entity in this case is a
long
value representing the number of connected users. Such oort object may be named 'user_count', and there will be an oort object instance with this name in each node. Each oort object instance will have a different local value, along with all the values from the other nodes.A particular
OortObject
has a unique name across the node and is made of N parts, where N is the number of active nodes. A part is represented byOortObject.Info
instances. EachOortObject.Info
instance represents the contribution of that node to the wholeOortObject
and stores the Oort URL of the node it represents along with the entity in that node.+------------+ | user_count | +---+---+----+---+--------------------+ | part1 | 13 | local - http://oort1/ | +-------+----+------------------------+ | part2 | 19 | remote - http://oort2/ | +-------+----+------------------------+ | part3 | 29 | remote - http://oort3/ | +-------+----+------------------------+
An
OortObject
must be created and thenstarted
:Oort oort1 = ...; OortObject userCount1 = new OortObject(oort1, "user_count", OortObjectFactories.forLong()); userCount1.start();
Once started, it connects via Oort facilities to the other nodes and communicates with the oort object instances that have the same name that live in the other nodes. The communication is performed on a channel constructed from the oort object's name and returned by
getChannelName()
.Oort objects work best when the entity they hold is an immutable, value-type object:
OortObject<Long>
works better thanOortObject<AtomicLong>
because AtomicLong is mutable and its APIs (for example,AtomicLong.compareAndSet(long, long)
) are not exposed byOortObject
.Objects stored by an oort object are created using a
OortObject.Factory
. This is necessary to recreate objects that may be serialized differently when transmitted via JSON, without forcing a global JSON serializer. A number of factories are available inOortObjectFactories
, and applications can write their own.Applications can change the entity value of the oort object and broadcast the change to other nodes via
setAndShare(Object, Result)
. The other nodes will receive a message on the oort object's channel and set the new entity value in the part that corresponds to the node that changed the entity. The diagram below shows one oort object with name "user_count" in two nodes. On the left of the arrow (A), the situation before calling:userCount1.setAndShare(17, result -> { ... });
and on the right of the arrow (A) the situation afterwards, that shows how the value is first changed (1) locally on
node_1
, then a message (2) is broadcast on the cluster, reachesnode_2
, where it updates (3) the part corresponding tonode_1
to the new value.+-------------+ +-------------+ +-----------------+ +-----------------+ | node_1 | | node_2 | | node_1 | | node_2 | +-------------+ +-------------+ +-----------------+ (2) +-----------------+ | user_count | | user_count | (A) | user_count | ----> | user_count | +--------+----+ +--------+----+ ----> +--------+--------+ +--------+--------+ | local | 13 | | local | 19 | | local | 17 (1) | | local | 19 | +--------+----+ +--------+----+ +--------+--------+ +--------+--------+ | remote | 19 | | remote | 13 | | remote | 19 | | remote | 17 (3) | +--------+----+ +-------+----+ +--------+--------+ +-------+---------+
When an entity is updated, either locally or remotely, an event is fired to registered
OortObject.Listener
s.Oort objects can only update the entity they own; in the example above,
node_1
can only update the "local" value 13 to 17, but cannot modify the "remote" value 19, which is owned bynode_2
. Only update messages fromnode_1
can update the "remote" value onnode_2
. Every node has a part that belongs to a particular node, and only that particular node can update it.Values of oort objects may be merged using a
OortObject.Merger
viamerge(Merger)
. A number of mergers are available inOortObjectMergers
, and applications can write their own. For example:long totalUsersOnAllNodes = userCount1.merge(OortObjectMergers.longSum()); // yields 17+19=36
Oort objects implement a strategy where value objects are replicated in each node, trading increased memory usage for reduced latency accessing the data. An alternative strategy that trades reduced memory usage for increased latency is implemented by
OortService
.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static class
OortObject.Data<T>
static interface
OortObject.Factory<T>
Factory that creates objects stored byOortObject
s.static class
OortObject.Info<T>
The oort object part holding the object and the metadata associated with it.static interface
OortObject.Listener<T>
Listener for events that update the value of aOortObject.Info
, either local or remote.static interface
OortObject.Merger<T,R>
A merge strategy for object values.static interface
OortObject.Result<R>
An asynchronous result.-
Nested classes/interfaces inherited from class org.eclipse.jetty.util.component.AbstractLifeCycle
org.eclipse.jetty.util.component.AbstractLifeCycle.AbstractLifeCycleListener, org.eclipse.jetty.util.component.AbstractLifeCycle.StopException
-
Nested classes/interfaces inherited from interface org.cometd.bayeux.server.ConfigurableServerChannel.Initializer
ConfigurableServerChannel.Initializer.Persistent
-
Nested classes/interfaces inherited from interface org.eclipse.jetty.util.component.Dumpable
org.eclipse.jetty.util.component.Dumpable.DumpableContainer
-
Nested classes/interfaces inherited from interface org.cometd.oort.Oort.CometListener
Oort.CometListener.Event
-
-
Field Summary
Fields Modifier and Type Field Description static java.lang.String
OORT_OBJECTS_CHANNEL
-
Constructor Summary
Constructors Constructor Description OortObject(Oort oort, java.lang.String name, OortObject.Factory<T> factory)
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
addListener(OortObject.Listener<T> listener)
void
cometJoined(Oort.CometListener.Event event)
Callback method invoked when a new comet joins the cloudvoid
cometLeft(Oort.CometListener.Event event)
Callback method invoked when a comet leaves the cloudvoid
configureChannel(ConfigurableServerChannel channel)
Configures the channel used by this oort object.protected java.lang.Object
deserialize(java.lang.Object object)
protected void
doStart()
protected void
doStop()
void
dump(java.lang.Appendable out, java.lang.String indent)
java.lang.String
getChannelName()
Returns the channel name used by this oort object for communication with other oort objects in other nodes.OortObject.Factory<T>
getFactory()
OortObject.Info<T>
getInfo(java.lang.String oortURL)
OortObject.Info<T>
getInfoByObject(T object)
protected java.util.Collection<OortObject.Info<T>>
getInfos()
LocalSession
getLocalSession()
java.lang.String
getName()
Oort
getOort()
java.util.Iterator<OortObject.Info<T>>
iterator()
<R> R
merge(OortObject.Merger<T,R> strategy)
Merges the objects of all theOortObject.Info
s known to this oort object using the givenstrategy
.protected OortObject.Info<T>
newInfo(T local)
protected void
notifyRemoved(OortObject.Info<T> info)
protected void
notifyUpdated(OortObject.Info<T> oldInfo, OortObject.Info<T> newInfo)
protected void
onObject(java.util.Map<java.lang.String,java.lang.Object> data)
protected void
pullInfo(java.lang.String oortURL)
protected void
pushInfo(java.lang.String oortURL, java.util.Map<java.lang.String,java.lang.Object> fields)
void
removeListener(OortObject.Listener<T> listener)
void
removeListeners()
Removes all listeners.protected java.lang.Object
serialize(T object)
void
setAndShare(T newObject, OortObject.Result<T> callback)
Sets the given new object on this oort object, and then broadcast the new object to all nodes in the cluster.java.lang.String
toString()
-
Methods inherited from class org.eclipse.jetty.util.component.AbstractLifeCycle
addEventListener, getEventListeners, getState, getState, isFailed, isRunning, isStarted, isStarting, isStopped, isStopping, removeEventListener, setEventListeners, start, stop
-
-
-
-
Field Detail
-
OORT_OBJECTS_CHANNEL
public static final java.lang.String OORT_OBJECTS_CHANNEL
- See Also:
- Constant Field Values
-
-
Constructor Detail
-
OortObject
public OortObject(Oort oort, java.lang.String name, OortObject.Factory<T> factory)
-
-
Method Detail
-
doStart
protected void doStart()
- Overrides:
doStart
in classorg.eclipse.jetty.util.component.AbstractLifeCycle
-
doStop
protected void doStop()
- Overrides:
doStop
in classorg.eclipse.jetty.util.component.AbstractLifeCycle
-
configureChannel
public void configureChannel(ConfigurableServerChannel channel)
Configures the channel used by this oort object. By default does nothing, but subclasses may override this method to make the channel lazy, for example.- Specified by:
configureChannel
in interfaceConfigurableServerChannel.Initializer
- Parameters:
channel
- the channel to configure- See Also:
getChannelName()
-
getName
public java.lang.String getName()
- Returns:
- the name of this oort object, that must be unique across the node.
-
getFactory
public OortObject.Factory<T> getFactory()
- Returns:
- the factory to create objects contained in this oort object
-
getLocalSession
public LocalSession getLocalSession()
- Returns:
- the local session that sends messages to other nodes
-
getChannelName
public java.lang.String getChannelName()
Returns the channel name used by this oort object for communication with other oort objects in other nodes. The channel is of the form "/oort/objects/<name>" where <name> is this oort object'sname
.- Returns:
- the channel name used by this oort object
- See Also:
configureChannel(ConfigurableServerChannel)
-
setAndShare
public void setAndShare(T newObject, OortObject.Result<T> callback)
Sets the given new object on this oort object, and then broadcast the new object to all nodes in the cluster.
Setting an object triggers notification of
OortObject.Listener
s, both on this node and on remote nodes.The object is guaranteed to be set not when this method returns, but when the
OortObject.Result
parameter is notified.- Parameters:
newObject
- the new object to setcallback
- the callback invoked with the old object, ornull
if there is no interest in the old object
-
serialize
protected java.lang.Object serialize(T object)
-
deserialize
protected java.lang.Object deserialize(java.lang.Object object)
-
newInfo
protected OortObject.Info<T> newInfo(T local)
-
cometJoined
public void cometJoined(Oort.CometListener.Event event)
Description copied from interface:Oort.CometListener
Callback method invoked when a new comet joins the cloud- Specified by:
cometJoined
in interfaceOort.CometListener
- Parameters:
event
- the comet event
-
cometLeft
public void cometLeft(Oort.CometListener.Event event)
Description copied from interface:Oort.CometListener
Callback method invoked when a comet leaves the cloud- Specified by:
cometLeft
in interfaceOort.CometListener
- Parameters:
event
- the comet event
-
iterator
public java.util.Iterator<OortObject.Info<T>> iterator()
- Specified by:
iterator
in interfacejava.lang.Iterable<T>
- Returns:
- an iterator over the
OortObject.Info
known to this oort object
-
getInfo
public OortObject.Info<T> getInfo(java.lang.String oortURL)
- Parameters:
oortURL
- the oort URL used to search the correspondingOortObject.Info
- Returns:
- the
OortObject.Info
with the given oort URL, or null if no suchOortObject.Info
exists
-
getInfoByObject
public OortObject.Info<T> getInfoByObject(T object)
- Parameters:
object
- the object used to search the correspondingOortObject.Info
- Returns:
- the first
OortObject.Info
whose object equals (via a possibly overriddenObject.equals(Object)
) the givenobject
-
merge
public <R> R merge(OortObject.Merger<T,R> strategy)
Merges the objects of all theOortObject.Info
s known to this oort object using the givenstrategy
.- Type Parameters:
R
- the merge result type- Parameters:
strategy
- the strategy to merge the objects- Returns:
- the merged result
-
addListener
public void addListener(OortObject.Listener<T> listener)
- Parameters:
listener
- the listener to add- See Also:
removeListener(Listener)
-
removeListener
public void removeListener(OortObject.Listener<T> listener)
- Parameters:
listener
- the listener to remove- See Also:
addListener(Listener)
-
removeListeners
public void removeListeners()
Removes all listeners.- See Also:
addListener(Listener)
,removeListener(Listener)
-
notifyUpdated
protected void notifyUpdated(OortObject.Info<T> oldInfo, OortObject.Info<T> newInfo)
-
notifyRemoved
protected void notifyRemoved(OortObject.Info<T> info)
-
onObject
protected void onObject(java.util.Map<java.lang.String,java.lang.Object> data)
-
pushInfo
protected void pushInfo(java.lang.String oortURL, java.util.Map<java.lang.String,java.lang.Object> fields)
-
pullInfo
protected void pullInfo(java.lang.String oortURL)
-
getInfos
protected java.util.Collection<OortObject.Info<T>> getInfos()
-
dump
public void dump(java.lang.Appendable out, java.lang.String indent) throws java.io.IOException
- Specified by:
dump
in interfaceorg.eclipse.jetty.util.component.Dumpable
- Throws:
java.io.IOException
-
toString
public java.lang.String toString()
- Overrides:
toString
in classorg.eclipse.jetty.util.component.AbstractLifeCycle
-
-