/*
* (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.Method;
import cookxml.core.exception.FunctionHandlerException;
import cookxml.core.exception.HandlerException;
import cookxml.core.interfaces.Converter;
import cookxml.core.interfaces.Handler;
import cookxml.core.util.ClassUtils;
/**
* Ths handler deals with functions.
*
* @author Heng Yuan
* @version $Id: FunctionHandler.java 265 2007-06-10 18:47:06Z coconut $
* @since CookXml 1.0
*/
public class FunctionHandler implements Handler
{
private final Method m_method;
private final Class m_cl;
// check if we set accessible for the method before
private boolean m_access;
private FunctionHandler (Method method)
{
m_method = method;
m_cl = method.getParameterTypes ()[0];
}
public void invoke (String ns, Object obj, Object value, DecodeEngine decodeEngine) throws HandlerException
{
try
{
Method method = m_method;
if (value == null)
{
method.invoke (obj, new Object[]{ null });
if (!m_access)
{
try
{
m_method.setAccessible (true);
}
catch (Exception ex)
{
}
m_access = true;
}
return;
}
if (value instanceof String)
{
Converter converter = decodeEngine.getCookXml ().getTagLibrary ().getConverter (ns, m_cl);
if (converter != null)
value = converter.convert ((String)value, decodeEngine);
}
method.invoke (obj, new Object[]{ value });
if (!m_access)
{
try
{
m_method.setAccessible (true);
}
catch (Exception ex)
{
}
m_access = true;
}
}
catch (Exception ex)
{
throw new FunctionHandlerException (decodeEngine, ex, obj, value, m_method);
}
}
public Method getMethod ()
{
return m_method;
}
/**
* for debugging purpose.
*
* @return the method involved
*/
public String toString ()
{
return m_method.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 cl
* the class we are dealing with
* @param funcName
* the function 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 Method getMethod (Class cl, String funcName, Class valueClass)
{
Method[] methods = cl.getMethods ();
for (int i = 0; i < methods.length; ++i)
{
if (methods[i].getName ().equalsIgnoreCase (funcName))
{
Method method = methods[i];
// we need to check if it is possible to match the parameter type
Class[] params = method.getParameterTypes ();
if (params.length != 1)
continue;
if (valueClass == null)
return method;
Class targetClass = ClassUtils.getEquivalentClass (params[0]);
if (targetClass.isAssignableFrom (valueClass))
return method;
}
}
return null;
}
/**
* 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 funcName
* the function 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 funcName, Class valueClass)
{
Method[] methods = obj.getClass ().getMethods ();
for (int i = 0; i < methods.length; ++i)
{
if (methods[i].getName ().equalsIgnoreCase (funcName))
{
Method method = methods[i];
// we need to check if it is possible to match the parameter type
Class[] params = method.getParameterTypes ();
if (params.length != 1)
continue;
if (valueClass == null)
return new FunctionHandler (method);
Class targetClass = ClassUtils.getEquivalentClass (params[0]);
if (targetClass.isAssignableFrom (valueClass))
return new FunctionHandler (method);
}
}
return null;
}
}