001: /* RootComponent.java
002:
003: {{IS_NOTE
004: Purpose:
005:
006: Description:
007:
008: History:
009: Aug 7, 2007 5:56:49 PM 2007, Created by Dennis.Chen
010: }}IS_NOTE
011:
012: Copyright (C) 2007 Potix Corporation. All Rights Reserved.
013:
014: {{IS_RIGHT
015: This program is distributed under GPL Version 2.0 in the hope that
016: it will be useful, but WITHOUT ANY WARRANTY.
017: }}IS_RIGHT
018: */
019: package org.zkoss.jsf.zul.impl;
020:
021: import java.io.IOException;
022: import java.io.StringWriter;
023: import java.io.Writer;
024: import java.util.ArrayList;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import javax.faces.context.ExternalContext;
031: import javax.faces.context.FacesContext;
032: import javax.faces.context.ResponseWriter;
033: import javax.servlet.ServletContext;
034: import javax.servlet.http.HttpServletRequest;
035: import javax.servlet.http.HttpServletResponse;
036:
037: import org.zkoss.util.logging.Log;
038: import org.zkoss.zk.scripting.Namespace;
039: import org.zkoss.zk.scripting.Namespaces;
040: import org.zkoss.zk.ui.Component;
041: import org.zkoss.zk.ui.Desktop;
042: import org.zkoss.zk.ui.Execution;
043: import org.zkoss.zk.ui.Richlet;
044: import org.zkoss.zk.ui.RichletConfig;
045: import org.zkoss.zk.ui.Session;
046: import org.zkoss.zk.ui.UiException;
047: import org.zkoss.zk.ui.WebApp;
048: import org.zkoss.zk.ui.http.ExecutionImpl;
049: import org.zkoss.zk.ui.http.WebManager;
050: import org.zkoss.zk.ui.impl.RequestInfoImpl;
051: import org.zkoss.zk.ui.metainfo.LanguageDefinition;
052: import org.zkoss.zk.ui.metainfo.PageDefinitions;
053: import org.zkoss.zk.ui.metainfo.ZScript;
054: import org.zkoss.zk.ui.sys.PageCtrl;
055: import org.zkoss.zk.ui.sys.RequestInfo;
056: import org.zkoss.zk.ui.sys.SessionCtrl;
057: import org.zkoss.zk.ui.sys.SessionsCtrl;
058: import org.zkoss.zk.ui.sys.UiFactory;
059: import org.zkoss.zk.ui.sys.WebAppCtrl;
060: import org.zkoss.zul.Label;
061:
062: /**
063: * A skeletal class to implement the root ZK Component.
064: * Currently, only the page component ({@link org.zkoss.jsf.zul.Page})
065: * extends from this class.
066: *
067: * @author Dennis.Chen
068: */
069: public class RootComponent extends AbstractComponent {
070: private static final Log log = Log.lookup(RootComponent.class);
071: private LanguageDefinition _langdef;
072: private org.zkoss.zk.ui.Page _page;
073: private String _lang = "Java";
074: private ComponentInfo _componentInfo;
075: private boolean _nested;
076:
077: // these two field must follow the value of ZkFuns
078: /** Denotes whether style sheets are generated for this request. */
079: private static final String ATTR_LANG_CSS_GENED = "javax.zkoss.zk.lang.css.generated";
080: /** Denotes whether JavaScripts are generated for this request. */
081: private static final String ATTR_LANG_JS_GENED = "javax.zkoss.zk.lang.js.generated";
082:
083: /**
084: * protected Constructor. Construct a RootTag with
085: * LanguageDefinition = "xul/html".
086: */
087: protected RootComponent() {
088: _langdef = LanguageDefinition.lookup("xul/html");
089: }
090:
091: /** Adds a child ZUL Component.
092: */
093: /*package*/void addChildZULComponent(LeafComponent child) {
094: if (child instanceof BaseUi) {
095: Component[] comps = ((BaseUi) child).getComponent();
096: for (int i = 0; i < comps.length; i++) {
097: comps[i].setPage(_page);
098: }
099: } else {
100: child.getZULComponent().setPage(_page);
101: }
102:
103: }
104:
105: /** Returns the default scripting language.
106: */
107: public String getZScriptLanguage() {
108: return _lang;
109: }
110:
111: /**
112: * Sets the default scripting language in this RootComponent.
113: *
114: * <p>Default: Java.
115: *
116: * @param lang the name of the scripting language, such as
117: * Java, Ruby and Groovy.
118: */
119: public void setZScriptLanguage(String lang) {
120: _lang = lang != null ? lang : "Java";
121: }
122:
123: /**
124: * Sets the default scripting language in this RootComponent.
125: * It is the same as {@link #setZScriptLanguage} (used to simplify
126: * the typing in JSF page).
127: */
128: public void setZscriptLanguage(String lang) {
129: setZScriptLanguage(lang);
130: }
131:
132: /**
133: * Get ComponentInfo for current Component Tree.<br/>
134: * it check a existed instance and return it, if not, a new instance will be created and return.</br>
135: */
136: protected ComponentInfo getComponentInfo() {
137: if (_componentInfo == null) {
138: _componentInfo = new ComponentInfo();
139: }
140: return _componentInfo;
141: }
142:
143: /** Initializes the page.
144: * It is called after the ZUL Page is created, and
145: * before any ZUL Component is created.
146: *
147: * <p>Default: does nothing
148: *
149: * @param exec the execution.
150: * Note: when this method is called, the execution is not activated.
151: * For example, Executions.getCurrent() returns null.
152: * @param page the page
153: */
154: protected void init(Execution exec, org.zkoss.zk.ui.Page page) {
155: }
156:
157: /**
158: * A Richlet class to handle build ZUL Component Tree.
159: * @author Dennis.Chen
160: *
161: */
162: private class MyRichlet implements Richlet {
163: FacesContext fctx;
164:
165: public MyRichlet(FacesContext fctx) {
166: this .fctx = fctx;
167: }
168:
169: public void init(RichletConfig config) {
170: }
171:
172: public void destroy() {
173: }
174:
175: public void service(org.zkoss.zk.ui.Page page) {
176:
177: FacesContext context = getFacesContext();
178: if (context == null) {
179: throw new UiException("FacesContext is null");
180: }
181: Map requestMap = (Map) context.getExternalContext()
182: .getRequestMap();
183:
184: //handle component definition
185: Map compDefs = (Map) requestMap
186: .get(BaseComponentDefinition.class.getName());
187: if (compDefs != null) {
188: for (Iterator it = compDefs.values().iterator(); it
189: .hasNext();)
190: ((BaseComponentDefinition) it.next())
191: .registerComponentDefinition(page);
192: }
193:
194: //handle initiator
195: Initiators inits = (Initiators) requestMap
196: .get(Initiators.class.getName());
197: if (inits != null)
198: inits.doInit(page);
199: try {
200: //load children
201: ComponentInfo ci = getComponentInfo();
202: List children = ci.getChildrenInfo(RootComponent.this );
203: final String bodyContent = getBodyContent();
204:
205: if (children != null) {
206: StringWriter writer = new StringWriter();
207:
208: writer.write(bodyContent);
209: for (Iterator kids = children.iterator(); kids
210: .hasNext();) {
211: AbstractComponent kid = (AbstractComponent) kids
212: .next();
213: kid.loadZULTree(page, writer);
214: }
215: if (inits != null)
216: inits.doAfterCompose(page);
217: Utils
218: .adjustChildren(
219: page,
220: RootComponent.this ,
221: ci
222: .getChildrenInfo(RootComponent.this ),
223: writer.toString()/*new String(bos.toString("UTF-8"))*/);
224:
225: //a bug? if last child of page is inline, then Messagebox.show will cause error.
226: //so, add a un-visible label to work around this.
227: Label junk = new Label();
228: junk.setVisible(false);
229:
230: //java.lang.UnsupportedOperationException
231: //at java.util.Collections$UnmodifiableCollection.add(Collections.java:1018)
232: //page.getRoots().add(junk);
233:
234: junk.setPage(page);
235:
236: } else {
237: //bug #1832862 Content disappear in JSFComponent
238: Utils.adjustChildren(page, RootComponent.this ,
239: new ArrayList(), bodyContent);
240: }
241: setBodyContent(null);//clear it;
242: } catch (Exception ex) {
243: log.realCauseBriefly(ex);
244: if (inits != null)
245: inits.doCatch(ex);
246: throw UiException.Aide.wrap(ex);
247: } finally {
248: if (inits != null)
249: inits.doFinally();
250: }
251: }
252:
253: public LanguageDefinition getLanguageDefinition() {
254: return _langdef;
255: }
256: }
257:
258: /**
259: * RootComponent was supposed to handle all children's ZScript.
260: * @param parent The owner of zscript segment.
261: * @param zs A ZScript object.
262: * @throws IOException
263: */
264: public void processZScript(Component parent, ZScript zs)
265: throws IOException {
266: if (zs.getLanguage() == null) {
267: zs.setLanguage(_page.getZScriptLanguage());
268: }
269: if (zs.isDeferred()) {
270: ((PageCtrl) _page).addDeferredZScript(parent, zs);
271: } else {
272: final Map backup = new HashMap();
273: final Namespace ns = parent != null ? Namespaces
274: .beforeInterpret(backup, parent, false)
275: : Namespaces.beforeInterpret(backup, _page, false);
276: try {
277: _page.interpret(zs.getLanguage(), zs.getContent(_page,
278: parent), ns);
279: } finally {
280: Namespaces.afterInterpret(backup, ns, false);
281: }
282: }
283: }
284:
285: StringWriter fakeSw = null;
286:
287: ResponseWriter fakeOw = null;
288:
289: public void encodeBegin(FacesContext context) throws IOException {
290:
291: /*
292: * UIComponentTagBase is the base class for all JSP tags that use
293: * the "classic" JSP tag interface that correspond to a UIComponent instance in the view.
294: * In Faces 1.2, all component tags are BodyTag instances to allow for the execution of the page to build the component tree,
295: * but not render it. Rendering happens only after the component tree is completely built.
296: *
297: * In UIComponentClassicTagBase doStartTag phrase, inline text which appears before tag will be generated to
298: * a verbatim and attached to its parent. Then, it will be cleared. In order to adapt JSF 1.2,
299: * a temporary StringWriter is needed for holding the content and assigns the content to bodyContent in
300: * encodeEnd()
301: */
302: fakeSw = new StringWriter();
303:
304: fakeOw = context.getResponseWriter();
305:
306: context.setResponseWriter(fakeOw.cloneWithWriter(fakeSw));
307:
308: if (!isRendered() || !isEffective())
309: return; //nothing to do
310: final ExternalContext exc = context.getExternalContext();
311: final HttpServletRequest request = (HttpServletRequest) exc
312: .getRequest();
313:
314: final AbstractComponent ac = (AbstractComponent) findAncestorWithClass(
315: this , AbstractComponent.class);
316:
317: if (ac != null) {
318: _nested = true;
319: } else {
320: _nested = false;
321: //skip the other zul to generate js or css which is not controlled by this page,
322: //such as <jsp:include page="other.zul"/> in a page.
323: WebManager.setRequestLocal(request, ATTR_LANG_JS_GENED,
324: Boolean.TRUE);
325: WebManager.setRequestLocal(request, ATTR_LANG_CSS_GENED,
326: Boolean.TRUE);
327: }
328: }
329:
330: /**
331: * Override Method,
332: * When encodeEnd in RootComponent, all it's children ZULJSF Component has encoded,
333: * then we start initial the ZK environment, and initial ZUL component by calling {@link AbstractComponent#loadZULTree} of each children under RootComponent.
334: */
335: public void encodeEnd(FacesContext context) throws IOException {
336: if (!isRendered() || !isEffective())
337: return; //nothing to do
338:
339: //for providing page initial and render
340: final WebApp _wapp;
341: final WebAppCtrl _wappc;
342: final Execution _exec;
343: final Richlet _richlet;
344:
345: final ExternalContext exc = context.getExternalContext();
346: final ServletContext svlctx = (ServletContext) exc.getContext();
347: final HttpServletRequest request = (HttpServletRequest) exc
348: .getRequest();
349: final HttpServletResponse response = (HttpServletResponse) exc
350: .getResponse();
351:
352: final WebManager webman = WebManager.getWebManager(svlctx);
353: final Session sess = WebManager.getSession(svlctx, request);
354:
355: if (!_nested) {
356: WebManager.setRequestLocal(request, ATTR_LANG_JS_GENED,
357: null);
358: WebManager.setRequestLocal(request, ATTR_LANG_CSS_GENED,
359: null);
360: }
361: /*
362: * UIComponentTagBase is the base class for all JSP tags that use
363: * the "classic" JSP tag interface that correspond to a UIComponent instance in the view.
364: * In Faces 1.2, all component tags are BodyTag instances to allow for the execution of the page to build the component tree,
365: * but not render it. Rendering happens only after the component tree is completely built.
366: *
367: * In UIComponentClassicTagBase doStartTag phrase, inline text which appears before tag will be generated to
368: * a verbatim and attached to its parent. Then, it will be cleared. In order to adapt JSF 1.2,
369: * a temporary StringWriter is needed for holding the content and assigns the content to bodyContent in
370: * encodeEnd()
371: */
372: context.setResponseWriter(fakeOw);
373: fakeSw.close();
374: String content = fakeSw.toString();
375: if (this .getBodyContent() != null) {
376: content = fakeSw.toString() + this .getBodyContent();
377: }
378:
379: fakeSw = null;
380:
381: this .setBodyContent(content);
382:
383: //TODO check push
384: //RequestContexts.push(pgctx);
385:
386: SessionsCtrl.setCurrent(sess);
387: try {
388: _wapp = sess.getWebApp();
389: _wappc = (WebAppCtrl) _wapp;
390:
391: //final Desktop desktop = webman.getDesktop(sess, request, null, true);
392:
393: String requestPath = context.getViewRoot().getViewId();
394: final Desktop desktop = webman.getDesktop(sess, request,
395: response, requestPath, true);
396: final RequestInfo ri = new RequestInfoImpl(_wapp, sess,
397: desktop, request, PageDefinitions.getLocator(_wapp,
398: null));
399: ((SessionCtrl) sess).notifyClientRequest(true);
400:
401: final UiFactory uf = _wappc.getUiFactory();
402:
403: _richlet = new MyRichlet(context);
404: _page = uf.newPage(ri, _richlet, null);
405: if (_lang != null)
406: _page.setZScriptLanguage(_lang);
407:
408: _exec = new ExecutionImpl(svlctx, request, response,
409: desktop, _page);
410: _exec.setAttribute(PageCtrl.ATTR_REDRAW_BY_INCLUDE,
411: Boolean.TRUE);
412: //Always use include; not forward
413:
414: init(_exec, _page); //initialize the page
415: _wappc.getUiEngine().execNewPage(_exec, _richlet, _page,
416: context.getResponseWriter());
417: } finally {
418: SessionsCtrl.setCurrent(null);
419: //RequestContexts.pop();
420: }
421: }
422:
423: /**
424: * Override Method, save the state of this component.
425: */
426: public Object saveState(FacesContext context) {
427: Object values[] = new Object[2];
428: values[0] = super .saveState(context);
429: values[1] = _lang;
430: return (values);
431: }
432:
433: /**
434: * Override Method, restore the state of this component.
435: */
436: public void restoreState(FacesContext context, Object state) {
437:
438: Object values[] = (Object[]) state;
439: super .restoreState(context, values[0]);
440: _lang = ((String) values[1]);
441: }
442:
443: }
|