/* *************************************************************************************** * 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.event; import com.espertech.esper.client.*; import com.espertech.esper.client.scopetest.EPAssertionUtil; import com.espertech.esper.client.scopetest.SupportUpdateListener; import com.espertech.esper.collection.Pair; import com.espertech.esper.metrics.instrumentation.InstrumentationHelper; import com.espertech.esper.supportregression.bean.SupportBeanSimple; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.supportregression.event.SupportXML; import com.espertech.esper.supportregression.util.SupportMessageAssertUtil; import com.espertech.esper.util.JavaClassHelper; import com.espertech.esper.util.support.SupportEventTypeAssertionEnum; import com.espertech.esper.util.support.SupportEventTypeAssertionUtil; import junit.framework.TestCase; import org.apache.avro.Schema; import org.apache.avro.SchemaBuilder; import org.apache.avro.generic.GenericData; import org.w3c.dom.Document; import org.w3c.dom.Node; import java.util.*; import static com.espertech.esper.avro.core.AvroConstant.PROP_JAVA_STRING_KEY; import static com.espertech.esper.avro.core.AvroConstant.PROP_JAVA_STRING_VALUE; import static com.espertech.esper.supportregression.event.SupportEventInfra.*; public class TestEventInfraPropertyUnderlyingAndSimple extends TestCase { private final static String BEAN_TYPENAME = SupportBeanSimple.class.getSimpleName(); private static final FunctionSendEventIntString FMAP = (epService, a, b) -> { Map<String, Object> map = new HashMap<>(); map.put("myInt", a); map.put("myString", b); epService.getEPRuntime().sendEvent(map, MAP_TYPENAME); return map; }; private static final FunctionSendEventIntString FOA = (epService, a, b) -> { Object[] oa = new Object[] {a, b}; epService.getEPRuntime().sendEvent(oa, OA_TYPENAME); return oa; }; private static final FunctionSendEventIntString FBEAN = (epService, a, b) -> { SupportBeanSimple bean = new SupportBeanSimple(b, a); epService.getEPRuntime().sendEvent(bean); return bean; }; private static final FunctionSendEventIntString FXML = (epService, a, b) -> { String xml = "<myevent myInt=\"XXXXXX\" myString=\"YYYYYY\">\n" + "</myevent>\n"; xml = xml.replace("XXXXXX", a.toString()); xml = xml.replace("YYYYYY", b); try { Document d = SupportXML.sendEvent(epService.getEPRuntime(), xml); return d.getDocumentElement(); } catch (Exception e) { throw new RuntimeException(e); } }; private static final FunctionSendEventIntString FAVRO = (epService, a, b) -> { GenericData.Record datum = new GenericData.Record(getAvroSchema()); datum.put("myInt", a); datum.put("myString", b); epService.getEPRuntime().sendEventAvro(datum, AVRO_TYPENAME); return datum; }; private EPServiceProvider epService; protected void setUp() { Configuration configuration = SupportConfigFactory.getConfiguration(); addMapEventType(configuration); addOAEventType(configuration); configuration.addEventType(BEAN_TYPENAME, SupportBeanSimple.class); addXMLEventType(configuration); addAvroEventType(configuration); epService = EPServiceProviderManager.getDefaultProvider(configuration); epService.initialize(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());} } public void tearDown() { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();} } public void testPassUnderlyingGetViaPropertyExpression() { Pair<String, FunctionSendEventIntString>[] pairs = new Pair[]{ new Pair<>(MAP_TYPENAME, FMAP), new Pair<>(OA_TYPENAME, FOA), new Pair<>(BEAN_TYPENAME, FBEAN), new Pair<>(XML_TYPENAME, FXML), new Pair<>(AVRO_TYPENAME, FAVRO) }; for (Pair<String, FunctionSendEventIntString> pair : pairs) { runAssertionPassUnderlying(pair.getFirst(), pair.getSecond()); runAssertionPropertiesWGetter(pair.getFirst(), pair.getSecond()); runAssertionTypeValidProp(pair.getFirst(), (pair.getSecond() == FMAP || pair.getSecond() == FXML || pair.getSecond() == FOA)); runAssertionTypeInvalidProp(pair.getFirst(), pair.getSecond() == FXML); } } private void runAssertionPassUnderlying(String typename, FunctionSendEventIntString send) { String epl = "select * from " + typename; EPStatement statement = epService.getEPAdministrator().createEPL(epl); SupportUpdateListener listener = new SupportUpdateListener(); statement.addListener(listener); String[] fields = "myInt,myString".split(","); assertEquals(Integer.class, JavaClassHelper.getBoxedType(statement.getEventType().getPropertyType("myInt"))); assertEquals(String.class, statement.getEventType().getPropertyType("myString")); Object eventOne = send.apply(epService, 3, "some string"); EventBean event = listener.assertOneGetNewAndReset(); SupportEventTypeAssertionUtil.assertConsistency(event); assertEquals(eventOne, event.getUnderlying()); EPAssertionUtil.assertProps(event, fields, new Object[] {3, "some string"}); Object eventTwo = send.apply(epService, 4, "other string"); event = listener.assertOneGetNewAndReset(); assertEquals(eventTwo, event.getUnderlying()); EPAssertionUtil.assertProps(event, fields, new Object[] {4, "other string"}); statement.destroy(); } private void runAssertionPropertiesWGetter(String typename, FunctionSendEventIntString send) { String epl = "select myInt, exists(myInt) as exists_myInt, myString, exists(myString) as exists_myString from " + typename; EPStatement statement = epService.getEPAdministrator().createEPL(epl); SupportUpdateListener listener = new SupportUpdateListener(); statement.addListener(listener); String[] fields = "myInt,exists_myInt,myString,exists_myString".split(","); assertEquals(Integer.class, JavaClassHelper.getBoxedType(statement.getEventType().getPropertyType("myInt"))); assertEquals(String.class, statement.getEventType().getPropertyType("myString")); assertEquals(Boolean.class, statement.getEventType().getPropertyType("exists_myInt")); assertEquals(Boolean.class, statement.getEventType().getPropertyType("exists_myString")); send.apply(epService, 3, "some string"); EventBean event = listener.assertOneGetNewAndReset(); runAssertionEventInvalidProp(event); EPAssertionUtil.assertProps(event, fields, new Object[] {3, true, "some string", true}); send.apply(epService, 4, "other string"); event = listener.assertOneGetNewAndReset(); EPAssertionUtil.assertProps(event, fields, new Object[] {4, true, "other string", true}); statement.destroy(); } private void runAssertionEventInvalidProp(EventBean event) { for (String prop : Arrays.asList("xxxx", "myString[1]", "myString('a')", "x.y", "myString.x")) { SupportMessageAssertUtil.tryInvalidProperty(event, prop); SupportMessageAssertUtil.tryInvalidGetFragment(event, prop); } } private void runAssertionTypeValidProp(String typeName, boolean boxed) { EventType eventType = epService.getEPAdministrator().getConfiguration().getEventType(typeName); Object[][] expectedType = new Object[][]{{"myInt", boxed ? Integer.class : int.class, null, null}, {"myString", String.class, null, null}}; SupportEventTypeAssertionUtil.assertEventTypeProperties(expectedType, eventType, SupportEventTypeAssertionEnum.getSetWithFragment()); EPAssertionUtil.assertEqualsAnyOrder(new String[] {"myString", "myInt"}, eventType.getPropertyNames()); assertNotNull(eventType.getGetter("myInt")); assertTrue(eventType.isProperty("myInt")); assertEquals(boxed ? Integer.class : int.class, eventType.getPropertyType("myInt")); assertEquals(new EventPropertyDescriptor("myString", String.class, null, false, false, false, false, false), eventType.getPropertyDescriptor("myString")); } private void runAssertionTypeInvalidProp(String typeName, boolean xml) { EventType eventType = epService.getEPAdministrator().getConfiguration().getEventType(typeName); for (String prop : Arrays.asList("xxxx", "myString[0]", "myString('a')", "myString.x", "myString.x.y", "myString.x")) { assertEquals(false, eventType.isProperty(prop)); Class expected = null; if (xml) { if (prop.equals("myString[0]")) { expected = String.class; } if (prop.equals("myString.x?")) { expected = Node.class; } } assertEquals(expected, eventType.getPropertyType(prop)); assertNull(eventType.getPropertyDescriptor(prop)); assertNull(eventType.getFragmentType(prop)); } } private void addMapEventType(Configuration configuration) { LinkedHashMap<String, Object> properties = new LinkedHashMap<>(); properties.put("myInt", Integer.class); properties.put("myString", "string"); configuration.addEventType(MAP_TYPENAME, properties); } private void addOAEventType(Configuration configuration) { String[] names = {"myInt", "myString"}; Object[] types = {Integer.class, String.class}; configuration.addEventType(OA_TYPENAME, names, types); } private void addXMLEventType(Configuration configuration) { ConfigurationEventTypeXMLDOM eventTypeMeta = new ConfigurationEventTypeXMLDOM(); eventTypeMeta.setRootElementName("myevent"); String schema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<xs:schema targetNamespace=\"http://www.espertech.com/schema/esper\" elementFormDefault=\"qualified\" xmlns:esper=\"http://www.espertech.com/schema/esper\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n" + "\t<xs:element name=\"myevent\">\n" + "\t\t<xs:complexType>\n" + "\t\t\t<xs:attribute name=\"myInt\" type=\"xs:int\" use=\"required\"/>\n" + "\t\t\t<xs:attribute name=\"myString\" type=\"xs:string\" use=\"required\"/>\n" + "\t\t</xs:complexType>\n" + "\t</xs:element>\n" + "</xs:schema>\n"; eventTypeMeta.setSchemaText(schema); configuration.addEventType(XML_TYPENAME, eventTypeMeta); } private void addAvroEventType(Configuration configuration) { configuration.addEventTypeAvro(AVRO_TYPENAME, new ConfigurationEventTypeAvro(getAvroSchema())); } private static Schema getAvroSchema() { return SchemaBuilder.record(AVRO_TYPENAME) .fields() .name("myInt").type().intType().noDefault() .name("myString").type().stringBuilder().prop(PROP_JAVA_STRING_KEY, PROP_JAVA_STRING_VALUE).endString().noDefault() .endRecord(); } @FunctionalInterface interface FunctionSendEventIntString { public Object apply (EPServiceProvider epService, Integer intValue, String stringValue); } }