1 package com.panogenesis.webapp.taglib;
2
3 import java.io.IOException;
4 import java.util.List;
5 import java.util.Locale;
6
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.jsp.JspException;
9 import javax.servlet.jsp.tagext.TagSupport;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.apache.commons.validator.Field;
14 import org.apache.commons.validator.Form;
15 import org.apache.commons.validator.ValidatorResources;
16 import org.springframework.beans.factory.BeanFactoryUtils;
17 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
18 import org.springframework.context.MessageSource;
19 import org.springframework.context.NoSuchMessageException;
20 import org.springframework.validation.Errors;
21 import org.springframework.validation.ObjectError;
22 import org.springframework.validation.commons.ValidatorFactory;
23 import org.springframework.web.context.support.WebApplicationContextUtils;
24 import org.springframework.web.context.WebApplicationContext;
25 import org.springframework.web.servlet.support.RequestContext;
26 import org.springframework.web.servlet.DispatcherServlet;
27
28
29 /***
30 * <p>This class is designed to render a <label> tag for labeling your forms and
31 * adds an asterik (*) for required fields. It was originally written by Erik
32 * Hatcher (http://www.ehatchersolutions.com/JavaDevWithAnt/).</p>
33 *
34 * <p>It is designed to be used as follows:
35 * <pre><tag:label key="userForm.username" /></pre>
36 * </p>
37 *
38 * @jsp.tag name="label" bodycontent="empty"
39 */
40 public class LabelTag extends TagSupport {
41
42 protected RequestContext requestContext;
43 protected transient final Log log = LogFactory.getLog(LabelTag.class);
44 protected String key = null;
45 protected String styleClass = null;
46 protected String errorClass = null;
47 protected boolean colon = true;
48 protected boolean helpTip = false;
49
50 public int doStartTag() throws JspException {
51
52 try {
53 this.requestContext =
54 new RequestContext((HttpServletRequest) this.pageContext.getRequest());
55 }
56 catch (RuntimeException ex) {
57 throw ex;
58 }
59 catch (Exception ex) {
60 pageContext.getServletContext().log("Exception in custom tag", ex);
61 }
62
63
64 boolean requiredField = false;
65 boolean validationError = false;
66
67 ValidatorResources resources = getValidatorResources();
68
69 Locale locale = pageContext.getRequest().getLocale();
70
71 if (locale == null) {
72 locale = Locale.getDefault();
73 }
74
75
76 String formName = key.substring(0, key.indexOf('.'));
77 String fieldName = key.substring(formName.length() + 1);
78
79 if (resources != null) {
80 Form form = resources.getForm(locale, formName);
81
82 if (form != null) {
83 Field field = form.getField(fieldName);
84
85 if (field != null) {
86 if (field.isDependency("required")) {
87 requiredField = true;
88 }
89 }
90 }
91 }
92
93 Errors errors = requestContext.getErrors(formName, false);
94 List fes = null;
95 String errorMsg = null;
96 if (errors != null) {
97 fes = errors.getFieldErrors(fieldName);
98 errorMsg = getErrorMessages(fes);
99 }
100
101
102 String message = null;
103 try {
104 message = getMessageSource().getMessage(key, null, locale);
105 } catch (NoSuchMessageException nsm) {
106 message = "???" + key + "???";
107 }
108
109 String cssClass = null;
110 if (styleClass != null) {
111 cssClass = styleClass;
112 } else if (requiredField) {
113 cssClass = "required";
114 }
115
116 String cssErrorClass = (errorClass != null) ? errorClass : "error";
117 StringBuffer label = new StringBuffer();
118
119 if ((message == null) || "".equals(message.trim())) {
120 label.append("");
121 } else {
122 label.append("<label for=\"" + fieldName + "\"");
123
124 if (validationError) {
125 label.append(" class=\"" + cssErrorClass + "\"");
126 } else if (cssClass != null) {
127 label.append(" class=\"" + cssClass + "\"");
128 }
129
130 label.append(">" + ((requiredField) ? "* " : "") + message);
131 String marker = (locale.equals(Locale.FRENCH)) ? " :" : ":";
132 label.append(((colon) ? marker : "") + "</label>");
133
134 if (fes != null && fes.size() > 0) {
135
136 if (helpTip) {
137 label.append(" <a class=\"errorLink\" href=\"?\" onclick=\"showHelpTip(event, '");
138 label.append(errorMsg + "', false); return false\" ");
139 label.append("onmouseover=\"showHelpTip(event, '");
140 label.append(errorMsg + "', false); return false\" ");
141 label.append("onmouseout=\"hideHelpTip(event); return false\">");
142 }
143
144 label.append("<img class=\"validationWarning\" alt=\"");
145 label.append(getMessageSource().getMessage("icon.warning", null, locale));
146 label.append("\"");
147
148 String context =
149 ((HttpServletRequest) pageContext.getRequest()).getContextPath();
150
151 label.append("src=\"" + context);
152 label.append(getMessageSource().getMessage("icon.warning.img", null, locale));
153 label.append("\" />");
154
155 if (helpTip) {
156 label.append("</a>");
157 }
158 }
159 }
160
161
162 try {
163 writeMessage(label.toString());
164 } catch (IOException io) {
165 io.printStackTrace();
166 throw new JspException("Error writing label: " + io.getMessage());
167 }
168
169
170 return (SKIP_BODY);
171 }
172
173 /***
174 * Extract the error messages from the given ObjectError list.
175 */
176 private String getErrorMessages(List fes) throws NoSuchMessageException {
177 StringBuffer message = new StringBuffer();
178 for (int i = 0; i < fes.size(); i++) {
179 ObjectError error = (ObjectError) fes.get(i);
180 message.append(this.requestContext.getMessage(error, true));
181 }
182 return message.toString();
183 }
184
185 /***
186 * Write the message to the page.
187 * @param msg the message to write
188 * @throws IOException if writing failed
189 */
190 protected void writeMessage(String msg) throws IOException {
191 pageContext.getOut().write(msg);
192 }
193
194 /***
195 * @jsp.attribute required="true" rtexprvalue="true"
196 */
197 public void setKey(String key) {
198 this.key = key;
199 }
200
201 /***
202 * Setter for specifying whether to include colon
203 * @jsp.attribute required="false" rtexprvalue="true"
204 */
205 public void setColon(boolean colon) {
206 this.colon = colon;
207 }
208
209 /***
210 * Setter for assigning a CSS class, default is label.
211 *
212 * @jsp.attribute required="false" rtexprvalue="true"
213 */
214 public void setStyleClass(String styleClass) {
215 this.styleClass = styleClass;
216 }
217
218 /***
219 * Setter for assigning a CSS class when errors occur,
220 * defaults to labelError.
221 *
222 * @jsp.attribute required="false" rtexprvalue="true"
223 */
224 public void setErrorClass(String errorClass) {
225 this.errorClass = errorClass;
226 }
227
228 /***
229 * Setter for displaying a JavaScript popup helptip. Default
230 * is false because error text is shown next to field.
231 *
232 * @jsp.attribute required="false" rtexprvalue="true"
233 */
234 public void setHelpTip(boolean helpTip) {
235 this.helpTip = helpTip;
236 }
237
238 /***
239 * Release all allocated resources.
240 */
241 public void release() {
242 super.release();
243 key = null;
244 colon = true;
245 styleClass = null;
246 errorClass = null;
247 helpTip = false;
248 }
249
250 /***
251 * Get the validator resources from a ValidatorFactory defined in the
252 * web application context or one of its parent contexts.
253 * The bean is resolved by type (org.springframework.validation.commons.ValidatorFactory).
254 *
255 * @return ValidatorResources from a ValidatorFactory.
256 */
257 private ValidatorResources getValidatorResources() {
258
259 WebApplicationContext ctx = (WebApplicationContext) pageContext.getRequest()
260 .getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
261 ValidatorFactory factory = null;
262 try {
263 factory = (ValidatorFactory) BeanFactoryUtils
264 .beanOfTypeIncludingAncestors(ctx, ValidatorFactory.class, true, true);
265 } catch (NoSuchBeanDefinitionException e) {
266
267 ctx = WebApplicationContextUtils
268 .getRequiredWebApplicationContext(pageContext.getServletContext());
269 factory = (ValidatorFactory) BeanFactoryUtils
270 .beanOfTypeIncludingAncestors(ctx, ValidatorFactory.class, true, true);
271 }
272 return factory.getValidatorResources();
273 }
274
275
276 /***
277 * Use the application context itself for default message resolution.
278 */
279 private MessageSource getMessageSource() {
280 return requestContext.getWebApplicationContext();
281 }
282
283
284 }