package org.jboss.ha.core.jgroups.blocks.mux;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jgroups.Event;
import org.jgroups.Message;
import org.jgroups.UpHandler;
import org.jgroups.blocks.mux.MuxHeader;
import org.jgroups.blocks.mux.MuxRequestCorrelator;
import org.jgroups.blocks.mux.NoMuxHandler;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.stack.StateTransferInfo;
/**
* Allows up handler multiplexing.
*
* @author Bela Ban
* @author Paul Ferraro
* @author Brian Stansberry
*
* @version $Id: MuxUpHandler.java,v 1.2 2010/04/15 20:05:22 ferraro Exp $
*/
public class MuxUpHandler
extends org.jgroups.blocks.mux.MuxUpHandler {
//implements UpHandler, Muxer<UpHandler> {
protected final Log log=LogFactory.getLog(getClass());
protected final static short MUX_ID = ClassConfigurator.getProtocolId(MuxRequestCorrelator.class);
private final Map<Short, UpHandler> handlers = new ConcurrentHashMap<Short, UpHandler>();
private volatile UpHandler defaultHandler;
private volatile Event lastFlushEvent;
private final Object flushMutex = new Object();
/**
* Creates a multiplexing up handler, with no default handler.
*/
public MuxUpHandler() {
this.defaultHandler = null;
}
/**
* Creates a multiplexing up handler using the specified default handler.
* @param defaultHandler a default up handler to handle messages with no {@link MuxHeader}
*/
public MuxUpHandler(UpHandler defaultHandler) {
this.defaultHandler = defaultHandler;
}
/**
* {@inheritDoc}
* @see org.jgroups.blocks.mux.Muxer#add(short, java.lang.Object)
*/
@Override
public void add(short id, UpHandler handler) {
synchronized (flushMutex)
{
if (lastFlushEvent != null)
{
handler.up(lastFlushEvent);
}
handlers.put(id, handler);
}
}
/**
* {@inheritDoc}
* @see org.jgroups.blocks.mux.Muxer#remove(short)
*/
@Override
public void remove(short id) {
handlers.remove(id);
}
/**
* {@inheritDoc}
* @see org.jgroups.UpHandler#up(org.jgroups.Event)
*/
@Override
public Object up(Event evt) {
switch (evt.getType()) {
case Event.MSG: {
Message msg = (Message) evt.getArg();
MuxHeader hdr = (MuxHeader) msg.getHeader(MUX_ID);
if (hdr != null) {
short id = hdr.getId();
UpHandler handler = handlers.get(id);
return (handler != null) ? handler.up(evt) : new NoMuxHandler(id);
}
break;
}
case Event.GET_APPLSTATE:
case Event.GET_STATE_OK:
case Event.STATE_TRANSFER_OUTPUTSTREAM:
case Event.STATE_TRANSFER_INPUTSTREAM: {
StateTransferInfo info=(StateTransferInfo)evt.getArg();
String state_id=info.state_id;
UpHandler basicHandler = null;
boolean multipleBasic = false;
for (UpHandler uh: handlers.values())
{
if (uh instanceof StateTransferFilter)
{
if (((StateTransferFilter) uh).accepts(state_id))
{
return (uh.up(evt));
}
}
else if (basicHandler == null)
{
basicHandler = uh;
}
else
{
multipleBasic = true;
}
}
if (basicHandler != null)
{
if (multipleBasic)
{
// TODO throw exception
log.warn("Received state transfer related event with more " +
"than one basic UpHandler registered. Arbitrarily " +
"picking a handler to handle request");
}
return basicHandler.up(evt);
}
// else let default handler handle it below
break;
}
case Event.BLOCK:
case Event.UNBLOCK: {
synchronized (flushMutex)
{
this.lastFlushEvent = evt;
passToAllHandlers(evt);
break;
}
}
case Event.VIEW_CHANGE:
case Event.SET_LOCAL_ADDRESS:
case Event.SUSPECT: {
passToAllHandlers(evt);
break;
}
default: {
passToAllHandlers(evt);
break;
}
}
return (defaultHandler != null) ? defaultHandler.up(evt) : null;
}
private void passToAllHandlers(Event evt)
{
for (UpHandler handler: handlers.values()) {
handler.up(evt);
}
}
}