Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (c) 2010 Daniel Murphy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
Created at 2:19:39 AM, Mar 12, 2010
 
 package com.dmurph.mvc;
 
 
 
This stores all the listener information, dispatches events to the corresponding listeners. To dispatch events use MVCEvent.dispatch() . Also, look at splitOff(). To set up Google analytics, call setTracker(com.dmurph.tracking.JGoogleAnalyticsTracker), or implement com.dmurph.mvc.tracking.ICustomTracker in your events to be tracked, and then any event that implements com.dmurph.mvc.tracking.ITrackable will be tracked. If com.dmurph.mvc.tracking.ITrackable.getTrackingCategory() or com.dmurph.mvc.tracking.ITrackable.getTrackingAction() returns null, then it will be ignored.

Author(s):
Daniel Murphy
 
 public class MVC extends Thread {
 	
 	private static final Logger log = LoggerFactory.getLogger(MVC.class);
 	
 	private static final ThreadGroup mvcThreadGroup = new ThreadGroup("MVC Thread Group");
 	private static final ArrayList<MVCmvcThreads = new ArrayList<MVC>();
 	private static final Queue<MVCEventeventQueue = new LinkedList<MVCEvent>();
 	
 	private static final Object trackerLock = new Object();
 	private volatile static JGoogleAnalyticsTracker tracker = null;
 	private static final Object monitorLock = new Object();
 	private volatile static IGlobalEventMonitor monitor = new LoggingMonitor();
 	private static final Object mainThreadLock = new Object();
 	private volatile static MVC mainThread;
 	private volatile static String currKey = null;
 	
 	private volatile boolean running = false;
 	private final int threadCount;
 	
 	private MVC(int argNum) {
 		super("MVC Thread #" + argNum);
 		 = argNum;
 		.add(this);
 	}
 	
 	public static void setTracker(JGoogleAnalyticsTracker argTracker) {
 		synchronized () {
 			 = argTracker;
 		}
 	}
 	
 	public static JGoogleAnalyticsTracker getTracker() {
 		return ;
 	}

Adds a listener for the given event key. If the listener is already listening to that key, then nothing is done. On the rare occurrence that the key is being dispatched at the same time by the mvc thread, this call will wait till all the events of that key are dispatched before adding and returning. If that happens and the thead making this call is also the mvc thread, (a listener for a key adds another listener for the same key), then a runtime exception is thrown.

Parameters:
argKey
argListener
	public static void addEventListener(String argKeyIEventListener argListener) {
		if (argKey == null) {
			throw new RuntimeException("Key cannot be null");
		}
		synchronized () {
			synchronized () {
				if (argKey.equals() && Thread.currentThread() == ) {
					throw new RuntimeException("Cannot add a listener to the same key that's being dispatched");
				}
			}
			if (.containsKey(argKey)) {
				// return if we're already listening
				if (.get(argKey).contains(argListener)) {
					.debug("We already have that listener here"argListener);
					return;
				}
				fifo = .get(argKey);
			}
			else {
				fifo = new LinkedList<IEventListener>();
				.put(argKeyfifo);
			}
			fifo.add(argListener);
		}
	}

Checks to see if the listener is listening to the given key.

Parameters:
argKey
argListener
Returns:
	public static boolean isEventListener(String argKeyIEventListener argListener) {
		if (argKey == null) {
			throw new RuntimeException("Key cannot be null");
		}
		synchronized () {
			if (!.containsKey(argKey)) {
				return false;
			}
			return stack.contains(argListener);
		}
	}

Gets a copy of the listeners for the given event key.

Parameters:
argKey
Returns:
	public static LinkedList<IEventListenergetListeners(String argKey) {
		if (argKey == null) {
			throw new RuntimeException("Key cannot be null");
		}
		synchronized () {
			if (.containsKey(argKey)) {
				return new LinkedList<IEventListener>(.get(argKey));
			}
			else {
				return new LinkedList<IEventListener>();
			}
		}
	}

removes a listener from the given key.

Parameters:
argKey
argListener
Returns:
true if the listener was removed, and false if it wasn't there to begin with
	public static boolean removeEventListener(String argKeyIEventListener argListener) {
		if (argKey == null) {
			throw new RuntimeException("Key cannot be null");
		}
		synchronized () {
			synchronized () {
				if (argKey.equals() && Thread.currentThread() == ) {
					throw new RuntimeException(
							"Cannot remove a listener to the same key that's being dispatched.  Return false instead.");
				}
			}
			if (.containsKey(argKey)) {
				return stack.remove(argListener);
			}
			else {
				return false;
			}
		}
	}

Adds an event to the dispatch queue for the MVC thread. Used by MVCEvent.dispatch().

Parameters:
argEvent
	protected static void dispatchEvent(MVCEvent argEvent) {
		boolean hasListeners;
		synchronized () {
			hasListeners = .containsKey(argEvent.key);
		}
		if (hasListeners) {
			synchronized () {
				.add(argEvent);
			}
			}
		}
		else {
			synchronized () {
				if ( != null) {
					try {
catch (Exception e) {
						.error("Exception caught from monitor"e);
					}
				}
			}
		}
	}

Split off the current MVC thread, all queued events and future event dispatches are handled by a new MVC thread, while this one runs to completion. If the thread calling this is not the current core MVC thread, then an exception is thrown

Throws:
IllegalThreadException if the thread calling this is not an MVC thread
IncorrectThreadException if the MVC thread calling this is not the main thread, e.g. it has already split off.
	public static void splitOff() throws IllegalThreadExceptionIncorrectThreadException {
		if (Thread.currentThread() instanceof MVC) {
			MVC thread = (MVC) Thread.currentThread();
			synchronized () {
				if (thread == ) {
					.debug("Splitting off...");
					MVC old = ;
					old.running = false;
					 = new MVC(old.threadCount + 1);
					.debug("Starting next MVC thread");
				}
				else {
					.error("Can't split off when this isn't the main thread");
				}
			}
		}
		else {
			.error("Can't split off, we're not in the MVC thread.");
		}
	}

Wait for all remaining events to dispatch

Parameters:
timeoutMillis The maximum number of milliseconds to wait.
	public static void completeRemainingEvents(long timeoutMillis) {
		boolean fifoEmpty = false;
		long absTimeout = System.currentTimeMillis() + timeoutMillis;
		while (System.currentTimeMillis() < absTimeout) {
			synchronized () {
				fifoEmpty = (.size() == 0);
			}
			if (fifoEmpty) {
				break;
			}
			try {
				Thread.sleep(100);
catch (InterruptedException e) {
				break;
			}
		}
	}

Stops the dispatch thread, dispatching any remaining events before cleanly returning. Thread automatically gets started when new events are dispatched
	public static void stopDispatchThread(long argTimeoutMillis) {
		synchronized () {
			synchronized () {
			}
			if (( != null) && (argTimeoutMillis > 0)) {
				try {
					.join(argTimeoutMillis);
catch (InterruptedException e) {}
				 = null;
			}
		}
	}
	public static boolean isDispatchThreadRunning() {
		synchronized () {
			return  != null && (. || .getState() == .);
		}
	}

Manually starts the dispatch thread.
	public static void startDispatchThread() {
		synchronized () {
			if ( == null) {
				 = new MVC(0);
			}
				if (.getState() == .) {
				}
			}
		}
	}

Sets the global event monitor, which is called before and after each event is dispatched.

Parameters:
argMonitor
See also:
IGlobalEventMonitor
	public static void setGlobalEventMonitor(IGlobalEventMonitor argMonitor) {
		synchronized () {
			 = argMonitor;
		}
	}

Gets the global event monitor. Default is com.dmurph.mvc.monitor.WarningMonitor.

Returns:
See also:
IGlobalEventMonitor
		synchronized () {
			return ;
		}
	}
	private volatile static EventMonitor guiMonitor = null;

Convenience method to construct and show an com.dmurph.mvc.monitor.EventMonitor. To have more control on how the com.dmurph.mvc.monitor.EventMonitor is configured, you can just create it yourself and use setGlobalEventMonitor(com.dmurph.mvc.IGlobalEventMonitor) to have it be the global event monitor.

	public static EventMonitor showEventMonitor() {
		if ( == null) {
			synchronized () {
			}
		}
		return ;
	}

Hides the event monitor, if you had used showEventMonitor().
	public static void hideEventMonitor() {
		if ( != null) {
		}
	}
	public void run() {
		 = true;
		.info("MVC thread #" +  + " starting up");
		while () {
			try {
				MVCEvent event = null;
				synchronized () {
					}
					if (!.isEmpty()) {
						event = .poll();
					}
				}
				if (event != null) {
				}
catch (Exception e) {
				.error("Caught exception in dispatch thread"e);
			}
		}
	}
	private void internalDispatchEvent(MVCEvent argEvent) {
		if ( != null) {
			synchronized () {
				try {
catch (Exception e) {
					.error("Exception caught from monitor"e);
				}
			}
		}
		if (argEvent instanceof ITrackable) {
			ITrackable event = (ITrackableargEvent;
			if (event.getTrackingCategory() != null && event.getTrackingAction() != null) {
				if (event instanceof ICustomTracker) {
				}
				else if ( != null) {
					synchronized () {
					}
				}
				else {
					.warn("Event could not be tracked, as the tracker is null"event);
				}
			}
		}
		 = argEvent.key;
		synchronized () {
			stack = .get(argEvent.key);
			while (it.hasNext() && argEvent.isPropagating()) {
				try {
					if (!it.next().eventReceived(argEvent)) {
						it.remove();
					}
catch (Exception e) {
					synchronized () {
						if ( != null) {
							try {// why do I have to do this? monitors shouldn't throw
									// exceptions
								.exceptionThrown(argEvente);
catch (Exception e2) {
								.error("Exception caught from event dispatch"e);
								.error("Exception caught from monitor"e2);
							}
						}
						else {
							.error("Exception caught from event dispatch"e);
						}
					}
				}
			}
			 = null;
		}
		synchronized () {
			if ( != null) {
				try {
catch (Exception e) {
					.error("Exception caught from monitor"e);
				}
			}
		}
	}
New to GrepCode? Check out our FAQ X