/* Copyright 2005-2006 Tim Fennell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.stripes.tag;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.ParameterName;
import net.sourceforge.stripes.controller.StripesConstants;
import net.sourceforge.stripes.exception.StripesJspException;
import net.sourceforge.stripes.util.CryptoUtil;
import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.util.bean.BeanUtil;
import net.sourceforge.stripes.util.bean.ExpressionException;
import net.sourceforge.stripes.validation.ValidationErrors;
import net.sourceforge.stripes.validation.ValidationMetadata;
/**
* <p>Default implementation of the form input tag population strategy. First looks to see if there
* is a parameter with the same name as the tag submitted in the current request. If there is,
* it will be returned as a String[] in order to support multiple-value parameters.</p>
*
* <p>If there is no value in the request then an ActionBean bound to the current form will be
* looked for. If the ActionBean is found and the value is non-null it will be returned.
* If no value can be found in either place, null will returned.
*
* @author Tim Fennell
*/
public class DefaultPopulationStrategy implements PopulationStrategy {
/** Configuration object handed to the class at init time. */
private Configuration config;
/** Log used to log any errors that occur. */
private static final Log log = Log.getInstance(DefaultPopulationStrategy.class);
/** Called by the Configuration to configure the component. */
public void init(Configuration configuration) throws Exception {
this.config = configuration;
}
/** Accessor for the configuration supplied when the population strategy is initialized. */
protected Configuration getConfiguration() {
return this.config;
}
/**
* Implementation of the interface method that will follow the search described in the class
* level JavaDoc and attempt to find a value for this tag.
*
* @param tag the form input tag whose value to populate
* @return Object will be one of null, a single Object or an Array of Objects depending upon
* what was submitted in the prior request, and what is declared on the ActionBean
*/
public Object getValue(InputTagSupport tag) throws StripesJspException {
// Look first for something that the user submitted in the current request
Object value = getValuesFromRequest(tag);
// If that's not there, let's look on the ActionBean
if (value == null) {
value = getValueFromActionBean(tag);
}
// And if there's no value there, look at the tag's own value
if (value == null) {
value = getValueFromTag(tag);
}
return value;
}
/**
* Helper method that will check the current request for user submitted values for the
* tag supplied and return them as a String[] if there is one or more present.
*
* @param tag the tag whose values to look for
* @return a String[] if values are found, null otherwise
*/
protected String[] getValuesFromRequest(InputTagSupport tag) throws StripesJspException {
String[] value = tag.getPageContext().getRequest().getParameterValues(tag.getName());
/*
* If the value was pulled from a request parameter and the ActionBean property it would
* bind to is flagged as encrypted, then the value needs to be decrypted now.
*/
if (value != null) {
// find the action bean class we're dealing with
Class<? extends ActionBean> beanClass = tag.getParentFormTag().getActionBeanClass();
if (beanClass != null) {
ValidationMetadata validate = config.getValidationMetadataProvider()
.getValidationMetadata(beanClass, new ParameterName(tag.getName()));
if (validate != null && validate.encrypted()) {
String[] copy = new String[value.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = CryptoUtil.decrypt(value[i]);
}
value = copy;
}
}
}
return value;
}
/**
* Helper method that will check to see if there is an ActionBean present in the request,
* and if so, retrieve the value for this tag from the ActionBean.
*
* @param tag the tag whose values to look for
* @return an Object, possibly null, representing the tag's value
*/
protected Object getValueFromActionBean(InputTagSupport tag) throws StripesJspException {
ActionBean actionBean = tag.getParentFormTag().getActionBean();
Object value = null;
if (actionBean != null) {
try {
value = BeanUtil.getPropertyValue(tag.getName(), actionBean);
}
catch (ExpressionException ee) {
if (!StripesConstants.SPECIAL_URL_KEYS.contains(tag.getName())) {
log.info("Could not find property [", tag.getName(), "] on ActionBean.", ee);
}
}
}
return value;
}
/**
* Helper method that will retrieve the preferred value set on the tag in the JSP. For
* most tags this is usually the body if it is present, or the value attribute. In some
* cases tags implement this differently, notably the radio and checkbox tags.
*
* @param tag the tag that is being repopulated
* @return a value for the tag if one is specified on the JSP
*/
protected Object getValueFromTag(InputTagSupport tag) {
return tag.getValueOnPage();
}
/**
* Helper method that will check to see if the form containing this tag is being rendered
* as a result of validation errors. This is not actually used by the default strategy,
* but is here to help subclasses provide different behaviour for when the form is rendering
* normally vs. in error.
*
* @param tag the tag that is being repopulated
* @return boolean true if the form is in error, false otherwise
*/
protected boolean isFormInError(InputTagSupport tag) throws StripesJspException {
boolean inError = false;
ActionBean actionBean = tag.getParentFormTag().getActionBean();
if (actionBean != null) {
ValidationErrors errors = actionBean.getContext().getValidationErrors();
inError = (errors != null && errors.size() > 0);
}
return inError;
}
}