/*
* Copyright 2005-2006 the original author or authors.
*
* 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 org.strecks.form.controller;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.strecks.bind.handler.BindHandler;
import org.strecks.bind.internal.BindConvertInfo;
import org.strecks.converter.ConversionState;
import org.strecks.converter.Converter;
import org.strecks.converter.handler.ConversionHandler;
import org.strecks.exceptions.ApplicationConfigurationException;
import org.strecks.exceptions.ConversionRuntimeException;
import org.strecks.util.Assert;
import org.strecks.validator.internal.MethodValidators;
import org.strecks.validator.internal.OrderedProperty;
import org.strecks.validator.internal.ValidationInfo;
/**
* Action form which handles annotation based validation, conversion and data binding
* @author Phil Zoio
*/
public class DelegatingForm extends ActionForm implements ValidForm, BindingForm, WrappingForm, Deferable
{
private static Log log = LogFactory.getLog(DelegatingForm.class);
private static final long serialVersionUID = 1L;
public static final Object CONVERSION_FAILED = new Object();
private boolean bindOutwards;
private ValidationInfo validationInfo;
private BindConvertInfo bindConvertInfo;
private Map<String, Object> convertedValues;
private ActionForm form;
public DelegatingForm(ActionForm form)
{
super();
Assert.notNull(form);
this.form = form;
}
/* **************************** validation related methods **************************** */
public void setValidationInfo(ValidationInfo validationInfo)
{
this.validationInfo = validationInfo;
}
public void setBindConvertInfo(BindConvertInfo bindConvertInfo)
{
this.bindConvertInfo = bindConvertInfo;
}
@Override
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)
{
//if validation is deferred, do not validate now
if (isDeferred()) return null;
Assert.notNull(validationInfo);
Assert.notNull(form);
ConversionHandler conversionHandler = validationInfo.getConversionHandler();
Map<OrderedProperty, MethodValidators> validators = validationInfo.getValidators();
Set<OrderedProperty> keySet = validators.keySet();
for (OrderedProperty property : keySet)
{
MethodValidators methodValidators = validators.get(property);
if (methodValidators.getRequiresConversion())
{
if (convertedValues == null)
convertedValues = new HashMap<String, Object>();
Converter converter = methodValidators.getConverter();
Object converted = null;
// catch the conversion exception, and throw
String propertyName = property.getPropertyName();
try
{
converted = conversionHandler.getAndConvertInwards(form, propertyName, converter);
if (converted != null)
{
// check that converted is actually of correct type
Class<?> converterType = methodValidators.getConverterType();
if (!converterType.isAssignableFrom(converted.getClass()))
{
String message = "Supplied value of " + propertyName + " in " + form.getClass()
+ " converted to " + converted.getClass() + " and not the "
+ converterType + " expected by one or more validators. "
+ "Check that the property contains an appropriate converter in its getter method";
log.info(message);
throw new ApplicationConfigurationException(message);
}
}
else
{
converted = ConversionState.NULL;
}
}
catch (ConversionRuntimeException e)
{
converted = ConversionState.FAILURE;
}
convertedValues.put(propertyName, converted);
}
}
return validationInfo.getValidationHandler().validate(validationInfo, form, mapping, request, convertedValues);
}
@Override
public void reset(ActionMapping mapping, HttpServletRequest request)
{
form.reset(mapping, request);
bindOutwards = false;
}
/* **************************** bind related methods **************************** */
/**
* Bind from the to the String form bean properties to the target object(s)
*/
public void bindInwards(Object actionBean)
{
Assert.notNull(bindConvertInfo);
Assert.notNull(form);
Map<String, BindHandler> bindMap = bindConvertInfo.getBindMap();
Set<String> keySet = bindMap.keySet();
for (String propertyName : keySet)
{
BindHandler bindHandler = bindMap.get(propertyName);
Object convertedValue = null;
if (convertedValues != null)
{
convertedValue = convertedValues.get(propertyName);
}
bindHandler.bindInwards(form, actionBean, convertedValue);
}
}
/**
* Bind from the target object(s) to the String form bean properties
*/
public void bindOutwards(Object actionBean)
{
Assert.notNull(bindConvertInfo);
Assert.notNull(form);
Map<String, BindHandler> bindMap = bindConvertInfo.getBindMap();
Set<String> keySet = bindMap.keySet();
for (String propertyName : keySet)
{
BindHandler bindHandler = bindMap.get(propertyName);
bindHandler.bindOutwards(form, actionBean);
}
}
public void setBindOutwards(boolean bindOutwards)
{
this.bindOutwards = true;
}
public boolean getBindOutwards()
{
return bindOutwards;
}
public ActionForm getWrappedForm()
{
return form;
}
public BindConvertInfo getBindConvertInfo()
{
return bindConvertInfo;
}
public ValidationInfo getValidationInfo()
{
return validationInfo;
}
public boolean isDeferred()
{
return false;
}
}