/* *************************************************************************************** * 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.epl; import com.espertech.esper.avro.core.AvroEventType; import com.espertech.esper.client.*; import com.espertech.esper.client.hook.EPLMethodInvocationContext; import com.espertech.esper.client.hook.EPLScriptContext; 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.epl.script.AgentInstanceScriptContext; import com.espertech.esper.event.avro.AvroConstantsNoDep; import com.espertech.esper.metrics.instrumentation.InstrumentationHelper; import com.espertech.esper.regression.script.SupportScriptUtil; import com.espertech.esper.supportregression.bean.SupportBean; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.util.EventRepresentationChoice; import junit.framework.TestCase; import org.apache.avro.Schema; import org.apache.avro.generic.GenericData; import java.util.*; import static org.apache.avro.SchemaBuilder.record; public class TestContainedEventSplitExpr extends TestCase { private EPServiceProvider epService; private SupportUpdateListener listener; public void setUp() { epService = EPServiceProviderManager.getDefaultProvider(SupportConfigFactory.getConfiguration()); epService.initialize(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName()); } listener = new SupportUpdateListener(); } protected void tearDown() throws Exception { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest(); } listener = null; } public void testScriptContextValue() throws Exception { epService.getEPAdministrator().getConfiguration().addEventType(SupportBean.class); String script = "@name('mystmt') create expression Object js:myGetScriptContext() [\n" + "myGetScriptContext();" + "function myGetScriptContext() {" + " return epl;\n" + "}]"; epService.getEPAdministrator().createEPL(script); epService.getEPAdministrator().createEPL("select myGetScriptContext() as c0 from SupportBean").addListener(listener); epService.getEPRuntime().sendEvent(new SupportBean()); EPLScriptContext context = (EPLScriptContext) listener.assertOneGetNewAndReset().get("c0"); assertNotNull(context.getEventBeanService()); } public void testSplitExprReturnsEventBean() throws Exception { epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction("mySplitUDFReturnEventBeanArray", this.getClass().getName(), "mySplitUDFReturnEventBeanArray"); String script = "create expression EventBean[] js:mySplitScriptReturnEventBeanArray(value) [\n" + "mySplitScriptReturnEventBeanArray(value);" + "function mySplitScriptReturnEventBeanArray(value) {" + " var split = value.split(',');\n" + " var EventBeanArray = Java.type(\"com.espertech.esper.client.EventBean[]\");\n" + " var events = new EventBeanArray(split.length); " + " for (var i = 0; i < split.length; i++) {\n" + " var pvalue = split[i].substring(1);\n" + " if (split[i].startsWith(\"A\")) {\n" + " events[i] = epl.getEventBeanService().adapterForMap(java.util.Collections.singletonMap(\"p0\", pvalue), \"AEvent\");\n" + " }\n" + " else if (split[i].startsWith(\"B\")) {\n" + " events[i] = epl.getEventBeanService().adapterForMap(java.util.Collections.singletonMap(\"p1\", pvalue), \"BEvent\");\n" + " }\n" + " else {\n" + " throw new UnsupportedOperationException(\"Unrecognized type\");\n" + " }\n" + " }\n" + " return events;\n" + "}]"; epService.getEPAdministrator().createEPL(script); String epl = "create schema BaseEvent();\n" + "create schema AEvent(p0 string) inherits BaseEvent;\n" + "create schema BEvent(p1 string) inherits BaseEvent;\n" + "create schema SplitEvent(value string);\n"; epService.getEPAdministrator().getDeploymentAdmin().parseDeploy(epl); runAssertionSplitExprReturnsEventBean("mySplitUDFReturnEventBeanArray"); runAssertionSplitExprReturnsEventBean("mySplitScriptReturnEventBeanArray"); } private void runAssertionSplitExprReturnsEventBean(String functionOrScript) { String epl = "@name('s0') select * from SplitEvent[" + functionOrScript + "(value) @type(BaseEvent)]"; EPStatement statement = epService.getEPAdministrator().createEPL(epl); statement.addListener(listener); epService.getEPRuntime().sendEvent(Collections.singletonMap("value", "AE1,BE2,AE3"), "SplitEvent"); EventBean[] events = listener.getAndResetLastNewData(); assertSplitEx(events[0], "AEvent", "p0", "E1"); assertSplitEx(events[1], "BEvent", "p1", "E2"); assertSplitEx(events[2], "AEvent", "p0", "E3"); statement.destroy(); } public void testSingleRowSplitAndType() { for (EventRepresentationChoice rep : EventRepresentationChoice.values()) { runAssertionSingleRowSplitAndType(rep); } } private void runAssertionSingleRowSplitAndType(EventRepresentationChoice eventRepresentationEnum) { String[] methods; if (eventRepresentationEnum.isObjectArrayEvent()) { methods = "splitSentenceMethodReturnObjectArray,splitSentenceBeanMethodReturnObjectArray,splitWordMethodReturnObjectArray".split(","); } else if (eventRepresentationEnum.isMapEvent()) { methods = "splitSentenceMethodReturnMap,splitSentenceBeanMethodReturnMap,splitWordMethodReturnMap".split(","); } else if (eventRepresentationEnum.isAvroEvent()) { methods = "splitSentenceMethodReturnAvro,splitSentenceBeanMethodReturnAvro,splitWordMethodReturnAvro".split(","); } else { throw new IllegalStateException("Unrecognized enum " + eventRepresentationEnum); } String[] funcs = "splitSentence,splitSentenceBean,splitWord".split(","); for (int i = 0; i < funcs.length; i++) { epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction(funcs[i], this.getClass().getName(), methods[i]); } epService.getEPAdministrator().getConfiguration().addPlugInSingleRowFunction("invalidSentence", this.getClass().getName(), "invalidSentenceMethod"); epService.getEPAdministrator().createEPL(eventRepresentationEnum.getAnnotationText() + " create schema SentenceEvent(sentence String)"); epService.getEPAdministrator().createEPL(eventRepresentationEnum.getAnnotationText() + " create schema WordEvent(word String)"); epService.getEPAdministrator().createEPL(eventRepresentationEnum.getAnnotationText() + " create schema CharacterEvent(char String)"); String stmtText; EPStatement stmt; String[] fields = "word".split(","); // test single-row method stmtText = "select * from SentenceEvent[splitSentence(sentence)@type(WordEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); assertTrue(eventRepresentationEnum.matchesClass(stmt.getEventType().getUnderlyingType())); sendSentenceEvent(eventRepresentationEnum, "I am testing this code"); EPAssertionUtil.assertPropsPerRow(listener.getAndResetLastNewData(), fields, new Object[][]{{"I"}, {"am"}, {"testing"}, {"this"}, {"code"}}); sendSentenceEvent(eventRepresentationEnum, "the second event"); EPAssertionUtil.assertPropsPerRow(listener.getAndResetLastNewData(), fields, new Object[][]{{"the"}, {"second"}, {"event"}}); stmt.destroy(); // test SODA EPStatementObjectModel model = epService.getEPAdministrator().compileEPL(stmtText); assertEquals(stmtText, model.toEPL()); stmt = epService.getEPAdministrator().create(model); assertEquals(stmtText, stmt.getText()); stmt.addListener(listener); sendSentenceEvent(eventRepresentationEnum, "the third event"); EPAssertionUtil.assertPropsPerRow(listener.getAndResetLastNewData(), fields, new Object[][]{{"the"}, {"third"}, {"event"}}); stmt.destroy(); // test script if (eventRepresentationEnum.isMapEvent()) { if (SupportScriptUtil.JAVA_VERSION <= 1.7) { stmtText = "expression Collection js:splitSentenceJS(sentence) [" + " importPackage(java.util);" + " var words = new ArrayList();" + " words.add(Collections.singletonMap('word', 'wordOne'));" + " words.add(Collections.singletonMap('word', 'wordTwo'));" + " words;" + "]" + "select * from SentenceEvent[splitSentenceJS(sentence)@type(WordEvent)]"; } else { stmtText = "expression Collection js:splitSentenceJS(sentence) [" + " var CollectionsClazz = Java.type('java.util.Collections');" + " var words = new java.util.ArrayList();" + " words.add(CollectionsClazz.singletonMap('word', 'wordOne'));" + " words.add(CollectionsClazz.singletonMap('word', 'wordTwo'));" + " words;" + "]" + "select * from SentenceEvent[splitSentenceJS(sentence)@type(WordEvent)]"; } stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); epService.getEPRuntime().sendEvent(Collections.emptyMap(), "SentenceEvent"); EPAssertionUtil.assertPropsPerRowAnyOrder(listener.getAndResetLastNewData(), fields, new Object[][]{{"wordOne"}, {"wordTwo"}}); stmt.destroy(); } // test multiple splitters stmtText = "select * from SentenceEvent[splitSentence(sentence)@type(WordEvent)][splitWord(word)@type(CharacterEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("CharacterEvent", stmt.getEventType().getName()); sendSentenceEvent(eventRepresentationEnum, "I am"); EPAssertionUtil.assertPropsPerRowAnyOrder(listener.getAndResetLastNewData(), "char".split(","), new Object[][]{{"I"}, {"a"}, {"m"}}); stmt.destroy(); // test wildcard parameter stmtText = "select * from SentenceEvent[splitSentenceBean(*)@type(WordEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); sendSentenceEvent(eventRepresentationEnum, "another test sentence"); EPAssertionUtil.assertPropsPerRowAnyOrder(listener.getAndResetLastNewData(), fields, new Object[][]{{"another"}, {"test"}, {"sentence"}}); stmt.destroy(); // test property returning untyped collection if (eventRepresentationEnum.isObjectArrayEvent()) { epService.getEPAdministrator().getConfiguration().addEventType(ObjectArrayEvent.class); stmtText = eventRepresentationEnum.getAnnotationText() + " select * from ObjectArrayEvent[someObjectArray@type(WordEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); Object[][] rows = new Object[][]{{"this"}, {"is"}, {"collection"}}; epService.getEPRuntime().sendEvent(new ObjectArrayEvent(rows)); EPAssertionUtil.assertPropsPerRow(listener.getAndResetLastNewData(), fields, new Object[][]{{"this"}, {"is"}, {"collection"}}); stmt.destroy(); } else if (eventRepresentationEnum.isMapEvent()) { epService.getEPAdministrator().getConfiguration().addEventType(CollectionEvent.class); stmtText = eventRepresentationEnum.getAnnotationText() + " select * from CollectionEvent[someCollection@type(WordEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); Collection<Map> coll = new ArrayList<Map>(); coll.add(Collections.singletonMap("word", "this")); coll.add(Collections.singletonMap("word", "is")); coll.add(Collections.singletonMap("word", "collection")); epService.getEPRuntime().sendEvent(new CollectionEvent(coll)); EPAssertionUtil.assertPropsPerRowAnyOrder(listener.getAndResetLastNewData(), fields, new Object[][]{{"this"}, {"is"}, {"collection"}}); stmt.destroy(); } else if (eventRepresentationEnum.isAvroEvent()) { epService.getEPAdministrator().getConfiguration().addEventType(AvroArrayEvent.class); stmtText = eventRepresentationEnum.getAnnotationText() + " select * from AvroArrayEvent[someAvroArray@type(WordEvent)]"; stmt = epService.getEPAdministrator().createEPL(stmtText); stmt.addListener(listener); assertEquals("WordEvent", stmt.getEventType().getName()); GenericData.Record[] rows = new GenericData.Record[3]; String[] words = "this,is,avro".split(","); for (int i = 0; i < words.length; i++) { rows[i] = new GenericData.Record(((AvroEventType) stmt.getEventType()).getSchemaAvro()); rows[i].put("word", words[i]); } epService.getEPRuntime().sendEvent(new AvroArrayEvent(rows)); EPAssertionUtil.assertPropsPerRow(listener.getAndResetLastNewData(), fields, new Object[][]{{"this"}, {"is"}, {"avro"}}); stmt.destroy(); } else { throw new IllegalArgumentException("Unrecognized enum " + eventRepresentationEnum); } // invalid: event type not found tryInvalid("select * from SentenceEvent[splitSentence(sentence)@type(XYZ)]", "Event type by name 'XYZ' could not be found [select * from SentenceEvent[splitSentence(sentence)@type(XYZ)]]"); // invalid lib-function annotation tryInvalid("select * from SentenceEvent[splitSentence(sentence)@dummy(WordEvent)]", "Invalid annotation for property selection, expected 'type' but found 'dummy' in text '@dummy(WordEvent)'"); // invalid type assignment to event type if (eventRepresentationEnum.isObjectArrayEvent()) { tryInvalid("select * from SentenceEvent[invalidSentence(sentence)@type(WordEvent)]", "Event type 'WordEvent' underlying type [Ljava.lang.Object; cannot be assigned a value of type"); } else if (eventRepresentationEnum.isMapEvent()) { tryInvalid("select * from SentenceEvent[invalidSentence(sentence)@type(WordEvent)]", "Event type 'WordEvent' underlying type java.util.Map cannot be assigned a value of type"); } else if (eventRepresentationEnum.isAvroEvent()) { tryInvalid("select * from SentenceEvent[invalidSentence(sentence)@type(WordEvent)]", "Event type 'WordEvent' underlying type " + AvroConstantsNoDep.GENERIC_RECORD_CLASSNAME + " cannot be assigned a value of type"); } else { fail(); } // invalid subquery tryInvalid("select * from SentenceEvent[splitSentence((select * from SupportBean#keepall))@type(WordEvent)]", "Invalid contained-event expression 'splitSentence(subselect_0)': Aggregation, sub-select, previous or prior functions are not supported in this context [select * from SentenceEvent[splitSentence((select * from SupportBean#keepall))@type(WordEvent)]]"); epService.initialize(); } private void sendSentenceEvent(EventRepresentationChoice eventRepresentationEnum, String sentence) { if (eventRepresentationEnum.isObjectArrayEvent()) { epService.getEPRuntime().sendEvent(new Object[]{sentence}, "SentenceEvent"); } else if (eventRepresentationEnum.isMapEvent()) { epService.getEPRuntime().sendEvent(Collections.singletonMap("sentence", sentence), "SentenceEvent"); } else if (eventRepresentationEnum.isAvroEvent()) { Schema schema = record("sentence").fields().requiredString("sentence").endRecord(); GenericData.Record record = new GenericData.Record(schema); record.put("sentence", sentence); epService.getEPRuntime().sendEventAvro(record, "SentenceEvent"); } else { throw new IllegalStateException("Unrecognized enum " + eventRepresentationEnum); } } private void assertSplitEx(EventBean event, String typeName, String propertyName, String propertyValue) { assertEquals(typeName, event.getEventType().getName()); assertEquals(propertyValue, event.get(propertyName)); } public static EventBean[] mySplitUDFReturnEventBeanArray(String value, EPLMethodInvocationContext context) { String[] split = value.split(","); EventBean[] events = new EventBean[split.length]; for (int i = 0; i < split.length; i++) { String pvalue = split[i].substring(1); if (split[i].startsWith("A")) { events[i] = context.getEventBeanService().adapterForMap(Collections.singletonMap("p0", pvalue), "AEvent"); } else if (split[i].startsWith("B")) { events[i] = context.getEventBeanService().adapterForMap(Collections.singletonMap("p1", pvalue), "BEvent"); } else { throw new UnsupportedOperationException("Unrecognized type"); } } return events; } public static Map[] splitSentenceMethodReturnMap(String sentence) { String[] words = sentence.split(" "); Map[] events = new Map[words.length]; for (int i = 0; i < words.length; i++) { events[i] = Collections.singletonMap("word", words[i]); } return events; } public static GenericData.Record[] splitSentenceMethodReturnAvro(String sentence) { Schema wordSchema = record("word").fields().requiredString("word").endRecord(); String[] words = sentence.split(" "); GenericData.Record[] events = new GenericData.Record[words.length]; for (int i = 0; i < words.length; i++) { events[i] = new GenericData.Record(wordSchema); events[i].put(0, words[i]); } return events; } public static Object[][] splitSentenceMethodReturnObjectArray(String sentence) { String[] words = sentence.split(" "); Object[][] events = new Object[words.length][]; for (int i = 0; i < words.length; i++) { events[i] = new Object[]{words[i]}; } return events; } public static Map[] splitSentenceBeanMethodReturnMap(Map sentenceEvent) { return splitSentenceMethodReturnMap((String) sentenceEvent.get("sentence")); } public static GenericData.Record[] splitSentenceBeanMethodReturnAvro(GenericData.Record sentenceEvent) { return splitSentenceMethodReturnAvro((String) sentenceEvent.get("sentence")); } public static Object[][] splitSentenceBeanMethodReturnObjectArray(Object[] sentenceEvent) { return splitSentenceMethodReturnObjectArray((String) sentenceEvent[0]); } public static Object[][] splitWordMethodReturnObjectArray(String word) { int count = word.length(); Object[][] events = new Object[count][]; for (int i = 0; i < word.length(); i++) { events[i] = new Object[]{Character.toString(word.charAt(i))}; } return events; } public static Map[] splitWordMethodReturnMap(String word) { List<Map> maps = new ArrayList<Map>(); for (int i = 0; i < word.length(); i++) { maps.add(Collections.singletonMap("char", Character.toString(word.charAt(i)))); } return maps.toArray(new Map[maps.size()]); } public static GenericData.Record[] splitWordMethodReturnAvro(String word) { Schema schema = record("chars").fields().requiredString("char").endRecord(); GenericData.Record[] records = new GenericData.Record[word.length()]; for (int i = 0; i < word.length(); i++) { records[i] = new GenericData.Record(schema); records[i].put("char", Character.toString(word.charAt(i))); } return records; } public static SupportBean[] invalidSentenceMethod(String sentence) { return null; } private void tryInvalid(String epl, String expected) { try { epService.getEPAdministrator().createEPL(epl); fail(); } catch (EPStatementException ex) { assertFalse(expected.isEmpty()); assertTrue("Received message: " + ex.getMessage(), ex.getMessage().startsWith(expected)); } } public static class CollectionEvent { private Collection someCollection; public CollectionEvent(Collection someCollection) { this.someCollection = someCollection; } public Collection getSomeCollection() { return someCollection; } public void setSomeCollection(Collection someCollection) { this.someCollection = someCollection; } } public static class ObjectArrayEvent { private Object[][] someObjectArray; public ObjectArrayEvent(Object[][] someObjectArray) { this.someObjectArray = someObjectArray; } public Object[][] getSomeObjectArray() { return someObjectArray; } } public static class AvroArrayEvent { private GenericData.Record[] someAvroArray; public AvroArrayEvent(GenericData.Record[] someAvroArray) { this.someAvroArray = someAvroArray; } public GenericData.Record[] getSomeAvroArray() { return someAvroArray; } } }