/*
* 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.bind.handler;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.strecks.converter.ConversionState;
import org.strecks.exceptions.ApplicationRuntimeException;
import org.strecks.util.Assert;
import org.strecks.util.PropertyValueGetter;
import org.strecks.util.PropertyValueSetter;
/**
* <p>
* Adds support for binding a selection, represented by a String scalar ID value, to an object.
* </p>
* <p>
* For example suppose you want to select male or female, each represented by an instance of Gender,
* to a Person object. The form will receive a "gender id" representing a gender. This id needs to
* be type converted (for example to an Integer), then used to lookup the actual Gender object. This
* Gender object is then itself bound to a target object. The mechanism can be applied for radio
* buttons, single value check boxes, and drop down lists.
* </p>
* @see org.strecks.bind.annotations.BindSelect
*
* @author Phil Zoio
*/
public class BindSelectHandler extends AbstractBindHandler implements BindHandler
{
private static Log log = LogFactory.getLog(BindSelectHandler.class);
/**
* holds the expression of the bean to set (eg. person.gender)
*/
private String targetBeanExpression;
/**
* holds the expression of the target bean to set (eg. person)
*/
private String beanLocatingExpression;
/**
* the property for the bean part of target bean to (eg. the gender part of person.gender.id)
*/
private String beanPropertyName;
/**
* the property for the id part of target bean to (eg. the gender part of person.gender.id)
*/
private String beanPropertyIdName;
/**
* the expression to the map containing the lookups for the person
*/
private String beanLookupExpression;
/**
* the class of the id
*/
private Class beanPropertyClass;
public void bindInwards(Object form, Object actionBean, Object convertedValue)
{
checkInwardState();
Object targetBean = PropertyValueGetter.getTargetBean(form, getBeanLocatingExpression());
if (targetBean != null)
{
Object idValue = null;
if (convertedValue == null || convertedValue == ConversionState.FAILURE)
{
idValue = getAndConvertInwards(form, getPropertyDescriptor().getName(), this.getConverter());
}
else if (convertedValue == ConversionState.NULL)
{
idValue = null;
}
else
{
//use converted value if already available
idValue = convertedValue;
}
// now get corresponding value from map
Object property = PropertyValueGetter.getPropertyValue(form, getBeanLookupExpression());
Map map = getPropertyAsMap(property);
if (map != null)
{
Object mappedValue = map.get(idValue);
if (mappedValue == null)
{
if (log.isDebugEnabled())
{
log.debug("No object found in map " + form.getClass().getName() + " using epxression "
+ getBeanLookupExpression() + " using id " + idValue);
}
}
PropertyValueSetter.setPropertyValue(targetBean, this.getBeanPropertyName(), getBeanPropertyClass(),
mappedValue);
}
else
{
log.warn("Map not found for bean " + form.getClass().getName() + " using epxression "
+ getBeanLookupExpression());
}
}
}
public void bindOutwards(Object source, Object target)
{
checkOutwardState();
Object targetBean = PropertyValueGetter.getTargetBean(source, getBeanLocatingExpression());
if (targetBean != null)
{
Object selectedObject = PropertyValueGetter.getPropertyValue(targetBean, this.getBeanPropertyName());
if (selectedObject != null)
{
Object idValue = getAndConvertOutwards(selectedObject, this.getBeanPropertyIdName(), this
.getConverter());
PropertyValueSetter.setPropertyValue(source, getPropertyDescriptor(), idValue);
}
else
{
PropertyValueSetter.setPropertyValue(source, getPropertyDescriptor(), null);
}
}
}
Map getPropertyAsMap(Object property)
{
Map map = null;
if (property instanceof Map)
{
map = (Map) property;
}
else
{
if (property instanceof Collection)
{
Collection collection = (Collection) property;
map = createMap(collection);
// CollectionUtils.getMap(collection);
}
else
if (property != null)
{
throw new ApplicationRuntimeException("Property " + getBeanLookupExpression()
+ " should evaluate to a java.util.Map or java.util.Collection, not a "
+ property.getClass().getName());
}
}
return map;
}
private void checkInwardState()
{
Assert.notNull(targetBeanExpression);
Assert.notNull(beanLocatingExpression);
Assert.notNull(beanPropertyIdName);
Assert.notNull(beanLookupExpression);
Assert.notNull(beanPropertyName);
Assert.notNull(beanPropertyClass);
Assert.notNull(getConversionHandler());
Assert.notNull(getConverter());
}
private void checkOutwardState()
{
Assert.notNull(beanLocatingExpression);
Assert.notNull(beanPropertyIdName);
Assert.notNull(beanPropertyName);
Assert.notNull(beanPropertyClass);
Assert.notNull(getPropertyDescriptor());
Assert.notNull(getConversionHandler());
Assert.notNull(getConverter());
}
Map createMap(Collection collection)
{
Map map;
map = new HashMap();
for (Object item : collection)
{
addItem(map, item);
}
return map;
}
@SuppressWarnings("unchecked")
private void addItem(Map map, Object item)
{
Object itemId = PropertyValueGetter.getPropertyValue(item, beanPropertyIdName);
map.put(itemId, item);
}
/* **** getter and setters ****** */
public String getBeanLocatingExpression()
{
return beanLocatingExpression;
}
public void setBeanLocatingExpression(String beanLocatingExpression)
{
this.beanLocatingExpression = beanLocatingExpression;
//FIXME set target source property
}
public String getBeanLookupExpression()
{
return beanLookupExpression;
}
public void setBeanLookupExpression(String beanLookupExpression)
{
this.beanLookupExpression = beanLookupExpression;
//FIXME set target source property
}
public Class getBeanPropertyClass()
{
return beanPropertyClass;
}
public void setBeanPropertyClass(Class beanPropertyClass)
{
this.beanPropertyClass = beanPropertyClass;
}
public String getBeanPropertyName()
{
return beanPropertyName;
}
public void setBeanPropertyName(String beanPropertyName)
{
this.beanPropertyName = beanPropertyName;
}
public String getTargetBeanExpression()
{
return targetBeanExpression;
}
public void setTargetBeanExpression(String targetBeanExpression)
{
this.targetBeanExpression = targetBeanExpression;
//FIXME set target source property
}
public String getBeanPropertyIdName()
{
return beanPropertyIdName;
}
public void setBeanPropertyIdName(String beanPropertyIdName)
{
this.beanPropertyIdName = beanPropertyIdName;
}
}