/*
***************************************************************************************
* 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.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.*;
public class TestEventInfraPropertyNestedSimple extends TestCase {
private final static String BEAN_TYPENAME = InfraNestedSimplePropTop.class.getName();
private static final FunctionSendEvent4Int FMAP = (epService, lvl1, lvl2, lvl3, lvl4) -> {
Map<String, Object> l4 = Collections.singletonMap("lvl4", lvl4);
Map<String, Object> l3 = twoEntryMap("l4", l4, "lvl3", lvl3);
Map<String, Object> l2 = twoEntryMap("l3", l3, "lvl2", lvl2);
Map<String, Object> l1 = twoEntryMap("l2", l2, "lvl1", lvl1);
Map<String, Object> top = Collections.singletonMap("l1", 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[] {l4, lvl3};
Object[] l2 = new Object[] {l3, lvl2};
Object[] l1 = new Object[] {l2, lvl1};
Object[] top = new Object[] {l1};
epService.getEPRuntime().sendEvent(top, OA_TYPENAME);
};
private static final FunctionSendEvent4Int FBEAN = (epService, lvl1, lvl2, lvl3, lvl4) -> {
InfraNestedSimplePropLvl4 l4 = new InfraNestedSimplePropLvl4(lvl4);
InfraNestedSimplePropLvl3 l3 = new InfraNestedSimplePropLvl3(l4, lvl3);
InfraNestedSimplePropLvl2 l2 = new InfraNestedSimplePropLvl2(l3, lvl2);
InfraNestedSimplePropLvl1 l1 = new InfraNestedSimplePropLvl1(l2, lvl1);
InfraNestedSimplePropTop top = new InfraNestedSimplePropTop(l1);
epService.getEPRuntime().sendEvent(top);
};
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();
Schema lvl2Schema = lvl1Schema.getField("l2").schema();
Schema lvl3Schema = lvl2Schema.getField("l3").schema();
Schema lvl4Schema = lvl3Schema.getField("l4").schema();
GenericData.Record lvl4Rec = new GenericData.Record(lvl4Schema);
lvl4Rec.put("lvl4", lvl4);
GenericData.Record lvl3Rec = new GenericData.Record(lvl3Schema);
lvl3Rec.put("l4", lvl4Rec);
lvl3Rec.put("lvl3", lvl3);
GenericData.Record lvl2Rec = new GenericData.Record(lvl2Schema);
lvl2Rec.put("l3", lvl3Rec);
lvl2Rec.put("lvl2", lvl2);
GenericData.Record lvl1Rec = new GenericData.Record(lvl1Schema);
lvl1Rec.put("l2", lvl2Rec);
lvl1Rec.put("lvl1", lvl1);
GenericData.Record datum = new GenericData.Record(schema);
datum.put("l1", 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();
addMapEventType();
addOAEventType();
epService.getEPAdministrator().getConfiguration().addEventType(BEAN_TYPENAME, InfraNestedSimplePropTop.class);
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, InfraNestedSimplePropLvl1.class, InfraNestedSimplePropLvl1.class.getTypeName());
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, "MyAvroEvent_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.lvl1,l1.l2.lvl2,l1.l2.l3.lvl3,l1.l2.l3.l4.lvl4".split(","), new Object[] {1, 2, 3, 4});
SupportEventTypeAssertionUtil.assertConsistency(event);
SupportEventTypeAssertionUtil.assertFragments(event, typename.equals(BEAN_TYPENAME), false, "l1,l1.l2,l1.l2.l3,l1.l2.l3.l4");
runAssertionEventInvalidProp(event);
statement.destroy();
}
private void runAssertionSelectNested(String typename, FunctionSendEvent4Int send) {
String epl = "select " +
"l1.lvl1 as c0, " +
"exists(l1.lvl1) as exists_c0, " +
"l1.l2.lvl2 as c1, " +
"exists(l1.l2.lvl2) as exists_c1, " +
"l1.l2.l3.lvl3 as c2, " +
"exists(l1.l2.l3.lvl3) as exists_c2, " +
"l1.l2.l3.l4.lvl4 as c3, " +
"exists(l1.l2.l3.l4.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\"/>\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\"/>\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\"/>\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\"/>\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(s4).noDefault()
.requiredInt("lvl3")
.endRecord();
Schema s2 = SchemaBuilder.record(AVRO_TYPENAME+"_2").fields()
.name("l3").type(s3).noDefault()
.requiredInt("lvl2")
.endRecord();
Schema s1 = SchemaBuilder.record(AVRO_TYPENAME+"_1").fields()
.name("l2").type(s2).noDefault()
.requiredInt("lvl1")
.endRecord();
return SchemaBuilder.record(AVRO_TYPENAME).fields().name("l1").type(s1).noDefault().endRecord();
}
private void runAssertionEventInvalidProp(EventBean event) {
for (String prop : Arrays.asList("l2", "l1.l3", "l1.xxx", "l1.l2.x", "l1.l2.l3.x", "l1.lvl1.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);
Object[][] expectedType = new Object[][]{{"l1", nestedClass, fragmentTypeName, false}};
SupportEventTypeAssertionUtil.assertEventTypeProperties(expectedType, eventType, SupportEventTypeAssertionEnum.getSetWithFragment());
EPAssertionUtil.assertEqualsAnyOrder(new String[] {"l1"}, eventType.getPropertyNames());
for (String prop : Arrays.asList("l1", "l1.lvl1", "l1.l2", "l1.l2.lvl2")) {
assertNotNull(eventType.getGetter(prop));
assertTrue(eventType.isProperty(prop));
}
assertEquals(nestedClass, eventType.getPropertyType("l1"));
for (String prop : Arrays.asList("l1.lvl1", "l1.l2.lvl2", "l1.l2.l3.lvl3")) {
assertEquals(Integer.class, JavaClassHelper.getBoxedType(eventType.getPropertyType(prop)));
}
FragmentEventType lvl1Fragment = eventType.getFragmentType("l1");
assertFalse(lvl1Fragment.isIndexed());
assertEquals(send == FBEAN, lvl1Fragment.isNative());
assertEquals(fragmentTypeName, lvl1Fragment.getFragmentType().getName());
FragmentEventType lvl2Fragment = eventType.getFragmentType("l1.l2");
assertFalse(lvl2Fragment.isIndexed());
assertEquals(send == FBEAN, lvl2Fragment.isNative());
assertEquals(new EventPropertyDescriptor("l1", nestedClass, null, false, false, false, false, true), eventType.getPropertyDescriptor("l1"));
}
private void runAssertionTypeInvalidProp(String typeName) {
EventType eventType = epService.getEPAdministrator().getConfiguration().getEventType(typeName);
for (String prop : Arrays.asList("l2", "l1.l3", "l1.lvl1.lvl1", "l1.l2.l4", "l1.l2.xx", "l1.l2.l3.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 InfraNestedSimplePropTop {
private InfraNestedSimplePropLvl1 l1;
public InfraNestedSimplePropTop(InfraNestedSimplePropLvl1 l1) {
this.l1 = l1;
}
public InfraNestedSimplePropLvl1 getL1() {
return l1;
}
}
private final static class InfraNestedSimplePropLvl1 {
private InfraNestedSimplePropLvl2 l2;
private int lvl1;
public InfraNestedSimplePropLvl1(InfraNestedSimplePropLvl2 l2, int lvl1) {
this.l2 = l2;
this.lvl1 = lvl1;
}
public InfraNestedSimplePropLvl2 getL2() {
return l2;
}
public int getLvl1() {
return lvl1;
}
}
private final static class InfraNestedSimplePropLvl2 {
private InfraNestedSimplePropLvl3 l3;
private int lvl2;
public InfraNestedSimplePropLvl2(InfraNestedSimplePropLvl3 l3, int lvl2) {
this.l3 = l3;
this.lvl2 = lvl2;
}
public InfraNestedSimplePropLvl3 getL3() {
return l3;
}
public int getLvl2() {
return lvl2;
}
}
private final static class InfraNestedSimplePropLvl3 {
private InfraNestedSimplePropLvl4 l4;
private int lvl3;
public InfraNestedSimplePropLvl3(InfraNestedSimplePropLvl4 l4, int lvl3) {
this.l4 = l4;
this.lvl3 = lvl3;
}
public InfraNestedSimplePropLvl4 getL4() {
return l4;
}
public int getLvl3() {
return lvl3;
}
}
private final static class InfraNestedSimplePropLvl4 {
private int lvl4;
public InfraNestedSimplePropLvl4(int lvl4) {
this.lvl4 = lvl4;
}
public int getLvl4() {
return lvl4;
}
}
}