/* *************************************************************************************** * 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.vaevent; import com.espertech.esper.client.EventPropertyGetter; import com.espertech.esper.client.EventType; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * A thread-safe cache for property getters per event type. * <p> * Since most often getters are used in a row for the same type, keeps a row of last used getters for * fast lookup based on type. */ public class VariantPropertyGetterCache { private volatile EventType[] knownTypes; private volatile VariantPropertyGetterRow lastUsedGetters; private List<String> properties; private Map<EventType, VariantPropertyGetterRow> allGetters; /** * Ctor. * * @param knownTypes types known at cache construction type, may be an empty list for the ANY type variance. */ public VariantPropertyGetterCache(EventType[] knownTypes) { this.knownTypes = knownTypes; allGetters = new HashMap<EventType, VariantPropertyGetterRow>(); properties = new ArrayList<String>(); } /** * Adds the getters for a property that is identified by a property number which indexes into array of getters per type. * * @param assignedPropertyNumber number of property * @param propertyName to add */ public void addGetters(int assignedPropertyNumber, String propertyName) { for (EventType type : knownTypes) { EventPropertyGetter getter = type.getGetter(propertyName); VariantPropertyGetterRow row = allGetters.get(type); if (row == null) { synchronized (this) { row = new VariantPropertyGetterRow(type, new EventPropertyGetter[assignedPropertyNumber + 1]); allGetters.put(type, row); } } row.addGetter(assignedPropertyNumber, getter); } properties.add(propertyName); } /** * Fast lookup of a getter for a property and type. * * @param assignedPropertyNumber number of property to use as index * @param eventType type of underlying event * @return getter */ public EventPropertyGetter getGetter(int assignedPropertyNumber, EventType eventType) { VariantPropertyGetterRow lastGetters = lastUsedGetters; if ((lastGetters != null) && (lastGetters.eventType == eventType)) { return lastGetters.getGetterPerProp()[assignedPropertyNumber]; } VariantPropertyGetterRow row = allGetters.get(eventType); // newly seen type (Using ANY type variance or as a subtype of an existing variance type) // synchronized add, if added twice then that is ok too if (row == null) { synchronized (this) { row = allGetters.get(eventType); if (row == null) { row = addType(eventType); } } } EventPropertyGetter getter = row.getGetterPerProp()[assignedPropertyNumber]; lastUsedGetters = row; return getter; } private VariantPropertyGetterRow addType(EventType eventType) { EventType[] newKnownTypes = (EventType[]) resizeArray(knownTypes, knownTypes.length + 1); newKnownTypes[newKnownTypes.length - 1] = eventType; // create getters EventPropertyGetter[] getters = new EventPropertyGetter[properties.size()]; for (int i = 0; i < properties.size(); i++) { getters[i] = eventType.getGetter(properties.get(i)); } VariantPropertyGetterRow row = new VariantPropertyGetterRow(eventType, getters); Map<EventType, VariantPropertyGetterRow> newAllGetters = new HashMap<EventType, VariantPropertyGetterRow>(); newAllGetters.putAll(allGetters); newAllGetters.put(eventType, row); // overlay volatiles knownTypes = newKnownTypes; allGetters = newAllGetters; return row; } private static Object resizeArray(Object oldArray, int newSize) { int oldSize = java.lang.reflect.Array.getLength(oldArray); Class elementType = oldArray.getClass().getComponentType(); Object newArray = java.lang.reflect.Array.newInstance( elementType, newSize); int preserveLength = Math.min(oldSize, newSize); if (preserveLength > 0) System.arraycopy(oldArray, 0, newArray, 0, preserveLength); return newArray; } private static class VariantPropertyGetterRow { private EventType eventType; private EventPropertyGetter[] getterPerProp; private VariantPropertyGetterRow(EventType eventType, EventPropertyGetter[] getterPerProp) { this.eventType = eventType; this.getterPerProp = getterPerProp; } public EventType getEventType() { return eventType; } public EventPropertyGetter[] getGetterPerProp() { return getterPerProp; } public void setGetterPerProp(EventPropertyGetter[] getterPerProp) { this.getterPerProp = getterPerProp; } public void addGetter(int assignedPropertyNumber, EventPropertyGetter getter) { if (assignedPropertyNumber > (getterPerProp.length - 1)) { getterPerProp = (EventPropertyGetter[]) resizeArray(getterPerProp, getterPerProp.length + 10); } getterPerProp[assignedPropertyNumber] = getter; } } }