/*
***************************************************************************************
* 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.metrics.instrumentation.InstrumentationHelper;
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.apache.avro.generic.GenericRecord;
import org.w3c.dom.Node;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import static com.espertech.esper.supportregression.event.SupportEventInfra.*;
import static org.apache.avro.SchemaBuilder.array;
public class TestEventInfraPropertyNestedIndexed extends TestCase {
private final static String BEAN_TYPENAME = InfraNestedIndexPropTop.class.getName();
private static final FunctionSendEvent4Int FBEAN = (epService, lvl1, lvl2, lvl3, lvl4) -> {
InfraNestedIndexedPropLvl4 l4 = new InfraNestedIndexedPropLvl4(lvl4);
InfraNestedIndexedPropLvl3 l3 = new InfraNestedIndexedPropLvl3(new InfraNestedIndexedPropLvl4[]{l4}, lvl3);
InfraNestedIndexedPropLvl2 l2 = new InfraNestedIndexedPropLvl2(new InfraNestedIndexedPropLvl3[]{l3}, lvl2);
InfraNestedIndexedPropLvl1 l1 = new InfraNestedIndexedPropLvl1(new InfraNestedIndexedPropLvl2[]{l2}, lvl1);
InfraNestedIndexPropTop top = new InfraNestedIndexPropTop(new InfraNestedIndexedPropLvl1[]{l1});
epService.getEPRuntime().sendEvent(top);
};
private static final FunctionSendEvent4Int FMAP = (epService, lvl1, lvl2, lvl3, lvl4) -> {
Map<String, Object> l4 = Collections.singletonMap("lvl4", lvl4);
Map<String, Object> l3 = twoEntryMap("l4", new Map[] {l4}, "lvl3", lvl3);
Map<String, Object> l2 = twoEntryMap("l3", new Map[] {l3}, "lvl2", lvl2);
Map<String, Object> l1 = twoEntryMap("l2", new Map[] {l2}, "lvl1", lvl1);
Map<String, Object> top = Collections.singletonMap("l1", new Map[] {l1});
epService.getEPRuntime().sendEvent(top, MAP_TYPENAME);
};
private static final FunctionSendEvent4Int FOA = (epService, lvl1, lvl2, lvl3, lvl4) -> {
Object[] l4 = new Object[] {lvl4};
Object[] l3 = new Object[] {new Object[] {l4}, lvl3};
Object[] l2 = new Object[] {new Object[] {l3}, lvl2};
Object[] l1 = new Object[] {new Object[] {l2}, lvl1};
Object[] top = new Object[] {new Object[] {l1}};
epService.getEPRuntime().sendEvent(top, OA_TYPENAME);
};
private static final FunctionSendEvent4Int FXML = (epService, lvl1, lvl2, lvl3, lvl4) -> {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<myevent>\n" +
"\t<l1 lvl1=\"${lvl1}\">\n" +
"\t\t<l2 lvl2=\"${lvl2}\">\n" +
"\t\t\t<l3 lvl3=\"${lvl3}\">\n" +
"\t\t\t\t<l4 lvl4=\"${lvl4}\">\n" +
"\t\t\t\t</l4>\n" +
"\t\t\t</l3>\n" +
"\t\t</l2>\n" +
"\t</l1>\n" +
"</myevent>";
xml = xml.replace("${lvl1}", Integer.toString(lvl1));
xml = xml.replace("${lvl2}", Integer.toString(lvl2));
xml = xml.replace("${lvl3}", Integer.toString(lvl3));
xml = xml.replace("${lvl4}", Integer.toString(lvl4));
try {
SupportXML.sendEvent(epService.getEPRuntime(), xml);
}
catch (Exception e) {
throw new RuntimeException(e);
}
};
private static final FunctionSendEvent4Int FAVRO = (epService, lvl1, lvl2, lvl3, lvl4) -> {
Schema schema = getAvroSchema();
Schema lvl1Schema = schema.getField("l1").schema().getElementType();
Schema lvl2Schema = lvl1Schema.getField("l2").schema().getElementType();
Schema lvl3Schema = lvl2Schema.getField("l3").schema().getElementType();
Schema lvl4Schema = lvl3Schema.getField("l4").schema().getElementType();
GenericData.Record lvl4Rec = new GenericData.Record(lvl4Schema);
lvl4Rec.put("lvl4", lvl4);
GenericData.Record lvl3Rec = new GenericData.Record(lvl3Schema);
lvl3Rec.put("l4", Collections.singletonList(lvl4Rec));
lvl3Rec.put("lvl3", lvl3);
GenericData.Record lvl2Rec = new GenericData.Record(lvl2Schema);
lvl2Rec.put("l3", Collections.singletonList(lvl3Rec));
lvl2Rec.put("lvl2", lvl2);
GenericData.Record lvl1Rec = new GenericData.Record(lvl1Schema);
lvl1Rec.put("l2", Collections.singletonList(lvl2Rec));
lvl1Rec.put("lvl1", lvl1);
GenericData.Record datum = new GenericData.Record(schema);
datum.put("l1", Collections.singletonList(lvl1Rec));
epService.getEPRuntime().sendEventAvro(datum, AVRO_TYPENAME);
};
private EPServiceProvider epService;
protected void setUp()
{
Configuration configuration = SupportConfigFactory.getConfiguration();
addXMLEventType(configuration);
epService = EPServiceProviderManager.getDefaultProvider(configuration);
epService.initialize();
epService.getEPAdministrator().getConfiguration().addEventType(BEAN_TYPENAME, InfraNestedIndexPropTop.class);
addMapEventType();
addOAEventType();
addAvroEventType();
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());}
}
public void tearDown() {
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();}
}
public void testNested() {
runAssertion(BEAN_TYPENAME, FBEAN, InfraNestedIndexedPropLvl1.class, InfraNestedIndexedPropLvl1.class.getName());
runAssertion(MAP_TYPENAME, FMAP, Map.class, MAP_TYPENAME + "_1");
runAssertion(OA_TYPENAME, FOA, Object[].class, OA_TYPENAME + "_1");
runAssertion(XML_TYPENAME, FXML, Node.class, "MyXMLEvent.l1");
runAssertion(AVRO_TYPENAME, FAVRO, GenericData.Record.class, AVRO_TYPENAME + "_1");
}
private void runAssertion(String typename, FunctionSendEvent4Int send, Class nestedClass, String fragmentTypeName) {
runAssertionSelectNested(typename, send);
runAssertionBeanNav(typename, send);
runAssertionTypeValidProp(typename, send, nestedClass, fragmentTypeName);
runAssertionTypeInvalidProp(typename);
}
private void runAssertionBeanNav(String typename, FunctionSendEvent4Int send) {
String epl = "select * from " + typename;
EPStatement statement = epService.getEPAdministrator().createEPL(epl);
SupportUpdateListener listener = new SupportUpdateListener();
statement.addListener(listener);
send.apply(epService, 1, 2, 3, 4);
EventBean event = listener.assertOneGetNewAndReset();
EPAssertionUtil.assertProps(event, "l1[0].lvl1,l1[0].l2[0].lvl2,l1[0].l2[0].l3[0].lvl3,l1[0].l2[0].l3[0].l4[0].lvl4".split(","), new Object[] {1, 2, 3, 4});
SupportEventTypeAssertionUtil.assertConsistency(event);
boolean isNative = typename.equals(BEAN_TYPENAME);
SupportEventTypeAssertionUtil.assertFragments(event, isNative, true, "l1,l1[0].l2,l1[0].l2[0].l3,l1[0].l2[0].l3[0].l4");
SupportEventTypeAssertionUtil.assertFragments(event, isNative, false, "l1[0],l1[0].l2[0],l1[0].l2[0].l3[0],l1[0].l2[0].l3[0].l4[0]");
runAssertionEventInvalidProp(event);
statement.destroy();
}
private void runAssertionSelectNested(String typename, FunctionSendEvent4Int send) {
String epl = "select " +
"l1[0].lvl1 as c0, " +
"exists(l1[0].lvl1) as exists_c0, " +
"l1[0].l2[0].lvl2 as c1, " +
"exists(l1[0].l2[0].lvl2) as exists_c1, " +
"l1[0].l2[0].l3[0].lvl3 as c2, " +
"exists(l1[0].l2[0].l3[0].lvl3) as exists_c2, " +
"l1[0].l2[0].l3[0].l4[0].lvl4 as c3, " +
"exists(l1[0].l2[0].l3[0].l4[0].lvl4) as exists_c3 " +
"from " + typename;
EPStatement statement = epService.getEPAdministrator().createEPL(epl);
SupportUpdateListener listener = new SupportUpdateListener();
statement.addListener(listener);
String[] fields = "c0,exists_c0,c1,exists_c1,c2,exists_c2,c3,exists_c3".split(",");
for (String property : fields) {
assertEquals(property.startsWith("exists") ? Boolean.class : Integer.class, JavaClassHelper.getBoxedType(statement.getEventType().getPropertyType(property)));
}
send.apply(epService, 1, 2, 3, 4);
EventBean event = listener.assertOneGetNewAndReset();
EPAssertionUtil.assertProps(event, fields, new Object[] {1, true, 2, true, 3, true, 4, true});
SupportEventTypeAssertionUtil.assertConsistency(event);
send.apply(epService, 10, 5, 50, 400);
EPAssertionUtil.assertProps(listener.assertOneGetNewAndReset(), fields, new Object[] {10, true, 5, true, 50, true, 400, true});
statement.destroy();
}
private void addMapEventType() {
epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME + "_4", Collections.singletonMap("lvl4", int.class));
epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME + "_3", twoEntryMap("l4", MAP_TYPENAME + "_4[]", "lvl3", int.class));
epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME + "_2", twoEntryMap("l3", MAP_TYPENAME + "_3[]", "lvl2", int.class));
epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME + "_1", twoEntryMap("l2", MAP_TYPENAME + "_2[]", "lvl1", int.class));
epService.getEPAdministrator().getConfiguration().addEventType(MAP_TYPENAME, Collections.singletonMap("l1", MAP_TYPENAME + "_1[]"));
}
private void addOAEventType() {
String type_4 = OA_TYPENAME + "_4";
String[] names_4 = {"lvl4"};
Object[] types_4 = {int.class};
epService.getEPAdministrator().getConfiguration().addEventType(type_4, names_4, types_4);
String type_3 = OA_TYPENAME + "_3";
String[] names_3 = {"l4", "lvl3"};
Object[] types_3 = {type_4 + "[]", int.class};
epService.getEPAdministrator().getConfiguration().addEventType(type_3, names_3, types_3);
String type_2 = OA_TYPENAME + "_2";
String[] names_2 = {"l3", "lvl2"};
Object[] types_2 = {type_3 + "[]", int.class};
epService.getEPAdministrator().getConfiguration().addEventType(type_2, names_2, types_2);
String type_1 = OA_TYPENAME + "_1";
String[] names_1 = {"l2", "lvl1"};
Object[] types_1 = {type_2 + "[]", int.class};
epService.getEPAdministrator().getConfiguration().addEventType(type_1, names_1, types_1);
String[] names = {"l1"};
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:l1\" maxOccurs=\"unbounded\"/>\n" +
"\t\t\t</xs:sequence>\n" +
"\t\t</xs:complexType>\n" +
"\t</xs:element>\n" +
"\t<xs:element name=\"l1\">\n" +
"\t\t<xs:complexType>\n" +
"\t\t\t<xs:sequence>\n" +
"\t\t\t\t<xs:element ref=\"esper:l2\" maxOccurs=\"unbounded\"/>\n" +
"\t\t\t</xs:sequence>\n" +
"\t\t\t<xs:attribute name=\"lvl1\" type=\"xs:int\" use=\"required\"/>\n" +
"\t\t</xs:complexType>\n" +
"\t</xs:element>\n" +
"\t<xs:element name=\"l2\">\n" +
"\t\t<xs:complexType>\n" +
"\t\t\t<xs:sequence>\n" +
"\t\t\t\t<xs:element ref=\"esper:l3\" maxOccurs=\"unbounded\"/>\n" +
"\t\t\t</xs:sequence>\n" +
"\t\t\t<xs:attribute name=\"lvl2\" type=\"xs:int\" use=\"required\"/>\n" +
"\t\t</xs:complexType>\n" +
"\t</xs:element>\n" +
"\t<xs:element name=\"l3\">\n" +
"\t\t<xs:complexType>\n" +
"\t\t\t<xs:sequence>\n" +
"\t\t\t\t<xs:element ref=\"esper:l4\" maxOccurs=\"unbounded\"/>\n" +
"\t\t\t</xs:sequence>\n" +
"\t\t\t<xs:attribute name=\"lvl3\" type=\"xs:int\" use=\"required\"/>\n" +
"\t\t</xs:complexType>\n" +
"\t</xs:element>\n" +
"\t<xs:element name=\"l4\">\n" +
"\t\t<xs:complexType>\n" +
"\t\t\t<xs:attribute name=\"lvl4\" type=\"xs:int\" 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() {
epService.getEPAdministrator().getConfiguration().addEventTypeAvro(AVRO_TYPENAME, new ConfigurationEventTypeAvro(getAvroSchema()));
}
private static Schema getAvroSchema() {
Schema s4 = SchemaBuilder.record(AVRO_TYPENAME+"_4").fields().requiredInt("lvl4").endRecord();
Schema s3 = SchemaBuilder.record(AVRO_TYPENAME+"_3").fields()
.name("l4").type(array().items(s4)).noDefault()
.requiredInt("lvl3")
.endRecord();
Schema s2 = SchemaBuilder.record(AVRO_TYPENAME+"_2").fields()
.name("l3").type(array().items(s3)).noDefault()
.requiredInt("lvl2")
.endRecord();
Schema s1 = SchemaBuilder.record(AVRO_TYPENAME+"_1").fields()
.name("l2").type(array().items(s2)).noDefault()
.requiredInt("lvl1")
.endRecord();
return SchemaBuilder.record(AVRO_TYPENAME).fields().name("l1").type(array().items(s1)).noDefault().endRecord();
}
private void runAssertionEventInvalidProp(EventBean event) {
for (String prop : Arrays.asList("l2", "l2[0]", "l1[0].l3", "l1[0].l2[0].l3[0].x")) {
SupportMessageAssertUtil.tryInvalidProperty(event, prop);
SupportMessageAssertUtil.tryInvalidGetFragment(event, prop);
}
}
private void runAssertionTypeValidProp(String typeName, FunctionSendEvent4Int send, Class nestedClass, String fragmentTypeName) {
EventType eventType = epService.getEPAdministrator().getConfiguration().getEventType(typeName);
Class arrayType = nestedClass == Object[].class ? nestedClass : JavaClassHelper.getArrayType(nestedClass);
arrayType = arrayType == GenericData.Record[].class ? Collection.class : arrayType;
Object[][] expectedType = new Object[][]{{"l1", arrayType, fragmentTypeName, true}};
SupportEventTypeAssertionUtil.assertEventTypeProperties(expectedType, eventType, SupportEventTypeAssertionEnum.getSetWithFragment());
EPAssertionUtil.assertEqualsAnyOrder(new String[] {"l1"}, eventType.getPropertyNames());
for (String prop : Arrays.asList("l1[0]", "l1[0].lvl1", "l1[0].l2", "l1[0].l2[0]", "l1[0].l2[0].lvl2")) {
assertNotNull(eventType.getGetter(prop));
assertTrue(eventType.isProperty(prop));
}
assertEquals(arrayType, eventType.getPropertyType("l1"));
for (String prop : Arrays.asList("l1[0].lvl1", "l1[0].l2[0].lvl2", "l1[0].l2[0].l3[0].lvl3")) {
assertEquals(Integer.class, JavaClassHelper.getBoxedType(eventType.getPropertyType(prop)));
}
FragmentEventType lvl1Fragment = eventType.getFragmentType("l1");
assertTrue(lvl1Fragment.isIndexed());
assertEquals(send == FBEAN, lvl1Fragment.isNative());
assertEquals(fragmentTypeName, lvl1Fragment.getFragmentType().getName());
FragmentEventType lvl2Fragment = eventType.getFragmentType("l1[0].l2");
assertTrue(lvl2Fragment.isIndexed());
assertEquals(send == FBEAN, lvl2Fragment.isNative());
assertEquals(new EventPropertyDescriptor("l1", arrayType, nestedClass, false, false, true, false, true), eventType.getPropertyDescriptor("l1"));
}
private void runAssertionTypeInvalidProp(String typeName) {
EventType eventType = epService.getEPAdministrator().getConfiguration().getEventType(typeName);
for (String prop : Arrays.asList("l2[0]", "l1[0].l3", "l1[0].lvl1.lvl1", "l1[0].l2.l4", "l1[0].l2[0].xx", "l1[0].l2[0].l3[0].lvl5")) {
assertEquals(false, eventType.isProperty(prop));
assertEquals(null, eventType.getPropertyType(prop));
assertNull(eventType.getPropertyDescriptor(prop));
}
}
@FunctionalInterface
interface FunctionSendEvent4Int {
public void apply(EPServiceProvider epService, int lvl1, int lvl2, int lvl3, int lvl4);
}
private final static class InfraNestedIndexPropTop {
private InfraNestedIndexedPropLvl1[] l1;
public InfraNestedIndexPropTop(InfraNestedIndexedPropLvl1[] l1) {
this.l1 = l1;
}
public InfraNestedIndexedPropLvl1[] getL1() {
return l1;
}
}
private final static class InfraNestedIndexedPropLvl1 {
private InfraNestedIndexedPropLvl2[] l2;
private int lvl1;
public InfraNestedIndexedPropLvl1(InfraNestedIndexedPropLvl2[] l2, int lvl1) {
this.l2 = l2;
this.lvl1 = lvl1;
}
public InfraNestedIndexedPropLvl2[] getL2() {
return l2;
}
public int getLvl1() {
return lvl1;
}
}
private final static class InfraNestedIndexedPropLvl2 {
private InfraNestedIndexedPropLvl3[] l3;
private int lvl2;
public InfraNestedIndexedPropLvl2(InfraNestedIndexedPropLvl3[] l3, int lvl2) {
this.l3 = l3;
this.lvl2 = lvl2;
}
public InfraNestedIndexedPropLvl3[] getL3() {
return l3;
}
public int getLvl2() {
return lvl2;
}
}
private final static class InfraNestedIndexedPropLvl3 {
private InfraNestedIndexedPropLvl4[] l4;
private int lvl3;
public InfraNestedIndexedPropLvl3(InfraNestedIndexedPropLvl4[] l4, int lvl3) {
this.l4 = l4;
this.lvl3 = lvl3;
}
public InfraNestedIndexedPropLvl4[] getL4() {
return l4;
}
public int getLvl3() {
return lvl3;
}
}
private final static class InfraNestedIndexedPropLvl4 {
private int lvl4;
public InfraNestedIndexedPropLvl4(int lvl4) {
this.lvl4 = lvl4;
}
public int getLvl4() {
return lvl4;
}
}
}