📄 uiengineimpl.java
字号:
/* UiEngineImpl.java{{IS_NOTE Purpose: Description: History: Thu Jun 9 13:05:28 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.Iterator;import java.util.Map;import java.util.HashMap;import java.util.LinkedHashMap;import java.util.IdentityHashMap;import java.util.Set;import java.util.HashSet;import java.util.List;import java.util.LinkedList;import java.util.Collections;import java.util.Collection;import java.io.Writer;import java.io.IOException;import org.zkoss.lang.D;import org.zkoss.lang.Classes;import org.zkoss.lang.Objects;import org.zkoss.lang.Threads;import org.zkoss.lang.Exceptions;import org.zkoss.lang.Expectable;import org.zkoss.mesg.Messages;import org.zkoss.util.logging.Log;import org.zkoss.zk.mesg.MZk;import org.zkoss.zk.ui.*;import org.zkoss.zk.ui.sys.*;import org.zkoss.zk.ui.event.*;import org.zkoss.zk.ui.metainfo.*;import org.zkoss.zk.ui.ext.AfterCompose;import org.zkoss.zk.ui.ext.Native;import org.zkoss.zk.ui.util.*;import org.zkoss.zk.scripting.*;import org.zkoss.zk.au.*;import org.zkoss.zk.au.out.*;/** * An implementation of {@link UiEngine}. * * @author tomyeh */public class UiEngineImpl implements UiEngine { private static final Log log = Log.lookup(UiEngineImpl.class); /** The Web application this engine belongs to. */ private WebApp _wapp; /** A pool of idle EventProcessingThreadImpl. */ private final List _idles = new LinkedList(); /** A map of suspended processing: * (Desktop desktop, IdentityHashMap(Object mutex, List(EventProcessingThreadImpl)). */ private final Map _suspended = new HashMap(); /** A map of resumed processing * (Desktop desktop, List(EventProcessingThreadImpl)). */ private final Map _resumed = new HashMap(); /** # of suspended event processing threads. */ private int _suspCnt; public UiEngineImpl() { } //-- UiEngine --// public void start(WebApp wapp) { _wapp = wapp; } public void stop(WebApp wapp) { synchronized (_idles) { for (Iterator it = _idles.iterator(); it.hasNext();) ((EventProcessingThreadImpl)it.next()).cease("Stop application"); _idles.clear(); } synchronized (_suspended) { for (Iterator it = _suspended.values().iterator(); it.hasNext();) { final Map map = (Map)it.next(); synchronized (map) { for (Iterator i2 = map.values().iterator(); i2.hasNext();) { final List list = (List)i2.next(); for (Iterator i3 = list.iterator(); i3.hasNext();) ((EventProcessingThreadImpl)i3.next()).cease("Stop application"); } } } _suspended.clear(); } synchronized (_resumed) { for (Iterator it = _resumed.values().iterator(); it.hasNext();) { final List list = (List)it.next(); synchronized (list) { for (Iterator i2 = list.iterator(); i2.hasNext();) ((EventProcessingThreadImpl)i2.next()).cease("Stop application"); } } _resumed.clear(); } } public boolean hasSuspendedThread() { if (!_suspended.isEmpty()) { synchronized (_suspended) { for (Iterator it = _suspended.values().iterator(); it.hasNext();) { final Map map = (Map)it.next(); if (!map.isEmpty()) return true; } } } return false; } public Collection getSuspendedThreads(Desktop desktop) { final Map map; synchronized (_suspended) { map = (Map)_suspended.get(desktop); } return map == null || map.isEmpty() ? Collections.EMPTY_LIST: Collections.synchronizedMap(map).values(); } public boolean ceaseSuspendedThread(Desktop desktop, EventProcessingThread evtthd, String cause) { final Map map; synchronized (_suspended) { map = (Map)_suspended.get(desktop); } if (map == null) return false; boolean found = false; synchronized (map) { for (Iterator it = map.entrySet().iterator(); it.hasNext();) { final Map.Entry me = (Map.Entry)it.next(); final List list = (List)me.getValue(); found = list.remove(evtthd); //found if (found) { if (list.isEmpty()) it.remove(); //(mutex, list) no longer useful break; //DONE } } } if (found) ((EventProcessingThreadImpl)evtthd).cease(cause); return found; } public void desktopDestroyed(Desktop desktop) {// if (log.debugable()) log.debug("destroy "+desktop); final Configuration conf = _wapp.getConfiguration(); final Map map; synchronized (_suspended) { map = (Map)_suspended.remove(desktop); } if (map != null) { synchronized (map) { for (Iterator it = map.values().iterator(); it.hasNext();) { final List list = (List)it.next(); for (Iterator i2 = list.iterator(); i2.hasNext();) { final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl)i2.next(); evtthd.ceaseSilently("Destroy desktop "+desktop); conf.invokeEventThreadResumeAborts( evtthd.getComponent(), evtthd.getEvent()); } } } } final List list; synchronized (_resumed) { list = (List)_resumed.remove(desktop); } if (list != null) { synchronized (list) { for (Iterator it = list.iterator(); it.hasNext();) { final EventProcessingThreadImpl evtthd = (EventProcessingThreadImpl)it.next(); evtthd.ceaseSilently("Destroy desktop "+desktop); conf.invokeEventThreadResumeAborts( evtthd.getComponent(), evtthd.getEvent()); } } } ((DesktopCtrl)desktop).destroy(); } private static UiVisualizer getCurrentVisualizer() { final ExecutionCtrl execCtrl = ExecutionsCtrl.getCurrentCtrl(); if (execCtrl == null) throw new IllegalStateException("Components can be accessed only in event listeners"); return (UiVisualizer)execCtrl.getVisualizer(); } public void pushOwner(Component comp) { getCurrentVisualizer().pushOwner(comp); } public void popOwner() { getCurrentVisualizer().popOwner(); } public void addInvalidate(Page page) { if (page == null) throw new IllegalArgumentException(); getCurrentVisualizer().addInvalidate(page); } public void addInvalidate(Component comp) { if (comp == null) throw new IllegalArgumentException(); getCurrentVisualizer().addInvalidate(comp); } public void addSmartUpdate(Component comp, String attr, String value) { if (comp == null) throw new IllegalArgumentException(); getCurrentVisualizer().addSmartUpdate(comp, attr, value); } public void addResponse(String key, AuResponse response) { getCurrentVisualizer().addResponse(key, response); } public void addMoved(Component comp, Component oldparent, Page oldpg, Page newpg) { if (comp == null) throw new IllegalArgumentException(); getCurrentVisualizer().addMoved(comp, oldparent, oldpg, newpg); } /** Called before changing the component's UUID. * * @param addOnlyMoved if true, it is added only if it was moved * before (see {@link #addMoved}). */ public void addUuidChanged(Component comp, boolean addOnlyMoved) { if (comp == null) throw new IllegalArgumentException(); getCurrentVisualizer().addUuidChanged(comp, addOnlyMoved); } //-- Creating a new page --// public void execNewPage(Execution exec, Richlet richlet, Page page, Writer out) throws IOException { execNewPage0(exec, null, richlet, page, out); } public void execNewPage(Execution exec, PageDefinition pagedef, Page page, Writer out) throws IOException { execNewPage0(exec, pagedef, null, page, out); } /** It assumes exactly one of pagedef and richlet is not null. */ public void execNewPage0(final Execution exec, final PageDefinition pagedef, final Richlet richlet, final Page page, final Writer out) throws IOException { //Update the device type first. If this is the second page and not //belonging to the same device type, an exception is thrown final Desktop desktop = exec.getDesktop(); final LanguageDefinition langdef = //default page pagedef != null ? pagedef.getLanguageDefinition(): richlet != null ? richlet.getLanguageDefinition(): null; if (langdef != null) desktop.setDeviceType(langdef.getDeviceType()); //set and check! //It is possible this method is invoked when processing other exec final Execution oldexec = Executions.getCurrent(); final ExecutionCtrl oldexecCtrl = (ExecutionCtrl)oldexec; final UiVisualizer olduv = oldexecCtrl != null ? (UiVisualizer)oldexecCtrl.getVisualizer(): null; final UiVisualizer uv; if (olduv != null) uv = doReactivate(exec, olduv); else uv = doActivate(exec, null, false); final ExecutionCtrl execCtrl = (ExecutionCtrl)exec; final Page old = execCtrl.getCurrentPage(); final PageDefinition olddef = execCtrl.getCurrentPageDefinition(); execCtrl.setCurrentPage(page); execCtrl.setCurrentPageDefinition(pagedef); final Configuration config = _wapp.getConfiguration(); boolean cleaned = false; try { config.invokeExecutionInits(exec, oldexec); if (olduv != null) { final Component owner = olduv.getOwner(); if (owner != null) { ((PageCtrl)page).setOwner(owner);// if (D.ON && log.finerable()) log.finer("Set owner of "+page+" to "+owner); } } //Cycle 1: Creates all components //Note: //1) stylesheet, tablib are inited in Page's contructor //2) we add variable resolvers before init because //init's zscirpt might depend on it. if (pagedef != null) { pagedef.initXelContext(page); final Initiators inits = Initiators.doInit(pagedef, page); try { //Request 1472813: sendRedirect in init; test: sendRedirectNow.zul pagedef.init(page, !uv.isEverAsyncUpdate() && !uv.isAborting()); final Component[] comps = uv.isAborting() || exec.isVoided() ? null: execCreate( new CreateInfo( ((WebAppCtrl)_wapp).getUiFactory(), exec, page), pagedef, null); inits.doAfterCompose(page, comps); } catch(Throwable ex) { if (!inits.doCatch(ex)) throw UiException.Aide.wrap(ex); } finally { inits.doFinally(); } } else { //FUTURE: a way to allow richlet to set page ID ((PageCtrl)page).init(new PageConfig() { public String getId() {return null;} public String getUuid() {return null;} public String getTitle() {return null;} public String getStyle() {return null;} public String getHeaders() {return null;} public String getRootAttributes() {return null;} public String getContentType() {return null;} public String getDocType() {return null;} public String getFirstLine() {return null;} public Boolean getCacheable() {return null;} }); richlet.service(page); } if (exec.isVoided()) return; //don't generate any output //Cycle 2: process pending events //Unlike execUpdate, execution is aborted here if any exception Event event = nextEvent(uv); do { for (; event != null; event = nextEvent(uv)) process(desktop, event); resumeAll(desktop, uv, null); } while ((event = nextEvent(uv)) != null); //Cycle 2a: Handle aborting reason final AbortingReason abrn = uv.getAbortingReason(); if (abrn != null) abrn.execute(); //always execute even if !isAborting //Cycle 3: Redraw the page (and responses) List responses = uv.getResponses(); if (olduv != null && olduv.addToFirstAsyncUpdate(responses)) responses = null; //A new ZK page might be included by an async update //(example: ZUL's include). //If so, we cannot generate the responses in the page. //Rather, we shall add them to the async update. ((PageCtrl)page).redraw(responses, out); } catch (Throwable ex) { cleaned = true; final List errs = new LinkedList(); errs.add(ex); config.invokeExecutionCleanups(exec, oldexec, errs); //CONSIDER: whether to pass cleanup's error to users if (!errs.isEmpty()) { ex = (Throwable)errs.get(0); if (ex instanceof IOException) throw (IOException)ex; throw UiException.Aide.wrap(ex); } } finally { if (!cleaned) config.invokeExecutionCleanups(exec, oldexec, null); //CONSIDER: whether to pass cleanup's error to users execCtrl.setCurrentPage(old); //restore it execCtrl.setCurrentPageDefinition(olddef); //restore it if (olduv != null) doDereactivate(exec, olduv); else doDeactivate(exec);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -