/************************************************************************************** * 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.property; import com.asper.sources.net.sf.cglib.reflect.FastClass; import com.asper.sources.net.sf.cglib.reflect.FastMethod; import com.espertech.esper.client.EventPropertyGetter; import com.espertech.esper.client.EventType; import com.espertech.esper.event.EventAdapterService; import com.espertech.esper.event.EventPropertyGetterAndIndexed; import com.espertech.esper.event.EventTypeUtility; import com.espertech.esper.event.arr.ObjectArrayArrayPOJOEntryIndexedPropertyGetter; import com.espertech.esper.event.arr.ObjectArrayArrayPropertyGetter; import com.espertech.esper.event.arr.ObjectArrayEventPropertyGetterAndIndexed; import com.espertech.esper.event.bean.*; import com.espertech.esper.event.map.MapArrayPOJOEntryIndexedPropertyGetter; import com.espertech.esper.event.map.MapArrayPropertyGetter; import com.espertech.esper.event.map.MapEventPropertyGetterAndIndexed; import com.espertech.esper.event.map.MapEventType; import com.espertech.esper.event.xml.*; import com.espertech.esper.util.JavaClassHelper; import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import java.util.Map; /** * Represents an indexed property or array property, ie. an 'value' property with read method getValue(int index) * or a 'array' property via read method getArray() returning an array. */ public class IndexedProperty extends PropertyBase { private int index; public IndexedProperty(String propertyName) { super(propertyName); } /** * Ctor. * @param propertyName is the property name * @param index is the index to use to access the property value */ public IndexedProperty(String propertyName, int index) { super(propertyName); this.index = index; } public boolean isDynamic() { return false; } public String[] toPropertyArray() { return new String[] {this.getPropertyNameAtomic()}; } /** * Returns index for indexed access. * @return index value */ public int getIndex() { return index; } public EventPropertyGetterAndIndexed getGetter(BeanEventType eventType, EventAdapterService eventAdapterService) { FastClass fastClass = eventType.getFastClass(); InternalEventPropDescriptor propertyDesc = eventType.getIndexedProperty(propertyNameAtomic); if (propertyDesc != null) { if (fastClass != null) { Method method = propertyDesc.getReadMethod(); FastMethod fastMethod = fastClass.getMethod(method); return new KeyedFastPropertyGetter(fastMethod, index, eventAdapterService); } else { return new KeyedMethodPropertyGetter(propertyDesc.getReadMethod(), index, eventAdapterService); } } // Try the array as a simple property propertyDesc = eventType.getSimpleProperty(propertyNameAtomic); if (propertyDesc == null) { return null; } Class returnType = propertyDesc.getReturnType(); if (returnType.isArray()) { if (propertyDesc.getReadMethod() != null) { Method method = propertyDesc.getReadMethod(); if (fastClass != null) { FastMethod fastMethod = fastClass.getMethod(method); return new ArrayFastPropertyGetter(fastMethod, index, eventAdapterService); } else { return new ArrayMethodPropertyGetter(method, index, eventAdapterService); } } else { Field field = propertyDesc.getAccessorField(); return new ArrayFieldPropertyGetter(field, index, eventAdapterService); } } else if (JavaClassHelper.isImplementsInterface(returnType, List.class)) { if (propertyDesc.getReadMethod() != null) { Method method = propertyDesc.getReadMethod(); if (fastClass != null) { FastMethod fastMethod = fastClass.getMethod(method); return new ListFastPropertyGetter(method, fastMethod, index, eventAdapterService); } else { return new ListMethodPropertyGetter(method, index, eventAdapterService); } } else { Field field = propertyDesc.getAccessorField(); return new ListFieldPropertyGetter(field, index, eventAdapterService); } } else if (JavaClassHelper.isImplementsInterface(returnType, Iterable.class)) { if (propertyDesc.getReadMethod() != null) { Method method = propertyDesc.getReadMethod(); if (fastClass != null) { FastMethod fastMethod = fastClass.getMethod(method); return new IterableFastPropertyGetter(method, fastMethod, index, eventAdapterService); } else { return new IterableMethodPropertyGetter(method, index, eventAdapterService); } } else { Field field = propertyDesc.getAccessorField(); return new IterableFieldPropertyGetter(field, index, eventAdapterService); } } return null; } public GenericPropertyDesc getPropertyTypeGeneric(BeanEventType eventType, EventAdapterService eventAdapterService) { InternalEventPropDescriptor descriptor = eventType.getIndexedProperty(propertyNameAtomic); if (descriptor != null) { return new GenericPropertyDesc(descriptor.getReturnType()); } // Check if this is an method returning array which is a type of simple property descriptor = eventType.getSimpleProperty(propertyNameAtomic); if (descriptor == null) { return null; } Class returnType = descriptor.getReturnType(); if (returnType.isArray()) { return new GenericPropertyDesc(returnType.getComponentType()); } else if (JavaClassHelper.isImplementsInterface(returnType, Iterable.class)) { if (descriptor.getReadMethod() != null) { Class genericType = JavaClassHelper.getGenericReturnType(descriptor.getReadMethod(), false); return new GenericPropertyDesc(genericType); } else if (descriptor.getAccessorField() != null) { Class genericType = JavaClassHelper.getGenericFieldType(descriptor.getAccessorField(), false); return new GenericPropertyDesc(genericType); } else { return null; } } return null; } public Class getPropertyType(BeanEventType eventType, EventAdapterService eventAdapterService) { InternalEventPropDescriptor descriptor = eventType.getIndexedProperty(propertyNameAtomic); if (descriptor != null) { return descriptor.getReturnType(); } // Check if this is an method returning array which is a type of simple property descriptor = eventType.getSimpleProperty(propertyNameAtomic); if (descriptor == null) { return null; } Class returnType = descriptor.getReturnType(); if (returnType.isArray()) { return returnType.getComponentType(); } else if (JavaClassHelper.isImplementsInterface(returnType, Iterable.class)) { if (descriptor.getReadMethod() != null) { return JavaClassHelper.getGenericReturnType(descriptor.getReadMethod(), false); } else if (descriptor.getAccessorField() != null) { return JavaClassHelper.getGenericFieldType(descriptor.getAccessorField(), false); } else { return null; } } return null; } public Class getPropertyTypeMap(Map optionalMapPropTypes, EventAdapterService eventAdapterService) { Object type = optionalMapPropTypes.get(propertyNameAtomic); if (type == null) { return null; } if (type instanceof String) // resolve a property that is a map event type { String nestedName = type.toString(); boolean isArray = EventTypeUtility.isPropertyArray(nestedName); if (isArray) { nestedName = EventTypeUtility.getPropertyRemoveArray(nestedName); } EventType innerType = eventAdapterService.getExistsTypeByName(nestedName); if (!(innerType instanceof MapEventType)) { return null; } if (!isArray) { return null; // must be declared as an index to use array notation } else { return Map[].class; } } else { if (!(type instanceof Class)) { return null; } if (!((Class) type).isArray()) { return null; } return ((Class) type).getComponentType(); } } public MapEventPropertyGetterAndIndexed getGetterMap(Map optionalMapPropTypes, EventAdapterService eventAdapterService) { Object type = optionalMapPropTypes.get(propertyNameAtomic); if (type == null) { return null; } if (type instanceof String) // resolve a property that is a map event type { String nestedName = type.toString(); boolean isArray = EventTypeUtility.isPropertyArray(nestedName); if (isArray) { nestedName = EventTypeUtility.getPropertyRemoveArray(nestedName); } EventType innerType = eventAdapterService.getExistsTypeByName(nestedName); if (!(innerType instanceof MapEventType)) { return null; } if (!isArray) { return null; // must be declared as an array to use an indexed notation } else { return new MapArrayPropertyGetter(this.propertyNameAtomic, index, eventAdapterService, innerType); } } else { if (!(type instanceof Class)) { return null; } if (!((Class) type).isArray()) { return null; } Class componentType = ((Class)type).getComponentType(); // its an array return new MapArrayPOJOEntryIndexedPropertyGetter(propertyNameAtomic, index, eventAdapterService, componentType); } } public void toPropertyEPL(StringWriter writer) { writer.append(propertyNameAtomic); writer.append("["); writer.append(Integer.toString(index)); writer.append("]"); } public EventPropertyGetter getGetterDOM() { return new DOMIndexedGetter(propertyNameAtomic, index, null); } public EventPropertyGetter getGetterDOM(SchemaElementComplex complexProperty, EventAdapterService eventAdapterService, BaseXMLEventType eventType, String propertyExpression) { for (SchemaElementSimple simple : complexProperty.getSimpleElements()) { if (!simple.isArray()) { continue; } if (!simple.getName().equals(propertyNameAtomic)) { continue; } return new DOMIndexedGetter(propertyNameAtomic, index, null); } for (SchemaElementComplex complex : complexProperty.getChildren()) { if (!complex.isArray()) { continue; } if (!complex.getName().equals(propertyNameAtomic)) { continue; } return new DOMIndexedGetter(propertyNameAtomic, index, new FragmentFactoryDOMGetter(eventAdapterService, eventType, propertyExpression)); } return null; } public SchemaItem getPropertyTypeSchema(SchemaElementComplex complexProperty, EventAdapterService eventAdapterService) { for (SchemaElementSimple simple : complexProperty.getSimpleElements()) { if (!simple.isArray()) { continue; } if (!simple.getName().equals(propertyNameAtomic)) { continue; } // return the simple as a non-array since an index is provided return new SchemaElementSimple(simple.getName(), simple.getNamespace(), simple.getXsSimpleType(), simple.getTypeName(), false, simple.getFractionDigits()); } for (SchemaElementComplex complex : complexProperty.getChildren()) { if (!complex.isArray()) { continue; } if (!complex.getName().equals(propertyNameAtomic)) { continue; } // return the complex as a non-array since an index is provided return new SchemaElementComplex(complex.getName(), complex.getNamespace(), complex.getAttributes(), complex.getChildren(), complex.getSimpleElements(), false, complex.getOptionalSimpleType(), complex.getOptionalSimpleTypeName()); } return null; } /** * Returns the index number for an indexed property expression. * @param propertyName property expression * @return index */ public static Integer getIndex(String propertyName) { int start = propertyName.indexOf('['); int end = propertyName.indexOf(']'); String indexStr = propertyName.substring(start, end); return Integer.parseInt(indexStr); } public ObjectArrayEventPropertyGetterAndIndexed getGetterObjectArray(Map<String, Integer> indexPerProperty, Map<String, Object> nestableTypes, EventAdapterService eventAdapterService) { Integer propertyIndex = indexPerProperty.get(propertyNameAtomic); if (propertyIndex == null) { return null; } Object type = nestableTypes.get(getPropertyNameAtomic()); if (type == null) { return null; } if (type instanceof String) // resolve a property that is a map event type { String nestedName = type.toString(); boolean isArray = EventTypeUtility.isPropertyArray(nestedName); if (isArray) { nestedName = EventTypeUtility.getPropertyRemoveArray(nestedName); } EventType innerType = eventAdapterService.getExistsTypeByName(nestedName); if (!(innerType instanceof MapEventType)) { return null; } if (!isArray) { return null; // must be declared as an array to use an indexed notation } else { return new ObjectArrayArrayPropertyGetter(propertyIndex, index, eventAdapterService, innerType); } } else { if (!(type instanceof Class)) { return null; } if (!((Class) type).isArray()) { return null; } Class componentType = ((Class)type).getComponentType(); // its an array return new ObjectArrayArrayPOJOEntryIndexedPropertyGetter(propertyIndex, index, eventAdapterService, componentType); } } }