📄 eventprocessingthread.java
字号:
/* EventProcessingThread.java{{IS_NOTE Purpose: Description: History: Wed Jul 20 11:24:00 2005, Created by tomyeh}}IS_NOTECopyright (C) 2005 Potix Corporation. All Rights Reserved.{{IS_RIGHT This program is distributed under GPL Version 2.0 in the hope that it will be useful, but WITHOUT ANY WARRANTY.}}IS_RIGHT*/package org.zkoss.zk.ui.impl;import java.util.List;import java.util.LinkedList;import java.util.Iterator;import java.util.Locale;import java.util.TimeZone;import java.lang.reflect.Method;import org.zkoss.lang.D;import org.zkoss.lang.Threads;import org.zkoss.lang.Exceptions;import org.zkoss.util.Locales;import org.zkoss.util.TimeZones;import org.zkoss.util.logging.Log;import org.zkoss.zk.ui.Execution;import org.zkoss.zk.ui.Desktop;import org.zkoss.zk.ui.Page;import org.zkoss.zk.ui.Component;import org.zkoss.zk.ui.UiException;import org.zkoss.zk.ui.event.Event;import org.zkoss.zk.ui.event.EventListener;import org.zkoss.zk.ui.event.Express;import org.zkoss.zk.ui.util.Namespace;import org.zkoss.zk.ui.util.Namespaces;import org.zkoss.zk.ui.util.Configuration;import org.zkoss.zk.ui.sys.SessionsCtrl;import org.zkoss.zk.ui.sys.ExecutionCtrl;import org.zkoss.zk.ui.sys.ExecutionsCtrl;import org.zkoss.zk.ui.sys.ComponentCtrl;/** Thread to handle events. * We need to handle events in a separate thread, because it might * suspend (by calling {@link org.zkoss.zk.ui.sys.UiEngine#wait}), such as waiting * a modal dialog to complete. * * @author tomyeh */public class EventProcessingThread extends Thread { private static final Log log = Log.lookup(EventProcessingThread.class); /** Part of the command: component to handle the event. */ private Component _comp; /** Part of the command: event to process. */ private Event _event; /** The desktop that the component belongs to. */ private Desktop _desktop; /** Part of the command: locale. */ private Locale _locale; /** Part of the command: time zone. */ private TimeZone _timeZone; /** Part of the result: a list of EventThreadInit instances. */ private List _evtThdInits; /** Part of the result: a list of EventThreadResume instances. */ private List _evtThdResumes; /** Part of the result: a list of EventThreadCleanup instances. */ private List _evtThdCleanups; /** Result of the result. */ private Throwable _ex; private static int _nThd, _nBusyThd; /** The mutex use to notify an event is ready for processing, or * has been processed. */ private final Object _evtmutex = new Object(); /** The mutex use to suspend an event processing. */ private Object _suspmutex; private boolean _ceased; /** Whether not to show message when stopping. */ private boolean _silent; /** Whether it is suspended. */ private transient boolean _suspended; public EventProcessingThread() { if (log.debugable()) log.debug("Starting an event processing thread"); Threads.setDaemon(this, true); start(); } /** Returns the number of event threads. */ public static final int getThreadNumber() { return _nThd; } /** Returns the number of event threads in processing. */ public static final int getThreadNumberInProcessing() { return _nBusyThd; } /** Returns whether it is ceased. */ public boolean isCeased() { return _ceased; } /** Returns whether this thread is idle, i.e., not processing any event. */ synchronized public boolean isIdle() { return _event == null; } /** Returns the event being processed by this thread, or null if idle. */ public final Event getEvent() { return _event; } /** Returns the component being processed by this thread, or null if idle. */ public final Component getComponent() { return _comp; } /** Stops the thread. Called only by {@link org.zkoss.zk.ui.sys.UiEngine} * when it is stopping. */ public void cease() { synchronized (_evtmutex) { _ceased = true; _evtmutex.notifyAll(); } if (_suspmutex != null) { synchronized (_suspmutex) { _suspmutex.notifyAll(); } } } /** Stops the thread silently. Called by {@link org.zkoss.zk.ui.sys.UiEngine} * to stop abnormal * page. */ public void ceaseSilently() { _silent = true; cease(); } /** Suspends the current thread and Waits until {@link #doResume} * is called. * * <p>Note: * <ul> * <li>It is used internally only for implementing {@link org.zkoss.zk.ui.sys.UiEngine} * <li>Caller must invoke {@link Configuration#invokeEventThreadSuspends} * before calling this method. (Reason: UiEngine might have to store some info * after {!link Configuration#invokeEventThreadSuspends} is called. * <li>The current thread must be {@link EventProcessingThread}. * <li>It is a static method. * </ul> */ public static void doSuspend(Object mutex) throws InterruptedException { ((EventProcessingThread)Thread.currentThread()).doSuspend0(mutex); } private void doSuspend0(Object mutex) throws InterruptedException { if (log.finerable()) log.finer("Suspend event processing; "+_event); if (mutex == null) throw new IllegalArgumentException("null mutex"); if (isIdle()) throw new InternalError("Called without processing event?"); if (_suspmutex != null) throw new InternalError("Suspend twice?"); //Spec: locking mutex is optional for app developers //so we have to lock it first _suspmutex = mutex; try { synchronized (_suspmutex) { _suspended = true; //let the main thread continue synchronized (_evtmutex) { _evtmutex.notify(); } if (!_ceased) _suspmutex.wait(); } } finally { _suspmutex = null; _suspended = false; //just in case (such as _ceased) } if (_ceased) throw new InterruptedException("Ceased"); setup(); if (_evtThdResumes != null && !_evtThdResumes.isEmpty()) { _desktop.getWebApp().getConfiguration() .invokeEventThreadResumes(_evtThdResumes, _comp, _event, null); //FUTURE: how to propogate errors to the client _evtThdResumes = null; } } /** Resumes this thread and returns only if the execution (being suspended * by {@link #doSuspend}) completes. * * <p>It executes in the main thread (i.e., the servlet thread). * * @return whether the event has been processed completely or just be suspended */ public boolean doResume() throws InterruptedException { if (this.equals(Thread.currentThread())) throw new IllegalStateException("A thread cannot resume itself"); if (D.ON && log.finerable()) log.finer("Resume event processing; "+_event); if (isIdle()) throw new InternalError("Called without processing event?"); if (_suspmutex == null) throw new InternalError("Resume non-suspended thread?"); //Copy first since event thread clean up them, when completed final Configuration config = _desktop.getWebApp().getConfiguration(); final Component comp = _comp; final Event event = _event; try { _evtThdResumes = config.newEventThreadResumes(comp, event); //Spec: locking mutex is optional for app developers //so we have to lock it first synchronized (_suspmutex) { _suspended = false; _suspmutex.notify(); //wake the suspended event thread } //wait until the event thread completes or suspends again //If complete: isIdle() is true //If suspend again: _suspended is true synchronized (_evtmutex) { if (!_ceased && !isIdle() && !_suspended) _evtmutex.wait(); } } finally { //_evtThdCleanups is null if //1) no listener; //2) the event thread is suspended again (handled by another doResume) invokeEventThreadCompletes(config, comp, event); } checkError(); return isIdle(); } /** Ask this event thread to process the specified event. * * <p>Used internally to implement {@link org.zkoss.zk.ui.sys.UiEngine}.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -