/* Executions.java
Purpose:
Description:
History:
Fri Jun 3 17:55:08 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;
import java.io.IOException;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.servlet.ServletRequest;
import org.zkoss.idom.Document;
import org.zkoss.xel.ExpressionFactory;
import org.zkoss.xel.VariableResolver;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.metainfo.LanguageDefinition;
import org.zkoss.zk.ui.metainfo.PageDefinition;
import org.zkoss.zk.ui.sys.DesktopCtrl;
import org.zkoss.zk.ui.sys.UiEngine;
import org.zkoss.zk.ui.sys.WebAppCtrl;
import org.zkoss.zk.xel.Evaluator;
/**
* Utilities to access {@link Execution}.
*
* @author tomyeh
*/
public class Executions {
/** Stores the current {@link Execution}. */
protected static final ThreadLocal<Execution> _exec = new ThreadLocal<Execution>();
/** Returns the current execution.
*/
public static final Execution getCurrent() {
return _exec.get();
}
/** Returns the evaluator of the current execution.
* It is usually used to parse the expression into {@link org.zkoss.xel.Expression}
* or used with {@link org.zkoss.zk.xel.ExValue}.
* for performance improvement.
*
* @param page the page that this evaluator is associated.
* If null, the current page and then the first page is assumed.
* @param expfcls the implementation of {@link ExpressionFactory},
* or null to use the default ({@link org.zkoss.zk.ui.util.Configuration#getExpressionFactoryClass}.
* @since 3.0.0
*/
public static final Evaluator getEvaluator(Page page, Class<? extends ExpressionFactory> expfcls) {
return getCurrent().getEvaluator(page, expfcls);
}
/** Returns the evaluator of the current execution.
* It is a shortcut of getEvaluator(comp != null ? comp.getPage(): null)
*
* @param comp the component to retrieve the page for the evaluator
* @param expfcls the implementation of {@link ExpressionFactory},
* or null to use the default ({@link org.zkoss.zk.ui.util.Configuration#getExpressionFactoryClass}.
* @since 3.0.0
*/
public static final Evaluator getEvaluator(Component comp, Class<? extends ExpressionFactory> expfcls) {
return getCurrent().getEvaluator(comp, expfcls);
}
/** Evaluates the specified expression by use of the current context
* ({@link #getCurrent}).
*
* <p>The function mapper is retrieved from component's page's function
* mapper ({@link Page#getFunctionMapper}).
* If null, the current page, if any, is used to retrieve
* the mapper.
*
* <p>For better performance, you can use the instance returned by
*{@link #getEvaluator} to parse and cached the parsed expression.
* {@link org.zkoss.zk.xel.ExValue} is a utility class to simply
* the task.
*
* @param comp as the self variable (ignored if null)
*/
public static final Object evaluate(Component comp, String expr, Class expectedType) {
return getCurrent().evaluate(comp, expr, expectedType);
}
/** Evaluates the specified expression with the resolver of the current
* execution ({@link #getCurrent}).
*
* <p>The function mapper is retrieved from page's function
* mapper ({@link Page#getFunctionMapper}).
* If null, the current page, if any, is used to retrieve
* the mapper.
*
* <p>For better performance, you can use the instance returned by
*{@link #getEvaluator} to parse and cached the parsed expression.
* {@link org.zkoss.zk.xel.ExValue} is a utility class to simply
* the task.
*
* @param page used as the self variable and to retrieve the function
* mapper if funmap is not defined. Ignored if null.
*/
public static final Object evaluate(Page page, String expr, Class expectedType) {
return getCurrent().evaluate(page, expr, expectedType);
}
/** Encodes the specified URL.
*
* <p>It resolves "*" contained in URI, if any, to the proper Locale,
* and the browser code.
* Refer to {@link org.zkoss.web.servlet.Servlets#locate(javax.servlet.ServletContext, ServletRequest, String, Locator)}
* for details.
*
* @exception NullPointerException if the current execution is not
* available.
* @see #encodeURL
*/
public static final String encodeURL(String uri) {
return getCurrent().encodeURL(uri);
}
/** Encodes the specified URL into an instance of {@link URL}.
* It is similar to {@link #encodeURL}, except it returns an instance
* of {@link URL}.
*
* @exception NullPointerException if the current execution is not
* available.
* @exception MalformedURLException if failed to convert it to
* a legal {@link URL}
* @since 3.5.0
*/
public static final URL encodeToURL(String uri) throws MalformedURLException {
final Execution exec = getCurrent();
uri = exec.encodeURL(uri);
if (uri.indexOf("://") < 0) {
final StringBuffer sb = new StringBuffer(256).append(exec.getScheme()).append("://")
.append(exec.getServerName());
int port = exec.getServerPort();
if (port != 80)
sb.append(':').append(port);
if (uri.length() > 0 && uri.charAt(0) != '/')
sb.append('/');
uri = sb.append(uri).toString();
}
return new URL(uri);
}
/** Creates components from a page file specified by an URI.
* Shortcut to {@link Execution#createComponents(String, Component, Map)}.
*
* @param parent the parent component, or null if you want it to be
* a root component. If parent is null, the page is assumed to be
* the current page, which is determined by the execution context.
* In other words, the new component will be the root component
* of the current page if parent is 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 first component being created.
* @see #createComponents(PageDefinition, Component, Map)
*/
public static final Component createComponents(String uri, Component parent, Map<?, ?> arg) {
return getCurrent().createComponents(uri, parent, arg);
}
/** Creates components based on the specified page definition.
* Shortcut to {@link Execution#createComponents(PageDefinition, Component, Map)}.
*
* @param pagedef the page definition to use. It cannot be null.
* @param parent the parent component, or null if you want it to be
* a root component. If parent is null, the page is assumed to be
* the current page, which is determined by the execution context.
* In other words, the new component will be the root component
* of the current page if parent is 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 first component being created.
* @see #createComponents(String, Component, Map)
*/
public static final Component createComponents(PageDefinition pagedef, Component parent, Map<?, ?> arg) {
return getCurrent().createComponents(pagedef, parent, arg);
}
/** Creates components that don't belong to any page
* from the specified page definition.
*
* <p>Unlike {@link #createComponents(PageDefinition,Component,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param pagedef the page definition to use. It cannot be 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 all top-level components being created.
* @see #createComponents(WebApp, String, Map)
* @since 3.6.2
*/
public static Component[] createComponents(WebApp wapp, PageDefinition pagedef, Map<?, ?> arg) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.createComponents(pagedef, arg);
} finally {
afterCC(cci);
}
}
/** Creates components that don't belong to any page
* from a page file specified by an URI.
*
* <p>It loads the page definition from the specified URI (by
* use {@link #getPageDefinition} ), and then
* invokes {@link #createComponents(WebApp,PageDefinition,Map)}
* to create components.
*
* <p>Unlike {@link #createComponents(String,Component,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param arg a map of parameters that is accessible by the arg variable
* in EL, or by {@link Execution#getArg}.
* Ignored if null.
* @return all top-level components being created.
* @see #createComponents(WebApp, PageDefinition, Map)
* @see #createComponentsDirectly(WebApp, String, String, Map)
* @see #createComponentsDirectly(WebApp, Document, String, Map)
* @see #createComponentsDirectly(WebApp, Reader, String, Map)
* @since 3.6.2
*/
public static Component[] createComponents(WebApp wapp, String uri, Map<?, ?> arg) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.createComponents(uri, arg);
} finally {
afterCC(cci);
}
}
/** Creates components that belong to the given page
* from a page file specified by an URI.
*
* @param page the page, or null if you want it to attach the created components.
* @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 all top-level components being created.
* @see #createComponents(WebApp, PageDefinition, Map)
* @see #createComponentsDirectly(WebApp, String, String, Map)
* @see #createComponentsDirectly(WebApp, Document, String, Map)
* @see #createComponentsDirectly(WebApp, Reader, String, Map)
* @since 8.0.1
*/
public static Component[] createComponents(String uri, Page page, VariableResolver resolver, Map<?, ?> arg) {
return getCurrent().createComponents(uri, page, resolver, arg);
}
/** Creates components from the raw content specified by a string.
* Shortcut to {@link Execution#createComponentsDirectly(String, String, Component, Map)}.
*
* @param content the raw content of the page. It must be a XML and
* compliant to the page format (such as ZUL).
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param parent the parent component, or null if you want it to be
* a root component. If parent is null, the page is assumed to be
* the current page, which is determined by the execution context.
* In other words, the new component will be the root component
* of the current page if parent is 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 first component being created.
* @see #createComponents(PageDefinition, Component, Map)
* @see #createComponents(String, Component, Map)
* @see #createComponentsDirectly(Document, String, Component, Map)
* @see #createComponentsDirectly(Reader, String, Component, Map)
*/
public static final Component createComponentsDirectly(String content, String extension, Component parent,
Map<?, ?> arg) {
return getCurrent().createComponentsDirectly(content, extension, parent, arg);
}
/** Creates components from the raw content specified by a DOM tree.
* Shortcut to {@link Execution#createComponentsDirectly(Document, String, Component, Map)}.
*
* @param content the raw content in DOM.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param parent the parent component, or null if you want it to be
* a root component. If parent is null, the page is assumed to be
* the current page, which is determined by the execution context.
* In other words, the new component will be the root component
* of the current page if parent is 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 first component being created.
* @see #createComponents(PageDefinition, Component, Map)
* @see #createComponents(String, Component, Map)
* @see #createComponentsDirectly(String, String, Component, Map)
* @see #createComponentsDirectly(Reader, String, Component, Map)
*/
public static final Component createComponentsDirectly(Document content, String extension, Component parent,
Map<?, ?> arg) {
return getCurrent().createComponentsDirectly(content, extension, parent, arg);
}
/** Creates components from the raw content read from the specified reader.
* Shortcut to {@link Execution#createComponentsDirectly(Reader, String, Component, Map)}.
*
* <p>The raw content is loader and parsed to a page defintion by use of
* {@link Execution#getPageDefinitionDirectly(Reader, String)}, and then
* invokes {@link #createComponents(PageDefinition,Component,Map)}
* to create components.
*
* @param reader the reader to retrieve the raw content.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param parent the parent component, or null if you want it to be
* a root component. If parent is null, the page is assumed to be
* the current page, which is determined by the execution context.
* In other words, the new component will be the root component
* of the current page if parent is 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 first component being created.
* @see #createComponents(PageDefinition, Component, Map)
* @see #createComponents(String, Component, Map)
* @see #createComponentsDirectly(Document, String, Component, Map)
* @see #createComponentsDirectly(String, String, Component, Map)
*/
public static Component createComponentsDirectly(Reader reader, String extension, Component parent, Map<?, ?> arg)
throws IOException {
return getCurrent().createComponentsDirectly(reader, extension, parent, arg);
}
/** Creates components that don't belong to any page
* from the raw content specified by a string.
*
* <p>The raw content is parsed to a page definition by use of
* {@link #getPageDefinitionDirectly(WebApp,String,String)}, and then
* invokes {@link #createComponents(WebApp,PageDefinition,Map)}
* to create components.
*
* <p>Unlike {@link #createComponentsDirectly(String,String,Component,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param content the raw content of the page. It must be in ZUML.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param arg a map of parameters that is accessible by the arg variable
* in EL, or by {@link Execution#getArg}.
* Ignored if null.
* @return all top-level components being created.
* @see #createComponents(WebApp, PageDefinition, Map)
* @see #createComponents(WebApp, String, Map)
* @see #createComponentsDirectly(WebApp, Document, String, Map)
* @see #createComponentsDirectly(WebApp, Reader, String, Map)
* @since 3.6.2
*/
public static Component[] createComponentsDirectly(WebApp wapp, String content, String extension, Map<?, ?> arg) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.createComponentsDirectly(content, extension, arg);
} finally {
afterCC(cci);
}
}
/** Creates components that don't belong to any page
* from the raw content specified by a DOM tree.
*
* <p>The raw content is parsed to a page definition by use of
* {@link #getPageDefinitionDirectly(WebApp,Document, String)}, and then
* invokes {@link #createComponents(WebApp,PageDefinition,Map)}
* to create components.
*
* <p>Unlike {@link #createComponentsDirectly(Document,String,Component,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param content the raw content in DOM.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param arg a map of parameters that is accessible by the arg variable
* in EL, or by {@link Execution#getArg}.
* Ignored if null.
* @return all top-level components being created.
* @see #createComponents(WebApp, PageDefinition, Map)
* @see #createComponents(WebApp, String, Map)
* @see #createComponentsDirectly(WebApp, Document, String, Map)
* @see #createComponentsDirectly(WebApp, Reader, String, Map)
* @since 3.6.2
*/
public static Component[] createComponentsDirectly(WebApp wapp, Document content, String extension, Map<?, ?> arg) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.createComponentsDirectly(content, extension, arg);
} finally {
afterCC(cci);
}
}
/** Creates components that don't belong to any page
* from the raw content read from the specified reader.
*
* <p>Unl
*
* <p>The raw content is loaded and parsed to a page definition by use of
* {@link #getPageDefinitionDirectly(WebApp,Reader,String)}, and then
* invokes {@link #createComponents(WebApp,PageDefinition,Map)}
* to create components.
*
* <p>Unlike {@link #createComponentsDirectly(Reader,String,Component,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param reader the reader to retrieve the raw content in ZUML.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @param arg a map of parameters that is accessible by the arg variable
* in EL, or by {@link Execution#getArg}.
* Ignored if null.
* @return all top-level components being created.
* @see #createComponents(WebApp, PageDefinition, Map)
* @see #createComponents(WebApp, String, Map)
* @see #createComponentsDirectly(WebApp, Document, String, Map)
* @see #createComponentsDirectly(WebApp, String, String, Map)
* @since 3.6.2
*/
public static Component[] createComponentsDirectly(WebApp wapp, Reader reader, String extension, Map<?, ?> arg)
throws IOException {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.createComponentsDirectly(reader, extension, arg);
} finally {
afterCC(cci);
}
}
/** Returns the page definition from the page file specified by an URI.
*
* <p>Like {@link #createComponents(WebApp,PageDefinition,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param uri the URI of the page file.
*
* @see #getPageDefinitionDirectly(WebApp, String, String)
* @see #getPageDefinitionDirectly(WebApp, Document, String)
* @see #getPageDefinitionDirectly(WebApp, Reader, String)
* @since 3.6.2
*/
public static PageDefinition getPageDefinition(WebApp wapp, String uri) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.getPageDefinition(uri);
} finally {
afterCC(cci);
}
}
/** Converts the specified page content to a page definition.
*
* <p>Like {@link #createComponents(WebApp,PageDefinition,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param content the raw content of the page. It must be in ZUML.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @see #getPageDefinitionDirectly(WebApp, Document, String)
* @see #getPageDefinitionDirectly(WebApp, Reader, String)
* @see #getPageDefinition
* @since 3.6.2
*/
public PageDefinition getPageDefinitionDirectly(WebApp wapp, String content, String extension) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.getPageDefinitionDirectly(content, extension);
} finally {
afterCC(cci);
}
}
/** Converts the specified page content, in DOM, to a page definition.
*
* <p>Like {@link #createComponentsDirectly(WebApp,Document,String,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param content the raw content of the page in DOM.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @see #getPageDefinitionDirectly(WebApp, String, String)
* @see #getPageDefinitionDirectly(WebApp, Reader, String)
* @see #getPageDefinition
* @since 3.6.2
*/
public PageDefinition getPageDefinitionDirectly(WebApp wapp, Document content, String extension) {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.getPageDefinitionDirectly(content, extension);
} finally {
afterCC(cci);
}
}
/** Reads the raw content from a reader and converts it into
* a page definition.
*
* <p>Like {@link #createComponentsDirectly(WebApp,Reader,String,Map)},
* this method can be invoked without the current execution, such as
* a working thread. In this case, the wapp argument must be specified.
*
* @param wapp the Web application. It is optional and used only if
* no current execution (e.g., in a working thread).
* The instance of {@link WebApp} can be retrieved by use of {@link org.zkoss.zk.ui.http.WebManager#getWebApp},
* while the instance of {@link org.zkoss.zk.ui.http.WebManager} can be retrieved
* by {@link org.zkoss.zk.ui.http.WebManager#getWebManager}
* @param reader used to input the raw content of the page. It must be in ZUML.
* @param extension the default extension if the content doesn't specify
* an language. In other words, if
* the content doesn't specify an language, {@link LanguageDefinition#getByExtension}
* is called.
* If extension is null and the content doesn't specify a language,
* the language called "xul/html" is assumed.
* @see #getPageDefinitionDirectly(WebApp, String, String)
* @see #getPageDefinitionDirectly(WebApp, Document, String)
* @see #getPageDefinition
* @since 3.6.2
*/
public PageDefinition getPageDefinitionDirectly(WebApp wapp, Reader reader, String extension) throws IOException {
final CCInfo cci = beforeCC(wapp);
try {
return cci.exec.getPageDefinitionDirectly(reader, extension);
} finally {
afterCC(cci);
}
}
private static final CCInfo beforeCC(WebApp wapp) {
Execution exec = Executions.getCurrent();
if (exec != null)
return new CCInfo(exec, false);
((WebAppCtrl) wapp).getUiEngine().activate(exec = CCExecution.newInstance(wapp));
return new CCInfo(exec, true);
}
private static final void afterCC(CCInfo cci) {
if (cci.created) {
try {
((WebAppCtrl) cci.exec.getDesktop().getWebApp()).getUiEngine().deactivate(cci.exec);
} catch (Throwable ex) {
}
}
}
private static class CCInfo {
private final Execution exec;
private final boolean created;
private CCInfo(Execution exec, boolean created) {
this.exec = exec;
this.created = created;
}
}
/** Sends a temporary redirect response to the client using the specified
* redirect location URL by use of the current execution,
* {@link #getCurrent}.
*
* <p>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
* @see Execution#sendRedirect
*/
public static void sendRedirect(String uri) {
getCurrent().sendRedirect(uri);
}
/** A shortcut of Executions.getCurrent().include(page).
*
* @see Execution#include(java.io.Writer,String,Map,int)
* @see Execution#include(String)
*/
public static void include(String page) throws IOException {
getCurrent().include(page);
}
/** A shortcut of Executions.getCurrent().forward(page).
*
* @see Execution#forward(java.io.Writer,String,Map,int)
* @see Execution#forward(String)
*/
public static void forward(String page) throws IOException {
getCurrent().forward(page);
}
//-- 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.
*
* <p>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.
*
* <p>It is typical use to implement a modal dialog where it won't return
* until the modal dialog ends.
*
* @param mutex any non-null object to identify what to notify.
* It must be same object passed to {@link #notify(Desktop, Object)}.
* If there is racing issue, you have to enclose it with
* <code>synchronized</code> (though it is optional).
* @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 <code>max-suspended-thread</code> in <code>zk.xml</code>,
* or invoking {@link org.zkoss.zk.ui.util.Configuration#setMaxSuspendedThreads}.
*/
public static final void wait(Object mutex) throws InterruptedException, SuspendNotAllowedException {
getUiEngine().wait(mutex);
}
/** Wakes up a single event processing thread that is waiting on the
* specified object.
*
* <p>Unlike {@link #notify(Desktop, Object)}, this method can be invoked only
* in the event listener that processing the same desktop.
* In addition, this method can be called under the event listener.
*
* <p>Use {@link #notify(Desktop, Object)} if you want to notify in other
* thread, such as a working thread.
*
* @param mutex any non-null object to identify what to notify.
* It must be same object passed to {@link #wait}.
* If there is racing issue, you have to enclose it with
* <code>synchronized</code> (though it is optional).
* @see #notify(Desktop, Object)
* @see #notifyAll(Object)
* @exception UiException if it is called not during event processing.
*/
public static final void notify(Object mutex) {
getUiEngine().notify(mutex);
}
/** Wakes up a single event processing thread for the specified desktop
* that is waiting on the specified object.
*
* <p>Unlike {@link #notify(Object)}, this method can be called any time.
* It is designed to let working threads resume an event processing
* thread.
*
* <p>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).
*
* <p>Notice: to resolve racing issue, you usually need to follow
* this pattern.
* <pre><code>
//Event Handling Thread
synchronized (mutex) {
final WorkingThread worker = new WorkingThread(desktop);
synchronized (mutex) {
worker.start();
Executions.wait(mutex);
}
....
}
//Working Thread
public void run() {
....
synchronized (mutex) {
Executions.notify(desktop, mutex);
}
}
</code></pre>
*
* @param desktop the desktop which the suspended thread is processing.
* It must be the same desktop of the suspended thread.
* @param mutex any non-null object to identify what to notify.
* It must be same object passed to {@link #wait}.
* If there is racing issue, you have to enclose it with
* <code>synchronized</code> (though it is optional).
* @see #notify(Object)
* @see #notifyAll(Desktop, Object)
*/
public static final void notify(Desktop desktop, Object mutex) {
getUiEngine(desktop).notify(desktop, mutex);
}
/** Wakes up all event processing thread that are waiting on the
* specified object.
*
* <p>Unlike {@link #notify(Desktop, Object)}, this method can be invoked only
* in the event listener that processing the same desktop.
* In addition, this method can be called under the event listener.
*
* <p>Use {@link #notifyAll(Desktop, Object)} if you want to notify in other
* thread, such as a working thread.
*
* @param mutex any non-null object to identify what to notify.
* It must be same object passed to {@link #wait}.
* If there is racing issue, you have to enclose it with
* <code>synchronized</code> (though it is optional).
* @see #notify(Desktop, Object)
* @see #notifyAll(Object)
* @exception UiException if it is called not during event processing.
*/
public static final void notifyAll(Object mutex) {
getUiEngine().notifyAll(mutex);
}
/** Wakes up all event processing threads for the specified desktop
* that are waiting on the specified object.
*
* <p>Unlike {@link #notifyAll(Object)}, this method can be called any time.
* It is designed to let working threads resume an event processing
* thread.
*
* <p>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).
*
* <p>Notice: to resolve racing issue, you usually need to follow
* this pattern.
* <pre><code>
//Event Handling Thread
synchronized (mutex) {
final WorkingThread worker = new WorkingThread(desktop);
synchronized (mutex) {
worker.start();
Executions.wait(mutex);
}
....
}
//Working Thread
public void run() {
....
synchronized (mutex) {
Executions.notifyAll(desktop, mutex);
}
}
</code></pre>
*
* @param desktop the desktop which the suspended thread is processing.
* It must be the same desktop of the suspended thread.
* @param mutex any non-null object to identify what to notify.
* It must be same object passed to {@link #wait}.
* If there is racing issue, you have to enclose it with
* <code>synchronized</code> (though it is optional).
* @see #notify(Object)
* @see #notifyAll(Desktop, Object)
*/
public static final void notifyAll(Desktop desktop, Object mutex) {
getUiEngine(desktop).notifyAll(desktop, mutex);
}
/** Schedules a task to run under the server push of the given desktop asynchronously.
* The caller can be any thread, not
* limited to the event listener of the given desktop.
*
* <p>The task is executed when the server push of the given desktop
* is granted. The task is executed asynchronously. That is, this method
* return without waiting for the task to be executed.
*
* <p>The task is executed in the thread serving the server-push request,
* so no additional thread will be created. It is safe to use in a clustering
* environment.
*
* <p>The task is represented by an event listener. When the server push
* is ready to serve the given task, {@link EventListener#onEvent} is called
* with the given event.
*
* <p>Like {@link #activate}, this method can be called anywhere, not limited
* to the event listener of the given desktop. It can be called even
* if there is no current execution.
*
* <p>Alternative to {@link #schedule}, you could use {@link #activate}/{@link #deactivate}
* if you prefer something to be done synchronously.
*
* <p>The server-push is disabled by default. To use it, you have to enable
* it first with {@link Desktop#enableServerPush} for the given desktop.
* Once enabled, you can use as many as server-push threads you like
* (for the desktop with the server-push feature enabled).
*
* @param task the task to execute
* @param event the event to be passed to the task (i.e., the event listener).
* It could null or any instance as long as the task recognizes it.
* @exception IllegalStateException if the server push is not enabled.
* @exception DesktopUnavailableException if the desktop is removed
* (when activating).
* @since 5.0.6
*/
public static <T extends Event> void schedule(Desktop desktop, EventListener<T> task, T event) {
((DesktopCtrl) desktop).scheduleServerPush(task, event);
}
/** Activates a thread to allow it access the given desktop synchronously.
* It causes the current thread to wait until the desktop is available
* to access, the desktop no longer exists,
* or some other thread interrupts this thread.
*
* <p>Alternative to {@link #activate}/{@link #deactivate}, you could use
* {@link #schedule} to execute a task under server push. {@link #schedule} is
* asynchronous, while {@link #activate}/{@link #deactivate} is synchronous
*
* <p>Like {@link #schedule}, this method can be called anywhere, not limited
* to the event listener of the given desktop. It can be called even
* if there is no current execution.
*
* <p>The server-push is disabled by default. To use it, you have to enable
* it first with {@link Desktop#enableServerPush} for the given desktop.
* Once enabled, you can use as many as server-push threads you like
* (for the desktop with the server-push feature enabled).
*
* <p>Before a thread, not running in the event listener of the given desktop,
* can access the desktop, you have to activate it first by {@link #activate}.
* Once this method returns, the thread is activated and it, like
* an event listener of the given desktop, can manipulate the desktop directly.
*
* <p>A typical use pattern:
*
* <pre><code>class MyWorkingThread extends Thread {
* public void run() {
* while (anything_to_publish) {
* //prepare something to publish
* //you can create new components and manipulate them before
* //activation, as long as they are not attached to the desktop
*
* Executions.activate(desktop);
* try {
* try {
* //activated
* //manipulate the components that are attached the desktop
* } finally {
* Executions.deactivate(desktop)
* }
* } catch (DesktopUnavailableException ex) {
* //clean up (since desktop is dead)
* }
* }
* }
*}</code></pre>
*
* <p>Note: the access of components is sequentialized. That is,
* at most one thread is activated. All others, including
* the event listeners, have to wait until it is deactivated
* (i.e., until {@link #deactivate} is called).
* Thus, it is better to minimize the time remaining activated.
* A typical practice is to create new components and manipulate them
* before activated. Then, you have to only attach them after activated.
*
* <pre><code> Tree tree = new Tree();
* new Treechildren().setParent(tree); //initialize the tree
* Exections.activate(desktop);
* try {
* tree.setPage(page); //assume page is a page of desktop
*</code></pre>
*
* <p>Note: you don't need to invoke this method in the event listener
* since it is already activated when an event listen starts execution.
*
* <p> Note: When you call this method, ZK framework would require a lock on the
* thread. In the rare case that the framework, at the same time, is waiting
* on the release of another lock from your application, then a deadlock
* would result.
*
* @exception InterruptedException if it is interrupted by other thread
* @exception IllegalStateException if the server push is not enabled.
* @exception DesktopUnavailableException if the desktop is removed
* (when activating).
* @since 3.0.0
*/
public static final void activate(Desktop desktop) throws InterruptedException, DesktopUnavailableException {
activate(desktop, 0);
}
/** Activates a thread to allow it access the given desktop synchronously,
* or until a certain amount of time has elapsed.
* It causes the current thread to wait until the desktop is available
* to access, the desktop no longer exists,
* some other thread interrupts this thread,
* or a certain amount of real time has elapsed.
* <p> Note: When you call this method, ZK framework would require a lock on the
* thread. In the rare case that the framework, at the same time, is waiting
* on the release of another lock from your application, then a deadlock
* would result.
*
* @param timeout the maximum time to wait in milliseconds.
* Ignored (i.e., never timeout) if non-positive.
* @return whether it is activated or it is timeout.
* The only reason it returns false is timeout.
* @exception InterruptedException if it is interrupted by other thread
* @exception DesktopUnavailableException if the desktop is removed
* (when activating).
* @exception IllegalStateException if the server push is not
* enabled for this desktop yet ({@link Desktop#enableServerPush}).
* @since 3.0.0
* @see #activate(Desktop)
* @see #deactivate
*/
public static final boolean activate(Desktop desktop, long timeout)
throws InterruptedException, DesktopUnavailableException {
return ((DesktopCtrl) desktop).activateServerPush(timeout);
}
/** Deactivates a thread that has invoked {@link #activate} successfully.
* @since 3.0.0
* @see #activate(Desktop)
* @see #activate(Desktop, long)
*/
public static final void deactivate(Desktop desktop) {
((DesktopCtrl) desktop).deactivateServerPush();
}
private static final UiEngine getUiEngine(Desktop desktop) {
if (desktop == null)
throw new IllegalArgumentException("desktop cannot be null");
return ((WebAppCtrl) desktop.getWebApp()).getUiEngine();
}
private static final UiEngine getUiEngine() {
final Execution exec = getCurrent();
if (exec == null)
throw new IllegalStateException("This method can be called only under an event listener");
return ((WebAppCtrl) exec.getDesktop().getWebApp()).getUiEngine();
}
}