com.espertech.esper.avro.core.EventAdapterAvroHandlerBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esper-avro Show documentation
Show all versions of esper-avro Show documentation
Complex event processing and event series analysis component
The newest version!
/*
***************************************************************************************
* 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.avro.core;
import com.espertech.esper.avro.selectexprrep.SelectExprProcessorRepresentationFactoryAvro;
import com.espertech.esper.client.*;
import com.espertech.esper.client.hook.ObjectValueTypeWidenerFactory;
import com.espertech.esper.client.hook.TypeRepresentationMapper;
import com.espertech.esper.epl.core.engineimport.EngineImportService;
import com.espertech.esper.epl.core.select.SelectExprProcessorRepresentationFactory;
import com.espertech.esper.epl.expression.core.ExprValidationException;
import com.espertech.esper.event.*;
import com.espertech.esper.event.avro.AvroSchemaEventType;
import com.espertech.esper.event.avro.EventAdapterAvroHandler;
import com.espertech.esper.util.JavaClassHelper;
import com.espertech.esper.util.TypeWidenerCustomizer;
import org.apache.avro.Schema;
import org.apache.avro.SchemaBuilder;
import org.apache.avro.generic.GenericData;
import java.lang.annotation.Annotation;
import java.util.*;
import static org.apache.avro.SchemaBuilder.record;
public abstract class EventAdapterAvroHandlerBase implements EventAdapterAvroHandler {
private final static SelectExprProcessorRepresentationFactoryAvro FACTORY_SELECT = new SelectExprProcessorRepresentationFactoryAvro();
private ConfigurationEngineDefaults.EventMeta.AvroSettings avroSettings;
private TypeRepresentationMapper optionalTypeMapper;
private ObjectValueTypeWidenerFactory optionalWidenerFactory;
protected abstract AvroSchemaEventType makeType(EventTypeMetadata metadata, String eventTypeName, int typeId, EventAdapterService eventAdapterService, Schema schema, ConfigurationEventTypeAvro optionalConfig, EventType[] supertypes, Set deepSupertypes);
public void init(ConfigurationEngineDefaults.EventMeta.AvroSettings avroSettings, EngineImportService engineImportService) {
this.avroSettings = avroSettings;
if (avroSettings.getTypeRepresentationMapperClass() != null) {
optionalTypeMapper = (TypeRepresentationMapper) JavaClassHelper.instantiate(TypeRepresentationMapper.class, avroSettings.getTypeRepresentationMapperClass(), engineImportService.getClassForNameProvider());
}
if (avroSettings.getObjectValueTypeWidenerFactoryClass() != null) {
optionalWidenerFactory = (ObjectValueTypeWidenerFactory) JavaClassHelper.instantiate(ObjectValueTypeWidenerFactory.class, avroSettings.getObjectValueTypeWidenerFactoryClass(), engineImportService.getClassForNameProvider());
}
}
public AvroSchemaEventType newEventTypeFromSchema(EventTypeMetadata metadata, String eventTypeName, int typeId, EventAdapterService eventAdapterService, ConfigurationEventTypeAvro requiredConfig, EventType[] superTypes, Set deepSuperTypes) {
Object avroSchemaObj = requiredConfig.getAvroSchema();
String avroSchemaText = requiredConfig.getAvroSchemaText();
if (avroSchemaObj == null && avroSchemaText == null) {
throw new IllegalArgumentException("Null value for schema and schema text");
}
if (avroSchemaObj != null && avroSchemaText != null) {
throw new IllegalArgumentException("Both avro schema and avro schema text are supplied and one can be provided");
}
if (avroSchemaObj != null && !(avroSchemaObj instanceof Schema)) {
throw new IllegalArgumentException("Schema expected of type " + Schema.class.getName() + " but received " + avroSchemaObj.getClass().getName());
}
Schema schema;
if (avroSchemaObj != null) {
schema = (Schema) avroSchemaObj;
} else {
try {
schema = new Schema.Parser().parse(avroSchemaText);
} catch (Throwable t) {
throw new EPException("Failed for parse avro schema: " + t.getMessage(), t);
}
}
return makeType(metadata, eventTypeName, typeId, eventAdapterService, schema, requiredConfig, superTypes, deepSuperTypes);
}
public AvroSchemaEventType newEventTypeFromNormalized(EventTypeMetadata metadata, String eventTypeName, int typeId, EventAdapterService eventAdapterService, Map properties, Annotation[] annotations, ConfigurationEventTypeAvro optionalConfig, EventType[] superTypes, Set deepSuperTypes, String statementName, String engineURI) {
SchemaBuilder.FieldAssembler assembler = record(eventTypeName).fields();
// add supertypes first so the positions are comparable
Set added = new HashSet<>();
if (superTypes != null) {
for (int i = 0; i < superTypes.length; i++) {
AvroEventType superType = (AvroEventType) superTypes[i];
for (Schema.Field field : superType.getSchemaAvro().getFields()) {
if (properties.containsKey(field.name()) || added.contains(field.name())) {
continue;
}
added.add(field.name());
assembler.name(field.name()).type(field.schema()).noDefault();
}
}
}
for (Map.Entry prop : properties.entrySet()) {
if (!added.contains(prop.getKey())) {
AvroSchemaUtil.assembleField(prop.getKey(), prop.getValue(), assembler, annotations, avroSettings, eventAdapterService, statementName, engineURI, optionalTypeMapper);
added.add(prop.getKey());
}
}
Schema schema = assembler.endRecord();
return makeType(metadata, eventTypeName, typeId, eventAdapterService, schema, optionalConfig, superTypes, deepSuperTypes);
}
public EventBean adapterForTypeAvro(Object avroGenericDataDotRecord, EventType existingType) {
if (!(avroGenericDataDotRecord instanceof GenericData.Record)) {
throw new EPException("Unexpected event object type '" + (avroGenericDataDotRecord == null ? "null" : avroGenericDataDotRecord.getClass().getName()) + "' encountered, please supply a GenericData.Record");
}
GenericData.Record record = (GenericData.Record) avroGenericDataDotRecord;
return new AvroGenericDataEventBean(record, existingType);
}
public SelectExprProcessorRepresentationFactory getOutputFactory() {
return FACTORY_SELECT;
}
public EventBeanManufacturer getEventBeanManufacturer(AvroSchemaEventType avroSchemaEventType, EventAdapterService eventAdapterService, WriteablePropertyDescriptor[] properties) {
return new EventBeanManufacturerAvro(avroSchemaEventType, eventAdapterService, properties);
}
public EventBeanFactory getEventBeanFactory(EventType type, EventAdapterService eventAdapterService) {
return new EventBeanFactoryAvro(type, eventAdapterService);
}
public void validateExistingType(EventType existingType, AvroSchemaEventType proposedType) {
if (!(existingType instanceof AvroSchemaEventType)) {
throw new EventAdapterException("Type by name '" + proposedType.getName() + "' is not a compatible type " +
"(target type underlying is '" + existingType.getUnderlyingType().getName() + "', " +
"source type underlying is '" + proposedType.getUnderlyingType().getName() + "')");
}
Schema proposed = (Schema) proposedType.getSchema();
Schema existing = (Schema) ((AvroSchemaEventType) existingType).getSchema();
if (!proposed.equals(existing)) {
throw new EventAdapterException("Event type named '" + existingType.getName() +
"' has already been declared with differing column name or type information\n"
+ "schemaExisting: " + AvroSchemaUtil.toSchemaStringSafe(existing) + "\n"
+ "schemaProposed: " + AvroSchemaUtil.toSchemaStringSafe(proposed));
}
}
public void avroCompat(EventType existingType, Map selPropertyTypes) throws ExprValidationException {
Schema schema = ((AvroEventType) existingType).getSchemaAvro();
for (Map.Entry selected : selPropertyTypes.entrySet()) {
String propertyName = selected.getKey();
Schema.Field targetField = schema.getField(selected.getKey());
if (targetField == null) {
throw new ExprValidationException("Property '" + propertyName + "' is not found among the fields for event type '" + existingType.getName() + "'");
}
if (selected.getValue() instanceof EventType) {
EventType targetEventType = (EventType) selected.getValue();
AvroEventType targetAvro = checkAvroEventTpe(selected.getKey(), targetEventType);
if (targetField.schema().getType() != Schema.Type.RECORD || !targetField.schema().equals(targetAvro.getSchemaAvro())) {
throw new ExprValidationException("Property '" + propertyName + "' is incompatible, expecting a compatible schema '" + targetField.schema().getName() + "' but received schema '" + targetAvro.getSchemaAvro().getName() + "'");
}
} else if (selected.getValue() instanceof EventType[]) {
EventType targetEventType = ((EventType[]) selected.getValue())[0];
AvroEventType targetAvro = checkAvroEventTpe(selected.getKey(), targetEventType);
if (targetField.schema().getType() != Schema.Type.ARRAY ||
targetField.schema().getElementType().getType() != Schema.Type.RECORD ||
!targetField.schema().getElementType().equals(targetAvro.getSchemaAvro())) {
throw new ExprValidationException("Property '" + propertyName + "' is incompatible, expecting an array of compatible schema '" + targetField.schema().getName() + "' but received schema '" + targetAvro.getSchemaAvro().getName() + "'");
}
}
}
}
public Object convertEvent(EventBean theEvent, AvroSchemaEventType targetType) {
GenericData.Record original = ((AvroGenericDataBackedEventBean) theEvent).getProperties();
Schema targetSchema = (Schema) targetType.getSchema();
GenericData.Record target = new GenericData.Record(targetSchema);
List fields = original.getSchema().getFields();
for (Schema.Field field : fields) {
Schema.Field targetField = targetSchema.getField(field.name());
if (targetField == null) {
continue;
}
if (field.schema().getType() == Schema.Type.ARRAY) {
Collection originalColl = (Collection) original.get(field.pos());
if (originalColl != null) {
target.put(targetField.pos(), new ArrayList<>(originalColl));
}
} else if (field.schema().getType() == Schema.Type.MAP) {
Map originalMap = (Map) original.get(field.pos());
if (originalMap != null) {
target.put(targetField.pos(), new HashMap<>(originalMap));
}
} else {
target.put(targetField.pos(), original.get(field.pos()));
}
}
return target;
}
public TypeWidenerCustomizer getTypeWidenerCustomizer(EventType eventType) {
return optionalWidenerFactory == null ? AvroTypeWidenerCustomizerDefault.INSTANCE : new AvroTypeWidenerCustomizerWHook(optionalWidenerFactory, eventType);
}
private AvroEventType checkAvroEventTpe(String propertyName, EventType eventType) throws ExprValidationException {
if (!(eventType instanceof AvroEventType)) {
throw new ExprValidationException("Property '" + propertyName + "' is incompatible with event type '" + eventType.getName() + "' underlying type " + eventType.getUnderlyingType().getSimpleName());
}
return (AvroEventType) eventType;
}
}