Thread to handle events.
We need to handle events in a separate thread, because it might
suspend (by calling
), such as waiting
a modal dialog to complete.
| Method from org.zkoss.zk.ui.impl.EventProcessingThreadImpl Detail: |
public void cease(String cause) {
synchronized (_evtmutex) {
_ceased = cause != null ? cause: "";
_evtmutex.notifyAll();
}
if (_suspmutex != null) {
synchronized (_suspmutex) {
_suspmutex.notifyAll();
}
}
}
|
public void ceaseSilently(String cause) {
_silent = true;
cease(cause);
}
|
public boolean doResume() throws InterruptedException {
if (this.equals(Thread.currentThread()))
throw new IllegalStateException("A thread cannot resume itself");
// if (log.finerable()) log.finer("Resume event processing; "+_proc);
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 =
_proc.getDesktop().getWebApp().getConfiguration();
final Component comp = getComponent();
final Event event = getEvent();
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 == null && !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();
}
Resumes this thread and returns only if the execution (being suspended
by #doSuspend ) completes.
It executes in the main thread (i.e., the servlet thread). |
public static void doSuspend(Object mutex) throws InterruptedException {
((EventProcessingThreadImpl)Thread.currentThread()).doSuspend0(mutex);
}
Suspends the current thread and Waits until #doResume
is called.
Note:
|
public final Component getComponent() {
return _proc.getComponent();
}
|
public final Event getEvent() {
return _proc.getEvent();
}
|
public static final int getThreadNumber() {
return _nThd;
}
Returns the number of event threads. |
public static final int getThreadNumberInProcessing() {
return _nBusyThd;
}
Returns the number of event threads in processing. |
public boolean isCeased() {
return _ceased != null;
}
|
public synchronized boolean isIdle() {
return _proc == null;
}
|
public boolean isSuspended() {
return _suspended;
}
|
public void newEventThreadSuspends(Object mutex) {
if (_proc == null)
throw new IllegalStateException();
_evtThdSuspends = _proc.getDesktop().getWebApp().getConfiguration()
.newEventThreadSuspends(getComponent(), getEvent(), mutex);
//it might throw an exception, so process it before updating
//_suspended
}
|
public boolean processEvent(Desktop desktop,
Component comp,
Event event) {
if (Thread.currentThread() instanceof EventProcessingThreadImpl)
throw new IllegalStateException("processEvent cannot be called in an event thread");
if (_ceased != null)
throw new InternalError("The event thread has beeing stopped. Cause: "+_ceased);
if (_proc != null)
throw new InternalError("reentering processEvent not allowed");
_locale = Locales.getCurrent();
_timeZone = TimeZones.getCurrent();
_ex = null;
final EventProcessor proc = new EventProcessor(desktop, comp, event);
//it also check the correctness of desktop/comp/event
final Configuration config = desktop.getWebApp().getConfiguration();
_evtThdInits = config.newEventThreadInits(comp, event);
try {
synchronized (_evtmutex) {
_proc = proc; //Bug 1577842: don't let event thread start (and end) too early
_evtmutex.notify(); //ask the event thread to handle it
if (_ceased == null) {
_evtmutex.wait();
//wait until the event thread to complete or suspended
if (_suspended) {
config.invokeEventThreadSuspends(_evtThdSuspends, comp, event);
_evtThdSuspends = null;
}
}
}
} catch (InterruptedException ex) {
throw new UiException(ex);
} finally {
//_evtThdCleanups is null if //1) no listener;
//2) the event thread is suspended (then handled by doResume).
invokeEventThreadCompletes(config, comp, event);
}
checkError(); //check any error occurs
return isIdle();
}
|
public void run() {
++_nThd;
try {
while (_ceased == null) {
final boolean evtAvail = !isIdle();
if (evtAvail) {
final Configuration config =
_proc.getDesktop().getWebApp().getConfiguration();
boolean cleaned = false;
++_nBusyThd;
Execution exec = null;
try {
// if (log.finerable()) log.finer("Processing event: "+_proc);
Locales.setThreadLocal(_locale);
TimeZones.setThreadLocal(_timeZone);
setup();
exec = getExecution();
if (exec != null) {
((ExecutionCtrl)exec).onActivate();
_acted = true;
}
final boolean b = config.invokeEventThreadInits(
_evtThdInits, getComponent(), getEvent());
_evtThdInits = null;
if (b) process0();
} catch (Throwable ex) {
cleaned = true;
newEventThreadCleanups(config, ex);
} finally {
--_nBusyThd;
if (!cleaned) newEventThreadCleanups(config, _ex);
// if (log.finerable()) log.finer("Real processing is done: "+_proc);
if (exec != null && _acted) //_acted is false if suspended is killed
((ExecutionCtrl)exec).onDeactivate();
cleanup();
Locales.setThreadLocal(_locale = null);
TimeZones.setThreadLocal(_timeZone = null);
}
}
synchronized (_evtmutex) {
if (evtAvail)
_evtmutex.notify();
//wake the main thread OR the resuming thread
if (_ceased == null)
_evtmutex.wait();
//wait the main thread to issue another request
}
}
if (_silent) {
// if (log.debugable()) log.debug("The event processing thread stops");
} else {
System.out.println("The event processing thread stops");
//Don't use log because it might be stopped
}
} catch (InterruptedException ex) {
if (_silent) {
// if (log.debugable())
// log.debug("The event processing thread interrupted: "+Exceptions.getMessage(ex)
// +"\n"+Exceptions.getBriefStackTrace(ex));
} else {
System.out.println("The event processing thread interrupted: "+Exceptions.getMessage(ex));
//Don't use log because it might be stopped
}
} finally {
--_nThd;
}
}
|
public void sendEvent(Component comp,
Event event) throws Exception {
// if (log.finerable()) log.finer("Process sent event: "+event);
if (event == null || comp == null)
throw new IllegalArgumentException("Both comp and event must be specified");
if (!(Thread.currentThread() instanceof EventProcessingThreadImpl))
throw new IllegalStateException("Only callable when processing an event");
final EventProcessor oldproc = _proc;
_proc = new EventProcessor(_proc.getDesktop(), comp, event);
try {
setup();
process0();
} finally {
_proc = oldproc;
setup();
}
}
|
public String toString() {
return "[" +getName()+": "+_proc+", ceased="+_ceased+']";
}
|