/*
***************************************************************************************
* 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.util.support.SupportAvroUtil;
import com.espertech.esper.client.*;
import com.espertech.esper.client.hook.ObjectValueTypeWidenerFactory;
import com.espertech.esper.client.hook.ObjectValueTypeWidenerFactoryContext;
import com.espertech.esper.client.hook.TypeRepresentationMapper;
import com.espertech.esper.client.hook.TypeRepresentationMapperContext;
import com.espertech.esper.client.scopetest.SupportUpdateListener;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import com.espertech.esper.supportregression.bean.SupportBean;
import com.espertech.esper.supportregression.bean.SupportBean_S0;
import com.espertech.esper.supportregression.client.SupportConfigFactory;
import com.espertech.esper.supportregression.util.SupportMessageAssertUtil;
import com.espertech.esper.util.EventRepresentationChoice;
import com.espertech.esper.util.TypeWidener;
import junit.framework.TestCase;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import static org.apache.avro.SchemaBuilder.builder;
import static org.apache.avro.SchemaBuilder.record;
import static org.apache.avro.SchemaBuilder.unionOf;
public class TestAvroEventHook extends TestCase {
private EPServiceProvider epService;
private SupportUpdateListener listener;
protected void setUp()
{
Configuration configuration = SupportConfigFactory.getConfiguration();
configuration.getEngineDefaults().getEventMeta().getAvroSettings().setTypeRepresentationMapperClass(MyTypeRepresentationMapper.class.getName());
configuration.getEngineDefaults().getEventMeta().getAvroSettings().setObjectValueTypeWidenerFactoryClass(MyObjectValueTypeWidenerFactory.class.getName());
epService = EPServiceProviderManager.getDefaultProvider(configuration);
epService.initialize();
listener = new SupportUpdateListener();
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.startTest(epService, this.getClass(), getName());}
for (Class clazz : Arrays.asList(SupportBean.class, SupportBean_S0.class, MyEventWithLocalDateTime.class, MyEventWithZonedDateTime.class)) {
epService.getEPAdministrator().getConfiguration().addEventType(clazz);
}
}
public void tearDown() {
if (InstrumentationHelper.ENABLED) { InstrumentationHelper.endTest();}
listener = null;
}
/**
* Writeable-property tests: when a simple writable property needs to be converted
*/
public void testSimpleWriteablePropertyCoerce() {
Schema schema = record("MyEventSchema").fields().requiredString("isodate").endRecord();
epService.getEPAdministrator().getConfiguration().addEventTypeAvro("MyEvent", new ConfigurationEventTypeAvro(schema));
// invalid without explicit conversion
SupportMessageAssertUtil.tryInvalid(epService, "insert into MyEvent(isodate) select zdt from MyEventWithZonedDateTime",
"Error starting statement: Invalid assignment of column 'isodate' of type 'java.time.ZonedDateTime' to event property 'isodate' typed as 'java.lang.CharSequence', column and parameter types mismatch");
// with hook
EPStatement stmt = epService.getEPAdministrator().createEPL("insert into MyEvent(isodate) select ldt from MyEventWithLocalDateTime");
stmt.addListener(listener);
LocalDateTime now = LocalDateTime.now();
epService.getEPRuntime().sendEvent(new MyEventWithLocalDateTime(now));
assertEquals(DateTimeFormatter.ISO_DATE_TIME.format(now), listener.assertOneGetNewAndReset().get("isodate"));
}
/**
* Schema-from-Class
*/
public void testSchemaFromClass() {
String epl = EventRepresentationChoice.AVRO.getAnnotationText() + "insert into MyEvent select " + this.getClass().getName() + ".makeLocalDateTime() as isodate from SupportBean as e1";
EPStatement stmt = epService.getEPAdministrator().createEPL(epl);
SupportUpdateListener listener = new SupportUpdateListener();
stmt.addListener(listener);
Schema schema = SupportAvroUtil.getAvroSchema(stmt.getEventType());
assertEquals("{\"type\":\"record\",\"name\":\"MyEvent\",\"fields\":[{\"name\":\"isodate\",\"type\":\"string\"}]}", schema.toString());
epService.getEPRuntime().sendEvent(new SupportBean("E1", 10));
EventBean event = listener.assertOneGetNewAndReset();
SupportAvroUtil.avroToJson(event);
assertTrue(event.get("isodate").toString().length() > 10);
}
/**
* Mapping of Class to GenericRecord
*/
public void testPopulate() {
MySupportBeanWidener.supportBeanSchema = record("SupportBeanSchema").fields().requiredString("theString").requiredInt("intPrimitive").endRecord();
Schema schema = record("MyEventSchema").fields().name("sb").type(MySupportBeanWidener.supportBeanSchema).noDefault().endRecord();
epService.getEPAdministrator().getConfiguration().addEventTypeAvro("MyEvent", new ConfigurationEventTypeAvro(schema));
String epl = "insert into MyEvent(sb) select " + this.getClass().getName() + ".makeSupportBean() from SupportBean_S0 as e1";
EPStatement stmt = epService.getEPAdministrator().createEPL(epl);
SupportUpdateListener listener = new SupportUpdateListener();
stmt.addListener(listener);
epService.getEPRuntime().sendEvent(new SupportBean_S0(10));
EventBean event = listener.assertOneGetNewAndReset();
assertEquals("{\"sb\":{\"theString\":\"E1\",\"intPrimitive\":10}}", SupportAvroUtil.avroToJson(event));
}
public void testNamedWindowPropertyAssignment() {
MySupportBeanWidener.supportBeanSchema = record("SupportBeanSchema").fields().requiredString("theString").requiredInt("intPrimitive").endRecord();
Schema schema = record("MyEventSchema").fields().name("sb").type(unionOf().nullType().and().type(MySupportBeanWidener.supportBeanSchema).endUnion()).noDefault().endRecord();
epService.getEPAdministrator().getConfiguration().addEventTypeAvro("MyEvent", new ConfigurationEventTypeAvro(schema));
epService.getEPAdministrator().createEPL("@Name('NamedWindow') create window MyWindow#keepall as MyEvent");
epService.getEPAdministrator().createEPL("insert into MyWindow select * from MyEvent");
epService.getEPAdministrator().createEPL("on SupportBean thebean update MyWindow set sb = thebean");
GenericData.Record event = new GenericData.Record(schema);
epService.getEPRuntime().sendEventAvro(event, "MyEvent");
epService.getEPRuntime().sendEvent(new SupportBean("E1", 10));
EventBean eventBean = epService.getEPAdministrator().getStatement("NamedWindow").iterator().next();
assertEquals("{\"sb\":{\"SupportBeanSchema\":{\"theString\":\"E1\",\"intPrimitive\":10}}}", SupportAvroUtil.avroToJson(eventBean));
}
public static LocalDateTime makeLocalDateTime() {
return LocalDateTime.now();
}
public static SupportBean makeSupportBean() {
return new SupportBean("E1", 10);
}
public static class MyEventWithLocalDateTime {
private final LocalDateTime ldt;
public MyEventWithLocalDateTime(LocalDateTime ldt) {
this.ldt = ldt;
}
public LocalDateTime getLdt() {
return ldt;
}
}
public static class MyEventWithZonedDateTime {
private final ZonedDateTime zdt;
public MyEventWithZonedDateTime(ZonedDateTime zdt) {
this.zdt = zdt;
}
public ZonedDateTime getZdt() {
return zdt;
}
}
public static class MyObjectValueTypeWidenerFactory implements ObjectValueTypeWidenerFactory {
private static ObjectValueTypeWidenerFactoryContext context;
public TypeWidener make(ObjectValueTypeWidenerFactoryContext context) {
this.context = context;
if (context.getClazz() == LocalDateTime.class) {
return MyLDTTypeWidener.INSTANCE;
}
if (context.getClazz() == SupportBean.class) {
return new MySupportBeanWidener();
}
return null;
}
public static ObjectValueTypeWidenerFactoryContext getContext() {
return context;
}
}
public static class MyLDTTypeWidener implements TypeWidener {
public final static MyLDTTypeWidener INSTANCE = new MyLDTTypeWidener();
private MyLDTTypeWidener() {
}
public Object widen(Object input) {
LocalDateTime ldt = (LocalDateTime) input;
return DateTimeFormatter.ISO_DATE_TIME.format(ldt);
}
}
public static class MySupportBeanWidener implements TypeWidener {
public static Schema supportBeanSchema;
public Object widen(Object input) {
SupportBean sb = (SupportBean) input;
GenericData.Record record = new GenericData.Record(supportBeanSchema);
record.put("theString", sb.getTheString());
record.put("intPrimitive", sb.getIntPrimitive());
return record;
}
}
public static class MyTypeRepresentationMapper implements TypeRepresentationMapper {
public Object map(TypeRepresentationMapperContext context) {
if (context.getClazz() == LocalDateTime.class) {
return builder().stringBuilder().endString();
}
return null;
}
}
}