/* Bridge.java
Purpose:
Description:
History:
Thu Sep 16 10:49:20 TST 2010, Created by tomyeh
Copyright (C) 2010 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zkplus.embed;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.zkoss.json.JSONArray;
import org.zkoss.web.servlet.Charsets;
import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.Execution;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.http.ExecutionImpl;
import org.zkoss.zk.ui.http.WebManager;
import org.zkoss.zk.ui.sys.WebAppCtrl;
/**
* Utilities to allow developers to start an execution in foreign Ajax channel.
*
* <pre><code>Bridge bridge = Bridge.start(svlctx, request, response, desktop);
*try {
* //execution is activated and you could access anything belonging to the desktop
* String jscode = bridge.getResult();
* //send jscode back to the client to update DOM, if any
*} finally {
* bridge.close(); //stop the execution
*}</code></pre>
*
* <p>See also <a href="http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/Integration/Start_Execution_in_Foreign_Ajax_Channel">Start Execution in Foreign Ajax Channel</a>
*
* @author tomyeh
* @since 5.0.5
*/
public class Bridge {
private Execution _exec;
private Object _updctx;
private Object _locale;
/** Starts an execution.
* After returned, the execution is activated and the caller is free to access
* any components belonging the given desktop.
* <p>After processing, the caller shall invoke {@link #close} to stop
* the execution (in the finally clause).
* @param desktop the desktop you want to access.
* You could retrieve by use of {@link #getDesktop}.
*/
public static Bridge start(ServletContext svlctx, HttpServletRequest request, HttpServletResponse response,
Desktop desktop) {
try {
return new Bridge(svlctx, request, response, desktop, Charsets.setup(request, response, "utf-8"));
} catch (Exception ex) { //not possible
throw UiException.Aide.wrap(ex);
}
}
/** Returns the desktop of the given desktop ID, or null if not found.
* @param dtid the desktop's ID.
*/
public static Desktop getDesktop(ServletContext svlctx, HttpServletRequest request, String dtid) {
return ((WebAppCtrl) WebManager.getWebApp(svlctx)).getDesktopCache(WebManager.getSession(svlctx, request))
.getDesktop(dtid);
}
/** Constructor.
* Don't invoke this directly. Rather, use {@link #start} instead.
*/
protected Bridge(ServletContext svlctx, HttpServletRequest request, HttpServletResponse response, Desktop desktop,
Object locale) throws Exception {
_exec = new ExecutionImpl(svlctx, request, response, desktop, null);
_updctx = ((WebAppCtrl) desktop.getWebApp()).getUiEngine().startUpdate(_exec);
_locale = locale;
}
/** Returns the execution.
*/
public Execution getExecution() {
return _exec;
}
/** Returns the result in the JavaScript.
* The caller shall send it back and evaluate it at the client (<code>eval(jscode);</code>).
* <p>After calling this method, the caller shall not modify the component's state any more.
*/
public String getResult() {
final Desktop desktop = _exec.getDesktop();
try {
JSONArray result = ((WebAppCtrl) desktop.getWebApp()).getUiEngine().finishUpdate(_updctx);
return new StringBuffer(512).append("zAu.doCmds('").append(desktop.getId()).append("',")
.append(result.toString()).append(");").toString();
} catch (Exception ex) { //not possible
throw UiException.Aide.wrap(ex);
}
}
/** Closes the execution such that other requests targeting
* the same desktop can be processed.
* It must be called. Otherwise, the whole desktop might not be able
* to be accessed any more.
*/
public void close() {
final HttpServletRequest request = (HttpServletRequest) _exec.getNativeRequest();
try {
((WebAppCtrl) _exec.getDesktop().getWebApp()).getUiEngine().closeUpdate(_updctx);
_updctx = null;
_exec = null;
} catch (Exception ex) { //not possible
throw UiException.Aide.wrap(ex);
} finally {
Charsets.cleanup(request, _locale);
_locale = null;
}
}
}