package org.appfuse.webapp.taglib;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.Form;
import org.apache.commons.validator.ValidatorResources;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.validation.Errors;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.support.RequestContext;
import org.springmodules.validation.commons.ValidatorFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
/**
* <p>This class is designed to render a <label> tag for labeling your forms and
* adds an asterik (*) for required fields. It was originally written by Erik
* Hatcher (http://www.ehatchersolutions.com/JavaDevWithAnt/).
* <p/>
* <p>It is designed to be used as follows:
* <pre><tag:label key="userForm.username"/></pre>
*
* @jsp.tag name="label" bodycontent="empty"
*/
public class LabelTag extends TagSupport {
private static final long serialVersionUID = -5310144023136517119L;
protected RequestContext requestContext;
protected transient final Log log = LogFactory.getLog(LabelTag.class);
protected String key = null;
protected String styleClass = null;
protected String errorClass = null;
protected boolean colon = false;
public int doStartTag() throws JspException {
try {
this.requestContext =
new RequestContext((HttpServletRequest) this.pageContext.getRequest());
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
pageContext.getServletContext().log("Exception in custom tag", ex);
}
// Look up this key to see if its a field of the current form
boolean requiredField = false;
boolean validationError = false;
ValidatorResources resources = getValidatorResources();
Locale locale = pageContext.getRequest().getLocale();
if (locale == null) {
locale = Locale.getDefault();
}
// get the name of the bean from the key
String formName = key.substring(0, key.indexOf('.'));
String fieldName = key.substring(formName.length() + 1);
if (resources != null) {
Form form = resources.getForm(locale, formName);
if (form != null) {
Field field = form.getField(fieldName);
if (field != null) {
if (field.isDependency("required") || field.isDependency("validwhen")) {
requiredField = true;
}
}
}
}
Errors errors = requestContext.getErrors(formName, false);
List fes = null;
if (errors != null) {
fes = errors.getFieldErrors(fieldName);
//String errorMsg = getErrorMessages(fes);
}
if (fes != null && fes.size() > 0) {
validationError = true;
}
// Retrieve the message string we are looking for
String message = null;
try {
message = getMessageSource().getMessage(key, null, locale);
} catch (NoSuchMessageException nsm) {
message = "???" + key + "???";
}
String cssClass = null;
if (styleClass != null) {
cssClass = styleClass;
} else if (requiredField) {
cssClass = "required";
}
String cssErrorClass = (errorClass != null) ? errorClass : "error";
StringBuilder label = new StringBuilder();
if ((message == null) || "".equals(message.trim())) {
label.append("");
} else {
label.append("<label for=\"").append(fieldName).append("\"");
if (cssClass != null) {
label.append(" class=\"").append(cssClass);
if (validationError) {
label.append(" ").append(cssErrorClass);
}
}
label.append("\">").append(message);
label.append((requiredField) ? " <span class=\"required\">*</span>" : "");
label.append((colon) ? ":" : "");
label.append("</label>");
}
// Print the retrieved message to our output writer
try {
writeMessage(label.toString());
} catch (IOException io) {
io.printStackTrace();
throw new JspException("Error writing label: " + io.getMessage());
}
// Continue processing this page
return (SKIP_BODY);
}
/**
* Extract the error messages from the given ObjectError list.
*/
/*private String getErrorMessages(List fes) throws NoSuchMessageException {
StringBuffer message = new StringBuffer();
for (int i = 0; i < fes.size(); i++) {
ObjectError error = (ObjectError) fes.get(i);
message.append(this.requestContext.getMessage(error, true));
}
return message.toString();
}*/
/**
* Write the message to the page.
*
* @param msg the message to write
* @throws java.io.IOException if writing failed
*/
protected void writeMessage(String msg) throws IOException {
pageContext.getOut().write(msg);
}
/**
* @jsp.attribute required="true" rtexprvalue="true"
*/
public void setKey(String key) {
this.key = key;
}
/**
* Setter for specifying whether to include colon
*
* @jsp.attribute required="false" rtexprvalue="true"
*/
public void setColon(boolean colon) {
this.colon = colon;
}
/**
* Setter for assigning a CSS class, default is label.
*
* @jsp.attribute required="false" rtexprvalue="true"
*/
public void setStyleClass(String styleClass) {
this.styleClass = styleClass;
}
/**
* Setter for assigning a CSS class when errors occur,
* defaults to labelError.
*
* @jsp.attribute required="false" rtexprvalue="true"
*/
public void setErrorClass(String errorClass) {
this.errorClass = errorClass;
}
/**
* Release all allocated resources.
*/
public void release() {
super.release();
key = null;
colon = false;
styleClass = null;
errorClass = null;
requestContext = null;
}
/**
* Do End Tag to clear objects from memory
*/
public final int doEndTag()
{
super.release();
key = null;
colon = false;
styleClass = null;
errorClass = null;
requestContext = null;
return 1;
}
/**
* Get the validator resources from a ValidatorFactory defined in the
* web application context or one of its parent contexts.
* The bean is resolved by type (org.springframework.validation.commons.ValidatorFactory).
*
* @return ValidatorResources from a ValidatorFactory.
*/
private ValidatorResources getValidatorResources() {
// look in servlet beans definition (i.e. action-servlet.xml)
WebApplicationContext ctx = (WebApplicationContext) pageContext.getRequest()
.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
ValidatorFactory factory = null;
try {
factory = (ValidatorFactory) BeanFactoryUtils
.beanOfTypeIncludingAncestors(ctx, ValidatorFactory.class, true, true);
} catch (NoSuchBeanDefinitionException e) {
// look in main application context (i.e. applicationContext.xml)
ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(pageContext.getServletContext());
factory = (ValidatorFactory) BeanFactoryUtils
.beanOfTypeIncludingAncestors(ctx, ValidatorFactory.class, true, true);
}
return factory.getValidatorResources();
}
/**
* Use the application context itself for default message resolution.
*/
private MessageSource getMessageSource() {
return requestContext.getWebApplicationContext();
}
}