1
2
3
4
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 * <Item> 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 * <Menu name="indexMenuMore" title="More Examples">
39 * <Item name="actionExample" title="Example - 'action' attribute"
40 * <B>action="/menu/bullet"</B>/>
41 * <Item name="pageExample" title="Example - 'page' attribute"
42 * <B>page="/bulletmenu.jsp"</B>/>
43 * </Menu>
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
50
51 protected final static Log log = LogFactory.getLog(DisplayMenuTag.class);
52 private String name;
53 private String target;
54
55
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
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
85 if (target != null) {
86 displayer.setTarget(this.target);
87 }
88
89
90
91
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
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
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
154 if (queryString != null) {
155 menu.setUrl(url + parseString(queryString, request));
156 } else {
157
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
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
181
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
194
195
196
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
237 value = request.getParameter(variable);
238 }
239
240
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 }