Save This Page
Home » zk-src-3.5.1 » org » zkoss » zk » ui » impl » [javadoc | source]
    1   /* EventProcessor.java
    2   
    3   {{IS_NOTE
    4   	Purpose:
    5   		
    6   	Description:
    7   		
    8   	History:
    9   		Tue May  8 14:10:54     2007, Created by tomyeh
   10   }}IS_NOTE
   11   
   12   Copyright (C) 2007 Potix Corporation. All Rights Reserved.
   13   
   14   {{IS_RIGHT
   15   	This program is distributed under GPL Version 2.0 in the hope that
   16   	it will be useful, but WITHOUT ANY WARRANTY.
   17   }}IS_RIGHT
   18   */
   19   package org.zkoss.zk.ui.impl;
   20   
   21   import java.util.Set;
   22   import java.util.HashSet;
   23   import java.util.HashMap;
   24   import java.util.Iterator;
   25   import java.lang.reflect.Method;
   26   
   27   import org.zkoss.util.logging.Log;
   28   
   29   import org.zkoss.zk.ui.Execution;
   30   import org.zkoss.zk.ui.Desktop;
   31   import org.zkoss.zk.ui.Page;
   32   import org.zkoss.zk.ui.Component;
   33   import org.zkoss.zk.ui.event.Event;
   34   import org.zkoss.zk.ui.event.EventListener;
   35   import org.zkoss.zk.ui.event.Express;
   36   import org.zkoss.zk.ui.sys.SessionsCtrl;
   37   import org.zkoss.zk.ui.sys.ExecutionCtrl;
   38   import org.zkoss.zk.ui.sys.ExecutionsCtrl;
   39   import org.zkoss.zk.ui.sys.DesktopCtrl;
   40   import org.zkoss.zk.ui.sys.ComponentCtrl;
   41   import org.zkoss.zk.ui.sys.ComponentsCtrl;
   42   import org.zkoss.zk.ui.sys.EventProcessingThread;
   43   import org.zkoss.zk.ui.metainfo.ZScript;
   44   import org.zkoss.zk.scripting.Namespace;
   45   import org.zkoss.zk.scripting.Namespaces;
   46   
   47   /**
   48    * A utility class that simplify the implementation of
   49    * {@link org.zkoss.zk.ui.sys.EventProcessingThread}.
   50    *
   51    * @author tomyeh
   52    */
   53   public class EventProcessor {
   54   //	private static final Log log = Log.lookup(EventProcessor.class);
   55   
   56   	/** The desktop that the component belongs to. */
   57   	private final Desktop _desktop;
   58   	/** Part of the command: component to handle the event. */
   59   	private final Component _comp;
   60   	/** Part of the command: event to process. */
   61   	private Event _event;
   62   	/** Whether it is in processing an event.
   63   	 * It is used only the event processing thread is disabled.
   64   	 */
   65   	private static ThreadLocal _inEvt;
   66   
   67   	/** Returns whether the current thread is an event listener.
   68   	 */
   69   	public static final boolean inEventListener() {
   70   		return (Thread.currentThread() instanceof EventProcessingThread)
   71   			|| (_inEvt != null && _inEvt.get() != null); //used if event thread is disabled
   72   	}
   73   	/** Sets whether the current thread is an event listener.
   74   	 * It needs to be called only if the event processing thread is
   75   	 * disabled.
   76   	 *
   77   	 * <p>It is used only internally.
   78   	 */
   79   	/*package*/ static final void inEventListener(boolean in) {
   80   		if (in) {
   81   			if (_inEvt == null)
   82   				_inEvt = new ThreadLocal();
   83   			_inEvt.set(Boolean.TRUE);
   84   		} else {
   85   			if (_inEvt != null)
   86   				_inEvt.set(null);
   87   		}
   88   	}
   89   
   90   	/**
   91   	 * @param comp the component. Its desktop must be either null
   92   	 * or the same as desktop.
   93   	 */
   94   	public EventProcessor(Desktop desktop, Component comp, Event event) {
   95   		if (desktop == null || comp == null || event == null)
   96   			throw new IllegalArgumentException("null");
   97   
   98   		final Desktop dt = comp.getDesktop();
   99   		if (dt != null && desktop != dt)
  100   			throw new IllegalStateException("Process events for another desktop? "+comp);
  101   
  102   		_desktop = desktop;
  103   		_comp = comp;
  104   		_event = event;
  105   	}
  106   
  107   	/** Returns the desktop.
  108   	 */
  109   	public final Desktop getDesktop() {
  110   		return _desktop;
  111   	}
  112   	/** Returns the event.
  113   	 */
  114   	public final Event getEvent() {
  115   		return _event;
  116   	}
  117   	/** Returns the component.
  118   	 */
  119   	public final Component getComponent() {
  120   		return _comp;
  121   	}
  122   
  123   	/** Process the event.
  124   	 * Note: it doesn't invoke EventThreadInit and EventThreadCleanup.
  125   	 *
  126   	 * <p>This method is to implement
  127   	 * {@link org.zkoss.zk.ui.sys.EventProcessingThread}.
  128   	 * See also {@link org.zkoss.zk.ui.util.Configuration#isEventThreadEnabled}.
  129   	 */
  130   	public void process() throws Exception {
  131   		//Bug 1506712: event listeners might be zscript, so we have to
  132   		//keep built-in variables as long as possible
  133   		final HashMap backup = new HashMap();
  134   		final Namespace ns = Namespaces.beforeInterpret(backup, _comp, true);
  135   			//we have to push since process0 might invoke methods from zscript class
  136   		try {
  137   			Namespaces.backupVariable(backup, ns, "event");
  138   			ns.setVariable("event", _event, true);
  139   
  140   			_event = ((DesktopCtrl)_desktop).beforeProcessEvent(_event);
  141   			if (_event != null) {
  142   				ns.setVariable("event", _event, true); //_event might change
  143   				process0(ns);
  144   				((DesktopCtrl)_desktop).afterProcessEvent(_event);
  145   			}
  146   		} finally {
  147   			Namespaces.afterInterpret(backup, ns, true);
  148   		}
  149   	}
  150   	private void process0(Namespace ns) throws Exception {
  151   		final Page page = getPage();
  152   		final String evtnm = _event.getName();
  153   
  154   		final Set listenerCalled = new HashSet();
  155   		boolean retry = false;
  156   		for (Iterator it = _comp.getListenerIterator(evtnm);;) {
  157   			final EventListener el = nextListener(it);
  158   			if (el == null) {
  159   				break; //done
  160   
  161   			} else if (el == RETRY) {
  162   				retry = true;
  163   				it = _comp.getListenerIterator(evtnm);
  164   
  165   			} else if ((el instanceof Express)
  166   			&& (!retry || !listenerCalled.contains(el))) {
  167   				listenerCalled.add(el);
  168   
  169   				el.onEvent(_event);
  170   				if (!_event.isPropagatable())
  171   					return; //done
  172   			}
  173   		}
  174   
  175   		final ZScript zscript = ((ComponentCtrl)_comp).getEventHandler(evtnm);
  176   		if (zscript != null) {
  177   			page.interpret(
  178   				zscript.getLanguage(), zscript.getContent(page, _comp), ns);
  179   			if (!_event.isPropagatable())
  180   				return; //done
  181   		}
  182   
  183   		retry = false;
  184   		for (Iterator it = _comp.getListenerIterator(evtnm);;) {
  185   			final EventListener el = nextListener(it);
  186   			if (el == null) {
  187   				break; //done
  188   
  189   			} else if (el == RETRY) {
  190   				retry = true;
  191   				it = _comp.getListenerIterator(evtnm);
  192   
  193   			} else if (!(el instanceof Express)
  194   			&& (!retry || !listenerCalled.contains(el))) {
  195   				listenerCalled.add(el);
  196   
  197   				el.onEvent(_event);
  198   				if (!_event.isPropagatable())
  199   					return; //done
  200   			}
  201   		}
  202   
  203   		final Method mtd =
  204   			ComponentsCtrl.getEventMethod(_comp.getClass(), evtnm);
  205   		if (mtd != null) {
  206   //			if (log.finerable()) log.finer("Method for event="+evtnm+" comp="+_comp+" method="+mtd);
  207   
  208   			if (mtd.getParameterTypes().length == 0)
  209   				mtd.invoke(_comp, null);
  210   			else
  211   				mtd.invoke(_comp, new Object[] {_event});
  212   			if (!_event.isPropagatable())
  213   				return; //done
  214   		}
  215   
  216   		retry = false;
  217   		listenerCalled.clear();
  218   		for (Iterator it = page.getListenerIterator(evtnm);;) {
  219   			final EventListener el = nextListener(it);
  220   			if (el == null) {
  221   				break; //done
  222   
  223   			} else if (el == RETRY) {
  224   				retry = true;
  225   				it = page.getListenerIterator(evtnm);
  226   
  227   			} else if (!retry || !listenerCalled.contains(el)) {
  228   				listenerCalled.add(el);
  229   
  230   				el.onEvent(_event);
  231   				if (!_event.isPropagatable())
  232   					return; //done
  233   			}
  234   		}
  235   	}
  236   	private static EventListener nextListener(Iterator it) {
  237   		try {
  238   			return it.hasNext() ? (EventListener)it.next(): null;
  239   		} catch (java.util.ConcurrentModificationException ex) {
  240   			return RETRY;
  241   		}
  242   	}
  243   	/** Represents {@link #nextListener} encounter co-modification error. */
  244   	private static final EventListener RETRY = new EventListener() {
  245   		public void onEvent(Event event) {
  246   		}
  247   	};
  248   
  249   	/** Setup this processor before processing the event by calling
  250   	 * {@link #process}.
  251   	 *
  252   	 * <p>Note: it doesn't invoke {@link ExecutionCtrl#onActivate}
  253   	 */
  254   	public void setup() {
  255   		SessionsCtrl.setCurrent(_desktop.getSession());
  256   		final Execution exec = _desktop.getExecution();
  257   		ExecutionsCtrl.setCurrent(exec);
  258   		((ExecutionCtrl)exec).setCurrentPage(getPage());
  259   	}
  260   	/** Cleanup this process after processing the event by calling
  261   	 * {@link #process}.
  262   	 *
  263   	 * <p>Note: Don't call this method if the event process executes
  264   	 * in the same thread.
  265   	 */
  266   	public void cleanup() {
  267   		ExecutionsCtrl.setCurrent(null);
  268   		SessionsCtrl.setCurrent(null);
  269   	}
  270   
  271   	private Page getPage() {
  272   		final Page page = _comp.getPage();
  273   		if (page != null)
  274   			return page;
  275   
  276   		final Iterator it = _desktop.getPages().iterator();
  277   		return it.hasNext() ? (Page)it.next(): null;
  278   	}
  279   
  280   	//Object//
  281   	public String toString() {
  282   		return "[comp: "+_comp+", event: "+_event+']';
  283   	}
  284   }

Save This Page
Home » zk-src-3.5.1 » org » zkoss » zk » ui » impl » [javadoc | source]