org.zkoss.zk.ui.sys.UiEngine Maven / Gradle / Ivy
/* UiEngine.java
Purpose:
Description:
History:
Thu Jun 9 12:58:20 2005, Created by tomyeh
Copyright (C) 2005 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zk.ui.sys;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.zkoss.json.JSONArray;
import org.zkoss.xel.VariableResolver;
import org.zkoss.zk.au.AuRequest;
import org.zkoss.zk.au.AuResponse;
import org.zkoss.zk.au.AuWriter;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.Richlet;
import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.WebApp;
import org.zkoss.zk.ui.ext.Native;
import org.zkoss.zk.ui.metainfo.NodeInfo;
import org.zkoss.zk.ui.metainfo.PageDefinition;
/**
* UI engine is responsible to process requests from the client,
* sends the response back to the client with the assistance of
* {@link ExecutionCtrl}.
*
* {@link ExecutionCtrl} encapsulates protocol-dependent codes,
* such that UiEngine works independent of any protocol (such as HTTP).
*
*
Note: each application (a ServletContext in HTTP) has its own
* UI Engine (Singleton per app).
*
* @author tomyeh
*/
public interface UiEngine {
/** Starts the engine.
*/
public void start(WebApp wapp);
/** Stops the engine.
* Called only if the server is about to stop.
*/
public void stop(WebApp wapp);
/** Called when a desktop is being removed.
*
Application developers don't need to remove pages and desktops.
* They are removed and cleaned up automatically.
*/
public void desktopDestroyed(Desktop desktop);
//-- update (draw) --//
/** Called before a component redraws itself if the component might
* include another page.
*
*
If a new page is created, the specified component will become
* the owner of the new page.
*
*
It must reset the owner in the finally clause.
*
old = ue.setOwner(this);
*try{
* ...
*} finally {
* ue.setOwner(old);
*}
* Since 5.0.6, the owner must implement {@link org.zkoss.zk.ui.ext.Includer}.
* @return the previous owner
* @since 5.0.0
*/
public Component setOwner(Component comp);
/** Returns if this component needs to be redrawn.
*
Note:
*
* - It always returns true if the current execution is not an
* asynchronous update.
* - If its parent is invalidated, this component will be redrawn
* too, but this method returns false since {@link #addInvalidate(Component)}
* was not called against this component.
*
* @since 3.0.5
*/
public boolean isInvalidated(Component comp);
/** Invalidates the page to cause all of its components to redraw.
*/
public void addInvalidate(Page page);
/** Invalidates a component to cause redrawing.
* Called when {@link Component#invalidate} is called.
*/
public void addInvalidate(Component comp);
/** Smart-updates a property of the peer widget.
*
* @param append whether to append the updates of properties with the same
* name. If false, only the last value of the same property will be sent
* to the client.
* @since 5.0.2
*/
public void addSmartUpdate(Component comp, String attr, Object value, boolean append);
/**
* Adds a smart update that will be executed at the given priority.
* The higher priority, the earlier the update is executed.
* If {@link #addSmartUpdate(Component, String, Object, boolean)}
* is invoked, the priority is assumed to 0.
*
* If the priority is the same, the update is executed in the order
* of first-in-first out. You rarely need to control the sequence, unless
* the update is used to instantiate client-side widgets that other
* updates might depend on. In this case, it is suggested to
* specify the priority as 10000 (and not to use priority higher than
* 10000 for other situation).
* @since 6.0.0
*/
public void addSmartUpdate(Component comp, String attr, Object value, int priority);
/**
* Clears all existing smart updates that belong to the given component.
* @since 10.0.0
*/
public void clearSmartUpdate(Component comp);
/** Adds a response directly by using {@link AuResponse#getOverrideKey}
* as the override key.
* In other words, it is the same as addResponse(resposne.getOverrideKey(), response)
*
*
If the response is component-dependent, {@link AuResponse#getDepends}
* must return a component. And, if the component is removed, the response
* is removed, too.
* @since 5.0.2
* @see #addResponse(String, AuResponse)
*/
public void addResponse(AuResponse response);
/** Adds a response which will be sent to client at the end
* of the execution.
* Called by {@link org.zkoss.zk.ui.AbstractComponent#response}.
*
*
Note: {@link Execution#addAuResponse} is a shortcut to this method,
* and it is used by application developers.
*
*
If {@link AuResponse#getDepends} is not null, the response
* depends on the returned component. In other words, the response
* is removed if the component is removed.
* If it is null, the response is component-independent.
*
* @param key could be anything. If null, the response is appended.
* If not null, the second invocation of this method
* in the same execution with the same key and the same depends ({@link AuResponse#getDepends})
* will override the previous one.
* @see #addResponse(AuResponse)
*/
public void addResponse(String key, AuResponse response);
/** Adds a response with the given priority.
* The higher priority, the earlier the update is executed.
* The priority of {@link #addResponse(String, AuResponse)}
* and {@link #addResponse(AuResponse)} is assumed to be 0.
*
If the priority is the same, the update is executed in the order
* of first-in-first out.
* @since 6.0.1
*/
public void addResponse(String key, AuResponse response, int priority);
/** Called to update (redraw) a component, when a component is moved.
* If a component's page or parent is changed, this method need to be
* called only once for the top one.
*
* @param oldparent the parent before moved
* @param oldpg the page before moved
* @param newpg the page after moved
*/
public void addMoved(Component comp, Component oldparent, Page oldpg, Page newpg);
/** Called before changing the component's UUID.
* @since 5.0.3
*/
public void addUuidChanged(Component comp);
//-- execution --//
/** Creates components specified in the given page definition.
* Called when a new page is creates.
*/
public void execNewPage(Execution exec, PageDefinition pagedef, Page page, Writer out) throws IOException;
/** Invoke {@link Richlet#service}, when a new page is creates upon
* visiting a richlet.
*/
public void execNewPage(Execution exec, Richlet richlet, Page page, Writer out) throws IOException;
/** Reuse the desktop and generate the output.
* @since 5.0.0
*/
public void recycleDesktop(Execution exec, Page page, Writer out) throws IOException;
/** Executes an asynchronous update to a component (or page).
* It is the same as execUpdate(exec, requests, null, out).
*
*
Note: the output must be XML and UTF-8.
*
* @param requests a list of {@link AuRequest}.
*/
public void execUpdate(Execution exec, List requests, AuWriter out) throws IOException;
/** Activates an execution that will allow developers to update
* the state of components.
* It is designed to implement {@link org.zkoss.zkplus.embed.Bridge}.
*
* @return a context that shall be passed to {@link #finishUpdate}.
* @since 5.0.5
* @see #finishUpdate
* @see #closeUpdate
*/
public Object startUpdate(Execution exec) throws IOException;
/** Finishes the update and returns the result in an array of JSON object.
* Notice it does not deactivate the execution. Rather, the caller
* has to invoke {@link #closeUpdate}.
*
It is designed to implement {@link org.zkoss.zkplus.embed.Bridge}.
*
* @param ctx the context returned by the previous call to {@link #startUpdate}
* @since 5.0.5
* @see #startUpdate
* @see #closeUpdate
*/
public JSONArray finishUpdate(Object ctx) throws IOException;
/** Finishes the update and returns the result in an array of JSON object.
* Notice it does not deactivate the execution. Rather, the caller
* has to invoke {@link #closeUpdate}.
*
It is designed to implement {@link org.zkoss.zkplus.embed.Bridge}.
*
* @param ctx the context returned by the previous call to {@link #startUpdate}
* @param errs the collection of errors if any.
* @since 10.0.0
* @see #finishUpdate(Object)
*/
public JSONArray finishUpdate(Object ctx, List errs) throws IOException;
/** Deactivates the execution and cleans up.
* It is designed to implement {@link org.zkoss.zkplus.embed.Bridge}.
* @since 5.0.5
* @see #startUpdate
* @see #finishUpdate
*/
public void closeUpdate(Object ctx) throws IOException;
/** Executes the recovering.
*/
public void execRecover(Execution exec, FailoverManager failover);
/** Creates components from the specified page and definition.
* It can be called when {@link #execNewPage} or {@link #execUpdate}
* was called.
* It assumes the execution is already locked to this desktop.
*
*
Note: if both page and parent are null, the created components
* don't belong to any page/parent.
*
* @param exec the execution (never null).
* @param pagedef the page definition (never null).
* @param page the page. Ignored if parent is specified and
* parent's page is not null (parent's page will be used).
* If both page and parent are null, the created components won't belong
* to any page.
* @param parent the parent component, or null if no parent component.
* If parent is specified, page is ignored.
* @param insertBefore the sibling component that new components will be
* inserted before. Ignored if null (i.e., append as last children).
* @param resolver the variable resolver used to resolve variables.
* Ignored if null.
* @param arg a map of parameters that is accessible by the arg variable
* in EL, or by {@link Execution#getArg}.
* Ignored if null.
* @return the components being created.
* @since 6.0.0
*/
public Component[] createComponents(Execution exec, PageDefinition pagedef, Page page, Component parent,
Component insertBefore, VariableResolver resolver, Map, ?> arg);
/** Sends a temporary redirect response to the client using the specified
* redirect location URL.
*
*
After calling this method, the caller shall end the processing
* immediately (by returning). All pending requests and events will
* be dropped.
*
* @param uri the URI to redirect to, or null to reload the same page
* @param target the new target, or null to denote the same browser window
*/
public void sendRedirect(String uri, String target);
/** Aborts the current execution.
* if not null, it means the current execution is aborting
*
*
Note: if setAbortingReason is ever set with non-null, you
* CANNOT set it back to null.
*
*
After call this method, you shall not keep processing the page
* because the rendering is dropped and the client is out-of-sync
* with the server.
*
* @param aborting the aborting reason.
*/
public void setAbortingReason(AbortingReason aborting);
//-- wait/notify --//
/** Suspends the current processing of an event and wait until the
* other thread invokes {@link #notify(Object)}, {@link #notifyAll(Object)},
* {@link #notify(Desktop, Object)} or {@link #notifyAll(Desktop, Object)}
* for the specified object.
*
*
It can only be called when the current thread is processing an event.
* And, when called, the current processing is suspended and ZK continues
* to process the next event and finally render the result.
*
*
It is typical use to implement a modal dialog where it won't return
* until the modal dialog ends.
*
* @param obj any non-null object to identify what to wait, such that
* {@link #notify(Object)} and {@link #notify(Desktop, Object)} knows
* which object to notify.
* @exception UiException if it is called not during event processing.
* @exception SuspendNotAllowedException if there are too many suspended
* exceptions.
* Deployers can control the maximal allowed number of suspended exceptions
* by specifying max-suspended-thread
in zk.xml
,
* or invoking {@link org.zkoss.zk.ui.util.Configuration#setMaxSuspendedThreads}.
*/
public void wait(Object obj) throws InterruptedException, SuspendNotAllowedException;
/** Wakes up a single event processing thread that is waiting on the
* specified object.
*
*
Unlike {@link #notify(Desktop, Object)}, this method can be invoked only
* if the same desktop is locked for processing requests.
*
* @param obj any non-null object to identify what to notify. It must be
* same object passed to {@link #wait}.
* @see #notify(Desktop, Object)
* @see #notifyAll(Object)
* @exception UiException if it is called not during event processing.
*/
public void notify(Object obj);
/** Wakes up a single event processing thread for the specified desktop
* that is waiting on the specified object.
*
*
Unlike {@link #notify(Object)}, this method can be called any time.
* It is designed to let working threads resume an event processing
* thread.
*
*
Notice: if this method is NOT called in an event processing thread,
* the resumed thread won't execute until the next request is received.
* To enforce it happen, you might use the timer component (found in ZUL).
*
* @param desktop the desktop which the suspended thread is processing.
* It must be the same desktop of the suspended thread.
* @param obj any non-null object to identify what to notify. It must be
* same object passed to {@link #wait}.
* @see #notify(Object)
* @see #notifyAll(Desktop, Object)
*/
public void notify(Desktop desktop, Object obj);
/** Wakes up all event processing thread that are waiting on the
* specified object.
*
*
Unlike {@link #notify(Desktop, Object)}, this method can be invoked only
* if the same desktop is locked for processing requests.
*
* @param obj any non-null object to identify what to notify. It must be
* same object passed to {@link #wait}.
* @see #notify(Desktop, Object)
* @see #notifyAll(Object)
* @exception UiException if it is called not during event processing.
*/
public void notifyAll(Object obj);
/** Wakes up all event processing threads for the specified desktop
* that are waiting on the specified object.
*
*
Unlike {@link #notifyAll(Object)}, this method can be called any time.
* It is designed to let working threads resume an event processing
* thread.
*
*
If this method is NOT called in an event processing thread,
* the resumed thread won't execute until the next request is received.
* To enforce it happen, you might use the timer component (found in ZUL).
*
* @param desktop the desktop which the suspended thread is processing.
* It must be the same desktop of the suspended thread.
* @param obj any non-null object to identify what to notify. It must be
* same object passed to {@link #wait}.
* @see #notify(Object)
* @see #notifyAll(Desktop, Object)
*/
public void notifyAll(Desktop desktop, Object obj);
/** Activates an execution such that you can access a component.
* You must call {@link #deactivate} in the finally clause.
*
*
Note: you RARELY need to invoke this method because {@link #execNewPage}
* and {@link #execUpdate} will activate and deactivate automatically.
*
*
Note: this method can be called only when processing a client request
* (e.g., HTTP) other than creating a new page and processing async-update.
*
*
Also, even if you use this method to grant the right to access
* components of the specified page, don't post events, create, remove,
* invalidate and do any smart updates. In other words, READ ONLY.
*/
public void activate(Execution exec);
/** Activates an execution such that you can access a component.
* Unlike {@link #activate(Execution)}, you could specify an amount of
* time (timeout), and it returns false if it takes longer than the given
* amount of time before granted.
* @param timeout the number of milliseconds to wait before giving up.
* It is ignored if negative, i.e., it waits until granted if negative.
* @return whether the activation succeeds
* @since 5.0.6
*/
public boolean activate(Execution exec, int timeout);
/** Deactivates an execution, such that other threads could activate
* and access components.
*/
public void deactivate(Execution exec);
/** Activates and prepare for asynchronous update
* @since 3.5.0
*/
public void beginUpdate(Execution exec);
/** Executes posted events, deactivate and ends the asynchronous update.
*
* @since 5.0.0
*/
public void endUpdate(Execution exec) throws IOException;
/** Retrieve the native content for a property of the specified component.
* The native content is a value of a property that is represented
* by a XML fragment (actually {@link org.zkoss.zk.ui.metainfo.NativeInfo}).
*
*
Example:
*
<html>
* <attribute name="content">
* <br/>
* </attribute>
*</html>
*
* @param comp the component that the native content will be assigned to.
* It is the object that the self variable is assigned when evaluating
* EL expressions.
* @param children a list of {@link org.zkoss.zk.ui.metainfo.NativeInfo},
* {@link org.zkoss.zk.ui.metainfo.TextInfo} and others.
* This method evaluates them one-by-one and returns the result
* which is the value that will be assigned.
* @param helper the helper used to generate the content.
* @see org.zkoss.zk.ui.metainfo.Property
* @since 3.5.0
*/
public String getNativeContent(Component comp, List children, Native.Helper helper);
/** Returns if any suspended event processing thread in the
* whole system.
*/
public boolean hasSuspendedThread();
/** Returns a collection of suspended event processing threads
* belonging to the specified desktop,
* or empty if no suspended thread at all.
*
* An event processing thread is an instance of
* {@link EventProcessingThread}
*
* @param desktop the desktop that the suspended event processing
* threads belong to (never null).
*/
public Collection getSuspendedThreads(Desktop desktop);
/** Ceases the specified event thread.
*
* @param desktop which desktop the event thread belongs to
* @param cause an arbitrary text to describe the cause.
* It will be the message of the thrown InterruptedException.
* @return true if the event processing thread is ceased successfully;
* false if no such thread or it is not suspended.
*/
public boolean ceaseSuspendedThread(Desktop desktop, EventProcessingThread evtthd, String cause);
/** Sets whether to disable the update of the client widget.
* By default, if a component is attached to a page, modifications that
* change the visual representation will be sent to the client to
* ensure the consistency.
*
* @return whether it has been disabled before this invocation, i.e.,
* the previous disable status
* @since 3.6.2
*/
public boolean disableClientUpdate(Component comp, boolean disable);
}