/************************************************************************************** * 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.vaevent; import com.espertech.esper.util.JavaClassHelper; import com.espertech.esper.util.SimpleTypeCaster; import com.espertech.esper.util.SimpleTypeCasterFactory; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.client.EventPropertyGetter; import com.espertech.esper.client.PropertyAccessException; import java.util.LinkedHashSet; import java.util.Set; /** * A property resolution strategy that allows only the preconfigured types, wherein all properties * that are common (name and type) to all properties are considered. */ public class VariantPropResolutionStrategyDefault implements VariantPropResolutionStrategy { private int currentPropertyNumber; private VariantPropertyGetterCache propertyGetterCache; /** * Ctor. * @param variantSpec specified the preconfigured types */ public VariantPropResolutionStrategyDefault(VariantSpec variantSpec) { propertyGetterCache = new VariantPropertyGetterCache(variantSpec.getEventTypes()); } public VariantPropertyDesc resolveProperty(String propertyName, EventType[] variants) { boolean existsInAll = true; Class commonType = null; boolean mustCoerce = false; for (int i = 0; i < variants.length; i++) { Class type = JavaClassHelper.getBoxedType(variants[i].getPropertyType(propertyName)); if (type == null) { existsInAll = false; continue; } if (commonType == null) { commonType = type; continue; } // compare types if (type.equals(commonType)) { continue; } // coercion if (JavaClassHelper.isNumeric(type)) { if (JavaClassHelper.canCoerce(type, commonType)) { mustCoerce = true; continue; } if (JavaClassHelper.canCoerce(commonType, type)) { mustCoerce = true; commonType = type; } } else if (commonType == Object.class) { continue; } // common interface or base class else if (!JavaClassHelper.isJavaBuiltinDataType(type)) { Set<Class> supersForType = new LinkedHashSet<Class>(); JavaClassHelper.getSuper(type, supersForType); supersForType.remove(Object.class); if (supersForType.contains(commonType)) { continue; // type implements or extends common type } if (JavaClassHelper.isSubclassOrImplementsInterface(commonType, type)) { commonType = type; // common type implements type continue; } // find common interface or type both implement Set<Class> supersForCommonType = new LinkedHashSet<Class>(); JavaClassHelper.getSuper(commonType, supersForCommonType); supersForCommonType.remove(Object.class); // Take common classes first, ignoring interfaces boolean found = false; for (Class superClassType : supersForType) { if (!superClassType.isInterface() && (supersForCommonType.contains(superClassType))) { commonType = superClassType; found = true; break; } } if (found) { continue; } // Take common interfaces for (Class superClassType : supersForType) { if (superClassType.isInterface() && (supersForCommonType.contains(superClassType))) { break; } } } commonType = Object.class; } if (!existsInAll) { return null; } if (commonType == null) { return null; } // property numbers should start at zero since the serve as array index final int assignedPropertyNumber = currentPropertyNumber; currentPropertyNumber++; propertyGetterCache.addGetters(assignedPropertyNumber, propertyName); EventPropertyGetter getter; if (mustCoerce) { final SimpleTypeCaster caster = SimpleTypeCasterFactory.getCaster(null, commonType); getter = new EventPropertyGetter() { public Object get(EventBean eventBean) throws PropertyAccessException { VariantEvent variant = (VariantEvent) eventBean; EventPropertyGetter getter = propertyGetterCache.getGetter(assignedPropertyNumber, variant.getUnderlyingEventBean().getEventType()); if (getter == null) { return null; } Object value = getter.get(variant.getUnderlyingEventBean()); if (value == null) { return value; } return caster.cast(value); } public boolean isExistsProperty(EventBean eventBean) { VariantEvent variant = (VariantEvent) eventBean; EventPropertyGetter getter = propertyGetterCache.getGetter(assignedPropertyNumber, variant.getUnderlyingEventBean().getEventType()); if (getter == null) { return false; } return getter.isExistsProperty(variant.getUnderlyingEventBean()); } public Object getFragment(EventBean eventBean) { return null; } }; } else { getter = new EventPropertyGetter() { public Object get(EventBean eventBean) throws PropertyAccessException { VariantEvent variant = (VariantEvent) eventBean; EventPropertyGetter getter = propertyGetterCache.getGetter(assignedPropertyNumber, variant.getUnderlyingEventBean().getEventType()); if (getter == null) { return null; } return getter.get(variant.getUnderlyingEventBean()); } public boolean isExistsProperty(EventBean eventBean) { VariantEvent variant = (VariantEvent) eventBean; EventPropertyGetter getter = propertyGetterCache.getGetter(assignedPropertyNumber, variant.getUnderlyingEventBean().getEventType()); if (getter == null) { return false; } return getter.isExistsProperty(variant.getUnderlyingEventBean()); } public Object getFragment(EventBean eventBean) { return null; } }; } return new VariantPropertyDesc(commonType, getter, true); } }