📄 desktopimpl.java
字号:
/* DesktopImpl.java{{IS_NOTE Purpose: Description: History: Wed Jun 22 09:50:57 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.Collection;import java.util.Iterator;import java.util.Map;import java.util.HashMap;import java.util.LinkedHashMap;import org.zkoss.lang.D;import org.zkoss.lang.Strings;import org.zkoss.util.CacheMap;import org.zkoss.util.Cache;import org.zkoss.util.logging.Log;import org.zkoss.util.media.Media;import org.zkoss.io.Serializables;import org.zkoss.zk.mesg.MZk;import org.zkoss.zk.ui.WebApp;import org.zkoss.zk.ui.Desktop;import org.zkoss.zk.ui.Page;import org.zkoss.zk.ui.Component;import org.zkoss.zk.ui.Session;import org.zkoss.zk.ui.Sessions;import org.zkoss.zk.ui.Execution;import org.zkoss.zk.ui.Executions;import org.zkoss.zk.ui.UiException;import org.zkoss.zk.ui.ComponentNotFoundException;import org.zkoss.zk.ui.metainfo.LanguageDefinition;import org.zkoss.zk.ui.util.Configuration;import org.zkoss.zk.ui.util.Monitor;import org.zkoss.zk.ui.util.DesktopSerializationListener;import org.zkoss.zk.ui.util.EventInterceptor;import org.zkoss.zk.ui.event.Event;import org.zkoss.zk.ui.event.Events;import org.zkoss.zk.ui.ext.render.DynamicMedia;import org.zkoss.zk.ui.sys.PageCtrl;import org.zkoss.zk.ui.sys.SessionCtrl;import org.zkoss.zk.ui.sys.ExecutionCtrl;import org.zkoss.zk.ui.sys.ComponentCtrl;import org.zkoss.zk.ui.sys.ComponentsCtrl;import org.zkoss.zk.ui.sys.RequestQueue;import org.zkoss.zk.ui.sys.DesktopCache;import org.zkoss.zk.ui.sys.WebAppCtrl;import org.zkoss.zk.ui.sys.DesktopCtrl;import org.zkoss.zk.ui.sys.EventProcessingThread;import org.zkoss.zk.ui.sys.IdGenerator;import org.zkoss.zk.ui.sys.ServerPush;import org.zkoss.zk.ui.impl.EventInterceptors;import org.zkoss.zk.au.out.AuBookmark;import org.zkoss.zk.device.Device;import org.zkoss.zk.device.Devices;import org.zkoss.zk.device.DeviceNotFoundException;/** * The implementation of {@link Desktop}. * * <p>Note: though {@link DesktopImpl} is serializable, it is designed * to work with Web container to enable the serialization of sessions. * It is not suggested to serialize and desrialize it directly since * many fields might be lost. * * <p>On the other hand, it is OK to serialize and deserialize * {@link Component}. * * @author tomyeh */public class DesktopImpl implements Desktop, DesktopCtrl, java.io.Serializable { private static final Log log = Log.lookup(DesktopImpl.class); private static final long serialVersionUID = 20070416L; /** Represents media. It must be distinguishable from component's ID. */ private static final String MEDIA_PREFIX = "med"; private transient WebApp _wapp; private transient Session _sess; private String _id; /** The current directory of this desktop. */ private String _dir; /** The path of the request that causes this desktop to be created. */ private final String _path; /** The URI to access the update engine. */ private final String _updateURI; /** Map(String id, Page page). */ private final Map _pages = new LinkedHashMap(3); /** Map (String uuid, Component comp). */ private transient Map _comps; /** A map of attributes. */ private transient Map _attrs; //don't create it dynamically because PageImp._ip bind it at constructor private transient Execution _exec; /** Next available key. */ private int _nextKey; /** Next available UUID. */ private transient int _nextUuid; /** A special prefix to UUID generated by this desktop. * It is used to avoid ID conflicts with other desktops in the same * session. * Since UUID is long enough plus this prefix, the chance to conlict * is almost impossible. */ private String _uuidPrefix; /** The request queue. */ private transient RequestQueue _rque; private String _bookmark = ""; /** The device type. */ private String _devType = "ajax"; /** The device. */ private transient Device _dev; //it will re-init each time getDevice called /** A map of media (String key, Media content). */ private Cache _meds; /** ID used to identify what is stored in _meds. */ private int _medId; /** The server push controller, or null if not enabled. */ private ServerPush _spush; /** The event interceptors. */ private final EventInterceptors _eis = new EventInterceptors(); private static final int MAX_RESPONSE_SEQUENCE = 1024; /** The response sequence ID. */ private int _respSeqId = MAX_RESPONSE_SEQUENCE - 1; //so the next value will be 0 /** Whether any onPiggyback listener is registered. */ private boolean _piggybackListened; /** * @param updateURI the URI to access the update engine (no expression allowed). * Note: it is NOT encoded yet. * @param path the path that causes this desktop to create. * If null or empty is specified, it means not available. * @param deviceType the device type. * If null or empty is specified, "ajax" is assumed. */ public DesktopImpl(WebApp wapp, String updateURI, String path, String deviceType) { if (updateURI == null || wapp == null) throw new IllegalArgumentException("null"); //Feature 1811241: we create a temporary exec (in WebManager.newDesktop), //so DesktopInit can access Executions.getCurrent final Execution exec = Executions.getCurrent(); if (exec != null) ((ExecutionCtrl)exec).setDesktop(this); _wapp = wapp; _updateURI = updateURI; init(); _sess = Sessions.getCurrent(); //must be the current session String dir = null; if (path != null) { _path = path; final int j = path.lastIndexOf('/'); if (j >= 0) dir = path.substring(0, j + 1); } else { _path = ""; } setCurrentDirectory(dir); if (deviceType != null && deviceType.length() != 0) setDeviceType(deviceType); final Configuration config = _wapp.getConfiguration(); _exec = exec; //fake try { final WebAppCtrl wappc = (WebAppCtrl)_wapp; final DesktopCache dc = wappc.getDesktopCache(_sess); final IdGenerator idgen = wappc.getIdGenerator(); if (idgen != null) _id = idgen.nextDesktopId(this); if (_id == null) _id = Strings.encode( new StringBuffer(12).append("g"), dc.getNextKey()).toString(); updateUuidPrefix(); config.invokeDesktopInits(this); //it might throw exception dc.addDesktop(this); //add to cache after invokeDesktopInits final Monitor monitor = config.getMonitor(); if (monitor != null) { try { monitor.desktopCreated(this); } catch (Throwable ex) { log.error(ex); } } } finally { _exec = null; } } /** Initialization for contructor and de-serialized. */ private void init() { _rque = newRequestQueue(); _comps = new HashMap(41); _attrs = new HashMap(); } /** Updates _uuidPrefix based on _id. */ private void updateUuidPrefix() { _uuidPrefix = _id.substring(1, _id.length() <= 2 ? 2: 3); //the first few chars because of the encode's algorithm } public String getId() { return _id; } /** Creates the request queue. * It is called when the desktop is initialized. * * <p>You may override it to provide your implementation of * {@link RequestQueue} to control how to optimize the AU requests. * * <p>Default: creates an instance from {@link RequestQueueImpl}; * * @since 2.4.0 */ protected RequestQueue newRequestQueue() { return new RequestQueueImpl(); } //-- Desktop --// public String getDeviceType() { return _devType; } public Device getDevice() { if (_dev == null) _dev = Devices.getDevice(_devType); return _dev; } public void setDeviceType(String deviceType) { //Note: we check _comps.isEmpty() only if device type diffs, because //a desktop might have several richlet and each of them will call //this method once if (!_devType.equals(deviceType)) { if (deviceType == null || deviceType.length() == 0) throw new IllegalArgumentException("empty"); if (!Devices.exists(deviceType)) throw new DeviceNotFoundException(deviceType, MZk.NOT_FOUND, deviceType); if (!_comps.isEmpty()) throw new UiException("Unable to change the device type since some components are attached."); _devType = deviceType; _dev = null; ((SessionCtrl)_sess).setDeviceType(_devType); } } public Execution getExecution() { return _exec; } public final Session getSession() { return _sess; } public String getUpdateURI(String pathInfo) { final String uri; if (pathInfo == null || pathInfo.length() == 0) { uri = _updateURI; } else { if (pathInfo.charAt(0) != '/') pathInfo = '/' + pathInfo; uri = _updateURI + pathInfo; } return _exec.encodeURL(uri); } public String getDynamicMediaURI(Component comp, String pathInfo) { if (!(((ComponentCtrl)comp).getExtraCtrl() instanceof DynamicMedia)) throw new UiException(DynamicMedia.class+" not implemented by getExtraCtrl() of "+comp); final StringBuffer sb = new StringBuffer(64) .append("/view/").append(getId()) .append('/').append(comp.getUuid()); if (pathInfo != null && pathInfo.length() > 0) { if (!pathInfo.startsWith("/")) sb.append('/'); sb.append(pathInfo); } return getUpdateURI(sb.toString()); } public String getDownloadMediaURI(Media media, String pathInfo) { if (media == null) throw new IllegalArgumentException("null media"); if (_meds == null) { _meds = new CacheMap(); _meds.setMaxSize(1024 * 16); _meds.setLifetime(6 * 60 * 1000); //6 minutes (CONSIDER: configurable) } String medId = Strings.encode( new StringBuffer(12).append(MEDIA_PREFIX), _medId++).toString(); _meds.put(medId, media); final StringBuffer sb = new StringBuffer(64) .append("/view/").append(getId()) .append('/').append(medId); if (pathInfo != null && pathInfo.length() > 0) { if (!pathInfo.startsWith("/")) sb.append('/'); sb.append(pathInfo); } return getUpdateURI(sb.toString()); } public Media getDownloadMedia(String medId, boolean remove) { return _meds != null ? remove ? (Media)_meds.remove(medId): (Media)_meds.get(medId): null; } public Page getPage(String pageId) { //We allow user to access this method concurrently, so synchronized //is required final Page page = getPageIfAny(pageId); if (page == null) throw new ComponentNotFoundException("Page not found: "+pageId); return page; } public Page getPageIfAny(String pageId) { synchronized (_pages) { return (Page)_pages.get(pageId); } } public boolean hasPage(String pageId) { return _pages.containsKey(pageId); } public Collection getPages() { //No synchronized is required because it cannot be access concurrently return _pages.values(); } public String getBookmark() { return _bookmark; } public void setBookmark(String name) { if (_exec == null) throw new IllegalStateException("Not the current desktop: "+this); if (name.indexOf('#') >= 0 || name.indexOf('?') >= 0) throw new IllegalArgumentException("Illegal character: # ?"); _bookmark = name; ((WebAppCtrl)_wapp).getUiEngine() .addResponse("bookmark", new AuBookmark(name)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -