1 package com.randomnoun.common.webapp.taglib;
2
3 /* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
4 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
5 */
6
7 import java.io.*;
8 import java.util.*;
9
10 import jakarta.servlet.jsp.*;
11 import jakarta.servlet.jsp.tagext.*;
12
13 import com.randomnoun.common.Struct;
14 import com.randomnoun.common.Text;
15
16 /**
17 * Extends a javascript variable with a server-side resource or request attribute.
18 * The variable may contain any amount of maps or lists, which will be
19 * converted into the javascript equivalent.
20 *
21 * <p>Attributes defined for this tag (in common.tld) are:
22 * <ul>
23 * <li>baseName - the name of the javascript variable to extend
24 * <li>name - the name of the object within base (may contain sub-object names separated by '.')
25 * <li>value - the value of the javascript variable.
26 * <li>key - if defined, the value of this field within the value object is used to extend the base object.
27 * if key is supplied the object is replaced, not merged
28 * </ul>
29 *
30 * <p>Both name and value may contain EL-style expressions.
31 *
32 * @author knoxg
33 *
34 */
35 public class ExtendJavascriptVarTag
36 extends BodyTagSupport
37 {
38 /** Generated serialVersionUID */
39 private static final long serialVersionUID = -7010835090281695598L;
40
41
42 /** Base javscript object name */
43 private String baseName;
44
45 private String key;
46
47 /** The javscript variable name */
48 private String name;
49
50 // * * The string entered in the value attribute of this tag */
51 //private String valueString;
52
53 /** The calculated value of the java object to embed */
54 private Object value;
55
56 /** The method in which dates are serialised to JSON */
57 private String jsonFormat;
58
59
60 /** Sets the name of the javascript object to modify
61 *
62 * @param baseName the name of the javascript object to modify
63 */
64 public void setBaseName(String baseName)
65 {
66 this.baseName = baseName;
67 }
68
69 /**
70 * Gets the name of the javascript object to modify
71 *
72 * @return the name of the javascript object to modify
73 */
74 public String getBaseName()
75 {
76 return baseName;
77 }
78
79 /** Sets the name of the field within the object to modify
80 *
81 * @param key the name of the field within the object to modify
82 */
83 public void setKey(String key)
84 {
85 this.key = key;
86 }
87
88 /**
89 * Gets the name of the field within the object to modify
90 *
91 * @return the name of the field within the object to modify
92 */
93 public String getKey()
94 {
95 return key;
96 }
97
98 /** Sets the name of the javascript variable to generate
99 *
100 * @param name the name of the javascript variable to generate
101 */
102 public void setName(String name)
103 {
104 this.name = name;
105 }
106
107 /**
108 * Gets the name of the javascript variable to generate
109 *
110 * @return the name of the javascript variable to generate
111 */
112 public String getName()
113 {
114 return name;
115 }
116
117 /**
118 * Sets the object to convert into javascript
119 *
120 * @param value the object to convert into javascript
121 */
122 public void setValue(Object value)
123 {
124 this.value = value;
125 }
126
127 /**
128 * Returns the object to convert into javascript
129 *
130 * @return the object to convert into javascript
131 */
132 public Object getValue()
133 {
134 return value;
135 }
136
137 /** Sets the JSON format (e.g. method in which dates are serialised to JSON)
138 *
139 * @param name the JSON format
140 */
141 public void setJsonFormat(String jsonFormat)
142 {
143 this.jsonFormat = jsonFormat;
144 }
145
146 /**
147 * Gets the JSON format (e.g. method in which dates are serialised to JSON)
148 *
149 * @return the JSON format
150 */
151 public String getJsonFormat()
152 {
153 return jsonFormat;
154 }
155
156 /** doStart tag handler required to fulfill the Tag interface defined in the
157 * <a href="http://java.sun.com/products/jsp/">JSP specification</a>.
158 *
159 * This tag is always empty, and therefore must always
160 * return BodyTag.SKIP_BODY
161 *
162 * @return BodyTag.SKIP_BODY
163 */
164 @SuppressWarnings("rawtypes")
165 public int doStartTag()
166 throws jakarta.servlet.jsp.JspException
167 {
168 try {
169 JspWriter out = pageContext.getOut();
170
171 // ns = name.split('.');
172 // for (var i=0; i<ns.length; i++) { var n=ns[i]; if (!base.hasOwnProperty(n)) { obj[n]={}; } obj = obj[n]; };
173 // for (var i in obj) { if (obj.hasOwnProperty(i)) { base[i] = obj[i]; } };
174
175 out.print("(function(b,obj) {"); // b=base
176 out.print("function e(b,n){if (!b.hasOwnProperty(n)){b[n]={};}};\n");
177 //String[] names = name.split("\\.");
178 //for (String n : names) {
179 // out.print("n=\"" + Text.escapeJavascript(n) + "\";e(b,n);b=b[n];");
180 //};
181 out.print("var ns=\"" + Text.escapeJavascript(name) + "\".split('.');");
182 out.print("for (var i in ns) { e(b,ns[i]);b=b[ns[i]]; }; ");
183 if (!Text.isBlank(key)) {
184 out.print("b[obj[\"" + Text.escapeJavascript(key) + "\"]]={}; b=b[obj[\"" + Text.escapeJavascript(key) + "\"]]; ");
185 }
186 out.print("for (var i in obj) { if (obj.hasOwnProperty(i)) { b[i] = obj[i]; }}; ");
187 out.print("})(" + baseName + ", ");
188
189 if (value == null) {
190 out.append("null");
191 } else if (value instanceof String) {
192 out.append("\"");
193 out.append(Text.escapeJavascript((String) value));
194 out.append("\"");
195 } else if (value instanceof List) {
196 // out.append(Struct.structuredListToJson((List) value, jsonFormat));
197 Struct.structuredListToJson(out, (List) value, jsonFormat);
198 } else if (value instanceof Map) {
199 // out.append(Struct.structuredMapToJson((Map) value, jsonFormat));
200 Struct.structuredMapToJson(out, (Map) value, jsonFormat);
201 } else if (value instanceof Number) {
202 out.append(String.valueOf(value));
203 } else if (value instanceof Boolean) {
204 out.append(String.valueOf(value));
205 } else if (value instanceof java.util.Date) {
206 // MS-compatible JSON encoding of Dates:
207 // see http://weblogs.asp.net/bleroy/archive/2008/01/18/dates-and-json.aspx
208 // javascript += "\"\\/Date(" + ((java.util.Date)value).getTime() + ")\\/\"";
209 out.append(Struct.toDate((java.util.Date) value, jsonFormat));
210 } else if (value instanceof Struct.WriteJsonFormat) {
211 ((Struct.WriteJsonFormat) value).writeJsonFormat(out, jsonFormat);
212 } else if (value instanceof Struct.ToJsonFormat) {
213 out.append(((Struct.ToJsonFormat) value).toJson(jsonFormat));
214 } else if (value instanceof Struct.ToJson) {
215 out.append(((Struct.ToJson) value).toJson());
216 } else {
217 throw new RuntimeException("Cannot translate Java object " + value.getClass().getName() + " to javascript variable");
218 }
219 out.append(");");
220
221 // out.print(javascript);
222 } catch (IOException ex) {
223 // ignore these errors, since they can occur when the user hits 'stop' in their browser
224 } catch (Throwable t) {
225 // WAS does not log exceptions that occur within tag libraries; log and rethrow
226 t.printStackTrace();
227 throw (JspException) new JspException("Exception occurred in ExtendJavascriptVarTag").initCause(t);
228 }
229
230 return BodyTag.SKIP_BODY; // this tag always has an empty body.
231 }
232
233 /** doEnd tag handler required to fulfill the Tag interface defined in the
234 * <a href="http://java.sun.com/products/jsp/">JSP specification</a>.
235 *
236 * <p>This method does nothing, and always returns BodyTag.EVAL_PAGE
237 *
238 * @return BodyTag.EVAL_PAGE
239 */
240 public int doEndTag()
241 throws jakarta.servlet.jsp.JspException
242 {
243 name = null;
244 value = null;
245 jsonFormat = null;
246
247 return BodyTag.EVAL_PAGE;
248 }
249
250
251 }