View Javadoc

1   /*
2    * DisplayMenuTag.java
3    *
4    * Created on February 14, 2001, 11:44 AM
5    */
6   package net.sf.navigator.taglib;
7   
8   
9   import net.sf.navigator.displayer.MenuDisplayer;
10  import net.sf.navigator.menu.MenuComponent;
11  import net.sf.navigator.menu.MenuRepository;
12  import org.apache.commons.logging.Log;
13  import org.apache.commons.logging.LogFactory;
14  import org.apache.struts.taglib.TagUtils;
15  
16  import javax.servlet.http.HttpServletRequest;
17  import javax.servlet.http.HttpServletResponse;
18  import javax.servlet.jsp.JspException;
19  import javax.servlet.jsp.tagext.TagSupport;
20  import java.io.IOException;
21  import java.net.MalformedURLException;
22  
23  
24  /**
25   * <p>The major behavior of this tag is to set the value for the usage in the
26   * HTML hyperlink 'href' attribute. The value is determined by the following
27   * attributes defined in menu-config.xml, in this prioritize order:
28   * 'location', 'page', 'forward', 'action'.
29   *
30   * <p>You can now define a 'forward' or  'action' attribute in the
31   * &lt;Item&gt; element in your menu-config.xml. The 'action' attribute takes
32   * the value of a Logical Struts Action name for which to look up the
33   * context-relative URI. The resultant URI will carry the Context
34   * Path (if any), Module Prefix (if any), Session ID (if any),
35   * and Servlet Mapping (path mapping or extension mapping). Here is
36   * an example:
37   * <pre>
38   * &lt;Menu name="indexMenuMore" title="More Examples"&gt;
39   *   &lt;Item name="actionExample"  title="Example - 'action' attribute"
40   *         <B>action="/menu/bullet"</B>/&gt;
41   *   &lt;Item name="pageExample" title="Example - 'page' attribute"
42   *         <B>page="/bulletmenu.jsp"</B>/&gt;
43   * &lt;/Menu&gt;
44   * </pre>
45   * @author ssayles, mraible
46   * @version $Revision: 1.23 $ $Date: 2006/10/22 07:16:39 $
47   */
48  public class DisplayMenuTag extends TagSupport {
49      //~ Instance fields ========================================================
50  
51      protected final static Log log = LogFactory.getLog(DisplayMenuTag.class);
52      private String name;
53      private String target;
54  
55      //~ Methods ================================================================
56      public void setName(String name) {
57          this.name = name;
58      }
59  
60      public void setTarget(String target) {
61          this.target = target;
62      }
63  
64      public int doStartTag() throws JspException {
65          MenuDisplayer displayer =
66                  (MenuDisplayer) pageContext.getAttribute(UseMenuDisplayerTag.DISPLAYER_KEY);
67  
68          if (displayer == null) {
69              throw new JspException("Could not retrieve the menu displayer.");
70          }
71  
72          // This is set by the parent tag - UseMenuDisplayerTag
73          MenuRepository repository =
74                  (MenuRepository) pageContext.getAttribute(UseMenuDisplayerTag.PRIVATE_REPOSITORY);
75  
76          if (repository == null) {
77              throw new JspException("Could not obtain the menu repository");
78          }
79  
80          MenuComponent menu = repository.getMenu(this.name);
81  
82          if (menu != null) {
83              try {
84                  // use the overridden target
85                  if (target != null) {
86                      displayer.setTarget(this.target);
87                  }
88  
89                  // set the location value to use
90                  // the context relative page attribute
91                  // if specified in the menu
92                  try {
93                      setPageLocation(menu);
94                  } catch (MalformedURLException m) {
95                      log.error("Incorrect action or forward: " + m.getMessage());
96                      log.warn("Menu '" + menu.getName() + "' location set to #");
97                      menu.setLocation("#");
98                  } 
99  
100                 displayer.display(menu);
101                 displayer.setTarget(null);
102             } catch (Exception e) {
103                 // don't swallow the exception
104                 e.printStackTrace();
105                 throw new JspException(e);
106             }
107         } else {
108             String error = UseMenuDisplayerTag.messages.getString("menu.not.found") +
109                     " " + this.name;
110             log.warn(error);
111             try {
112                 pageContext.getOut().write(error);
113             } catch (IOException io) {
114                 throw new JspException(error);
115             }
116         }
117 
118         return SKIP_BODY;
119     }
120 
121     /**
122      * Sets the value for the menu location to the
123      * appropriate value if location is null.  If location
124      * is null, and the page attribute exists, it's value
125      * will be set to the the value for page prepended with
126      * the context path of the application.
127      *
128      * If the page is null, and the forward attribute exists,
129      * it's value will be looked up in struts-config.xml.
130      *
131      *                                     FIXME - ssayles - 121102
132      * Ideally, this should happen at menu initialization but
133      * I was unable to find a reliable way to get the context path
134      * outside of a request.  The performance impact is probably
135      * negligable, but it would be better to check for this only once.
136      *
137      * @param menu The menu component to set the location for.
138      */
139     protected void setPageLocation(MenuComponent menu) throws MalformedURLException, JspException {
140         HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
141         setLocation(menu);
142         String url = menu.getLocation();
143 
144         // Check if there are parameters on the value
145         if ((url != null) && (url.indexOf("${") > -1)) {
146             String queryString = null;
147 
148             if (url.indexOf("?") > -1) {
149                 queryString = url.substring(url.indexOf("?") + 1);
150                 url = url.substring(0, url.indexOf(queryString));
151             }
152 
153             // variable is in the URL
154             if (queryString != null) {
155                 menu.setUrl(url + parseString(queryString, request));
156             } else {
157                 // parse the URL, rather than the queryString
158                 menu.setUrl(parseString(url, request).toString());
159             }
160         } else {
161             menu.setUrl(url);
162         }
163 
164         HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
165         if (menu.getUrl() != null) {
166             menu.setUrl(response.encodeURL(menu.getUrl()));
167         }
168 
169         // do all contained menus
170         MenuComponent[] subMenus = menu.getMenuComponents();
171 
172         if (subMenus.length > 0) {
173             for (int i = 0; i < subMenus.length; i++) {
174                 this.setPageLocation(subMenus[i]);
175             }
176         }
177     }
178 
179     protected void setLocation(MenuComponent menu) throws MalformedURLException {
180         // if the location attribute is null, then set it with a context relative page
181         // attribute if it exists
182         if (menu.getLocation() == null) {
183             try {
184                 if (menu.getPage() != null) {
185                     HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
186                     menu.setLocation(request.getContextPath() + getPage(menu.getPage()));
187                     HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
188                     menu.setLocation(response.encodeURL(menu.getLocation()));
189                 } else if (menu.getForward() != null) {
190                     menu.setLocation(TagUtils.getInstance().computeURL(pageContext, menu.getForward(),
191                                         null, null, null, menu.getModule(), null, null, false));
192                 } else if (menu.getAction() != null) {
193                     // generate Struts Action URL,
194                     // this will append Context Path (if any),
195                     // Servlet Mapping (path mapping or extension mapping)
196                     // Module Prefix (if any) & Session ID (if any)
197                     menu.setLocation(TagUtils.getInstance().computeURL(pageContext, null, null, null,
198                                         menu.getAction(), menu.getModule(), null, null, false));
199                 }
200             } catch (NoClassDefFoundError e) {
201                 if (menu.getForward() != null) {
202                     throw new MalformedURLException("forward '" + menu.getForward() + "' invalid - no struts.jar");
203                 } else if (menu.getAction() != null) {
204                     throw new MalformedURLException("action '" + menu.getAction() + "' invalid - no struts.jar");
205                 }
206             }
207         }
208     }
209 
210     /**
211      * Returns the value with page prepended with a "/"
212      * if it is not already.
213      *
214      * @param page The value for the page.
215      */
216     protected String getPage(String page) {
217         if (page.startsWith("/")) {
218             return page;
219         } else {
220             page = "/" + page;
221         }
222 
223         return page;
224     }
225     
226     private StringBuffer parseString(String str, HttpServletRequest request) {
227         StringBuffer sb = new StringBuffer();
228 
229         while (str.indexOf("${") >= 0) {
230             sb.append(str.substring(0, str.indexOf("${")));
231 
232             String variable = str.substring(str.indexOf("${") + 2, str.indexOf("}"));
233             String value = String.valueOf(pageContext.findAttribute(variable)); 
234 
235             if (value == null) {
236                 // look for it as a request parameter
237                 value = request.getParameter(variable);
238             }
239 
240             // is value still null?!
241             if (value == null) {
242                 log.warn("Value for '" + variable +
243                         "' not found in pageContext or as a request parameter");
244             }
245 
246             sb.append(value);
247             str = str.substring(str.indexOf("}") + 1, str.length());
248         }
249 
250         return sb.append(str);
251     }
252 
253     public void release() {
254         this.name = null;
255         this.target = null;
256     }
257 }