📄 uiengineimpl.java
字号:
doDeactivate(exec); if (monitor != null) { try { monitor.afterUpdate(desktop); } catch (Throwable ex) { log.error(ex); } } return doneReqIds; } } /** Handles each error. The erros will be queued to the errs list * and processed later by {@link #visualizeErrors}. */ private static final void handleError(Throwable ex, UiVisualizer uv, List errs) { final Throwable err = ex; final Throwable t = Exceptions.findCause(ex, Expectable.class); if (t == null) { log.realCauseBriefly(ex); } else { ex = t; if (log.debugable()) log.debug(Exceptions.getRealCause(ex)); } if (ex instanceof WrongValueException) { WrongValueException wve = (WrongValueException)ex; final Component comp = wve.getComponent(); if (comp != null) { wve = ((ComponentCtrl)comp).onWrongValue(wve); if (wve != null) uv.addResponse("wrongValue", new AuWrongValue(comp, Exceptions.getMessage(wve))); return; } } errs.add(err); } /** Post-process the errors to represent them to the user. * Note: errs must be non-empty */ private final void visualizeErrors(Execution exec, UiVisualizer uv, List errs) { final StringBuffer sb = new StringBuffer(128); for (Iterator it = errs.iterator(); it.hasNext();) { final Throwable t = (Throwable)it.next(); if (sb.length() > 0) sb.append('\n'); sb.append(Exceptions.getMessage(t)); } final String msg = sb.toString(); final Throwable err = (Throwable)errs.get(0); final Desktop desktop = exec.getDesktop(); final Configuration config = desktop.getWebApp().getConfiguration(); final String location = config.getErrorPage(desktop.getDeviceType(), err); if (location != null) { try { exec.setAttribute("javax.servlet.error.message", msg); exec.setAttribute("javax.servlet.error.exception", err); exec.setAttribute("javax.servlet.error.exception_type", err.getClass()); exec.setAttribute("javax.servlet.error.status_code", new Integer(500)); //Future: consider to go thru UiFactory for the richlet //for the error page. //Challenge: how to call UiFactory.isRichlet final Richlet richlet = config.getRichletByPath(location); if (richlet != null) richlet.service(getCurrentPage(exec)); else exec.createComponents(location, null, null); //process pending events //the execution is aborted if an exception is thrown Event event = nextEvent(uv); do { for (; event != null; event = nextEvent(uv)) { try { process(desktop, event); } catch (SuspendNotAllowedException ex) { //ignore it (possible and reasonable) } } resumeAll(desktop, uv, null); } while ((event = nextEvent(uv)) != null); return; //done } catch (Throwable ex) { log.realCause("Unable to generate custom error page, "+location, ex); } } uv.addResponse(null, new AuAlert(msg)); //default handling } private static final Page getCurrentPage(Execution exec) { final Page page = ((ExecutionCtrl)exec).getCurrentPage(); return page != null ? page: (Page)exec.getDesktop().getPages().iterator().next(); } /** Processing the request and stores result into UiVisualizer. * @param everError whether any error ever occured before processing this * request. */ private void process(Execution exec, AuRequest request, boolean everError) {// if (log.finable()) log.finer("Processing request: "+request); final ExecutionCtrl execCtrl = (ExecutionCtrl)exec; execCtrl.setCurrentPage(request.getPage()); request.getCommand().process(request, everError); } /** Processing the event and stores result into UiVisualizer. */ private void process(Desktop desktop, Event event) {// if (log.finable()) log.finer("Processing event: "+event); final Component comp = event.getTarget(); if (comp != null) { processEvent(desktop, comp, event); } else { //since an event might change the page/desktop/component relation, //we copy roots first final List roots = new LinkedList(); for (Iterator it = desktop.getPages().iterator(); it.hasNext();) { roots.addAll(((Page)it.next()).getRoots()); } for (Iterator it = roots.iterator(); it.hasNext();) { final Component c = (Component)it.next(); if (c.getPage() != null) //might be removed, so check first processEvent(desktop, c, event); } } } public void wait(Object mutex) throws InterruptedException, SuspendNotAllowedException { if (mutex == null) throw new IllegalArgumentException("null mutex"); final Thread thd = Thread.currentThread(); if (!(thd instanceof EventProcessingThreadImpl)) throw new UiException("This method can be called only in an event listener, not in paging loading.");// if (log.finerable()) log.finer("Suspend "+thd+" on "+mutex); final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl)thd; evtthd.newEventThreadSuspends(mutex); //it may throw an exception, so process it before updating _suspended final Execution exec = Executions.getCurrent(); final Desktop desktop = exec.getDesktop(); incSuspended(); Map map; synchronized (_suspended) { map = (Map)_suspended.get(desktop); if (map == null) _suspended.put(desktop, map = new IdentityHashMap(3)); //note: we have to use IdentityHashMap because user might //use Integer or so as mutex } synchronized (map) { List list = (List)map.get(mutex); if (list == null) map.put(mutex, list = new LinkedList()); list.add(evtthd); } try { EventProcessingThreadImpl.doSuspend(mutex); } catch (Throwable ex) { //error recover synchronized (map) { final List list = (List)map.get(mutex); if (list != null) { list.remove(evtthd); if (list.isEmpty()) map.remove(mutex); } } if (ex instanceof InterruptedException) throw (InterruptedException)ex; throw UiException.Aide.wrap(ex, "Unable to suspend "+evtthd); } finally { decSuspended(); } } private void incSuspended() { final int v = _wapp.getConfiguration().getMaxSuspendedThreads(); synchronized (this) { if (v >= 0 && _suspCnt >= v) throw new SuspendNotAllowedException(MZk.TOO_MANY_SUSPENDED); ++_suspCnt; } } private void decSuspended() { synchronized (this) { --_suspCnt; } } public void notify(Object mutex) { notify(Executions.getCurrent().getDesktop(), mutex); } public void notify(Desktop desktop, Object mutex) { if (desktop == null || mutex == null) throw new IllegalArgumentException("desktop and mutex cannot be null"); final Map map; synchronized (_suspended) { map = (Map)_suspended.get(desktop); } if (map == null) return; //nothing to notify final EventProcessingThreadImpl evtthd; synchronized (map) { final List list = (List)map.get(mutex); if (list == null) return; //nothing to notify //Note: list is never empty evtthd = (EventProcessingThreadImpl)list.remove(0); if (list.isEmpty()) map.remove(mutex); //clean up } addResumed(desktop, evtthd); } public void notifyAll(Object mutex) { final Execution exec = Executions.getCurrent(); if (exec == null) throw new UiException("resume can be called only in processing a request"); notifyAll(exec.getDesktop(), mutex); } public void notifyAll(Desktop desktop, Object mutex) { if (desktop == null || mutex == null) throw new IllegalArgumentException("desktop and mutex cannot be null"); final Map map; synchronized (_suspended) { map = (Map)_suspended.get(desktop); } if (map == null) return; //nothing to notify final List list; synchronized (map) { list = (List)map.remove(mutex); if (list == null) return; //nothing to notify } for (Iterator it = list.iterator(); it.hasNext();) addResumed(desktop, (EventProcessingThreadImpl)it.next()); } /** Adds to _resumed */ private void addResumed(Desktop desktop, EventProcessingThreadImpl evtthd) {// if (log.finerable()) log.finer("Ready to resume "+evtthd); List list; synchronized (_resumed) { list = (List)_resumed.get(desktop); if (list == null) _resumed.put(desktop, list = new LinkedList()); } synchronized (list) { list.add(evtthd); } } /** Does the real resume. * <p>Note 1: the current thread will wait until the resumed threads, if any, complete * <p>Note 2: {@link #resume} only puts a thread into a resume queue in execution. */ private void resumeAll(Desktop desktop, UiVisualizer uv, List errs) { //We have to loop because a resumed thread might resume others for (;;) { final List list; synchronized (_resumed) { list = (List)_resumed.remove(desktop); if (list == null) return; //nothing to resume; done } synchronized (list) { for (Iterator it = list.iterator(); it.hasNext();) { final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl)it.next(); if (uv.isAborting()) { evtthd.ceaseSilently("Resume aborted"); } else {// if (log.finerable()) log.finer("Resume "+evtthd); try { if (evtthd.doResume()) //wait it complete or suspend again recycleEventThread(evtthd); //completed } catch (Throwable ex) { recycleEventThread(evtthd); if (errs == null) { log.error("Unable to resume "+evtthd, ex); throw UiException.Aide.wrap(ex); } handleError(ex, uv, errs); } } } } } } /** Process an event. */ private void processEvent(Desktop desktop, Component comp, Event event) { final Configuration config = desktop.getWebApp().getConfiguration(); if (config.isEventThreadEnabled()) { EventProcessingThreadImpl evtthd = null; synchronized (_idles) { if (!_idles.isEmpty()) evtthd = (EventProcessingThreadImpl)_idles.remove(0); } if (evtthd == null) evtthd = new EventProcessingThreadImpl(); try { if (evtthd.processEvent(desktop, comp, event)) recycleEventThread(evtthd); } catch (Throwable ex) { recycleEventThread(evtthd); throw UiException.Aide.wrap(ex); } } else { //event thread disabled //Note: we don't need to call proc.setup() and cleanup(), //since they are in the same thread EventProcessor proc = new EventProcessor(desktop, comp, event); //Note: it also checks the correctness List cleanups = null, errs = null; try { final List inits = config.newEventThreadInits(comp, event); EventProcessor.inEventListener(true); if (config.invokeEventThreadInits(inits, comp, event)) //false measn ignore proc.process(); } catch (Throwable ex) { errs = new LinkedList(); errs.add(ex); cleanups = config.newEventThreadCleanups(comp, event, errs); throw UiException.Aide.wrap(ex); } finally { EventProcessor.inEventListener(false); if (errs == null) //not cleanup yet cleanups = config.newEventThreadCleanups(comp, event, null); config.invokeEventThreadCompletes(cleanups, comp, event, errs); } } } private void recycleEventThread(EventProcessingThreadImpl evtthd) { if (!evtthd.isCeased()) { if (evtthd.isIdle()) { final int max = _wapp.getConfiguration().getMaxSpareThreads(); synchronized (_idles) { if (max < 0 || _idles.size() < max) { _idles.add(evtthd); //return to pool return; //done } } } evtthd.ceaseSilently("Recycled"); } } //-- Generate output from a response --// /** Output the next response sequence ID. */ private static void responseSequenceId(Desktop desktop, Writer out) throws IOException { out.write("\n<sid>"); out.write(Integer.toString( ((DesktopCtrl)desktop).getResponseSequence(true))); out.write("</sid>"); } public void response(AuResponse response, Writer out) throws IOException { out.write("\n<r><c>"); out.write(response.getCommand()); out.write("</c>"); final String[] data = response.getData(); if (data != null) { for (int j = 0; j < data.length; ++j) { out.write("\n<d>"); encodeXML(data[j], out); out.write("</d>"); } } out.write("\n</r>"); } public void response(List responses, Writer out) throws IOException { for (Iterator it = responses.iterator(); it.hasNext();) response((AuResponse)it.next(), out); } private static void encodeXML(String data, Writer out) throws IOException { if (data == null || data.length() == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -