Package com.espertech.esper.event.bean

Source Code of com.espertech.esper.event.bean.PropertyHelper

/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
* http://esper.codehaus.org                                                          *
* http://www.espertech.com                                                           *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license       *
* a copy of which has been included with this distribution in the license.txt file.  *
**************************************************************************************/
package com.espertech.esper.event.bean;

import com.espertech.esper.client.EventPropertyGetter;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.event.EventPropertyType;
import com.espertech.esper.event.WriteablePropertyDescriptor;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.beans.*;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.*;

/**
* This class offers utililty methods around introspection and CGLIB interaction.
*/
public class PropertyHelper
{
    /**
     * Return getter for the given method and CGLIB FastClass.
     * @param method to return getter for
     * @param fastClass is the CGLIB fast classs to make FastMethod for
     * @param eventAdapterService factory for event beans and event types
     * @return property getter
     */
    public static EventPropertyGetter getGetter(Method method, FastClass fastClass, EventAdapterService eventAdapterService)
    {
        // Get CGLib fast method handle
        FastMethod fastMethod = null;
        try
        {
            if (fastClass != null)
            {
                fastMethod = fastClass.getMethod(method);
            }
        }
        catch (Throwable ex)
        {
            log.warn(".getAccessors Unable to obtain CGLib fast method implementation, msg=" + ex.getMessage());
        }

        // Construct the appropriate property getter CGLib or reflect
        EventPropertyGetter getter;
        if (fastMethod != null)
        {
            getter = new CGLibPropertyGetter(method, fastMethod, eventAdapterService);
        }
        else
        {
            getter = new ReflectionPropMethodGetter(method, eventAdapterService);
        }

        return getter;
    }

    /**
     * Introspects the given class and returns event property descriptors for each property found
     * in the class itself, it's superclasses and all interfaces this class and the superclasses implements.
     * @param clazz is the Class to introspect
     * @return list of properties
     */
    public static List<InternalEventPropDescriptor> getProperties(Class clazz)
    {
        // Determine all interfaces implemented and the interface's parent interfaces if any
        Set<Class> propertyOrigClasses = new HashSet<Class>();
        getImplementedInterfaceParents(clazz, propertyOrigClasses);

        // Add class itself
        propertyOrigClasses.add(clazz);

        // Get the set of property names for all classes
        return getPropertiesForClasses(propertyOrigClasses);
    }

    /**
     * Introspects the given class and returns event property descriptors for each writable property found
     * in the class itself, it's superclasses and all interfaces this class and the superclasses implements.
     * @param clazz is the Class to introspect
     * @return list of properties
     */
    public static Set<WriteablePropertyDescriptor> getWritableProperties(Class clazz)
    {
        // Determine all interfaces implemented and the interface's parent interfaces if any
        Set<Class> propertyOrigClasses = new HashSet<Class>();
        getImplementedInterfaceParents(clazz, propertyOrigClasses);

        // Add class itself
        propertyOrigClasses.add(clazz);

        // Get the set of property names for all classes
        return getWritablePropertiesForClasses(propertyOrigClasses);
    }

    private static void getImplementedInterfaceParents(Class clazz, Set<Class> classesResult)
    {
        Class[] interfaces = clazz.getInterfaces();

        if (interfaces == null)
        {
            return;
        }

        for (int i = 0; i < interfaces.length; i++)
        {
            classesResult.add(interfaces[i]);
            getImplementedInterfaceParents(interfaces[i], classesResult);
        }
    }

    private static Set<WriteablePropertyDescriptor> getWritablePropertiesForClasses(Set<Class> propertyClasses)
    {
      Set<WriteablePropertyDescriptor> result = new HashSet<WriteablePropertyDescriptor>();

        for (Class clazz : propertyClasses)
        {
          addIntrospectPropertiesWritable(clazz, result);
        }

        return result;
    }

    private static List<InternalEventPropDescriptor> getPropertiesForClasses(Set<Class> propertyClasses)
    {
      List<InternalEventPropDescriptor> result = new LinkedList<InternalEventPropDescriptor>();

        for (Class clazz : propertyClasses)
        {
          addIntrospectProperties(clazz, result);
            addMappedProperties(clazz, result);
        }

        removeDuplicateProperties(result);
        removeJavaProperties(result);

        return result;
    }

    /**
     * Remove Java language specific properties from the given list of property descriptors.
     * @param properties is the list of property descriptors
     */
    protected static void removeJavaProperties(List<InternalEventPropDescriptor> properties)
    {
        List<InternalEventPropDescriptor> toRemove = new LinkedList<InternalEventPropDescriptor>();

        // add removed entries to separate list
        for (InternalEventPropDescriptor desc : properties)
        {
            if ((desc.getPropertyName().equals("class")) ||
                (desc.getPropertyName().equals("getClass")) ||
                (desc.getPropertyName().equals("toString")) ||
                (desc.getPropertyName().equals("hashCode")))
            {
                toRemove.add(desc);
            }
        }

        // remove
        for (InternalEventPropDescriptor desc : toRemove)
        {
            properties.remove(desc);
        }
    }

    /**
     * Removed duplicate properties using the property name to find unique properties.
     * @param properties is a list of property descriptors
     */
    protected static void removeDuplicateProperties(List<InternalEventPropDescriptor> properties)
    {
        LinkedHashMap<String, InternalEventPropDescriptor> set = new LinkedHashMap<String, InternalEventPropDescriptor>();
        List<InternalEventPropDescriptor> toRemove = new LinkedList<InternalEventPropDescriptor>();

        // add duplicates to separate list
        for (InternalEventPropDescriptor desc : properties)
        {
            if (set.containsKey(desc.getPropertyName()))
            {
                toRemove.add(desc);
                continue;
            }
            set.put(desc.getPropertyName(), desc);
        }

        // remove duplicates
        for (InternalEventPropDescriptor desc : toRemove)
        {
            properties.remove(desc);
        }
    }

    /**
     * Adds to the given list of property descriptors the properties of the given class
     * using the Introspector to introspect properties. This also finds array and indexed properties.
     * @param clazz to introspect
     * @param result is the list to add to
     */
    protected static void addIntrospectProperties(Class clazz, List<InternalEventPropDescriptor> result)
    {
        PropertyDescriptor properties[] = introspect(clazz);
        for (int i = 0; i < properties.length; i++)
        {
            PropertyDescriptor property = properties[i];
          String propertyName = property.getName();
          Method readMethod = property.getReadMethod();

          EventPropertyType type = EventPropertyType.SIMPLE;
          if (property instanceof IndexedPropertyDescriptor)
          {
                readMethod = ((IndexedPropertyDescriptor) property).getIndexedReadMethod();
            type = EventPropertyType.INDEXED;
          }

            if (readMethod == null)
            {
                continue;
            }

            result.add(new InternalEventPropDescriptor(propertyName, readMethod, type));
        }
    }
  
    private static void addIntrospectPropertiesWritable(Class clazz, Set<WriteablePropertyDescriptor> result)
    {
        PropertyDescriptor properties[] = introspect(clazz);
        for (int i = 0; i < properties.length; i++)
        {
            PropertyDescriptor property = properties[i];
          String propertyName = property.getName();
          Method writeMethod = property.getWriteMethod();

            if (writeMethod == null)
            {
                continue;
            }

            result.add(new WriteablePropertyDescriptor(propertyName, writeMethod.getParameterTypes()[0], writeMethod));
        }
    }

    /**
     * Adds to the given list of property descriptors the mapped properties, ie.
     * properties that have a getter method taking a single String value as a parameter.
     * @param clazz to introspect
     * @param result is the list to add to
     */
    protected static void addMappedProperties(Class clazz, List<InternalEventPropDescriptor> result)
    {
        Set<String> uniquePropertyNames = new HashSet<String>();
      Method[] methods = clazz.getMethods();

      for (int i = 0; i < methods.length; i++)
      {
        String methodName = methods[i].getName();
        if (!methodName.startsWith("get"))
        {
          continue;
        }

        String inferredName = methodName.substring(3, methodName.length());
        if (inferredName.length() == 0)
        {
          continue;
        }

        Class<?> parameterTypes[] = methods[i].getParameterTypes();
        if (parameterTypes.length != 1)
        {
          continue;
        }

        if (parameterTypes[0] != String.class)
        {
          continue;
        }

        String newInferredName = null;
            // Leave uppercase inferred names such as URL
        if (inferredName.length() >= 2)
            {
                if ((Character.isUpperCase(inferredName.charAt(0))) &&
              (Character.isUpperCase(inferredName.charAt(1))))
                {
                    newInferredName = inferredName;
                }
            }
        // camelCase the inferred name
            if (newInferredName == null)
        {
          newInferredName = Character.toString(Character.toLowerCase(inferredName.charAt(0)));
          if (inferredName.length() > 1)
          {
            newInferredName += inferredName.substring(1, inferredName.length());
          }
        }
        inferredName = newInferredName;

            // if the property inferred name already exists, don't supply it
            if (uniquePropertyNames.contains(inferredName))
            {
                continue;
            }

        result.add(new InternalEventPropDescriptor(inferredName, methods[i], EventPropertyType.MAPPED));
            uniquePropertyNames.add(inferredName);
      }
    }

    /**
     * Using the Java Introspector class the method returns the property descriptors obtained through introspection.
     * @param clazz to introspect
     * @return array of property descriptors
     */
    protected static PropertyDescriptor[] introspect(Class clazz)
    {
        BeanInfo beanInfo;

        try
        {
            beanInfo = Introspector.getBeanInfo(clazz);
        }
        catch (IntrospectionException e)
        {
            return (new PropertyDescriptor[0]);
        }

        return beanInfo.getPropertyDescriptors();
    }

    public static String getGetterMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "get");
    }

    public static String getSetterMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "set");
    }

    public static String getIsMethodName(String propertyName)
    {
        return getGetterSetterMethodName(propertyName, "is");
    }

    private static String getGetterSetterMethodName(String propertyName, String operation)
    {
        StringWriter writer = new StringWriter();
        writer.write(operation);
        writer.write(Character.toUpperCase(propertyName.charAt(0)));
        writer.write(propertyName.substring(1));
        return writer.toString();
    }

    private static final Log log = LogFactory.getLog(PropertyHelper.class);
}
TOP

Related Classes of com.espertech.esper.event.bean.PropertyHelper

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.