View Javadoc

1   package com.sri.common.taglib;
2   
3   import com.jcorporate.expresso.core.security.filters.FilterManager;
4   import com.jcorporate.expresso.core.security.filters.ISO_8859_1;
5   import com.jcorporate.expresso.services.taglib.ELTagSupport;
6   import com.sri.common.controller.AbstractDBController;
7   import org.apache.log4j.Logger;
8   
9   import javax.servlet.jsp.JspException;
10  import javax.servlet.jsp.JspWriter;
11  import javax.servlet.jsp.tagext.BodyTagSupport;
12  import javax.servlet.jsp.tagext.TagSupport;
13  import java.io.IOException;
14  
15  /***
16   * Renders a tree menu tag. It renders the entire tree inside a <div> tag
17   * that may optionally have specified id (useful for javascript manipulation)
18   * or CSS class.
19   *
20   * @author Michael Rimov
21   */
22  public class TreeMenuTag extends BodyTagSupport {
23  
24      /***
25  	 * 
26  	 */
27  	private static final long serialVersionUID = 1L;
28  
29  	/***
30       * Log used primarily for logging results of expression evaluation.
31       */
32      private static final Logger LOG = Logger.getLogger(TreeMenuTag.class);
33  
34      /***
35       * Pre-allocate StringBuffer size.
36       */
37      private static final int BUFFER_SIZE = 512;
38  
39  
40      /***
41       * Instance of the filter manager for filtering attributes and content.
42       */
43      private final FilterManager filterManager = FilterManager.getInstance();
44  
45      /***
46       * The bean to render the tree menu from.
47       */
48      private String value;
49  
50      /***
51       * Name of the child frame id.
52       */
53      private String childFrame;
54  
55      /***
56       * Default tag.
57       */
58      public TreeMenuTag() {
59          super();
60      }
61  
62      /***
63       * Sets the name of the bean object we're supposed to render.  Takes
64       * an EL expression.
65       *
66       * @param object String
67       */
68      public void setValue(final String object) {
69          this.value = object;
70      }
71  
72      /***
73       * Sets the id of the child frame for a target with javascript.  (Optional)
74       *
75       * @param childFrame String
76       */
77      public void setChildFrame(final String childFrame) {
78          this.childFrame = childFrame;
79      }
80  
81      /***
82       * Retrieve the bean value.
83       *
84       * @return String
85       */
86      public String getValue() {
87          return value;
88      }
89  
90      /***
91       * Retrieve the id of the child frame to target for javascript links.
92       *
93       * @return String
94       */
95      public String getChildFrame() {
96          return childFrame;
97      }
98  
99      /***
100      * Process the end tag for this instance.
101      *
102      * @return indication of whether to continue evaluating the JSP page.
103      * @throws JspException if an error occurred while processing this tag
104      */
105     public int doEndTag() throws JspException {
106 //        if (LOG.isDebugEnabled()) {
107 //            LOG.debug("Evaluating Tree Menu Tag: value=" + this.getValue());
108 //        }
109 
110         //Evaluate the EL-expression to get the root node.
111         TreeNode rootNode = getRootNode();
112 
113         JspWriter out = pageContext.getOut();
114 
115         //Write the enclosing <div? tag
116         StringBuffer buffer = new StringBuffer(BUFFER_SIZE);
117 
118         //Write Javascript associated with the tree.
119         writeTreeJavaScript(buffer);
120 
121         //Write the tree menu
122         writeTree(rootNode, buffer);
123 
124         try {
125             out.println(buffer.toString());
126         } catch (IOException ex) {
127             LOG.warn("I/O Error writing out tree menu.", ex);
128         }
129         //Evaluate the page.
130         return TagSupport.EVAL_PAGE;
131     }
132 
133     /***
134      * Writes the javascript associated with the tree menu.
135      *
136      * @param buffer StringBuffer
137      */
138     private void writeTreeJavaScript(final StringBuffer buffer) {
139         buffer.append("<script language=\"javascript\">\n//<!--\n");
140         buffer.append("function toggleStyles(targetObject, style1, style2){\n");
141         buffer.append("\tparentObject = targetObject.parentNode;\n");
142         buffer.append("\tparentObject.className = (parentObject.className == style1) ? style2 : style1;\n");
143         buffer.append("\ttargetObject.className = parentObject.className;\n");
144         buffer.append("}\n");
145         if (getChildFrame() != null) {
146             buffer.append("function followLink(href) {\n");
147             buffer.append("\t document.getElementById(\"");
148             buffer.append(getChildFrame());
149             buffer.append("\").src=href;\n");
150             buffer.append("\t return false;");
151             buffer.append("}\n");
152         }
153         buffer.append("//-->\n</script>\n");
154     }
155 
156     /***
157      * Retrieve the root node based upon the JSTL 'value' parameter passed in.
158      *
159      * @return TreeNode the root node or throws an Exception based on the
160      *         failure of the JSTL expression.
161      * @throws JspException upon evaluation error on being unable to find the
162      *                      error, or finding an object but it isn't an instance of TreeNode.
163      */
164     private TreeNode getRootNode() throws JspException {
165         TreeNode result;
166         ELTagSupport support = ELTagSupport.getInstance();
167         try {
168             result = (TreeNode) support.evaluate("value", this.getValue(),
169                     TreeNode.class,
170                     this, this.pageContext);
171 
172             if (result == null) {
173                 throw new JspException("Unable to locate tree menu bean: " + this.getValue());
174             }
175         } catch (ClassCastException ex1) {
176             LOG.error("ClassCastException evaluating parameter 'value'", ex1);
177             throw new JspException("Received wrong type back for parameter 'value'.  Expected java.lang.String");
178         }
179 
180         return result;
181     }
182 
183     /***
184      * Function iterates over the tree nodes, rendering any of the node values, etc.
185      *
186      * @param root TreeNode the root of the nodes.
187      * @param out  JspWriter
188      * @throws JspException upon error.
189      */
190     private void writeTree(final TreeNode root, final StringBuffer out) throws JspException {
191         out.append("<ul>\n");
192         writeNode(root, out);
193         out.append("</ul>");
194     }
195 
196 
197     /***
198      * Writes the contents of one node.
199      *
200      * @param node TreeNode
201      * @param out  StringBuffer
202      * @throws JspException upon error.
203      */
204     private void writeNode(final TreeNode node, final StringBuffer out) throws JspException {
205         if (node.getNested() == TreeNode.NO_CHILDREN) {
206             writeOneLeaf(node, out);
207         } else {
208             writeOneFolder(node, out);
209         }
210     }
211 
212     /***
213      * Writes the equivilant of a folder.  Example HTML from prototype:
214      * <p><code>
215      * &lt;li class=&quot;folder-open&quot;&gt;&lt;a class=&quot;folder-open&quot; href=&quot;#&quot;
216      * onClick=&quot;toggleStyles(this, 'folder-closed', 'folder-open')
217      * ;return false;&quot;&gt;Parent&lt;/a&gt;</code><p>
218      *
219      * @param node TreeNode
220      * @param out  StringBuffer
221      * @throws JspException upon error.
222      */
223     private void writeOneFolder(final TreeNode node, final StringBuffer out) throws JspException {
224         writeNodeIconAndLink(node, out);
225 
226         TreeNode[] children = node.getNested();
227         for (int i = 0; i < children.length; i++) {
228             writeNode(children[i], out);
229         }
230         out.append("</ul>");
231         out.append("</li>\n");
232     }
233 
234     /***
235      * Writes out the node icon and link.
236      *
237      * @param node TreeNode the tree node we're rendering.
238      * @param out  StringBuffer the sink for the results.
239      * @throws JspException upon error.
240      */
241     private void writeNodeIconAndLink(final TreeNode node, final StringBuffer out) throws JspException {
242         out.append("<li class=\"");
243         if (node.isSelected()) {
244             out.append(node.getSelectedStyle());
245         } else {
246             out.append(node.getUnselectedStyle());
247         }
248         out.append("\">");
249         out.append("<a href=\"");
250         out.append((node.getLink() == null) ? "#" : node.getLink());
251         out.append("\" onClick=\"toggleStyles(this, '");
252         out.append(node.getSelectedStyle());
253         out.append("','");
254         out.append(node.getUnselectedStyle());
255         out.append("');return false;\"");
256         out.append(" class=\"");
257         out.append(node.isSelected() ? node.getSelectedStyle() : node.getUnselectedStyle());
258         out.append("\"");
259         out.append(">");
260         if (node.getLink() != null) {
261             out.append("&nbsp;</a><a href=\"");
262             final String nodeURL = node.getLink();
263             out.append(nodeURL);
264             out.append("\"");
265             try {
266                 writeFollowLinkJavascript(node, out);
267             } catch (Exception ex1) {
268                 LOG.error("Error writing link through filter", ex1);
269                 throw new JspException("Error writing link through filter.  Details Logged" + ex1.getMessage());
270             }
271             out.append(" id=\"");
272             out.append(node.getSelectedStyle());
273             out.append("\"");
274             out.append(">");
275         }
276         writeNodeIcon(node, out);
277 
278         try {
279             out.append(filterManager.filterString(node.getLabel(), ISO_8859_1.class, FilterManager.STANDARD_FILTER));
280         } catch (Exception ex) {
281             throw new JspException("Error filtering node label", ex);
282         }
283 
284         out.append("</a>\n");
285 
286         out.append("<ul>");
287     }
288 
289     /***
290      * Writes a node with no children.  Writes the equivalent of:
291      * &lt;li&gt;&lt;a class=&quot;subitem&quot; href=&quot;#&quot;&gt;Item 1&lt;/a&gt;&lt;/li&gt;
292      *
293      * @param node TreeNode
294      * @param out  StringBuffer
295      * @throws JspException upon error.
296      */
297     private void writeOneLeaf(final TreeNode node, final StringBuffer out) throws JspException {
298         try {
299             String nodeStyle = node.isSelected() ? filterManager.filterString(node.getSelectedStyle(),
300                     ISO_8859_1.class, FilterManager.STANDARD_FILTER) : filterManager.filterString(
301                     node.getUnselectedStyle(), ISO_8859_1.class, FilterManager.STANDARD_FILTER);
302 
303 //            writeNodeIconAndLink(node,out);
304             out.append("\t<li class=\"");
305             out.append(nodeStyle);
306             out.append("\">");
307             out.append("<a href=\"");
308             if (node.getLink() == null) {
309                 out.append("#");
310             } else {
311                 out.append(node.getLink());
312             }
313 
314             out.append("\"");
315             writeFollowLinkJavascript(node, out);
316             out.append(" class=\"");
317             out.append(nodeStyle);
318             out.append("\"");
319             out.append(">");
320             out.append("&nbsp;</a>");
321 
322             out.append("<a href=\"");
323             out.append(
324                     (node.getLink() == null) ? "#" : filterManager.filterString(node.getLink(), ISO_8859_1.class,
325                             FilterManager.STANDARD_FILTER));
326             out.append("\"");
327             writeFollowLinkJavascript(node, out);
328             out.append("id=\"");
329             out.append(nodeStyle);
330             out.append("\">");
331             writeNodeIcon(node, out);
332             out.append(filterManager.filterString(node.getLabel(), ISO_8859_1.class, FilterManager.STANDARD_FILTER));
333             out.append("</a>");
334             out.append("</li>\n");
335 
336         } catch (Exception ex) {
337             throw new JspException("Error filtering node label", ex);
338         }
339     }
340 
341     private void writeFollowLinkJavascript(final TreeNode node, final StringBuffer out) throws Exception {
342         if (node.getLink() != null && this.getChildFrame() != null) {
343             String nodeLink = node.getLink();
344             if (nodeLink.indexOf("&amp;") > 0) {
345                 nodeLink = nodeLink + "?" + AbstractDBController.EMBEDDED_MODE + "=Y";
346             } else {
347                 nodeLink = nodeLink + "&amp;" + AbstractDBController.EMBEDDED_MODE + "=Y";
348             }
349             out.append(" onClick=\"return followLink('");
350             out.append(
351                     filterManager.filterString(nodeLink, ISO_8859_1.class, FilterManager.STANDARD_FILTER));
352             out.append("')\" ");
353         }
354     }
355 
356     /***
357      * Writes the node icon inside its own span.
358      *
359      * @param node TreeNode the tree node for the source of the image.
360      * @param out  StringBuffer the buffer we're appending the html code to.
361      * @throws JspException upon error.
362      */
363     private void writeNodeIcon(final TreeNode node, final StringBuffer out) throws JspException {
364         try {
365             if (node.getIconUrl() != null) {
366                 out.append("<span><img src=\"");
367                 out.append(
368                         filterManager.filterString(node.getIconUrl(), ISO_8859_1.class, FilterManager.STANDARD_FILTER));
369                 out.append("\"/> </span>");
370 
371             }
372         } catch (Exception ex) {
373             throw new JspException("Error writing node icon url", ex);
374         }
375     }
376 
377 }