/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* 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.*;
import com.espertech.esper.collection.Pair;
import com.espertech.esper.epl.core.EngineImportService;
import com.espertech.esper.epl.core.EngineNoSuchMethodException;
import com.espertech.esper.event.*;
import com.espertech.esper.event.property.*;
import com.espertech.esper.util.JavaClassHelper;
import com.espertech.esper.util.MethodResolver;
import net.sf.cglib.reflect.FastClass;
import net.sf.cglib.reflect.FastMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;
/**
* Implementation of the EventType interface for handling JavaBean-type classes.
*/
public class BeanEventType implements EventTypeSPI, NativeEventType {
private final EventTypeMetadata metadata;
private final Class clazz;
private final EventAdapterService eventAdapterService;
private final ConfigurationEventTypeLegacy optionalLegacyDef;
private final int eventTypeId;
private String[] propertyNames;
private Map<String, SimplePropertyInfo> simpleProperties;
private Map<String, InternalEventPropDescriptor> mappedPropertyDescriptors;
private Map<String, InternalEventPropDescriptor> indexedPropertyDescriptors;
private EventType[] superTypes;
private FastClass fastClass;
private Set<EventType> deepSuperTypes;
private Configuration.PropertyResolutionStyle propertyResolutionStyle;
private Map<String, List<SimplePropertyInfo>> simpleSmartPropertyTable;
private Map<String, List<SimplePropertyInfo>> indexedSmartPropertyTable;
private Map<String, List<SimplePropertyInfo>> mappedSmartPropertyTable;
private final Map<String, EventPropertyGetter> propertyGetterCache;
private EventPropertyDescriptor[] propertyDescriptors;
private EventPropertyDescriptor[] writeablePropertyDescriptors;
private Map<String, Pair<EventPropertyDescriptor, BeanEventPropertyWriter>> writerMap;
private Map<String, EventPropertyDescriptor> propertyDescriptorMap;
private String factoryMethodName;
private String copyMethodName;
private String startTimestampPropertyName;
private String endTimestampPropertyName;
/**
* Constructor takes a java bean class as an argument.
*
* @param clazz is the class of a java bean or other POJO
* @param optionalLegacyDef optional configuration supplying legacy event type information
* @param eventAdapterService factory for event beans and event types
* @param metadata event type metadata
* @param eventTypeId type id
*/
public BeanEventType(EventTypeMetadata metadata,
int eventTypeId,
Class clazz,
EventAdapterService eventAdapterService,
ConfigurationEventTypeLegacy optionalLegacyDef
) {
this.metadata = metadata;
this.clazz = clazz;
this.eventAdapterService = eventAdapterService;
this.optionalLegacyDef = optionalLegacyDef;
this.eventTypeId = eventTypeId;
if (optionalLegacyDef != null) {
this.factoryMethodName = optionalLegacyDef.getFactoryMethod();
this.copyMethodName = optionalLegacyDef.getCopyMethod();
this.propertyResolutionStyle = optionalLegacyDef.getPropertyResolutionStyle();
} else {
this.propertyResolutionStyle = eventAdapterService.getBeanEventTypeFactory().getDefaultPropertyResolutionStyle();
}
propertyGetterCache = new HashMap<String, EventPropertyGetter>();
initialize(false, eventAdapterService.getEngineImportService());
EventTypeUtility.TimestampPropertyDesc desc = EventTypeUtility.validatedDetermineTimestampProps(this, optionalLegacyDef == null ? null : optionalLegacyDef.getStartTimestampPropertyName(), optionalLegacyDef == null ? null : optionalLegacyDef.getEndTimestampPropertyName(), superTypes);
startTimestampPropertyName = desc.getStart();
endTimestampPropertyName = desc.getEnd();
}
public String getStartTimestampPropertyName() {
return startTimestampPropertyName;
}
public String getEndTimestampPropertyName() {
return endTimestampPropertyName;
}
public ConfigurationEventTypeLegacy getOptionalLegacyDef() {
return optionalLegacyDef;
}
public String getName() {
return metadata.getPublicName();
}
public EventPropertyDescriptor getPropertyDescriptor(String propertyName) {
return propertyDescriptorMap.get(propertyName);
}
public int getEventTypeId() {
return eventTypeId;
}
/**
* Returns the factory methods name, or null if none defined.
*
* @return factory methods name
*/
public String getFactoryMethodName() {
return factoryMethodName;
}
public final Class getPropertyType(String propertyName) {
SimplePropertyInfo simpleProp = getSimplePropertyInfo(propertyName);
if ((simpleProp != null) && (simpleProp.getClazz() != null)) {
return simpleProp.getClazz();
}
Property prop = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (prop instanceof SimpleProperty) {
// there is no such property since it wasn't in simplePropertyTypes
return null;
}
return prop.getPropertyType(this, eventAdapterService);
}
public boolean isProperty(String propertyName) {
if (getPropertyType(propertyName) == null) {
return false;
}
return true;
}
public final Class getUnderlyingType() {
return clazz;
}
/**
* Returns the property resolution style.
*
* @return property resolution style
*/
public Configuration.PropertyResolutionStyle getPropertyResolutionStyle() {
return propertyResolutionStyle;
}
public EventPropertyGetter getGetter(String propertyName) {
EventPropertyGetter cachedGetter = propertyGetterCache.get(propertyName);
if (cachedGetter != null) {
return cachedGetter;
}
SimplePropertyInfo simpleProp = getSimplePropertyInfo(propertyName);
if ((simpleProp != null) && (simpleProp.getter != null)) {
EventPropertyGetter getter = simpleProp.getGetter();
propertyGetterCache.put(propertyName, getter);
return getter;
}
Property prop = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (prop instanceof SimpleProperty) {
// there is no such property since it wasn't in simplePropertyGetters
return null;
}
EventPropertyGetter getter = prop.getGetter(this, eventAdapterService);
propertyGetterCache.put(propertyName, getter);
return getter;
}
public EventPropertyGetterMapped getGetterMapped(String mappedPropertyName) {
EventPropertyDescriptor desc = this.propertyDescriptorMap.get(mappedPropertyName);
if (desc == null || !desc.isMapped()) {
return null;
}
MappedProperty mappedProperty = new MappedProperty(mappedPropertyName);
return mappedProperty.getGetter(this, eventAdapterService);
}
public EventPropertyGetterIndexed getGetterIndexed(String indexedPropertyName) {
EventPropertyDescriptor desc = this.propertyDescriptorMap.get(indexedPropertyName);
if (desc == null || !desc.isIndexed()) {
return null;
}
IndexedProperty indexedProperty = new IndexedProperty(indexedPropertyName);
return indexedProperty.getGetter(this, eventAdapterService);
}
/**
* Looks up and returns a cached simple property's descriptor.
*
* @param propertyName to look up
* @return property descriptor
*/
public final InternalEventPropDescriptor getSimpleProperty(String propertyName) {
SimplePropertyInfo simpleProp = getSimplePropertyInfo(propertyName);
if (simpleProp != null) {
return simpleProp.getDescriptor();
}
return null;
}
/**
* Looks up and returns a cached mapped property's descriptor.
*
* @param propertyName to look up
* @return property descriptor
*/
public final InternalEventPropDescriptor getMappedProperty(String propertyName) {
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_SENSITIVE)) {
return mappedPropertyDescriptors.get(propertyName);
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_INSENSITIVE)) {
List<SimplePropertyInfo> propertyInfos = mappedSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
return propertyInfos != null
? propertyInfos.get(0).getDescriptor()
: null;
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.DISTINCT_CASE_INSENSITIVE)) {
List<SimplePropertyInfo> propertyInfos = mappedSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
if (propertyInfos != null) {
if (propertyInfos.size() != 1) {
throw new EPException("Unable to determine which property to use for \"" + propertyName + "\" because more than one property matched");
}
return propertyInfos.get(0).getDescriptor();
}
}
return null;
}
/**
* Looks up and returns a cached indexed property's descriptor.
*
* @param propertyName to look up
* @return property descriptor
*/
public final InternalEventPropDescriptor getIndexedProperty(String propertyName) {
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_SENSITIVE)) {
return indexedPropertyDescriptors.get(propertyName);
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_INSENSITIVE)) {
List<SimplePropertyInfo> propertyInfos = indexedSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
return propertyInfos != null
? propertyInfos.get(0).getDescriptor()
: null;
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.DISTINCT_CASE_INSENSITIVE)) {
List<SimplePropertyInfo> propertyInfos = indexedSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
if (propertyInfos != null) {
if (propertyInfos.size() != 1) {
throw new EPException("Unable to determine which property to use for \"" + propertyName + "\" because more than one property matched");
}
return propertyInfos.get(0).getDescriptor();
}
}
return null;
}
public String[] getPropertyNames() {
return propertyNames;
}
public EventType[] getSuperTypes() {
return superTypes;
}
public Iterator<EventType> getDeepSuperTypes() {
return deepSuperTypes.iterator();
}
/**
* Returns the fast class reference, if code generation is used for this type, else null.
*
* @return fast class, or null if no code generation
*/
public FastClass getFastClass() {
return fastClass;
}
public String toString() {
return "BeanEventType" +
" name=" + getName() +
" clazz=" + clazz.getName();
}
private void initialize(boolean isConfigured, EngineImportService engineImportService) {
PropertyListBuilder propertyListBuilder = PropertyListBuilderFactory.createBuilder(optionalLegacyDef);
List<InternalEventPropDescriptor> properties = propertyListBuilder.assessProperties(clazz);
this.propertyDescriptors = new EventPropertyDescriptor[properties.size()];
this.propertyDescriptorMap = new HashMap<String, EventPropertyDescriptor>();
this.propertyNames = new String[properties.size()];
this.simpleProperties = new HashMap<String, SimplePropertyInfo>();
this.mappedPropertyDescriptors = new HashMap<String, InternalEventPropDescriptor>();
this.indexedPropertyDescriptors = new HashMap<String, InternalEventPropDescriptor>();
if (usesSmartResolutionStyle()) {
simpleSmartPropertyTable = new HashMap<String, List<SimplePropertyInfo>>();
mappedSmartPropertyTable = new HashMap<String, List<SimplePropertyInfo>>();
indexedSmartPropertyTable = new HashMap<String, List<SimplePropertyInfo>>();
}
if ((optionalLegacyDef == null) ||
(optionalLegacyDef.getCodeGeneration() != ConfigurationEventTypeLegacy.CodeGeneration.DISABLED)) {
// get CGLib fast class using current thread class loader
fastClass = null;
try {
fastClass = FastClass.create(engineImportService.getFastClassClassLoader(clazz), clazz);
} catch (Throwable exWithThreadClassLoader) {
// get CGLib fast class based on given class (for OSGI support)
try {
fastClass = FastClass.create(clazz);
} catch (Throwable exWithoutThreadClassLoader) {
log.warn(".initialize Unable to obtain CGLib fast class and/or method implementation for class " +
clazz.getName() + ", error msg is " + exWithThreadClassLoader.getMessage(), exWithThreadClassLoader);
log.warn(".initialize Not using the provided class loader, the error msg is: " + exWithoutThreadClassLoader.getMessage(), exWithoutThreadClassLoader);
fastClass = null;
}
}
}
int count = 0;
for (InternalEventPropDescriptor desc : properties) {
String propertyName = desc.getPropertyName();
Class underlyingType;
Class componentType;
boolean isRequiresIndex;
boolean isRequiresMapkey;
boolean isIndexed;
boolean isMapped;
boolean isFragment;
if (desc.getPropertyType().equals(EventPropertyType.SIMPLE)) {
EventPropertyGetter getter;
Class type;
if (desc.getReadMethod() != null) {
getter = PropertyHelper.getGetter(desc.getReadMethod(), fastClass, eventAdapterService);
type = desc.getReadMethod().getReturnType();
} else {
if (desc.getAccessorField() == null) {
// Ignore property
continue;
}
getter = new ReflectionPropFieldGetter(desc.getAccessorField(), eventAdapterService);
type = desc.getAccessorField().getType();
}
underlyingType = type;
componentType = null;
isRequiresIndex = false;
isRequiresMapkey = false;
isIndexed = false;
isMapped = false;
if (JavaClassHelper.isImplementsInterface(type, Map.class)) {
isMapped = true;
// We do not yet allow to fragment maps entries.
// Class genericType = JavaClassHelper.getGenericReturnTypeMap(desc.getReadMethod(), desc.getAccessorField());
isFragment = false;
if (desc.getReadMethod() != null) {
componentType = JavaClassHelper.getGenericReturnTypeMap(desc.getReadMethod(), false);
} else if (desc.getAccessorField() != null) {
componentType = JavaClassHelper.getGenericFieldTypeMap(desc.getAccessorField(), false);
} else {
componentType = Object.class;
}
} else if (type.isArray()) {
isIndexed = true;
isFragment = JavaClassHelper.isFragmentableType(type.getComponentType());
componentType = type.getComponentType();
} else if (JavaClassHelper.isImplementsInterface(type, Iterable.class)) {
isIndexed = true;
Class genericType = JavaClassHelper.getGenericReturnType(desc.getReadMethod(), desc.getAccessorField(), true);
isFragment = JavaClassHelper.isFragmentableType(genericType);
if (genericType != null) {
componentType = genericType;
} else {
componentType = Object.class;
}
} else {
isMapped = false;
isFragment = JavaClassHelper.isFragmentableType(type);
}
simpleProperties.put(propertyName, new SimplePropertyInfo(type, getter, desc));
// Recognize that there may be properties with overlapping case-insentitive names
if (usesSmartResolutionStyle()) {
// Find the property in the smart property table
String smartPropertyName = propertyName.toLowerCase(Locale.ENGLISH);
List<SimplePropertyInfo> propertyInfoList = simpleSmartPropertyTable.get(smartPropertyName);
if (propertyInfoList == null) {
propertyInfoList = new ArrayList<SimplePropertyInfo>();
simpleSmartPropertyTable.put(smartPropertyName, propertyInfoList);
}
// Enter the property into the smart property list
SimplePropertyInfo propertyInfo = new SimplePropertyInfo(type, getter, desc);
propertyInfoList.add(propertyInfo);
}
} else if (desc.getPropertyType().equals(EventPropertyType.MAPPED)) {
mappedPropertyDescriptors.put(propertyName, desc);
underlyingType = desc.getReturnType();
componentType = Object.class;
isRequiresIndex = false;
isRequiresMapkey = desc.getReadMethod().getParameterTypes().length > 0;
isIndexed = false;
isMapped = true;
isFragment = false;
// Recognize that there may be properties with overlapping case-insentitive names
if (usesSmartResolutionStyle()) {
// Find the property in the smart property table
String smartPropertyName = propertyName.toLowerCase(Locale.ENGLISH);
List<SimplePropertyInfo> propertyInfoList = mappedSmartPropertyTable.get(smartPropertyName);
if (propertyInfoList == null) {
propertyInfoList = new ArrayList<SimplePropertyInfo>();
mappedSmartPropertyTable.put(smartPropertyName, propertyInfoList);
}
// Enter the property into the smart property list
SimplePropertyInfo propertyInfo = new SimplePropertyInfo(desc.getReturnType(), null, desc);
propertyInfoList.add(propertyInfo);
}
} else if (desc.getPropertyType().equals(EventPropertyType.INDEXED)) {
indexedPropertyDescriptors.put(propertyName, desc);
underlyingType = desc.getReturnType();
componentType = null;
isRequiresIndex = desc.getReadMethod().getParameterTypes().length > 0;
isRequiresMapkey = false;
isIndexed = true;
isMapped = false;
isFragment = JavaClassHelper.isFragmentableType(desc.getReturnType());
if (usesSmartResolutionStyle()) {
// Find the property in the smart property table
String smartPropertyName = propertyName.toLowerCase(Locale.ENGLISH);
List<SimplePropertyInfo> propertyInfoList = indexedSmartPropertyTable.get(smartPropertyName);
if (propertyInfoList == null) {
propertyInfoList = new ArrayList<SimplePropertyInfo>();
indexedSmartPropertyTable.put(smartPropertyName, propertyInfoList);
}
// Enter the property into the smart property list
SimplePropertyInfo propertyInfo = new SimplePropertyInfo(desc.getReturnType(), null, desc);
propertyInfoList.add(propertyInfo);
}
} else {
continue;
}
propertyNames[count] = desc.getPropertyName();
EventPropertyDescriptor descriptor = new EventPropertyDescriptor(desc.getPropertyName(),
underlyingType, componentType, isRequiresIndex, isRequiresMapkey, isIndexed, isMapped, isFragment);
propertyDescriptors[count++] = descriptor;
propertyDescriptorMap.put(descriptor.getPropertyName(), descriptor);
}
// Determine event type super types
superTypes = getSuperTypes(clazz, eventAdapterService.getBeanEventTypeFactory());
if (superTypes != null && superTypes.length == 0) {
superTypes = null;
}
if (metadata != null && metadata.getTypeClass() == EventTypeMetadata.TypeClass.NAMED_WINDOW) {
superTypes = null;
}
// Determine deep supertypes
// Get Java super types (superclasses and interfaces), deep get of all in the tree
Set<Class> supers = new HashSet<Class>();
getSuper(clazz, supers);
removeJavaLibInterfaces(supers); // Remove "java." super types
// Cache the supertypes of this event type for later use
deepSuperTypes = new HashSet<EventType>();
for (Class superClass : supers) {
EventType superType = eventAdapterService.getBeanEventTypeFactory().createBeanType(superClass.getName(), superClass, false, false, isConfigured);
deepSuperTypes.add(superType);
}
}
private static EventType[] getSuperTypes(Class clazz, BeanEventTypeFactory beanEventTypeFactory) {
List<Class> superclasses = new LinkedList<Class>();
// add superclass
Class superClass = clazz.getSuperclass();
if (superClass != null) {
superclasses.add(superClass);
}
// add interfaces
Class[] interfaces = clazz.getInterfaces();
superclasses.addAll(Arrays.asList(interfaces));
// Build event types, ignoring java language types
List<EventType> superTypes = new LinkedList<EventType>();
for (Class superclass : superclasses) {
if (!superclass.getName().startsWith("java")) {
EventType superType = beanEventTypeFactory.createBeanType(superclass.getName(), superclass, false, false, false);
superTypes.add(superType);
}
}
return superTypes.toArray(new EventType[superTypes.size()]);
}
/**
* Add the given class's implemented interfaces and superclasses to the result set of classes.
*
* @param clazz to introspect
* @param result to add classes to
*/
protected static void getSuper(Class clazz, Set<Class> result) {
getSuperInterfaces(clazz, result);
getSuperClasses(clazz, result);
}
private static void getSuperInterfaces(Class clazz, Set<Class> result) {
Class[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
result.add(interfaces[i]);
getSuperInterfaces(interfaces[i], result);
}
}
private static void getSuperClasses(Class clazz, Set<Class> result) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
return;
}
result.add(superClass);
getSuper(superClass, result);
}
private static void removeJavaLibInterfaces(Set<Class> classes) {
for (Class clazz : classes.toArray(new Class[0])) {
if (clazz.getName().startsWith("java")) {
classes.remove(clazz);
}
}
}
private boolean usesSmartResolutionStyle() {
return propertyResolutionStyle.equals(Configuration.PropertyResolutionStyle.CASE_INSENSITIVE) ||
propertyResolutionStyle.equals(Configuration.PropertyResolutionStyle.DISTINCT_CASE_INSENSITIVE);
}
private SimplePropertyInfo getSimplePropertyInfo(String propertyName) {
SimplePropertyInfo propertyInfo;
List<SimplePropertyInfo> simplePropertyInfoList;
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_SENSITIVE)) {
return simpleProperties.get(propertyName);
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.CASE_INSENSITIVE)) {
propertyInfo = simpleProperties.get(propertyName);
if (propertyInfo != null) {
return propertyInfo;
}
simplePropertyInfoList = simpleSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
return
simplePropertyInfoList != null
? simplePropertyInfoList.get(0)
: null;
}
if (this.getPropertyResolutionStyle().equals(Configuration.PropertyResolutionStyle.DISTINCT_CASE_INSENSITIVE)) {
propertyInfo = simpleProperties.get(propertyName);
if (propertyInfo != null) {
return propertyInfo;
}
simplePropertyInfoList = simpleSmartPropertyTable.get(propertyName.toLowerCase(Locale.ENGLISH));
if (simplePropertyInfoList != null) {
if (simplePropertyInfoList.size() != 1) {
throw new EPException("Unable to determine which property to use for \"" + propertyName + "\" because more than one property matched");
}
return simplePropertyInfoList.get(0);
}
}
return null;
}
/**
* Descriptor caching the getter, class and property info.
*/
public static class SimplePropertyInfo {
private Class clazz;
private EventPropertyGetter getter;
private InternalEventPropDescriptor descriptor;
/**
* Ctor.
*
* @param clazz is the class
* @param getter is the getter
* @param descriptor is the property info
*/
public SimplePropertyInfo(Class clazz, EventPropertyGetter getter, InternalEventPropDescriptor descriptor) {
this.clazz = clazz;
this.getter = getter;
this.descriptor = descriptor;
}
/**
* Returns the return type.
*
* @return return type
*/
public Class getClazz() {
return clazz;
}
/**
* Returns the getter.
*
* @return getter
*/
public EventPropertyGetter getGetter() {
return getter;
}
/**
* Returns the property info.
*
* @return property info
*/
public InternalEventPropDescriptor getDescriptor() {
return descriptor;
}
}
public EventTypeMetadata getMetadata() {
return metadata;
}
public EventPropertyDescriptor[] getPropertyDescriptors() {
return propertyDescriptors;
}
public FragmentEventType getFragmentType(String propertyExpression) {
SimplePropertyInfo simpleProp = getSimplePropertyInfo(propertyExpression);
if ((simpleProp != null) && (simpleProp.getClazz() != null)) {
GenericPropertyDesc genericProp = simpleProp.getDescriptor().getReturnTypeGeneric();
return EventBeanUtility.createNativeFragmentType(genericProp.getType(), genericProp.getGeneric(), eventAdapterService);
}
Property prop = PropertyParser.parseAndWalkLaxToSimple(propertyExpression);
if (prop instanceof SimpleProperty) {
// there is no such property since it wasn't in simplePropertyTypes
return null;
}
GenericPropertyDesc genericProp = prop.getPropertyTypeGeneric(this, eventAdapterService);
if (genericProp == null) {
return null;
}
return EventBeanUtility.createNativeFragmentType(genericProp.getType(), genericProp.getGeneric(), eventAdapterService);
}
public BeanEventPropertyWriter getWriter(String propertyName) {
if (writeablePropertyDescriptors == null) {
initializeWriters();
}
Pair<EventPropertyDescriptor, BeanEventPropertyWriter> pair = writerMap.get(propertyName);
if (pair != null) {
return pair.getSecond();
}
Property property = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (property instanceof MappedProperty) {
MappedProperty mapProp = (MappedProperty) property;
String methodName = PropertyHelper.getSetterMethodName(mapProp.getPropertyNameAtomic());
Method setterMethod;
try {
setterMethod = MethodResolver.resolveMethod(clazz, methodName, new Class[]{String.class, Object.class}, true, new boolean[2], new boolean[2]);
} catch (EngineNoSuchMethodException e) {
log.info("Failed to find mapped property setter method '" + methodName + "' for writing to property '" + propertyName + "' taking {String, Object} as parameters");
return null;
}
if (setterMethod == null) {
return null;
}
final FastMethod fastMethod = fastClass.getMethod(setterMethod);
return new BeanEventPropertyWriterMapProp(clazz, fastMethod, mapProp.getKey());
}
if (property instanceof IndexedProperty) {
IndexedProperty indexedProp = (IndexedProperty) property;
String methodName = PropertyHelper.getSetterMethodName(indexedProp.getPropertyNameAtomic());
Method setterMethod;
try {
setterMethod = MethodResolver.resolveMethod(clazz, methodName, new Class[]{int.class, Object.class}, true, new boolean[2], new boolean[2]);
} catch (EngineNoSuchMethodException e) {
log.info("Failed to find indexed property setter method '" + methodName + "' for writing to property '" + propertyName + "' taking {int, Object} as parameters");
return null;
}
if (setterMethod == null) {
return null;
}
final FastMethod fastMethod = fastClass.getMethod(setterMethod);
return new BeanEventPropertyWriterIndexedProp(clazz, fastMethod, indexedProp.getIndex());
}
return null;
}
public EventPropertyDescriptor getWritableProperty(String propertyName) {
if (writeablePropertyDescriptors == null) {
initializeWriters();
}
Pair<EventPropertyDescriptor, BeanEventPropertyWriter> pair = writerMap.get(propertyName);
if (pair != null) {
return pair.getFirst();
}
Property property = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (property instanceof MappedProperty) {
EventPropertyWriter writer = getWriter(propertyName);
if (writer == null) {
return null;
}
MappedProperty mapProp = (MappedProperty) property;
return new EventPropertyDescriptor(mapProp.getPropertyNameAtomic(), Object.class, null, false, true, false, true, false);
}
if (property instanceof IndexedProperty) {
EventPropertyWriter writer = getWriter(propertyName);
if (writer == null) {
return null;
}
IndexedProperty indexedProp = (IndexedProperty) property;
return new EventPropertyDescriptor(indexedProp.getPropertyNameAtomic(), Object.class, null, true, false, true, false, false);
}
return null;
}
public EventPropertyDescriptor[] getWriteableProperties() {
if (writeablePropertyDescriptors == null) {
initializeWriters();
}
return writeablePropertyDescriptors;
}
public EventBeanReader getReader() {
return new BeanEventBeanReader(this);
}
public EventBeanCopyMethod getCopyMethod(String[] properties) {
if (copyMethodName == null) {
if (JavaClassHelper.isImplementsInterface(clazz, Serializable.class)) {
return new BeanEventBeanSerializableCopyMethod(this, eventAdapterService);
}
return null;
}
Method method = null;
try {
method = clazz.getMethod(copyMethodName);
} catch (NoSuchMethodException e) {
log.error("Configured copy-method for class '" + clazz.getName() + " not found by name '" + copyMethodName + "': " + e.getMessage());
}
if (method == null) {
if (JavaClassHelper.isImplementsInterface(clazz, Serializable.class)) {
return new BeanEventBeanSerializableCopyMethod(this, eventAdapterService);
}
throw new EPException("Configured copy-method for class '" + clazz.getName() + " not found by name '" + copyMethodName + "' and class does not implement Serializable");
}
return new BeanEventBeanConfiguredCopyMethod(this, eventAdapterService, fastClass.getMethod(method));
}
public EventBeanWriter getWriter(String[] properties) {
if (writeablePropertyDescriptors == null) {
initializeWriters();
}
BeanEventPropertyWriter[] writers = new BeanEventPropertyWriter[properties.length];
for (int i = 0; i < properties.length; i++) {
Pair<EventPropertyDescriptor, BeanEventPropertyWriter> pair = writerMap.get(properties[i]);
if (pair != null) {
writers[i] = pair.getSecond();
} else {
writers[i] = getWriter(properties[i]);
}
}
return new BeanEventBeanWriter(writers);
}
public boolean equalsCompareType(EventType eventType) {
return this == eventType;
}
private void initializeWriters() {
Set<WriteablePropertyDescriptor> writables = PropertyHelper.getWritableProperties(fastClass.getJavaClass());
EventPropertyDescriptor[] desc = new EventPropertyDescriptor[writables.size()];
Map<String, Pair<EventPropertyDescriptor, BeanEventPropertyWriter>> writers = new HashMap<String, Pair<EventPropertyDescriptor, BeanEventPropertyWriter>>();
int count = 0;
for (final WriteablePropertyDescriptor writable : writables) {
EventPropertyDescriptor propertyDesc = new EventPropertyDescriptor(writable.getPropertyName(), writable.getType(), null, false, false, false, false, false);
desc[count++] = propertyDesc;
final FastMethod fastMethod = fastClass.getMethod(writable.getWriteMethod());
writers.put(writable.getPropertyName(), new Pair<EventPropertyDescriptor, BeanEventPropertyWriter>(propertyDesc, new BeanEventPropertyWriter(clazz, fastMethod)));
}
writerMap = writers;
writeablePropertyDescriptors = desc;
}
private static final Logger log = LoggerFactory.getLogger(BeanEventType.class);
}