Package net.commerce.zocalo.ajax.dispatch

This package allows Zocalo to publish significant events via Log4J and cometd (an AJAX technology).

See:
          Description

Class Summary
AppenderBase  
BidUpdateDispatcher marshal events that represent changes to the active bids displayed in the stripchart.
Dispatcher Dispatchers marshall events and publish them via cometd.
MockBayeux  
MockBayeuxChannel  
NewChartAppender publishes actions announcing new price charts to cometd.
NewChartDispatcher marshalls events that announce the availability of new price charts.
PriceActionAppender publishes actions describing bidding behavior to cometd
PriceChangeAppender publishes actions announcing new MarketMaker prices to cometd.
PriceChangeDispatcher marshalls events that represent new price levels.
PrivateEventAppender Uses log4j to dispatch events to individual endpoints rather than broadcasting them.
PrivateEventDispatcher marshalls private events and distributes them to a particular user via comet.
TradeEventDispatcher marshalls events that represent trades that have taken place.
TransitionAppender publishes actions representing Session state transitions to cometd.
TransitionDispatcher marshalls events that represent state transitions in the Session.
 

Package net.commerce.zocalo.ajax.dispatch Description

This package allows Zocalo to publish significant events via Log4J and cometd (an AJAX technology). The events (in events) are used to add information to the log, to store records in the database, to update the strip chart showing bidding activity to experimental subjects, and to notify the UI of significant events. Log4J provides a general framework for connecting together reports of events that can be output in a variety of formats and piped dynamically without changing the call site.

There are two hierarchies here: Dispatchers, and Appenders. The Appenders are specializations of Log4J's AppenderSkeleton. Dispatchers marshall events and publish them via cometd.

The Log4J framework is used to distribute the actions to cometd, to Zocalo's own Log4J logs, and to produce records of transactions in the database for the prediction market. The Appenders provide the connection between Log4J and cometd by registering an interest in particular Log4J channels, and when events arrive, publishing them to cometd using the Dispatchers.

PriceActionAppender is interested in trades and other changes in prices including new bids (Bid and Ask), retracted bids (OrderRemoval and SelfDealing), changes in the best bid and ask (BestBid, and BestAsk), and completed trades (Trade). The other Appender is TransitionAppender, which is interested in Transition actions affecting experiments.

The Dispatchers marshall the events and send them on to cometd. TradeEventDispatcher deals with events representing trades that have taken place, BidUpdateDispatcher handles events that involve changing the active bids displayed on the stripchart, and TransitionDispatcher handles events that represent state transitions in experiment sessions which have effects in the browser that go beyond the strip chart.

Event Flow

Event) objects are created when something significant happens in the server.

Events are instances of subclasses of Action, which extends LoggingEvent. This makes it possible for them to be handed directly to a logger which causes them to be passed as an argument to the AppenderSkeleton's append(LoggingEvent). method.

Log4j provides AppenderSkeleton, which is the prototype for Appenders that consume Events. Zocalo's Appenders format the events and distribute them to Dispatchers. The dispatchers have a reference to a bayeux channel (Bayeux is a protocol that supports AJAX-style browser intereactions.) The dispatchers can marshall events and thereby publish them to AJAX. There's also a MockBayeux and MockBayeuxChannel that allows Zocalo to collect events internally when necessary.

Each Appender has one or more Dispatcher. The Appenders react to specific server-side events, and distribute them to their dispatchers. The dispatchers represent a particular channel distributing messages for a set of clients. This allows javascript in the browser to specify which set of events it wants to consume and assign a handler method in the browser to be invoked when a message of interest arrives.

Here are three example cases. PriceChange events are generated during experiments whenever there's a change is the set of bids in the book, and are used in the browser to trigger updating the candle chart displaying all the outstanding offers. (They are distinct from Trades, which only occur when an actual trade takes place, and cause a new historical price to be displayed, and the candle moved right.) IndividualTimingEvents are distributed directly to a particular user (a Judge) when a timer expires. In the browser, we can then disable the judge's inputbox for entering price estimates. This only affects one experiment subject. The third case is used to update price charts after a trade in a prediction market. It takes a significant amount of time to compute the price charts, so we have a separate thread generating them, and once the chart is ready, we send out an update to all the browsers viewing that market so they can request a new copy. Since this is a simple image refresh, Jetty can handle it in parallel with the continuing market activity.

The table shows the current events and how and where the code sets up the path they traverse. For each, we show

  1. The use of the event.
  2. the event object and where it's created
  3. the Appender that the event gets registered on. Notice that PriceActionAppender handles only PriceActions, but has two client Dispatchers.
  4. The Logger used.
  5. where logger.callAppenders is called to invoke a Dispatcher
  6. The Dispatcher and where it's created.
  7. Where the dispatcher filters events by market. (The same logger can be re-used for multiple channels.)
  8. The Bayeux channel the Dispatcher publishes events to.
  9. Where the javascript subscribes to the Bayeux channel, and the function invoked to handle each event.
  10. If the events are also consumed within the server, where the server's subscription appears. (Not listed for Prediction Markets)
  11. What use is made of the events within the server. (Not listed for Prediction Markets)
There are two tables. The first shows combinations used in Experiments, and the second covers prediction markets.
EXPERIMENTS Book Price update (Exp) Timing Events (Exp) Trade Events (Exp) Transition Events (Exp)
Purpose Book Price update: modify candle and current bids and asks Judge timed out Trade took place: add a black dot Experiment transitioned to the next phase
Event PriceAction created in recordTrade in BinaryMarketMaker or MultiMarketMaker after trade created in TimerTask in Judge.getCutoffTimer() PriceAction created in Binary, Unary, and MultiMarket, in record*Trade() Transition is created in Session.logTransitionEvent()
Appender PriceActionAppender created in Session.initializeMarket() for bayeux and MockBayeux. PrivateEventAppender created in Session.initializeMarket(). PriceActionAppender created in Session.initializeMarket() for bayeux and MockBayeux. TransitionAppender created in Session.initializeTransitionAppender().
Logger PriceAction.class IndividualTimingEvent.class PriceAction.class Transition.class
callAppenders() PriceAction.log() called in event constructor, which uses Logger(PriceAction.class) in IndividualTimingEvent constructor logger.callAppenders(this); PriceAction.log() called in event constructor, which uses Logger(PriceAction.class) in Transition constructor
Dispatcher BidUpdateDispatcher created by PriceActionAppender PrivateEventDispatcher created by PrivateEventAppender. PrivateEventDispatcher uses deliver() to send the message to just one client. PriceActionAppender creates a TradeEventDispatcher TransitionDispatcher created by TransitionAppender
Bayeux channel /liveUpdate /service/privateEvent /historicalUpdate /transition
javascript subscription stripchartframe.html has onload_actions() (called from onload) that calls dojox.cometd.subscribe( "/liveUpdate", onLiveMessage); JudgeSubFrame.jsp has onload_actions() (called from onload) that calls dojox.cometd.subscribe( "/service/privateEvent",onPrivateMessage); stripchartframe.html has onload_actions() (called from onload) that calls dojox.cometd.subscribe( "/historicalUpdate",onHistMessage); stripchartframe.html has onload_actions() (called from onload) that calls dojox.cometd.subscribe( "/transition", onTransitionMessage);
Server Subscription NONE ExperimentServer. ExperimentBayeuxServer constructor calls subscribe( PrivateEventDispatcher. PRIVATE_EVENT_TOPIC_SUFFIX, "sendPrivateUpdate") Session.initializeMarket() calls tradeHistory = (MockBayeuxChannel) sessionHistory.getChannel( TradeEventDispatcher. TRADE_EVENT_TOPIC_SUFFIX, true); NONE
Server Client NONE redirect to specific client private MockBayeuxChannel tradeHistory; NONE

PREDICTION MARKETS MM Price Update (PM) New Charts (PM) Transition Events (PM)
Purpose Market Maker price update: update prices in table new price chart is ready: refresh A new Market opened, give Users a link
Event PriceChange created in recordTrade in BinaryMarketMaker or MultiMarketMaker after trade created in ChartGenerator updateChartFile() and writeMultiStepChartFile() Transition is created in MarketOwner.newBinaryMarket() or MarketOwner.newMultiMarket()
Appender PriceChangeAppender created in AllMarkets.MarketBayeuxService (bayeux, marketName). NewChartAppender created in AllMarkets.MarketBayeuxService (bayeux, marketName). TransitionAppender created in MarketBayeuxService constructor().
Logger PriceChange.class NewChart.class Transition.class
callAppenders() in PriceChange constructor, calls Logger(PriceChange.class) .callAppenders(this) NewChart constructor Transition constructors
Dispatcher PriceChangeDispatcher created in PriceChangeAppender constructor NewChartDispatcher created by NewChartAppender TransitionDispatcher created by TransitionAppender
Filtering PriceChangeDispatcher.publishTransition() NewChartDispatcher.publishTransition() NA
Bayeux channel Dispatcher.buildChannelName() produces /priceChange/ + marketName Dispatcher.buildChannelName() produces /newChart/ + marketName /transition
javascript subscription channels.push( dojox.cometd.subscribe( priceUpdateChannel, onPriceUpdate)); purchaseCost.jsp has onload_actions() (called from onload) that calls dojox.cometd.subscribe( /newChart/+claimName, onPriceUpdate); purchaseClaim.jsp and purchaseCost.jsp have onload_actions() (called from onload) that call dojox.cometd.subscribe( "/transition", onTransitionMessage);


© Copyright 2007-2009 Chris Hibbert. All rights reserved.
© 2006 CommerceNet Consortium, LLC.

This software is published under the terms of the MIT license, a copy
of which has been included with this distribution in the LICENSE file.