/* Renders.java Purpose: Description: History: Tue Aug 10 08:48:59 TST 2010, Created by tomyeh Copyright (C) 2010 Potix Corporation. All Rights Reserved. */ package org.zkoss.zkplus.embed; import java.io.IOException; import java.io.Writer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.zkoss.web.servlet.http.Https; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Desktop; import org.zkoss.zk.ui.Execution; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.GenericRichlet; import org.zkoss.zk.ui.Page; import org.zkoss.zk.ui.Richlet; import org.zkoss.zk.ui.Session; import org.zkoss.zk.ui.WebApp; import org.zkoss.zk.ui.http.ExecutionImpl; import org.zkoss.zk.ui.http.I18Ns; import org.zkoss.zk.ui.http.WebManager; import org.zkoss.zk.ui.impl.Attributes; import org.zkoss.zk.ui.impl.RequestInfoImpl; import org.zkoss.zk.ui.metainfo.PageDefinitions; import org.zkoss.zk.ui.sys.HtmlPageRenders; import org.zkoss.zk.ui.sys.RequestInfo; import org.zkoss.zk.ui.sys.SessionCtrl; import org.zkoss.zk.ui.sys.UiFactory; import org.zkoss.zk.ui.sys.WebAppCtrl; /** * Utilities to embed ZK component(s) as a native JSF component, a JSP tag, Zimlet or others. * It allows application developers to use the native element without knowing the existence of ZK. * For example, ZK Spreadsheet for JSF is a native JSF component made in this way. * * <p>Example: <pre><code> Calendar cal = new Calendar(); Renders.render(config.getServletContext(), request, response, cal, null, out); </code></pre> * * <p>See also <a href="http://books.zkoss.org/wiki/ZK_Developer%27s_Reference/Integration/Embed_ZK_Component_in_Foreign_Framework">Embed ZK Component in Foreign Framework</a>. * * @author tomyeh * @since 5.0.5 */ public class Renders { /** Outputs the HTML tags of the given component to the given writer. * @param comp the component to output (never null). It might have child components. * @param path the request path. If null, the servlet path is assumed. * @param out the output (never null). * @since 5.0.5 */ public static final void render(ServletContext ctx, HttpServletRequest request, HttpServletResponse response, Component comp, String path, Writer out) throws ServletException, IOException { if (comp == null) throw new IllegalArgumentException(); render(ctx, request, response, new EmbedRichlet(comp), path, false, out); } /** Outputs the HTML tags of the given component to the given writer. * It is the same as <code>render(ctx, request, response, richlet, path, false, out)</code>. * * @param path the request path. If null, the servlet path is assumed. * @param out the output (never null). * @param richlet the richlet to run. If you have only one component to show and no need * process it under an execution, you could use * {@link #render(ServletContext, HttpServletRequest, HttpServletResponse, Component, String, Writer)} * instead. * @since 5.0.5 */ public static final void render(ServletContext ctx, HttpServletRequest request, HttpServletResponse response, Richlet richlet, String path, Writer out) throws ServletException, IOException { render(ctx, request, response, richlet, path, false, out); } /** Outputs the HTML tags of the given component to the given writer with * additional control. * @param path the request path. If null, the servlet path is assumed. * @param out the output (never null). * @param richlet the richlet to run. If you have only one component to show and no need * process it under an execution, you could use * {@link #render(ServletContext, HttpServletRequest, HttpServletResponse, Component, String, Writer)} * instead. * @param pageDOM whether to generate the DOM element to represent the page. * In other words, if true is specified, the content will be enclosed with * an additional DIV element representing the tag. * @since 5.0.8 */ public static final void render(ServletContext ctx, HttpServletRequest request, HttpServletResponse response, Richlet richlet, String path, boolean pageDOM, Writer out) throws ServletException, IOException { if (path == null) path = Https.getThisServletPath(request); final WebManager webman = WebManager.getWebManager(ctx); final Session sess = WebManager.getSession(ctx, request); final WebApp wapp = sess.getWebApp(); final WebAppCtrl wappc = (WebAppCtrl) wapp; final Object old = I18Ns.setup(sess, request, response, wapp.getConfiguration().getResponseCharset()); Execution exec = null; try { final Desktop desktop = webman.getDesktop(sess, request, response, path, true); if (desktop == null) //forward or redirect return; final RequestInfo ri = new RequestInfoImpl(wapp, sess, desktop, request, PageDefinitions.getLocator(wapp, path)); ((SessionCtrl) sess).notifyClientRequest(true); final UiFactory uf = wappc.getUiFactory(); final Page page = WebManager.newPage(uf, ri, richlet, response, path); exec = new ExecutionImpl(ctx, request, response, desktop, page); exec.setAttribute(Attributes.PAGE_REDRAW_CONTROL, "page"); exec.setAttribute(Attributes.PAGE_RENDERER, new PageRenderer(exec, pageDOM)); wappc.getUiEngine().execNewPage(exec, richlet, page, out); //no need to set device type here, since UiEngine will do it later } finally { I18Ns.cleanup(request, old); if (exec != null) { exec.removeAttribute(Attributes.PAGE_REDRAW_CONTROL); exec.removeAttribute(Attributes.PAGE_RENDERER); } } } //Supporting classes// private static class EmbedRichlet extends GenericRichlet { private final Component _comp; private EmbedRichlet(Component comp) { _comp = comp; } public void service(Page page) { _comp.setPage(page); } } /** * A special page renderer that renders a page without generating * the HTML tag of the page. * In other words, it generates all components directly. * @author tomyeh * @since 5.0.4 */ public static class PageRenderer implements org.zkoss.zk.ui.sys.PageRenderer { private final Execution _exec; private final boolean _pageDOM; /** Default constructor. * It is the same as <code>PageRenderer(Executions.getCurrent())</code>. */ public PageRenderer() { this(Executions.getCurrent(), false); } public PageRenderer(Execution exec) { this(exec, false); } /** * @param pageDOM whether to generate the DOM element to represent the page. * In other words, if true is specified, the content will be enclosed with * an additional DIV element representing the tag. * @since 5.0.8 */ public PageRenderer(Execution exec, boolean pageDOM) { _exec = exec; _pageDOM = pageDOM; } public void render(Page page, Writer out) throws IOException { out.write(HtmlPageRenders.outLangStyleSheets(_exec, null, null)); out.write(HtmlPageRenders.outLangJavaScripts(_exec, null, null)); if (_pageDOM) { HtmlPageRenders.outPageContent(_exec, page, out, false); return; } final Desktop desktop = _exec.getDesktop(); out.write("<script class=\"z-runonce\" type=\"text/javascript\">zkpb('"); out.write(page.getUuid()); out.write("','"); out.write(desktop.getId()); out.write("','"); out.write(getContextURI()); out.write("','"); out.write(desktop.getUpdateURI(null)); out.write("','"); out.write(desktop.getRequestPath()); out.write('\''); String style = page.getStyle(); if (style != null && style.length() > 0) { out.write(",{style:'"); out.write(style); out.write("'}"); } out.write(");zkpe();</script>\n"); for (Component root = page.getFirstRoot(); root != null; root = root.getNextSibling()) { HtmlPageRenders.outStandalone(_exec, root, out); } } private String getContextURI() { if (_exec != null) { String s = _exec.encodeURL("/"); int j = s.lastIndexOf('/'); //might have jsessionid=... return j >= 0 ? s.substring(0, j) + s.substring(j + 1) : s; } return ""; } } }