View Javadoc
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 }