Package com.dmurph.mvc

Source Code of com.dmurph.mvc.MVC

/**
* 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;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;

import com.dmurph.mvc.monitor.EventMonitor;
import com.dmurph.mvc.monitor.WarningMonitor;
import com.dmurph.mvc.tracking.ICustomTracker;
import com.dmurph.mvc.tracking.ITrackable;
import com.dmurph.tracking.JGoogleAnalyticsTracker;


/**
* This stores all the listener information, dispatches events
* to the corresponding listeners.  To dispatch events use
* {@link MVCEvent#dispatch()}.</br>
* </br> 
* Also, look at {@link #splitOff()}.  To set up Google analytics, call {@link #setTracker(JGoogleAnalyticsTracker)},
* or implement {@link ICustomTracker} in your events to be tracked, and then any event that implements {@link ITrackable}
* will be tracked.  If {@link ITrackable#getTrackingCategory()} or {@link ITrackable#getTrackingAction()}
* returns <code>null</code>, then it will be ignored.
* @author Daniel Murphy
*/
public class MVC extends Thread{
 
  private static final ThreadGroup mvcThreadGroup = new ThreadGroup("MVC Thread Group");
  private static final ArrayList<MVC> mvcThreads = new ArrayList<MVC>();
  private volatile static MVC mainThread = new MVC();
  private IGlobalEventMonitor monitor;
 
  private final HashMap<String, LinkedList<IEventListener>> listeners = new HashMap<String, LinkedList<IEventListener>>();
  private final Queue<MVCEvent> eventQueue = new LinkedList<MVCEvent>();
  private volatile boolean running = false;
  private volatile JGoogleAnalyticsTracker tracker = null;
 
  private volatile static int threadCounter = 0;
 
  private MVC() {
    super(mvcThreadGroup, "MVC Thread #"+(threadCounter));
    threadCounter += 1;
    System.out.println("Next thread counter: "+threadCounter);
    mvcThreads.add(this);
    monitor = new WarningMonitor();
  }

  public static void setTracker(JGoogleAnalyticsTracker tracker) {
    mainThread.tracker = tracker;
  }

  public static JGoogleAnalyticsTracker getTracker() {
    return mainThread.tracker;
  }

  /**
   * Adds a listener for the given event key.  If the listener is already listening
   * to that key, then nothing is done.
   *
   * @param argKey
   * @param argListener
   */
  public synchronized static void addEventListener( String argKey, IEventListener argListener) {

    if (mainThread.listeners.containsKey(argKey)) {
      // return if we're already listening
      if( isEventListener( argKey, argListener)){
        return;
      }
      mainThread.listeners.get(argKey).addFirst(argListener);
    }
    else {
      final LinkedList<IEventListener> stack = new LinkedList<IEventListener>();
      stack.addFirst(argListener);
      mainThread.listeners.put(argKey, stack);
    }
  }
 
  /**
   * Checks to see if the listener is listening to the given key.
   * @param argKey
   * @param argListener
   * @return
   */
  public synchronized static boolean isEventListener( String argKey, IEventListener argListener) {
    if(!mainThread.listeners.containsKey( argKey)){
      return false;
    }
   
    LinkedList<IEventListener> stack = mainThread.listeners.get( argKey);
    return stack.contains( argListener);
  }

  /**
   * gets the listeners for the given event key.
   *
   * @param argKey
   * @return
   */
  public synchronized static LinkedList<IEventListener> getListeners( String argKey) {
    if (mainThread.listeners.containsKey(argKey)) {
      return mainThread.listeners.get(argKey);
    }
    else {
      LinkedList<IEventListener> stack = new LinkedList<IEventListener>();
      mainThread.listeners.put(argKey, stack);
      return stack;
    }
  }

  /**
   * removes a listener from the given key.
   *
   * @param argKey
   * @param argListener
   * @return true if the listener was removed, and false if it wasn't there to
   *         begin with
   */
  public static synchronized boolean removeEventListener( String argKey, IEventListener argListener) {
    if (mainThread.listeners.containsKey(argKey)) {
      LinkedList<IEventListener> stack = mainThread.listeners.get(argKey);
      return stack.remove(argListener);
    }
    return false;
  }
 
  /**
   * Adds an event to the dispatch queue for the MVC thread.
   * Used by {@link MVCEvent#dispatch()}.
   * @param argEvent
   */
  protected synchronized static void dispatchEvent( MVCEvent argEvent) {
    if (mainThread.listeners.containsKey(argEvent.key)) {
      mainThread.eventQueue.add( argEvent  );
      if(!mainThread.running){
        if(mainThread.getState() == State.NEW){
          mainThread.start();
        }
      }
    }else{
      if(mainThread.monitor != null){
        mainThread.monitor.noListeners(argEvent);
      }
    }
  }
 
  /**
   * 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
   * @throws IncorrectThreadException if the MVC thread calling this is not the main thread, e.g.
   *                  it has already split off.
   */
  public synchronized static void splitOff() throws IllegalThreadException, IncorrectThreadException{
    if( Thread.currentThread() instanceof MVC){
      MVC thread = (MVC) Thread.currentThread();
      if(thread == mainThread){
        MVC old = mainThread;
        mainThread = new MVC();
       
        for(MVCEvent event : old.eventQueue){
          mainThread.eventQueue.add(event);
        }
        old.eventQueue.clear();
       
        for(String key : old.listeners.keySet()){
          mainThread.listeners.put(key, old.listeners.get(key));
        }
        old.listeners.clear();
        old.running = false;
        mainThread.tracker = old.tracker;
        mainThread.monitor = old.monitor;
        old.tracker = null;
       
        mainThread.start();
      }else{
        throw new IncorrectThreadException();
      }
    }else{
      throw new IllegalThreadException();
    }
  }
 
  /**
   * Sets the global event monitor, which is called before and after each event is
   * dispatched.
   * @param argMonitor
   * @see IGlobalEventMonitor
   */
  public synchronized static void setGlobalEventMonitor(IGlobalEventMonitor argMonitor){
    mainThread.monitor = argMonitor;
  }
 
  /**
   * Gets the global event monitor.  Default is {@link WarningMonitor}.
   * @return
   * @see IGlobalEventMonitor
   */
  public synchronized static IGlobalEventMonitor getGlobalEventMonitor(){
    return mainThread.monitor;
  }
 
  private volatile static EventMonitor guiMonitor = null;
 
  /**
   * Convenience method to construct and show an {@link EventMonitor}.  To
   * have more control on how the {@link EventMonitor} is configured,
   * you can just create it yourself and use {@link #setGlobalEventMonitor(IGlobalEventMonitor)}
   * to have it be the global event monitor.
   * @return the {@link EventMonitor}.
   */
  public synchronized static EventMonitor showEventMonitor(){
    if(guiMonitor == null){
      guiMonitor = new EventMonitor(mainThread.monitor);
      setGlobalEventMonitor(guiMonitor);
    }
    guiMonitor.setVisible(true);
    return guiMonitor;
  }
 
  /**
   * Hides the event monitor, if you had used {@link #showEventMonitor()}.
   */
  public synchronized static void hideEventMonitor(){
    if(guiMonitor != null){
      guiMonitor.setVisible(false);
    }
  }
 
  /**
   * Stops the dispatch thread, dispatching any remaining events
   * before cleanly returning.  Thread automatically gets started
   * when new events are dispatched
   */
  public synchronized static void stopDispatchThread(){
    mainThread.running = false;
  }
 
  /**
   * Manually starts the dispatch thread.
   */
  public synchronized static void startDispatchThread(){
    if(mainThread.running){
      return;
    }
    mainThread.start();
  }
 
  public void stopGracefully(){
    running = false;
  }
 
  @Override
  public void run(){
    running = true;
    while(running){
      if(eventQueue.isEmpty()){
        try {
          Thread.sleep(100);
        } catch ( InterruptedException e) {}
      }else {
        MVCEvent event = eventQueue.poll();
        internalDispatchEvent( event);
      }
    }
    mvcThreads.remove(this);
  }
 
  private synchronized void internalDispatchEvent(MVCEvent argEvent){
    LinkedList<IEventListener> stack = listeners.get(argEvent.key);
   
    if(monitor != null){
      monitor.beforeDispatch(argEvent);
    }
    if(argEvent instanceof ITrackable){
      ITrackable event = (ITrackable) argEvent;
      if(event.getTrackingCategory() != null && event.getTrackingAction() != null){
        if(event instanceof ICustomTracker){
          ((ICustomTracker) event).getCustomTracker().trackEvent(event.getTrackingCategory(),
                                       event.getTrackingAction(),
                                       event.getTrackingLabel(),
                                       event.getTrackingValue());
        }
        else if(tracker != null){
          tracker.trackEvent(event.getTrackingCategory(),
                     event.getTrackingAction(),
                     event.getTrackingLabel(),
                     event.getTrackingValue());
        }
      }
    }
    Iterator<IEventListener> it = stack.iterator();
    while(it.hasNext() && argEvent.isPropagating()){
      try{
        it.next().eventReceived( argEvent);       
      }catch(Exception e){
        monitor.exceptionThrown(argEvent, e);
      }
    }
    if(monitor != null){
      monitor.afterDispatch(argEvent);
    }
  }
}
TOP

Related Classes of com.dmurph.mvc.MVC

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.