/* *************************************************************************************** * 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.regression.client; import com.espertech.esper.client.*; import com.espertech.esper.client.hook.EPLMethodInvocationContext; import com.espertech.esper.client.scopetest.EPAssertionUtil; import com.espertech.esper.client.scopetest.SupportUpdateListener; import com.espertech.esper.client.soda.EPStatementObjectModel; import com.espertech.esper.collection.UniformPair; import com.espertech.esper.metrics.instrumentation.InstrumentationHelper; import com.espertech.esper.supportregression.bean.ISupportBImpl; import com.espertech.esper.supportregression.bean.SupportBean; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.supportregression.util.SupportMessageAssertUtil; import junit.framework.TestCase; import java.io.StringWriter; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; public class TestSingleRowFunctionPlugIn extends TestCase { private EPServiceProvider epService; private SupportUpdateListener listener; public void setUp() { listener = new SupportUpdateListener(); Configuration configuration = SupportConfigFactory.getConfiguration(); configuration.addPlugInSingleRowFunction("power3", MySingleRowFunction.class.getName(), "computePower3"); configuration.addPlugInSingleRowFunction("chainTop", MySingleRowFunction.class.getName(), "getChainTop"); configuration.addPlugInSingleRowFunction("surroundx", MySingleRowFunction.class.getName(), "surroundx"); configuration.addPlugInSingleRowFunction("throwExceptionLogMe", MySingleRowFunction.class.getName(), "throwexception", ConfigurationPlugInSingleRowFunction.ValueCache.DISABLED, ConfigurationPlugInSingleRowFunction.FilterOptimizable.ENABLED, false); configuration.addPlugInSingleRowFunction("throwExceptionRethrow", MySingleRowFunction.class.getName(), "throwexception", ConfigurationPlugInSingleRowFunction.ValueCache.DISABLED, ConfigurationPlugInSingleRowFunction.FilterOptimizable.ENABLED, true); configuration.addPlugInSingleRowFunction("power3Rethrow", MySingleRowFunction.class.getName(), "computePower3", ConfigurationPlugInSingleRowFunction.ValueCache.DISABLED, ConfigurationPlugInSingleRowFunction.FilterOptimizable.ENABLED, true); configuration.addPlugInSingleRowFunction("power3Context", MySingleRowFunction.class.getName(), "computePower3WithContext", ConfigurationPlugInSingleRowFunction.ValueCache.DISABLED, ConfigurationPlugInSingleRowFunction.FilterOptimizable.ENABLED, true); configuration.addPlugInSingleRowFunction("isNullValue", MySingleRowFunction.class.getName(), "isNullValue"); configuration.addPlugInSingleRowFunction("getValueAsString", MySingleRowFunction.class.getName(), "getValueAsString"); configuration.addPlugInSingleRowFunction("eventsCheckStrings", MySingleRowFunction.class.getName(), "eventsCheckStrings"); configuration.addPlugInSingleRowFunction("varargsOnlyInt", MySingleRowFunction.class.getName(), "varargsOnlyInt"); configuration.addPlugInSingleRowFunction("varargsOnlyString", MySingleRowFunction.class.getName(), "varargsOnlyString"); configuration.addPlugInSingleRowFunction("varargsOnlyObject", MySingleRowFunction.class.getName(), "varargsOnlyObject"); configuration.addPlugInSingleRowFunction("varargsOnlyNumber", MySingleRowFunction.class.getName(), "varargsOnlyNumber"); configuration.addPlugInSingleRowFunction("varargsOnlyISupportBaseAB", MySingleRowFunction.class.getName(), "varargsOnlyISupportBaseAB"); configuration.addPlugInSingleRowFunction("varargsW1Param", MySingleRowFunction.class.getName(), "varargsW1Param"); configuration.addPlugInSingleRowFunction("varargsW2Param", MySingleRowFunction.class.getName(), "varargsW2Param"); configuration.addPlugInSingleRowFunction("varargsOnlyWCtx", MySingleRowFunction.class.getName(), "varargsOnlyWCtx"); configuration.addPlugInSingleRowFunction("varargsW1ParamWCtx", MySingleRowFunction.class.getName(), "varargsW1ParamWCtx"); configuration.addPlugInSingleRowFunction("varargsW2ParamWCtx", MySingleRowFunction.class.getName(), "varargsW2ParamWCtx"); configuration.addPlugInSingleRowFunction("varargsObjectsWCtx", MySingleRowFunction.class.getName(), "varargsObjectsWCtx"); configuration.addPlugInSingleRowFunction("varargsW1ParamObjectsWCtx", MySingleRowFunction.class.getName(), "varargsW1ParamObjectsWCtx"); epService = EPServiceProviderManager.getDefaultProvider(configuration); epService.initialize(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());} epService.getEPAdministrator().getConfiguration().addEventType("SupportBean", SupportBean.class); } public void tearDown() { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();} listener = null; } public void testReturnTypeIsEvents() { runAssertionReturnTypeIsEvents("myItemProducerEventBeanArray"); runAssertionReturnTypeIsEvents("myItemProducerEventBeanCollection"); runAssertionReturnTypeIsEventsInvalid(); } private void runAssertionReturnTypeIsEvents(String methodName) { ConfigurationPlugInSingleRowFunction entry = new ConfigurationPlugInSingleRowFunction(); entry.setName(methodName); entry.setFunctionClassName(this.getClass().getName()); entry.setFunctionMethodName(methodName); entry.setEventTypeName("MyItem"); epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction(entry); epService.getEPAdministrator().createEPL("create schema MyItem(id string)"); EPStatement stmt = epService.getEPAdministrator().createEPL("select " + methodName + "(theString).where(v => v.id in ('id1', 'id3')) as c0 from SupportBean"); stmt.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("id0,id1,id2,id3,id4", 0)); Collection<Map> coll = (Collection<Map>) listener.assertOneGetNewAndReset().get("c0"); EPAssertionUtil.assertPropsPerRow(coll.toArray(new Map[coll.size()]), "id".split(","), new Object[][] {{"id1"}, {"id3"}}); stmt.destroy(); } private void runAssertionReturnTypeIsEventsInvalid() { ConfigurationPlugInSingleRowFunction entry = new ConfigurationPlugInSingleRowFunction(); entry.setFunctionClassName(this.getClass().getName()); entry.setFunctionMethodName("myItemProducerEventBeanArray"); // test invalid: no event type name entry.setName("myItemProducerInvalidNoType"); entry.setEventTypeName(null); epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction(entry); epService.getEPAdministrator().createEPL("select myItemProducerInvalidNoType(theString) as c0 from SupportBean"); SupportMessageAssertUtil.tryInvalid(epService, "select myItemProducerInvalidNoType(theString).where(v => v.id='id1') as c0 from SupportBean", "Error starting statement: Failed to validate select-clause expression 'myItemProducerInvalidNoType(theStri...(68 chars)': Method 'myItemProducerEventBeanArray' returns EventBean-array but does not provide the event type name ["); // test invalid: event type name invalid entry.setName("myItemProducerInvalidWrongType"); entry.setEventTypeName("dummy"); epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction(entry); SupportMessageAssertUtil.tryInvalid(epService, "select myItemProducerInvalidWrongType(theString).where(v => v.id='id1') as c0 from SupportBean", "Error starting statement: Failed to validate select-clause expression 'myItemProducerInvalidWrongType(theS...(74 chars)': Method 'myItemProducerEventBeanArray' returns event type 'dummy' and the event type cannot be found [select myItemProducerInvalidWrongType(theString).where(v => v.id='id1') as c0 from SupportBean]"); } public void testVarargs() { runVarargAssertion( makePair("varargsOnlyInt(1, 2, 3, 4)", "1,2,3,4"), makePair("varargsOnlyInt(1, 2, 3)", "1,2,3"), makePair("varargsOnlyInt(1, 2)", "1,2"), makePair("varargsOnlyInt(1)", "1"), makePair("varargsOnlyInt()", "")); runVarargAssertion( makePair("varargsW1Param('abc', 1.0, 2.0)", "abc,1.0,2.0"), makePair("varargsW1Param('abc', 1, 2)", "abc,1.0,2.0"), makePair("varargsW1Param('abc', 1)", "abc,1.0"), makePair("varargsW1Param('abc')", "abc")); runVarargAssertion( makePair("varargsW2Param(1, 2.0, 3L, 4L)", "1,2.0,3,4"), makePair("varargsW2Param(1, 2.0, 3L)", "1,2.0,3"), makePair("varargsW2Param(1, 2.0)", "1,2.0"), makePair("varargsW2Param(1, 2.0, 3, 4L)", "1,2.0,3,4"), makePair("varargsW2Param(1, 2.0, 3L, 4L)", "1,2.0,3,4"), makePair("varargsW2Param(1, 2.0, 3, 4)", "1,2.0,3,4"), makePair("varargsW2Param(1, 2.0, 3L, 4)", "1,2.0,3,4")); runVarargAssertion( makePair("varargsOnlyWCtx(1, 2, 3)", "CTX+1,2,3"), makePair("varargsOnlyWCtx(1, 2)", "CTX+1,2"), makePair("varargsOnlyWCtx(1)", "CTX+1"), makePair("varargsOnlyWCtx()", "CTX+")); runVarargAssertion( makePair("varargsW1ParamWCtx('a', 1, 2, 3)", "CTX+a,1,2,3"), makePair("varargsW1ParamWCtx('a', 1, 2)", "CTX+a,1,2"), makePair("varargsW1ParamWCtx('a', 1)", "CTX+a,1"), makePair("varargsW1ParamWCtx('a')", "CTX+a,")); runVarargAssertion( makePair("varargsW2ParamWCtx('a', 'b', 1, 2, 3)", "CTX+a,b,1,2,3"), makePair("varargsW2ParamWCtx('a', 'b', 1, 2)", "CTX+a,b,1,2"), makePair("varargsW2ParamWCtx('a', 'b', 1)", "CTX+a,b,1"), makePair("varargsW2ParamWCtx('a', 'b')", "CTX+a,b,"), makePair(MySingleRowFunction.class.getName() + ".varargsW2ParamWCtx('a', 'b')", "CTX+a,b,")); runVarargAssertion( makePair("varargsOnlyObject('a', 1, new BigInteger('2'))", "a,1,2")); runVarargAssertion( makePair("varargsOnlyNumber(1f, 2L, 3, new BigInteger('4'))", "1.0,2,3,4")); runVarargAssertion( makePair("varargsOnlyNumber(1f, 2L, 3, new BigInteger('4'))", "1.0,2,3,4")); runVarargAssertion( makePair("varargsOnlyISupportBaseAB(new " + ISupportBImpl.class.getName() + "('a', 'b'))", "ISupportBImpl{valueB='a', valueBaseAB='b'}")); // tests for array-passthru runVarargAssertion( makePair("varargsOnlyString({'a'})", "a"), makePair("varargsOnlyString({'a', 'b'})", "a,b"), makePair("varargsOnlyObject({'a', 'b'})", "a,b"), makePair("varargsOnlyObject({})", ""), makePair("varargsObjectsWCtx({1, 'a'})", "CTX+1,a"), makePair("varargsW1ParamObjectsWCtx(1, {'a', 1})", "CTX+,1,a,1") ); // try Arrays.asList runAssertionArraysAsList(); } public void testEventBeanFootprint() { epService.getEPAdministrator().getConfiguration().addImport(this.getClass()); // test select-clause String fields[] = new String[] {"c0", "c1"}; String text = "select isNullValue(*, 'theString') as c0," + "TestSingleRowFunctionPlugIn.localIsNullValue(*, 'theString') as c1 from SupportBean"; EPStatement stmt = epService.getEPAdministrator().createEPL(text); stmt.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("a", 1)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[]{false, false}); epService.getEPRuntime().sendEvent(new SupportBean(null, 2)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[]{true, true}); stmt.destroy(); // test pattern String textPattern = "select * from pattern [a=SupportBean -> b=SupportBean(theString=getValueAsString(a, 'theString'))]"; EPStatement stmtPattern = epService.getEPAdministrator().createEPL(textPattern); stmtPattern.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("E1", 1)); epService.getEPRuntime().sendEvent(new SupportBean("E1", 2)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), "a.intPrimitive,b.intPrimitive".split(","), new Object[] {1, 2}); stmtPattern.destroy(); // test filter String textFilter = "select * from SupportBean('E1'=getValueAsString(*, 'theString'))"; EPStatement stmtFilter = epService.getEPAdministrator().createEPL(textFilter); stmtFilter.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("E2", 1)); epService.getEPRuntime().sendEvent(new SupportBean("E1", 2)); assertEquals(1, listener.getAndResetLastNewData().length); stmtFilter.destroy(); // test "first" String textAccessAgg = "select * from SupportBean#keepall having 'E2' = getValueAsString(last(*), 'theString')"; EPStatement stmtAccessAgg = epService.getEPAdministrator().createEPL(textAccessAgg); stmtAccessAgg.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("E2", 1)); epService.getEPRuntime().sendEvent(new SupportBean("E1", 2)); assertEquals(1, listener.getAndResetLastNewData().length); stmtAccessAgg.destroy(); // test "window" String textWindowAgg = "select * from SupportBean#keepall having eventsCheckStrings(window(*), 'theString', 'E1')"; EPStatement stmtWindowAgg = epService.getEPAdministrator().createEPL(textWindowAgg); stmtWindowAgg.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("E2", 1)); epService.getEPRuntime().sendEvent(new SupportBean("E1", 2)); assertEquals(1, listener.getAndResetLastNewData().length); stmtWindowAgg.destroy(); } public void testPropertyOrSingleRowMethod() throws Exception { String text = "select surroundx('test') as val from SupportBean"; EPStatement stmt = epService.getEPAdministrator().createEPL(text); stmt.addListener(listener); String fields[] = new String[] {"val"}; epService.getEPRuntime().sendEvent(new SupportBean("a", 3)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[]{"XtestX"}); } public void testChainMethod() throws Exception { String text = "select chainTop().chainValue(12,intPrimitive) as val from SupportBean"; EPStatement stmt = epService.getEPAdministrator().createEPL(text); stmt.addListener(listener); runAssertionChainMethod(); stmt.destroy(); EPStatementObjectModel model = epService.getEPAdministrator().compileEPL(text); assertEquals(text, model.toEPL()); stmt = epService.getEPAdministrator().create(model); assertEquals(text, stmt.getText()); stmt.addListener(listener); runAssertionChainMethod(); } public void testSingleMethod() throws Exception { String text = "select power3(intPrimitive) as val from SupportBean"; EPStatement stmt = epService.getEPAdministrator().createEPL(text); stmt.addListener(listener); runAssertionSingleMethod(); stmt.destroy(); EPStatementObjectModel model = epService.getEPAdministrator().compileEPL(text); assertEquals(text, model.toEPL()); stmt = epService.getEPAdministrator().create(model); assertEquals(text, stmt.getText()); stmt.addListener(listener); runAssertionSingleMethod(); stmt.destroy(); text = "select power3(2) as val from SupportBean"; stmt = epService.getEPAdministrator().createEPL(text); stmt.addListener(listener); runAssertionSingleMethod(); stmt.destroy(); // test passing a context as well text = "@Name('A') select power3Context(intPrimitive) as val from SupportBean"; stmt = epService.getEPAdministrator().createEPL(text, (Object) "my_user_object"); stmt.addListener(listener); MySingleRowFunction.getMethodInvokeContexts().clear(); runAssertionSingleMethod(); EPLMethodInvocationContext context = MySingleRowFunction.getMethodInvokeContexts().get(0); assertEquals("A", context.getStatementName()); assertEquals(epService.getURI(), context.getEngineURI()); assertEquals(-1, context.getContextPartitionId()); assertEquals("power3Context", context.getFunctionName()); assertEquals("my_user_object", context.getStatementUserObject()); stmt.destroy(); // test exception behavior // logged-only epService.getEPAdministrator().createEPL("select throwExceptionLogMe() from SupportBean").addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean("E1", 1)); epService.getEPAdministrator().destroyAllStatements(); // rethrow epService.getEPAdministrator().createEPL("@Name('S0') select throwExceptionRethrow() from SupportBean").addListener(listener); try { epService.getEPRuntime().sendEvent(new SupportBean("E1", 1)); fail(); } catch (EPException ex) { assertEquals("java.lang.RuntimeException: Unexpected exception in statement 'S0': Invocation exception when invoking method 'throwexception' of class 'com.espertech.esper.regression.client.MySingleRowFunction' passing parameters [] for statement 'S0': RuntimeException : This is a 'throwexception' generated exception", ex.getMessage()); epService.getEPAdministrator().destroyAllStatements(); } // NPE when boxed is null epService.getEPAdministrator().createEPL("@Name('S1') select power3Rethrow(intBoxed) from SupportBean").addListener(listener); try { epService.getEPRuntime().sendEvent(new SupportBean("E1", 1)); fail(); } catch (EPException ex) { assertEquals("java.lang.RuntimeException: Unexpected exception in statement 'S1': NullPointerException invoking method 'computePower3' of class 'com.espertech.esper.regression.client.MySingleRowFunction' in parameter 0 passing parameters [null] for statement 'S1': The method expects a primitive int value but received a null value", ex.getMessage()); } } private void runAssertionChainMethod() { String fields[] = new String[] {"val"}; epService.getEPRuntime().sendEvent(new SupportBean("a", 3)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[]{36}); listener.reset(); } private void runAssertionSingleMethod() { String fields[] = new String[] {"val"}; epService.getEPRuntime().sendEvent(new SupportBean("a", 2)); EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[]{8}); listener.reset(); } public void testFailedValidation() { Configuration configuration = SupportConfigFactory.getConfiguration(); configuration.addPlugInSingleRowFunction("singlerow", MySingleRowFunctionTwo.class.getName(), "testSingleRow"); epService = EPServiceProviderManager.getDefaultProvider(configuration); epService.initialize(); try { String text = "select singlerow('a', 'b') from " + SupportBean.class.getName(); epService.getEPAdministrator().createEPL(text); } catch (EPStatementException ex) { SupportMessageAssertUtil.assertMessage(ex, "Error starting statement: Failed to validate select-clause expression 'singlerow(\"a\",\"b\")': Could not find static method named 'testSingleRow' in class 'com.espertech.esper.regression.client.MySingleRowFunctionTwo' with matching parameter number and expected parameter type(s) 'String, String' (nearest match found was 'testSingleRow' taking type(s) 'String, int')"); } } public void testInvalidConfigure() { tryInvalidConfigure("a b", "MyClass", "some"); tryInvalidConfigure("abc", "My Class", "other s"); // configured twice try { epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction("concatstring", MySingleRowFunction.class.getName(), "xyz"); epService.getEPAdministrator().getConfiguration().addPlugInAggregationFunctionFactory("concatstring", MyConcatAggregationFunctionFactory.class.getName()); fail(); } catch (ConfigurationException ex) { // expected } // configured twice try { epService.getEPAdministrator().getConfiguration().addPlugInAggregationFunctionFactory("teststring", MyConcatAggregationFunctionFactory.class.getName()); epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction("teststring", MySingleRowFunction.class.getName(), "xyz"); fail(); } catch (ConfigurationException ex) { // expected } } private void tryInvalidConfigure(String funcName, String className, String methodName) { try { epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction(funcName, className, methodName); fail(); } catch (ConfigurationException ex) { // expected } } public static boolean localIsNullValue(EventBean event, String propertyName) { return event.get(propertyName) == null; } private void runVarargAssertion(UniformPair<String> ... pairs) { StringWriter buf = new StringWriter(); buf.append("@name('test') select "); int count = 0; for (UniformPair<String> pair : pairs) { buf.append(pair.getFirst()); buf.append(" as c"); buf.append(Integer.toString(count)); count++; buf.append(","); } buf.append("intPrimitive from SupportBean"); epService.getEPAdministrator().createEPL(buf.toString()).addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean()); EventBean out = listener.assertOneGetNewAndReset(); count = 0; for (UniformPair<String> pair : pairs) { assertEquals("failed for '" + pair.getFirst() + "'", pair.getSecond(), out.get("c" + count)); count++; } epService.getEPAdministrator().getStatement("test").destroy(); } private UniformPair<String> makePair(String expression, String expected) { return new UniformPair<String>(expression, expected); } private void runAssertionArraysAsList() { EPStatement stmt = epService.getEPAdministrator().createEPL("select " + "java.util.Arrays.asList('a') as c0, " + "java.util.Arrays.asList({'a'}) as c1, " + "java.util.Arrays.asList('a', 'b') as c2, " + "java.util.Arrays.asList({'a', 'b'}) as c3 " + "from SupportBean"); stmt.addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean()); EventBean event = listener.assertOneGetNewAndReset(); assertEqualsColl(event, "c0", "a"); assertEqualsColl(event, "c1", "a"); assertEqualsColl(event, "c2", "a", "b"); assertEqualsColl(event, "c3", "a", "b"); stmt.destroy(); } private void assertEqualsColl(EventBean event, String property, String ... values) { Collection data = (Collection) event.get(property); EPAssertionUtil.assertEqualsExactOrder(values, data.toArray()); } public static EventBean[] myItemProducerEventBeanArray(String string, EPLMethodInvocationContext context) { String[] split = string.split(","); EventBean[] events = new EventBean[split.length]; for (int i = 0; i < split.length; i++) { events[i] = context.getEventBeanService().adapterForMap(Collections.singletonMap("id", split[i]), "MyItem"); } return events; } public static Collection<EventBean> myItemProducerEventBeanCollection(String string, EPLMethodInvocationContext context) { return Arrays.asList(myItemProducerEventBeanArray(string, context)); } }