/* *************************************************************************************** * 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.avro.core.AvroSchemaUtil; import com.espertech.esper.client.*; 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.*; import com.espertech.esper.supportregression.client.SupportConfigFactory; import com.espertech.esper.supportregression.event.SupportEventInfra; import com.espertech.esper.supportregression.event.ValueWithExistsFlag; 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.Node; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; import static com.espertech.esper.supportregression.event.SupportEventInfra.*; import static com.espertech.esper.supportregression.event.ValueWithExistsFlag.*; public class TestEventInfraPropertyNestedDynamicDeep extends TestCase { private final static String BEAN_TYPENAME = SupportBeanDynRoot.class.getName(); private static final SupportEventInfra.FunctionSendEvent FAVRO = (epService, value) -> { Schema schema = getAvroSchema(); Schema itemSchema = schema.getField("item").schema(); GenericData.Record itemDatum = new GenericData.Record(itemSchema); itemDatum.put("nested", value); GenericData.Record datum = new GenericData.Record(schema); datum.put("item", itemDatum); epService.getEPRuntime().sendEventAvro(datum, AVRO_TYPENAME); }; private EPServiceProvider epService; protected void setUp() { Configuration configuration = SupportConfigFactory.getConfiguration(); addXMLEventType(configuration); epService = EPServiceProviderManager.getDefaultProvider(configuration); epService.initialize(); addMapEventType(); addOAEventType(); epService.getEPAdministrator().getConfiguration().addEventType(BEAN_TYPENAME, SupportBeanDynRoot.class); addAvroEventType(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());} } public void tearDown() { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();} } public void testIt() { final ValueWithExistsFlag[] NOT_EXISTS = multipleNotExists(6); // Bean SupportBeanComplexProps beanOne = SupportBeanComplexProps.makeDefaultBean(); String n1_v = beanOne.getNested().getNestedValue(); String n1_n_v = beanOne.getNested().getNestedNested().getNestedNestedValue(); SupportBeanComplexProps beanTwo = SupportBeanComplexProps.makeDefaultBean(); beanTwo.getNested().setNestedValue("nested1"); beanTwo.getNested().getNestedNested().setNestedNestedValue("nested2"); Pair[] beanTests = new Pair[]{ new Pair<>(new SupportBeanDynRoot(beanOne), allExist(n1_v, n1_v, n1_n_v, n1_n_v, n1_n_v, n1_n_v)), new Pair<>(new SupportBeanDynRoot(beanTwo), allExist("nested1", "nested1", "nested2", "nested2", "nested2", "nested2")), new Pair<>(new SupportBeanDynRoot("abc"), NOT_EXISTS) }; runAssertion(BEAN_TYPENAME, FBEAN, null, beanTests, Object.class); // Map Map<String,Object> mapOneL2 = new HashMap<>(); mapOneL2.put("nestedNestedValue", 101); Map<String,Object> mapOneL1 = new HashMap<>(); mapOneL1.put("nestedNested", mapOneL2); mapOneL1.put("nestedValue", 100); Map<String,Object> mapOneL0 = new HashMap<>(); mapOneL0.put("nested", mapOneL1); Map<String,Object> mapOne = Collections.singletonMap("item", mapOneL0); Pair[] mapTests = new Pair[]{ new Pair<>(mapOne, allExist(100, 100, 101, 101, 101, 101)), new Pair<>(Collections.emptyMap(), NOT_EXISTS), }; runAssertion(MAP_TYPENAME, FMAP, null, mapTests, Object.class); // Object-Array Object[] oaOneL2 = new Object[] {101}; Object[] oaOneL1 = new Object[] {oaOneL2, 100}; Object[] oaOneL0 = new Object[] {oaOneL1}; Object[] oaOne = new Object[] {oaOneL0}; Pair[] oaTests = new Pair[]{ new Pair<>(oaOne, allExist(100, 100, 101, 101, 101, 101)), new Pair<>(new Object[] {null}, NOT_EXISTS), }; runAssertion(OA_TYPENAME, FOA, null, oaTests, Object.class); // XML Pair[] xmlTests = new Pair[]{ new Pair<>("<item>\n" + "\t<nested nestedValue=\"100\">\n" + "\t\t<nestedNested nestedNestedValue=\"101\">\n" + "\t\t</nestedNested>\n" + "\t</nested>\n" + "</item>\n", allExist("100", "100", "101", "101", "101", "101")), new Pair<>("<item/>", NOT_EXISTS), }; runAssertion(XML_TYPENAME, FXML, XML_TO_VALUE, xmlTests, Node.class); // Avro Schema schema = getAvroSchema(); Schema nestedSchema = AvroSchemaUtil.findUnionRecordSchemaSingle(schema.getField("item").schema().getField("nested").schema()); Schema nestedNestedSchema = AvroSchemaUtil.findUnionRecordSchemaSingle(nestedSchema.getField("nestedNested").schema()); GenericData.Record nestedNestedDatum = new GenericData.Record(nestedNestedSchema); nestedNestedDatum.put("nestedNestedValue", 101); GenericData.Record nestedDatum = new GenericData.Record(nestedSchema); nestedDatum.put("nestedValue", 100); nestedDatum.put("nestedNested", nestedNestedDatum); GenericData.Record emptyDatum = new GenericData.Record(SchemaBuilder.record(AVRO_TYPENAME).fields().endRecord()); Pair[] avroTests = new Pair[]{ new Pair<>(nestedDatum, allExist(100, 100, 101, 101, 101, 101)), new Pair<>(emptyDatum, NOT_EXISTS), new Pair<>(null, NOT_EXISTS) }; runAssertion(AVRO_TYPENAME, FAVRO, null, avroTests, Object.class); } private void runAssertion(String typename, FunctionSendEvent send, Function<Object, Object> optionalValueConversion, Pair[] tests, Class expectedPropertyType) { runAssertionSelectNested(typename, send, optionalValueConversion, tests, expectedPropertyType); runAssertionBeanNav(typename, send, tests[0].getFirst()); } private void runAssertionBeanNav(String typename, FunctionSendEvent send, Object underlyingComplete) { String stmtText = "select * from " + typename; EPStatement stmt = epService.getEPAdministrator().createEPL(stmtText); SupportUpdateListener listener = new SupportUpdateListener(); stmt.addListener(listener); send.apply(epService, underlyingComplete); EventBean event = listener.assertOneGetNewAndReset(); SupportEventTypeAssertionUtil.assertConsistency(event); stmt.destroy(); } private void runAssertionSelectNested(String typename, FunctionSendEvent send, Function<Object, Object> optionalValueConversion, Pair[] tests, Class expectedPropertyType) { String stmtText = "select " + " item.nested?.nestedValue as n1, " + " exists(item.nested?.nestedValue) as exists_n1, " + " item.nested?.nestedValue? as n2, " + " exists(item.nested?.nestedValue?) as exists_n2, " + " item.nested?.nestedNested.nestedNestedValue as n3, " + " exists(item.nested?.nestedNested.nestedNestedValue) as exists_n3, " + " item.nested?.nestedNested?.nestedNestedValue as n4, " + " exists(item.nested?.nestedNested?.nestedNestedValue) as exists_n4, " + " item.nested?.nestedNested.nestedNestedValue? as n5, " + " exists(item.nested?.nestedNested.nestedNestedValue?) as exists_n5, " + " item.nested?.nestedNested?.nestedNestedValue? as n6, " + " exists(item.nested?.nestedNested?.nestedNestedValue?) as exists_n6 " + " from " + typename; EPStatement stmt = epService.getEPAdministrator().createEPL(stmtText); SupportUpdateListener listener = new SupportUpdateListener(); stmt.addListener(listener); String[] propertyNames = "n1,n2,n3,n4,n5,n6".split(","); for (String propertyName : propertyNames) { assertEquals(expectedPropertyType, stmt.getEventType().getPropertyType(propertyName)); assertEquals(Boolean.class, stmt.getEventType().getPropertyType("exists_" + propertyName)); } for (Pair pair : tests) { send.apply(epService, pair.getFirst()); EventBean event = listener.assertOneGetNewAndReset(); SupportEventInfra.assertValuesMayConvert(event, propertyNames, (ValueWithExistsFlag[]) pair.getSecond(), optionalValueConversion); } stmt.destroy(); } private void addMapEventType() { Map<String, Object> top = Collections.singletonMap("item", Map.class); epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME, top); } private void addOAEventType() { String type_3 = OA_TYPENAME + "_3"; String[] names_3 = {"nestedNestedValue"}; Object[] types_3 = {Object.class}; epService.getEPAdministrator().getConfiguration().addEventType(type_3, names_3, types_3); String type_2 = OA_TYPENAME + "_2"; String[] names_2 = {"nestedNested", "nestedValue"}; Object[] types_2 = {type_3, Object.class}; epService.getEPAdministrator().getConfiguration().addEventType(type_2, names_2, types_2); String type_1 = OA_TYPENAME + "_1"; String[] names_1 = {"nested"}; Object[] types_1 = {type_2}; epService.getEPAdministrator().getConfiguration().addEventType(type_1, names_1, types_1); String[] names = {"item"}; Object[] types = {type_1}; epService.getEPAdministrator().getConfiguration().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:sequence>\n" + "\t\t\t\t<xs:element ref=\"esper:item\"/>\n" + "\t\t\t</xs:sequence>\n" + "\t\t</xs:complexType>\n" + "\t</xs:element>\n" + "\t<xs:element name=\"item\">\n" + "\t\t<xs:complexType>\n" + "\t\t</xs:complexType>\n" + "\t</xs:element>\n" + "</xs:schema>\n"; eventTypeMeta.setSchemaText(schema); configuration.addEventType(XML_TYPENAME, eventTypeMeta); } private void addAvroEventType() { epService.getEPAdministrator().getConfiguration().addEventTypeAvro(AVRO_TYPENAME, new ConfigurationEventTypeAvro(getAvroSchema())); } private static Schema getAvroSchema() { Schema s3 = SchemaBuilder.record(AVRO_TYPENAME+"_3").fields() .optionalInt("nestedNestedValue") .endRecord(); Schema s2 = SchemaBuilder.record(AVRO_TYPENAME+"_2").fields() .optionalInt("nestedValue") .name("nestedNested").type().unionOf() .intType().and().type(s3).endUnion().noDefault() .endRecord(); Schema s1 = SchemaBuilder.record(AVRO_TYPENAME+"_1").fields() .name("nested").type().unionOf() .intType().and().type(s2).endUnion().noDefault() .endRecord(); return SchemaBuilder.record(AVRO_TYPENAME).fields().name("item").type(s1).noDefault().endRecord(); } }