/* *************************************************************************************** * 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.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.supportunit.bean.SupportBean; import com.espertech.esper.supportunit.event.SupportEventBeanFactory; import com.espertech.esper.supportunit.filter.SupportFilterHandle; import com.espertech.esper.supportunit.filter.SupportFilterSpecBuilder; import junit.framework.TestCase; import java.util.ArrayDeque; import java.util.LinkedList; import java.util.List; import java.util.concurrent.locks.ReentrantReadWriteLock; public class TestIndexTreeBuilder extends TestCase { private List<FilterHandle> matches; private EventBean eventBean; private EventType eventType; private FilterHandle testFilterCallback[]; private FilterServiceGranularLockFactory lockFactory = new FilterServiceGranularLockFactoryReentrant(); public void setUp() { SupportBean testBean = new SupportBean(); testBean.setIntPrimitive(50); testBean.setDoublePrimitive(0.5); testBean.setTheString("jack"); testBean.setLongPrimitive(10); testBean.setShortPrimitive((short) 20); eventBean = SupportEventBeanFactory.createObject(testBean); eventType = eventBean.getEventType(); matches = new LinkedList<FilterHandle>(); // Allocate a couple of callbacks testFilterCallback = new SupportFilterHandle[20]; for (int i = 0; i < testFilterCallback.length; i++) { testFilterCallback[i] = new SupportFilterHandle(); } } public void testBuildWithMatch() { FilterHandleSetNode topNode = new FilterHandleSetNode(new ReentrantReadWriteLock()); // Add some parameter-less expression FilterValueSet filterSpec = makeFilterValues(); IndexTreeBuilder.add(filterSpec, testFilterCallback[0], topNode, lockFactory); assertTrue(topNode.contains(testFilterCallback[0])); // Attempt a match topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 1); matches.clear(); // Add a filter that won't match, with a single parameter matching against an int filterSpec = makeFilterValues("intPrimitive", FilterOperator.EQUAL, 100); IndexTreeBuilder.add(filterSpec, testFilterCallback[1], topNode, lockFactory); assertTrue(topNode.getIndizes().size() == 1); assertTrue(topNode.getIndizes().get(0).sizeExpensive() == 1); // Match again topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 1); matches.clear(); // Add a filter that will match filterSpec = makeFilterValues("intPrimitive", FilterOperator.EQUAL, 50); IndexTreeBuilder.add(filterSpec, testFilterCallback[2], topNode, lockFactory); assertTrue(topNode.getIndizes().size() == 1); assertTrue(topNode.getIndizes().get(0).sizeExpensive() == 2); // match topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 2); matches.clear(); // Add some filter against a double filterSpec = makeFilterValues("doublePrimitive", FilterOperator.LESS, 1.1); IndexTreeBuilder.add(filterSpec, testFilterCallback[3], topNode, lockFactory); assertTrue(topNode.getIndizes().size() == 2); assertTrue(topNode.getIndizes().get(0).sizeExpensive() == 2); assertTrue(topNode.getIndizes().get(1).sizeExpensive() == 1); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 3); matches.clear(); filterSpec = makeFilterValues("doublePrimitive", FilterOperator.LESS_OR_EQUAL, 0.5); IndexTreeBuilder.add(filterSpec, testFilterCallback[4], topNode, lockFactory); assertTrue(topNode.getIndizes().size() == 3); assertTrue(topNode.getIndizes().get(0).sizeExpensive() == 2); assertTrue(topNode.getIndizes().get(1).sizeExpensive() == 1); assertTrue(topNode.getIndizes().get(2).sizeExpensive() == 1); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 4); matches.clear(); // Add an filterSpec against double and string filterSpec = makeFilterValues("doublePrimitive", FilterOperator.LESS, 1.1, "theString", FilterOperator.EQUAL, "jack"); IndexTreeBuilder.add(filterSpec, testFilterCallback[5], topNode, lockFactory); assertTrue(topNode.getIndizes().size() == 3); assertTrue(topNode.getIndizes().get(0).sizeExpensive() == 2); assertTrue(topNode.getIndizes().get(1).sizeExpensive() == 1); assertTrue(topNode.getIndizes().get(2).sizeExpensive() == 1); FilterHandleSetNode nextLevelSetNode = (FilterHandleSetNode) topNode.getIndizes().get(1).get(Double.valueOf(1.1)); assertTrue(nextLevelSetNode != null); assertTrue(nextLevelSetNode.getIndizes().size() == 1); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 5); matches.clear(); filterSpec = makeFilterValues("doublePrimitive", FilterOperator.LESS, 1.1, "theString", FilterOperator.EQUAL, "beta"); IndexTreeBuilder.add(filterSpec, testFilterCallback[6], topNode, lockFactory); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 5); matches.clear(); filterSpec = makeFilterValues("doublePrimitive", FilterOperator.LESS, 1.1, "theString", FilterOperator.EQUAL, "jack"); IndexTreeBuilder.add(filterSpec, testFilterCallback[7], topNode, lockFactory); assertTrue(nextLevelSetNode.getIndizes().size() == 1); FilterHandleSetNode nodeTwo = (FilterHandleSetNode) nextLevelSetNode.getIndizes().get(0).get("jack"); assertTrue(nodeTwo.getFilterCallbackCount() == 2); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 6); matches.clear(); // Try depth first filterSpec = makeFilterValues("theString", FilterOperator.EQUAL, "jack", "longPrimitive", FilterOperator.EQUAL, 10L, "shortPrimitive", FilterOperator.EQUAL, (short) 20); IndexTreeBuilder.add(filterSpec, testFilterCallback[8], topNode, lockFactory); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 7); matches.clear(); // Add an filterSpec in the middle filterSpec = makeFilterValues("longPrimitive", FilterOperator.EQUAL, 10L, "theString", FilterOperator.EQUAL, "jack"); IndexTreeBuilder.add(filterSpec, testFilterCallback[9], topNode, lockFactory); filterSpec = makeFilterValues("longPrimitive", FilterOperator.EQUAL, 10L, "theString", FilterOperator.EQUAL, "jim"); IndexTreeBuilder.add(filterSpec, testFilterCallback[10], topNode, lockFactory); filterSpec = makeFilterValues("longPrimitive", FilterOperator.EQUAL, 10L, "theString", FilterOperator.EQUAL, "joe"); IndexTreeBuilder.add(filterSpec, testFilterCallback[11], topNode, lockFactory); topNode.matchEvent(eventBean, matches); assertTrue(matches.size() == 8); matches.clear(); } public void testBuildMatchRemove() { FilterHandleSetNode top = new FilterHandleSetNode(new ReentrantReadWriteLock()); // Add a parameter-less filter FilterValueSet filterSpecNoParams = makeFilterValues(); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair> pathAddedTo[] = IndexTreeBuilder.add(filterSpecNoParams, testFilterCallback[0], top, lockFactory); // Try a match top.matchEvent(eventBean, matches); assertTrue(matches.size() == 1); matches.clear(); // Remove filter IndexTreeBuilder.remove(eventType, testFilterCallback[0], toArrayPath(pathAddedTo[0]), top); // Match should not be found top.matchEvent(eventBean, matches); assertTrue(matches.size() == 0); matches.clear(); // Add a depth-first filterSpec FilterValueSet filterSpecOne = makeFilterValues( "theString", FilterOperator.EQUAL, "jack", "longPrimitive", FilterOperator.EQUAL, 10L, "shortPrimitive", FilterOperator.EQUAL, (short) 20); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair>[] pathAddedToOne = IndexTreeBuilder.add(filterSpecOne, testFilterCallback[1], top, lockFactory); FilterValueSet filterSpecTwo = makeFilterValues( "theString", FilterOperator.EQUAL, "jack", "longPrimitive", FilterOperator.EQUAL, 10L, "shortPrimitive", FilterOperator.EQUAL, (short) 20); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair>[] pathAddedToTwo = IndexTreeBuilder.add(filterSpecTwo, testFilterCallback[2], top, lockFactory); FilterValueSet filterSpecThree = makeFilterValues( "theString", FilterOperator.EQUAL, "jack", "longPrimitive", FilterOperator.EQUAL, 10L); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair>[] pathAddedToThree = IndexTreeBuilder.add(filterSpecThree, testFilterCallback[3], top, lockFactory); FilterValueSet filterSpecFour = makeFilterValues( "theString", FilterOperator.EQUAL, "jack"); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair>[] pathAddedToFour = IndexTreeBuilder.add(filterSpecFour, testFilterCallback[4], top, lockFactory); FilterValueSet filterSpecFive = makeFilterValues( "longPrimitive", FilterOperator.EQUAL, 10L); ArrayDeque<EventTypeIndexBuilderIndexLookupablePair>[] pathAddedToFive = IndexTreeBuilder.add(filterSpecFive, testFilterCallback[5], top, lockFactory); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 5); matches.clear(); // Remove some of the nodes IndexTreeBuilder.remove(eventType, testFilterCallback[2], toArrayPath(pathAddedToTwo[0]), top); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 4); matches.clear(); // Remove some of the nodes IndexTreeBuilder.remove(eventType, testFilterCallback[4], toArrayPath(pathAddedToFour[0]), top); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 3); matches.clear(); // Remove some of the nodes IndexTreeBuilder.remove(eventType, testFilterCallback[5], toArrayPath(pathAddedToFive[0]), top); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 2); matches.clear(); // Remove some of the nodes IndexTreeBuilder.remove(eventType, testFilterCallback[1], toArrayPath(pathAddedToOne[0]), top); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 1); matches.clear(); // Remove some of the nodes IndexTreeBuilder.remove(eventType, testFilterCallback[3], toArrayPath(pathAddedToThree[0]), top); top.matchEvent(eventBean, matches); assertTrue(matches.size() == 0); matches.clear(); } private EventTypeIndexBuilderIndexLookupablePair[] toArrayPath(ArrayDeque<EventTypeIndexBuilderIndexLookupablePair> path) { return path.toArray(new EventTypeIndexBuilderIndexLookupablePair[path.size()]); } private FilterValueSet makeFilterValues(Object... filterSpecArgs) { FilterSpecCompiled spec = SupportFilterSpecBuilder.build(eventType, filterSpecArgs); FilterValueSet filterValues = spec.getValueSet(null, null, null); return filterValues; } }