Package org.jpox.store.query

Source Code of org.jpox.store.query.QueryUtils

/**********************************************************************
Copyright (c) 2005 Andy Jefferson and others. All rights reserved.
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.


Contributors:
    ...
**********************************************************************/
package org.jpox.store.query;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Map;

import org.jpox.ClassNameConstants;
import org.jpox.ObjectManagerFactoryImpl;
import org.jpox.exceptions.JPOXUserException;
import org.jpox.util.ClassUtils;
import org.jpox.util.JPOXLogger;
import org.jpox.util.Localiser;
import org.jpox.util.TypeConversionHelper;

/**
* Utilities for use in queries.
*
* @version $Revision: 1.23 $
*/
public class QueryUtils
{
    /** Localiser for messages. */
    protected static final Localiser LOCALISER=Localiser.getInstance("org.jpox.store.Localisation",
        ObjectManagerFactoryImpl.class.getClassLoader());

    /**
     * Utility to return if the passed result class is a user-type, and so requires fields matching up.
     * @param className the class name looked for
     * @return Whether it is a user class
     */
    public static boolean resultClassIsUserType(String className)
    {
        return !resultClassIsSimple(className) &&
            !className.equals(java.util.Map.class.getName()) &&
            !className.equals(ClassNameConstants.Object);
    }

    /**
     * Utility to return if the passed result class is a simple type with a single value.
     * Checks the class name against the supported "simple" JDOQL result-class types.
     * @param className the class name looked for
     * @return Whether the result class is "simple".
     */
    public static boolean resultClassIsSimple(String className)
    {
        if (className.equals(ClassNameConstants.JAVA_LANG_BOOLEAN) ||
            className.equals(ClassNameConstants.JAVA_LANG_BYTE) ||
            className.equals(ClassNameConstants.JAVA_LANG_CHARACTER) ||
            className.equals(ClassNameConstants.JAVA_LANG_DOUBLE) ||
            className.equals(ClassNameConstants.JAVA_LANG_FLOAT) ||
            className.equals(ClassNameConstants.JAVA_LANG_INTEGER) ||
            className.equals(ClassNameConstants.JAVA_LANG_LONG) ||
            className.equals(ClassNameConstants.JAVA_LANG_SHORT) ||
            className.equals(ClassNameConstants.JAVA_LANG_STRING) ||
            className.equals(BigDecimal.class.getName()) ||
            className.equals(BigInteger.class.getName()) ||
            className.equals(java.util.Date.class.getName()) ||
            className.equals(java.sql.Date.class.getName()) ||
            className.equals(java.sql.Time.class.getName()) ||
            className.equals(java.sql.Timestamp.class.getName()) ||
            className.equals(ClassNameConstants.Object))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    /**
     * Convenience method to create an instance of the result class with the provided field
     * values, using a constructor taking the arguments. If the returned object is null there
     * is no constructor with the correct signature.
     * @param resultClass The class of results that need creating
     * @param fieldValues The field values
     * @return The result class object
     */
    public static Object createResultObjectUsingArgumentedConstructor(Class resultClass, Object[] fieldValues)
    {
        Object obj = null;
        Class[] ctrTypes = new Class[fieldValues.length];
        for (int i=0;i<ctrTypes.length;i++)
        {
            ctrTypes[i] = (fieldValues[i] != null ? fieldValues[i].getClass() : null);
        }

        Constructor ctr = ClassUtils.getConstructorWithArguments(resultClass, ctrTypes);
        if (ctr != null)
        {
            try
            {
                obj = ctr.newInstance(fieldValues);
            }
            catch (Exception e)
            {
                // do nothing
            }
        }

        return obj;
    }

    /**
     * Convenience method to create an instance of the result class with the provided field
     * values, using the default constructor and setting the fields using either public fields,
     * or setters, or a put method. If one of these parts is not found in the result class the
     * returned object is null.
     * @param resultClass Result class that we need to create an object of
     * @param resultFieldNames Names of the fields in the results
     * @param resultClassFieldNames Map of the result class fields, keyed by the field name
     * @param fieldValues The field values
     * @return The result class object
     */
    public static Object createResultObjectUsingDefaultConstructorAndSetters(Class resultClass,
            String[] resultFieldNames,
            Map resultClassFieldNames,
            Object[] fieldValues)
    {
        Object obj = null;
        try
        {
            // Create the object
            obj = resultClass.newInstance();
        }
        catch (Exception e)
        {
            String msg = LOCALISER.msg("021037", resultClass.getName());
            JPOXLogger.QUERY.error(msg);
            throw new JPOXUserException(msg);
        }

        for (int i=0;i<fieldValues.length;i++)
        {
            // Update the fields of our object with the field values
            if (!setFieldForResultObject(resultClassFieldNames, obj, resultFieldNames[i], fieldValues[i]))
            {
                String fieldType = "null";
                if (fieldValues[i] != null)
                {
                    fieldType = fieldValues[i].getClass().getName();
                }
                String msg = LOCALISER.msg("021036", resultClass.getName(),
                    resultFieldNames[i], fieldType);
                JPOXLogger.QUERY.error(msg);
                throw new JPOXUserException(msg);
            }
        }

        return obj;
    }

    /**
     * Method to set a field of an object, using set/put methods, or via a public field.
     * See JDO2 spec [14.6.12] describing the 3 ways of setting the field values
     * after creating the result object using the default constructor.
     * @param resultClassFieldName Map of the field keyed by field name
     * @param obj The object to update the field for
     * @param fieldName Name of the field
     * @param value The value to apply
     * @return Whether it was updated
     */
    private static boolean setFieldForResultObject(Map resultClassFieldNames, Object obj, String fieldName, Object value)
    {
        boolean fieldSet = false;

        // Try setting the (public) field directly
        if (!fieldSet)
        {
            String declaredFieldName = fieldName;
            Field field = (Field) resultClassFieldNames.get(fieldName.toUpperCase());
            if (field != null)
            {
                declaredFieldName = field.getName();
            }
            Field f = ClassUtils.getFieldForClass(obj.getClass(),declaredFieldName);
            if (f != null && Modifier.isPublic(f.getModifiers()))
            {
                try
                {
                    f.set(obj, value);
                    fieldSet = true;
                }
                catch (Exception e)
                {
                    // Unable to set directly, so try converting the value to the type of the field
                    Object convertedValue = TypeConversionHelper.convertTo(value, f.getType());
                    if (convertedValue != value)
                    {
                        // Value has been converted so try setting the field now
                        try
                        {
                            f.set(obj, convertedValue);
                            fieldSet = true;
                        }
                        catch (Exception e2)
                        {
                            // Do nothing since unable to convert it
                        }
                    }
                }
            }
            if (!fieldSet && JPOXLogger.QUERY.isDebugEnabled())
            {
                JPOXLogger.QUERY.debug(LOCALISER.msg("021041",
                    obj.getClass().getName(), declaredFieldName));
            }
        }

        // Try (public) setMethod()
        if (!fieldSet)
        {
            String setMethodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
            Field field = (Field) resultClassFieldNames.get(fieldName.toUpperCase());
            if (field != null)
            {
                setMethodName = "set" + fieldName.substring(0,1).toUpperCase() + field.getName().substring(1);
            }

            Class argType = null;
            if (value != null)
            {
                argType = value.getClass();
            }
            else if (field != null)
            {
                argType = field.getType();
            }
            Method m = ClassUtils.getMethodWithArgument(obj.getClass(), setMethodName, argType);
            if (m != null && Modifier.isPublic(m.getModifiers()))
            {
                // Where a set method with the exact argument type exists use it
                try
                {
                    m.invoke(obj, new Object[]{value});
                    fieldSet = true;
                }
                catch (Exception e)
                {
                    //do nothing
                }
            }
            else if (m == null)
            {
                // Find a method with the right name and a single arg and try conversion of the supplied value
                Method[] methods = obj.getClass().getDeclaredMethods();
                for (int i=0;i<methods.length;i++)
                {
                    Class[] args = methods[i].getParameterTypes();
                    if (methods[i].getName().equals(setMethodName) && Modifier.isPublic(methods[i].getModifiers()) &&
                        args != null && args.length == 1)
                    {
                        try
                        {
                            methods[i].invoke(obj, new Object[]{ClassUtils.convertValue(value, args[0])});
                            fieldSet = true;
                            break;
                        }
                        catch (Exception e)
                        {
                            //do nothing
                        }
                    }
                }
            }
            if (!fieldSet && JPOXLogger.QUERY.isDebugEnabled())
            {
                JPOXLogger.QUERY.debug(LOCALISER.msg("021039",
                    obj.getClass().getName(), setMethodName, argType.getName()));
            }
        }

        // Try (public) putMethod()
        if (!fieldSet)
        {
            Method m = getPublicPutMethodForResultClass(obj.getClass());
            if (m != null)
            {
                try
                {
                    m.invoke(obj, new Object[]{fieldName, value});
                    fieldSet = true;
                }
                catch (Exception e)
                {
                    //do nothing
                }
            }
            if (!fieldSet && JPOXLogger.QUERY.isDebugEnabled())
            {
                JPOXLogger.QUERY.debug(LOCALISER.msg("021040",
                    obj.getClass().getName(), "put"));
            }
        }

        return fieldSet;
    }

    /**
     * Convenience method to return the setXXX method for a field of the result class.
     * @param resultClass The result class
     * @param fieldName Name of the field
     * @param fieldType The type of the field being set
     * @return The setter method
     */
    public static Method getPublicSetMethodForFieldOfResultClass(Class resultClass, String fieldName, Class fieldType)
    {
        String setMethodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
        Method m = ClassUtils.getMethodWithArgument(resultClass, setMethodName, fieldType);

        if (m != null && Modifier.isPublic(m.getModifiers()))
        {
            return m;
        }
        return null;
    }

    /**
     * Convenience method to return the put(Object, Object method for the result class.
     * @param resultClass The result class
     * @return The put(Object, Object) method
     */
    public static Method getPublicPutMethodForResultClass(Class resultClass)
    {
        String putMethodName = "put";
        Method m = ClassUtils.getMethodForClass(resultClass, putMethodName, new Class[]{Object.class, Object.class});

        if (m != null && Modifier.isPublic(m.getModifiers()))
        {
            return m;
        }
        return null;
    }

    /**
     * Convenience method to split an expression string into its constituent parts where separated by commas.
     * This is used in the case of, for example, a result specification, to get the column definitions.
     * @param str The expression string
     * @return The expression parts
     */
    public static String[] getExpressionsFromString(String str)
    {
        CharacterIterator ci = new StringCharacterIterator(str);
        int braces = 0;
        String text = "";
        ArrayList exprList = new ArrayList();
        while( ci.getIndex() != ci.getEndIndex() )
        {
            char c = ci.current();
            if( c == ',' && braces == 0)
            {
                exprList.add(text);
                text = "";
            }
            else if( c == '(' )
            {
                braces++;
                text += c;
            }
            else if( c == ')' )
            {
                braces--;
                text += c;
            }
            else
            {
                text += c;
            }
            ci.next();
        }
        exprList.add(text);
        return (String[])exprList.toArray(new String[exprList.size()]);
    }
}
TOP

Related Classes of org.jpox.store.query.QueryUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.