001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.jsp.tag.basic;
016:
017: import java.io.IOException;
018: import java.io.Writer;
019: import java.util.Iterator;
020: import java.util.Locale;
021: import java.util.Map;
022: import javax.servlet.jsp.JspException;
023: import org.araneaframework.framework.ConfirmationContext;
024: import org.araneaframework.framework.ExpiringServiceContext;
025: import org.araneaframework.http.util.EnvironmentUtil;
026: import org.araneaframework.http.util.ServletUtil;
027: import org.araneaframework.jsp.tag.PresentationTag;
028: import org.araneaframework.jsp.util.JspUtil;
029: import org.araneaframework.uilib.ConfigurationContext;
030:
031: /**
032: * Aranea HTML body tag.
033: *
034: * @author Taimo Peelo (taimo@araneaframework.org)
035: *
036: * @jsp.tag
037: * name = "body"
038: * body-content = "JSP"
039: * description = "HTML BODY tag with some Aranea JSP additions."
040: */
041: public class BodyHtmlTag extends PresentationTag {
042: public static final String ONLOAD = "_ap.onload()";
043: public static final String ONUNLOAD = "_ap.onunload()";
044:
045: public static final String KEY = "org.araneaframework.jsp.tag.basic.BodyHtmlTag";
046:
047: protected String onload = ONLOAD;
048: protected String onunload = ONUNLOAD;
049:
050: /** Another bunch of HTML attributes. */
051: protected String id;
052: protected String title;
053: protected String lang;
054: protected String dir;
055:
056: /** Scripts registered by nested tags. */
057: protected StringBuffer afterBodyEndScripts = null;
058:
059: protected int doStartTag(Writer out) throws Exception {
060: int r = super .doStartTag(out);
061:
062: addContextEntry(PresentationTag.ATTRIBUTED_TAG_KEY, null);
063: addContextEntry(AttributedTagInterface.HTML_ELEMENT_KEY, null);
064: addContextEntry(KEY, this );
065:
066: JspUtil.writeOpenStartTag(out, "body");
067: JspUtil.writeAttribute(out, "style", getStyle());
068: JspUtil.writeAttribute(out, "class", getStyleClass());
069: JspUtil.writeAttribute(out, "onload", onload);
070: JspUtil.writeAttribute(out, "onunload", onunload);
071:
072: JspUtil.writeAttribute(out, "id", id);
073: JspUtil.writeAttribute(out, "title", title);
074: JspUtil.writeAttribute(out, "lang", lang);
075: JspUtil.writeAttribute(out, "dir", dir);
076:
077: JspUtil.writeCloseStartTag_SS(out);
078:
079: writeAfterBodyStartScripts(out);
080:
081: return r;
082: }
083:
084: protected int doEndTag(Writer out) throws Exception {
085: JspUtil.writeEndTag(out, "body");
086: return super .doEndTag(out);
087: }
088:
089: /* ***********************************************************************************
090: * Methods for outputting scripts after opening and closing of HTML <body> tag.
091: * ***********************************************************************************/
092:
093: /**
094: * Writes the scripts immediately following the opening of <body> tag.
095: */
096: protected void writeAfterBodyStartScripts(Writer out)
097: throws Exception {
098: JspUtil.writeOpenStartTag(out, "script");
099: JspUtil.writeAttribute(out, "type", "text/javascript");
100: JspUtil.writeCloseStartTag_SS(out);
101:
102: writeServletURLScript(out);
103: writeLocaleScript(out);
104: writeKeepAliveRegistrationScripts(out);
105: writeAjaxValidationScript(out);
106: writeConfirmationScript(out);
107:
108: writeAdditionalAfterBodyStartScripts(out);
109:
110: JspUtil.writeEndTag(out, "script");
111: }
112:
113: /** @since 1.1 */
114: protected void writeConfirmationScript(Writer out) throws Exception {
115: ConfirmationContext ctx = (ConfirmationContext) getEnvironment()
116: .getEntry(ConfirmationContext.class);
117: if (ctx == null)
118: return;
119:
120: String message = ctx.getConfirmationMessage();
121: if (message != null) {
122: out
123: .write("_ap.addClientLoadEvent(function(){ Aranea.UI.flowEventConfirm('"
124: + message + "');});");
125: }
126: }
127:
128: /** Writes scripts that register client-side keepalive events for server-side expiring services. */
129: protected void writeKeepAliveRegistrationScripts(Writer out)
130: throws JspException, IOException {
131: ExpiringServiceContext expiringServiceContext = (ExpiringServiceContext) getEnvironment()
132: .getEntry(ExpiringServiceContext.class);
133: if (expiringServiceContext == null)
134: return;
135: Map expiringServiceMap = expiringServiceContext
136: .getServiceTTLMap();
137: if (expiringServiceMap != null && !expiringServiceMap.isEmpty()) { // there are some expiring services
138: for (Iterator i = expiringServiceMap.entrySet().iterator(); i
139: .hasNext();) {
140: Map.Entry entry = (Map.Entry) i.next();
141: Object keepAliveKey = "'" + entry.getKey() + "'";
142: // TODO: keepalives are just invoked a little (4 seconds) more often from client side,
143: // than specified in configuration, there could be a better way.
144: Long serviceTTL = new Long((((Long) entry.getValue())
145: .longValue() - 4000));
146:
147: Object topServiceId = EnvironmentUtil
148: .getTopServiceId(getEnvironment());
149: Object threadServiceId = EnvironmentUtil
150: .getThreadServiceId(getEnvironment());
151:
152: String sTop = topServiceId == null ? "null" : "'"
153: + topServiceId.toString() + "'";
154: String sThread = threadServiceId == null ? "null" : "'"
155: + threadServiceId.toString() + "'";
156:
157: out
158: .write("\n_ap.addKeepAlive(AraneaPage.getDefaultKeepAlive("
159: + sTop
160: + ","
161: + sThread
162: + ","
163: + keepAliveKey
164: + "),"
165: + serviceTTL.toString() + ");\n");
166: }
167: }
168: }
169:
170: /** Writes script that makes client-side aware of container URL. */
171: protected void writeServletURLScript(Writer out) throws IOException {
172: String servletUrl = ServletUtil.getInputData(
173: pageContext.getRequest()).getContainerURL();
174:
175: String encodedServletUrl = ServletUtil.getOutputData(
176: pageContext.getRequest()).encodeURL(servletUrl);
177:
178: out.write("_ap.setServletURL('");
179: out.write(servletUrl);
180: out.write("');");
181:
182: if (!servletUrl.equals(encodedServletUrl)) {
183: String urlSuffix = encodedServletUrl.substring(servletUrl
184: .length());
185: String function = "function(url) { return (url + '"
186: + urlSuffix + "'); }";
187: out.write("_ap.override('encodeURL'," + function + ");");
188: }
189: }
190:
191: /** Writes script that makes client-side aware of server-side locale. */
192: protected void writeLocaleScript(Writer out) throws JspException,
193: IOException {
194: Locale locale = getLocalizationContext().getLocale();
195:
196: out.write("_ap.setLocale(new AraneaLocale('");
197: out.write(locale.getLanguage());
198: out.write("','");
199: out.write(locale.getCountry());
200: out.write("'));");
201: }
202:
203: /**
204: * Writes script that sets the whether Uilib {@link org.araneaframework.uilib.form.FormWidget}'s should be validated
205: * seamlessly on the background with the actions or not.
206: *
207: * @see ConfigurationContext#BACKGROUND_FORM_VALIDATION
208: * @since 1.1 */
209: protected void writeAjaxValidationScript(Writer out)
210: throws JspException, IOException {
211: Boolean validationEnabled = (Boolean) getConfiguration()
212: .getEntry(
213: ConfigurationContext.BACKGROUND_FORM_VALIDATION);
214: out.write("_ap.setBackgroundValidation("
215: + String.valueOf(validationEnabled) + ");");
216: }
217:
218: /**
219: * Writes the scripts immediately following the closing of <body> tag.
220: */
221: protected void writeAfterBodyEndScripts(Writer out)
222: throws Exception {
223: JspUtil.writeOpenStartTag(out, "script");
224: JspUtil.writeAttribute(out, "type", "text/javascript");
225: JspUtil.writeCloseStartTag_SS(out);
226:
227: writeAdditionalAfterBodyEndScripts(out);
228:
229: JspUtil.writeEndTag(out, "script");
230: }
231:
232: /**
233: * Called before closing the script tag immediately following the HTML <body> start, use for
234: * additional client-side page (AraneaPage) initialization.
235: */
236: protected void writeAdditionalAfterBodyStartScripts(Writer out)
237: throws Exception {
238: }
239:
240: /**
241: * Called before closing the script tag immediately following the HTML <body> start, use for
242: * additional client-side page (AraneaPage) initialization.
243: */
244: protected void writeAdditionalAfterBodyEndScripts(Writer out)
245: throws Exception {
246: out.write(afterBodyEndScripts.toString());
247: }
248:
249: /**
250: * Nested tags should get surrounding body tag from <code>PageContext</code> and register
251: * their body end scripts with this method.
252: */
253: public void addAfterBodyEndScript(String script) {
254: if (afterBodyEndScripts == null)
255: afterBodyEndScripts = new StringBuffer();
256: afterBodyEndScripts.append(script);
257: }
258:
259: /* ***********************************************************************************
260: * Tag attributes
261: * ***********************************************************************************/
262:
263: /**
264: * @jsp.attribute
265: * type = "java.lang.String"
266: * required = "false"
267: * description = "Overwrite the standard Aranea JSP HTML body onload event. Use with caution."
268: */
269: public void setOnload(String onload) throws JspException {
270: this .onload = (String) evaluate("onload", onload, String.class);
271: }
272:
273: /**
274: * @jsp.attribute
275: * type = "java.lang.String"
276: * required = "false"
277: * description = "Overwrite the standard Aranea JSP HTML body onunload event. Use with caution."
278: */
279: public void setOnunload(String onunload) throws JspException {
280: this .onunload = (String) evaluate("onunload", onunload,
281: String.class);
282: }
283:
284: /**
285: * @jsp.attribute
286: * type = "java.lang.String"
287: * required = "false"
288: * description = "Text direction."
289: */
290: public void setDir(String dir) {
291: this .dir = dir;
292: }
293:
294: /**
295: * @jsp.attribute
296: * type = "java.lang.String"
297: * required = "false"
298: * description = "HTML body id"
299: */
300: public void setId(String id) {
301: this .id = id;
302: }
303:
304: /**
305: * @jsp.attribute
306: * type = "java.lang.String"
307: * required = "false"
308: * description = "Language information."
309: */
310: public void setLang(String lang) {
311: this .lang = lang;
312: }
313:
314: /**
315: * @jsp.attribute
316: * type = "java.lang.String"
317: * required = "false"
318: * description = "Title."
319: */
320: public void setTitle(String title) {
321: this.title = title;
322: }
323: }
|