FileDocCategorySizeDatePackage
MessageDispatcher.javaAPI DocAzureus 3.0.3.49687Sat Jun 09 17:22:10 BST 2007com.aelitis.azureus.ui.swt.browser.msg

MessageDispatcher

public class MessageDispatcher extends Object implements TitleListener, StatusTextListener
Dispatches messages to listeners registered with unique IDs. Each message sent from the browser must be given a message sequence number that is different from that of the previous message to detect duplicate events.

Messages are in the form

 PREFIX DELIM <seq-no> DELIM <listener-id> DELIM <operation-id> DELIM <params> . . .
For example,
 "AZMSG;37;publish;choose-files"
Sequence numbers are unique to each {@link Browser} instance in the UI, and they start at 1, being reset each time an HTML page loads.
author
dharkness
created
Jul 18, 2006

Fields Summary
public static final String
LISTENER_ID
public static final String
OP_RESET_SEQUENCE
public static final String
CONTEXT_LISTENER_ID
private static final int
INITIAL_LAST_SEQUENCE
private com.aelitis.azureus.core.messenger.ClientMessageContext
context
private Map
listeners
private int
lastSequence
private String
sLastEventText
private org.gudy.azureus2.core3.util.AEMonitor
class_mon
Constructors Summary
public MessageDispatcher(com.aelitis.azureus.core.messenger.ClientMessageContext context)
Registers itself as a listener to receive sequence number reset message.



                    
          
        this.context = context;
    
Methods Summary
public synchronized voidaddListener(MessageListener listener)
Registers the given listener for the given ID.

param
id unique identifier used when dispatching messages
param
listener receives messages targetted at the given ID
throws
IllegalStateException if another listener is already registered under the same ID

        String id = listener.getId();
        MessageListener registered = (MessageListener) listeners.get(id);
        if ( registered != null ) {
            if ( registered != listener ) {
                throw new IllegalStateException("Listener " + registered.getClass().getName()
                        + " already registered for ID " + id);
            }
        }
        else {
            listener.setContext(context);
            listeners.put(id, listener);
        }
    
public voidchanged(StatusTextEvent event)
Parses the event to see if it's a valid message and dispatches it.

param
event contains the message
see
org.eclipse.swt.browser.StatusTextListener#changed(org.eclipse.swt.browser.StatusTextEvent)

    	processIncomingMessage(event.text, ((Browser)event.widget).getUrl());
    
public voidchanged(TitleEvent event)

    	processIncomingMessage(event.title, ((Browser)event.widget).getUrl());
		
public voidderegisterBrowser(Browser browser)
Detaches this dispatcher from the given {@link Browser}. This dispatcher listens for dispose events from the browser and calls this method in response.

param
browser {@link Browser} which will no longer send messages

        browser.removeStatusTextListener(this);
        browser.removeTitleListener(this);
    
public voiddispatch(BrowserMessage message)
Dispatches the given message to the appropriate listener.

param
message holds the listener ID, operation ID and parameters
throws
IllegalArgumentException if no listener is registered with the given ID

        if ( message == null ) {
            return;
        }
        context.debug("Received " + message);
        
        // handle messages for dispatcher and context regardless of sequence number
        String listenerId = message.getListenerId();
        if ( LISTENER_ID.equals(listenerId) ) {
            handleMessage(message);
        }
        else if ( BrowserContext.LISTENER_ID.equals(listenerId) ) {
            context.handleMessage(message);
        }
        else {
            if ( ! isValidSequence(message) ) {
                context.debug("Ignoring duplicate: " + message);
            }
            else {
                MessageListener listener = getListener(listenerId);
                if ( listener == null ) {
                    context.debug("No listener registered with ID " + listenerId);
                }
                else {
                    listener.handleMessage(message);
                    message.complete(true, true, null);
                }
            }
        }
    
public MessageListenergetListener(java.lang.String id)
Returns the listener with the given ID.

param
id unique identifier of the listener to be returned
return
the located listener

        return (MessageListener) listeners.get(id);
    
public voidhandleMessage(BrowserMessage message)
Handles operations intended for the dispatcher.

param
message holds all message information

        String operationId = message.getOperationId();
        if ( OP_RESET_SEQUENCE.equals(operationId) ) {
            resetSequence();
        }
        else {
            throw new IllegalArgumentException("Unknown operation: " + operationId);
        }
    
public booleanisValidSequence(BrowserMessage message)
Determines whether or not the given sequence number is still valid for the given {@link Browser}. If the number is valid, it is stored as the last seen sequence number.

param
browser {@link Browser} to test
param
sequence the sequence number from an incoming message
return
true if the sequence number is valid (greater than the last seen sequence number); false otherwise

        int sequence = message.getSequence();
        if ( sequence < 0 ) {
            Debug.outNoStack("Invalid sequence number: " + sequence);
            return false;
        }
        
        if ( sequence <= lastSequence ) {
            context.debug("Duplicate sequence number: " + sequence 
                    + ", last: " + lastSequence);
            return false;
        }
        
        lastSequence = sequence;
        return true;
    
private voidprocessIncomingMessage(java.lang.String msg, java.lang.String referer)

		if (msg == null) {
			return;
		}

		try {
			class_mon.enter();
			if (sLastEventText != null && msg.equals(sLastEventText)) {
				return;
			}

			sLastEventText = msg;
		} finally {
			class_mon.exit();
		}

		if (msg.startsWith(BrowserMessage.MESSAGE_PREFIX)) {
			try {
				BrowserMessage browserMessage = new BrowserMessage(msg);
				browserMessage.setReferer(referer);
				dispatch(browserMessage);
			} catch (Exception e) {
				Debug.out(e);
			}
		}
	
public voidregisterBrowser(Browser browser)
Attaches this dispatcher to the given {@link Browser} to receive status text change and dispose events.

param
browser {@link Browser} which will send events

        browser.addStatusTextListener(this);
        browser.addTitleListener(this);
    
public synchronized voidremoveListener(MessageListener listener)
Deregisters the listener with the given ID.

param
id unique identifier of the listener to be removed

        removeListener(listener.getId());
    
public synchronized voidremoveListener(java.lang.String id)
Deregisters the listener with the given ID.

param
id unique identifier of the listener to be removed

        MessageListener removed = (MessageListener) listeners.remove(id);
        if ( removed == null ) {
//            throw new IllegalStateException("No listener is registered for ID " + id);
        }
        else {
            removed.setContext(null);
        }
    
public voidresetSequence()
Resets the sequence number for the given {@link Browser} to 0.

param
browser {@link Browser} to reset

        context.debug("Reseting sequence number");
        lastSequence = INITIAL_LAST_SEQUENCE;