/* *************************************************************************************** * 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.filter; import com.espertech.esper.client.EPException; import com.espertech.esper.client.EventType; import com.espertech.esper.core.context.mgr.ContextControllerAddendumUtil; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.epl.property.PropertyEvaluator; import com.espertech.esper.pattern.MatchedEventMap; import java.util.*; /** * Contains the filter criteria to sift through events. The filter criteria are the event class to look for and * a set of parameters (attribute names, operators and constant/range values). */ public final class FilterSpecCompiled { private final static FilterSpecParamComparator COMPARATOR_PARAMETERS = new FilterSpecParamComparator(); private final EventType filterForEventType; private final String filterForEventTypeName; private final FilterSpecParam[][] parameters; private final PropertyEvaluator optionalPropertyEvaluator; /** * Constructor - validates parameter list against event type, throws exception if invalid * property names or mismatcing filter operators are found. * * @param eventType is the event type * @param filterParameters is a list of filter parameters * @param eventTypeName is the name of the event type * @param optionalPropertyEvaluator optional if evaluating properties returned by filtered events * @throws IllegalArgumentException if validation invalid */ public FilterSpecCompiled(EventType eventType, String eventTypeName, List<FilterSpecParam>[] filterParameters, PropertyEvaluator optionalPropertyEvaluator) { this.filterForEventType = eventType; this.filterForEventTypeName = eventTypeName; this.parameters = sortRemoveDups(filterParameters); this.optionalPropertyEvaluator = optionalPropertyEvaluator; } /** * Returns type of event to filter for. * * @return event type */ public final EventType getFilterForEventType() { return filterForEventType; } /** * Returns list of filter parameters. * * @return list of filter params */ public final FilterSpecParam[][] getParameters() { return parameters; } /** * Returns the event type name. * * @return event type name */ public String getFilterForEventTypeName() { return filterForEventTypeName; } /** * Return the evaluator for property value if any is attached, or none if none attached. * * @return property evaluator */ public PropertyEvaluator getOptionalPropertyEvaluator() { return optionalPropertyEvaluator; } /** * Returns the result event type of the filter specification. * * @return event type */ public EventType getResultEventType() { if (optionalPropertyEvaluator != null) { return optionalPropertyEvaluator.getFragmentEventType(); } else { return filterForEventType; } } /** * Returns the values for the filter, using the supplied result events to ask filter parameters * for the value to filter for. * * @param matchedEvents contains the result events to use for determining filter values * @param agentInstanceContext context * @param addendum context addendum * @return filter values */ public FilterValueSet getValueSet(MatchedEventMap matchedEvents, AgentInstanceContext agentInstanceContext, FilterValueSetParam[][] addendum) { FilterValueSetParam[][] valueList = new FilterValueSetParam[parameters.length][]; for (int i = 0; i < parameters.length; i++) { valueList[i] = new FilterValueSetParam[parameters[i].length]; populateValueSet(valueList[i], matchedEvents, agentInstanceContext, parameters[i]); } if (addendum != null) { valueList = ContextControllerAddendumUtil.multiplyAddendum(addendum, valueList); } return new FilterValueSetImpl(filterForEventType, valueList); } private static void populateValueSet(FilterValueSetParam[] valueList, MatchedEventMap matchedEvents, AgentInstanceContext agentInstanceContext, FilterSpecParam[] specParams) { // Ask each filter specification parameter for the actual value to filter for int count = 0; for (FilterSpecParam specParam : specParams) { Object filterForValue = specParam.getFilterValue(matchedEvents, agentInstanceContext); FilterValueSetParam valueParam = new FilterValueSetParamImpl(specParam.getLookupable(), specParam.getFilterOperator(), filterForValue); valueList[count] = valueParam; count++; } } @SuppressWarnings({"StringConcatenationInsideStringBufferAppend"}) public final String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("FilterSpecCompiled type=" + this.filterForEventType); buffer.append(" parameters=" + Arrays.toString(parameters)); return buffer.toString(); } public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof FilterSpecCompiled)) { return false; } FilterSpecCompiled other = (FilterSpecCompiled) obj; if (!equalsTypeAndFilter(other)) { return false; } if ((this.optionalPropertyEvaluator == null) && (other.optionalPropertyEvaluator == null)) { return true; } if ((this.optionalPropertyEvaluator != null) && (other.optionalPropertyEvaluator == null)) { return false; } if ((this.optionalPropertyEvaluator == null) && (other.optionalPropertyEvaluator != null)) { return false; } return this.optionalPropertyEvaluator.compareTo(other.optionalPropertyEvaluator); } /** * Compares only the type and filter portion and not the property evaluation portion. * * @param other filter to compare * @return true if same */ public boolean equalsTypeAndFilter(FilterSpecCompiled other) { if (this.filterForEventType != other.filterForEventType) { return false; } if (this.parameters.length != other.parameters.length) { return false; } for (int i = 0; i < this.parameters.length; i++) { FilterSpecParam[] lineThis = this.parameters[i]; FilterSpecParam[] lineOther = other.parameters[i]; if (lineThis.length != lineOther.length) { return false; } for (int j = 0; j < lineThis.length; j++) { if (!lineThis[j].equals(lineOther[j])) { return false; } } } return true; } public int hashCode() { int hashCode = filterForEventType.hashCode(); for (FilterSpecParam[] paramLine : parameters) { for (FilterSpecParam param : paramLine) { hashCode ^= 31 * param.hashCode(); } } return hashCode; } public int getFilterSpecIndexAmongAll(FilterSpecCompiled[] filterSpecAll) { for (int i = 0; i < filterSpecAll.length; i++) { if (this == filterSpecAll[i]) { return i; } } throw new EPException("Failed to find find filter spec among list of known filters"); } protected static FilterSpecParam[][] sortRemoveDups(List<FilterSpecParam>[] parameters) { FilterSpecParam[][] processed = new FilterSpecParam[parameters.length][]; for (int i = 0; i < parameters.length; i++) { processed[i] = sortRemoveDups(parameters[i]); } return processed; } protected static FilterSpecParam[] sortRemoveDups(List<FilterSpecParam> parameters) { if (parameters.isEmpty()) { return FilterSpecParam.EMPTY_PARAM_ARRAY; } if (parameters.size() == 1) { return new FilterSpecParam[]{parameters.get(0)}; } ArrayDeque<FilterSpecParam> result = new ArrayDeque<FilterSpecParam>(); TreeMap<FilterOperator, List<FilterSpecParam>> map = new TreeMap<FilterOperator, List<FilterSpecParam>>(COMPARATOR_PARAMETERS); for (FilterSpecParam parameter : parameters) { List<FilterSpecParam> list = map.get(parameter.getFilterOperator()); if (list == null) { list = new ArrayList<FilterSpecParam>(); map.put(parameter.getFilterOperator(), list); } boolean hasDuplicate = false; for (FilterSpecParam existing : list) { if (existing.getLookupable().equals(parameter.getLookupable())) { hasDuplicate = true; break; } } if (hasDuplicate) { continue; } list.add(parameter); } for (Map.Entry<FilterOperator, List<FilterSpecParam>> entry : map.entrySet()) { result.addAll(entry.getValue()); } return FilterSpecParam.toArray(result); } }