/*
* (c) Copyright 2004 by Heng Yuan
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package cookxml.core;
import java.lang.reflect.Field;
import cookxml.core.exception.HandlerException;
import cookxml.core.exception.VariableHandlerException;
import cookxml.core.interfaces.Converter;
import cookxml.core.interfaces.Handler;
import cookxml.core.util.ClassUtils;
/**
* Ths handler deals with variables.
*
* @author Heng Yuan
* @version $Id: VariableHandler.java 265 2007-06-10 18:47:06Z coconut $
* @since CookXml 1.0
*/
public class VariableHandler implements Handler
{
private final Field m_field;
private boolean m_access;
private VariableHandler (Field field)
{
m_field = field;
}
public void invoke (String ns, Object obj, Object value, DecodeEngine decodeEngine) throws HandlerException
{
try
{
if (value == null)
{
m_field.set (obj, value);
if (!m_access)
{
try
{
m_field.setAccessible (true);
}
catch (Exception ex)
{
}
m_access = true;
}
return;
}
if (value instanceof String)
{
Class targetClass = m_field.getType ();
Converter converter = decodeEngine.getCookXml ().getTagLibrary ().getConverter (ns, targetClass);
if (converter != null)
value = converter.convert ((String)value, decodeEngine);
}
m_field.set (obj, value);
if (!m_access)
{
try
{
m_field.setAccessible (true);
}
catch (Exception ex)
{
}
m_access = true;
}
}
catch (Throwable t)
{
throw new VariableHandlerException (decodeEngine, t, obj, value, m_field);
}
}
/**
* for debugging purpose.
* @return the method involved
*/
public String toString ()
{
return m_field.toString ();
}
/**
* This function assumes that each function name is only associated with a single
* data type. Although it may be possible to switch types, but we won't be able
* to utilize cache in that case, making it rather slow to find function each
* and every time.
* @param obj
* the object we are dealing with. we are actually only interested in
* its class type.
* @param fieldName
* the field to be located in the class.
* @param valueClass
* the class type of the value, can be null to skip check.
* @return the handler which can be used to deal with the element.
*/
public static Handler getHandler (Object obj, String fieldName, Class valueClass)
{
if (fieldName == null)
return null;
Field[] fields = obj.getClass ().getFields ();
for (int i = 0; i < fields.length; ++i)
{
Field field = fields[i];
if (!field.getName ().equalsIgnoreCase (fieldName))
continue;
if (valueClass == null)
return new VariableHandler (field);
Class targetClass = ClassUtils.getEquivalentClass (field.getType ());
if (targetClass.isAssignableFrom (valueClass))
return new VariableHandler (field);
}
return null;
}
}