/*
***************************************************************************************
* 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.getter.AvroEventBeanGetterIndexedRuntimeKeyed;
import com.espertech.esper.avro.getter.AvroEventBeanGetterMappedRuntimeKeyed;
import com.espertech.esper.avro.getter.AvroEventBeanGetterSimple;
import com.espertech.esper.avro.writer.*;
import com.espertech.esper.client.*;
import com.espertech.esper.epl.parse.ASTUtil;
import com.espertech.esper.event.*;
import com.espertech.esper.event.avro.AvroSchemaEventType;
import com.espertech.esper.event.property.IndexedProperty;
import com.espertech.esper.event.property.MappedProperty;
import com.espertech.esper.event.property.Property;
import com.espertech.esper.event.property.PropertyParser;
import com.espertech.esper.util.CollectionUtil;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import java.util.*;
import static com.espertech.esper.avro.core.AvroFragmentTypeUtil.getFragmentEventTypeForField;
public class AvroEventType implements AvroSchemaEventType, EventTypeSPI {
private final EventTypeMetadata metadata;
private final String eventTypeName;
private final int typeId;
private final EventAdapterService eventAdapterService;
private final Schema avroSchema;
private final Map<String, PropertySetDescriptorItem> propertyItems;
private final String startTimestampPropertyName;
private final String endTimestampPropertyName;
private final EventType[] optionalSuperTypes;
private final Set<EventType> deepSupertypes;
private EventPropertyDescriptor[] propertyDescriptors;
private String[] propertyNames;
private HashMap<String, EventPropertyGetter> propertyGetterCache;
public AvroEventType(EventTypeMetadata metadata,
String eventTypeName,
int typeId,
EventAdapterService eventAdapterService,
Schema avroSchema,
String startTimestampPropertyName,
String endTimestampPropertyName,
EventType[] optionalSuperTypes,
Set<EventType> deepSupertypes) {
this.metadata = metadata;
this.eventTypeName = eventTypeName;
this.typeId = typeId;
this.eventAdapterService = eventAdapterService;
this.avroSchema = avroSchema;
this.optionalSuperTypes = optionalSuperTypes;
this.deepSupertypes = deepSupertypes == null ? Collections.emptySet() : deepSupertypes;
this.propertyItems = new LinkedHashMap<>();
init();
EventTypeUtility.TimestampPropertyDesc desc = EventTypeUtility.validatedDetermineTimestampProps(this, startTimestampPropertyName, endTimestampPropertyName, optionalSuperTypes);
this.startTimestampPropertyName = desc.getStart();
this.endTimestampPropertyName = desc.getEnd();
}
public Class getUnderlyingType() {
return GenericData.Record.class;
}
public Class getPropertyType(String propertyName) {
PropertySetDescriptorItem item = propertyItems.get(ASTUtil.unescapeDot(propertyName));
if (item != null) {
return item.getSimplePropertyType();
}
Property property = PropertyParser.parseAndWalkLaxToSimple(propertyName);
return AvroPropertyUtil.propertyType(avroSchema, property);
}
public boolean isProperty(String propertyExpression) {
Class propertyType = getPropertyType(propertyExpression);
if (propertyType != null) {
return true;
}
if (propertyGetterCache == null) {
propertyGetterCache = new HashMap<>();
}
return AvroPropertyUtil.getGetter(avroSchema, propertyGetterCache, propertyItems, propertyExpression, false, eventAdapterService) != null;
}
public EventPropertyGetter getGetter(String propertyExpression) {
if (propertyGetterCache == null) {
propertyGetterCache = new HashMap<>();
}
return AvroPropertyUtil.getGetter(avroSchema, propertyGetterCache, propertyItems, propertyExpression, true, eventAdapterService);
}
public FragmentEventType getFragmentType(String propertyExpression) {
return AvroFragmentTypeUtil.getFragmentType(avroSchema, propertyExpression, propertyItems, eventAdapterService);
}
public String[] getPropertyNames() {
return propertyNames;
}
public EventPropertyDescriptor[] getPropertyDescriptors() {
return propertyDescriptors;
}
public EventPropertyDescriptor getPropertyDescriptor(String propertyName) {
PropertySetDescriptorItem item = propertyItems.get(propertyName);
if (item == null) {
return null;
}
return item.getPropertyDescriptor();
}
public EventType[] getSuperTypes() {
return optionalSuperTypes;
}
public Iterator<EventType> getDeepSuperTypes() {
return deepSupertypes.iterator();
}
public String getName() {
return metadata.getPublicName();
}
public EventPropertyGetterMapped getGetterMapped(String mappedPropertyName) {
PropertySetDescriptorItem desc = propertyItems.get(mappedPropertyName);
if (desc == null || !desc.getPropertyDescriptor().isMapped()) {
return null;
}
Schema.Field field = avroSchema.getField(mappedPropertyName);
return new AvroEventBeanGetterMappedRuntimeKeyed(field.pos());
}
public EventPropertyGetterIndexed getGetterIndexed(String indexedPropertyName) {
PropertySetDescriptorItem desc = propertyItems.get(indexedPropertyName);
if (desc == null || !desc.getPropertyDescriptor().isIndexed()) {
return null;
}
Schema.Field field = avroSchema.getField(indexedPropertyName);
return new AvroEventBeanGetterIndexedRuntimeKeyed(field.pos());
}
public int getEventTypeId() {
return typeId;
}
public String getStartTimestampPropertyName() {
return startTimestampPropertyName;
}
public String getEndTimestampPropertyName() {
return endTimestampPropertyName;
}
public EventTypeMetadata getMetadata() {
return metadata;
}
public AvroEventBeanPropertyWriter getWriter(String propertyName) {
PropertySetDescriptorItem desc = propertyItems.get(propertyName);
if (desc != null) {
int pos = avroSchema.getField(propertyName).pos();
return new AvroEventBeanPropertyWriter(pos);
}
Property property = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (property instanceof MappedProperty) {
MappedProperty mapProp = (MappedProperty) property;
int pos = avroSchema.getField(property.getPropertyNameAtomic()).pos();
return new AvroEventBeanPropertyWriterMapProp(pos, mapProp.getKey());
}
if (property instanceof IndexedProperty) {
IndexedProperty indexedProp = (IndexedProperty) property;
int pos = avroSchema.getField(property.getPropertyNameAtomic()).pos();
return new AvroEventBeanPropertyWriterIndexedProp(pos, indexedProp.getIndex());
}
return null;
}
public EventPropertyDescriptor[] getWriteableProperties() {
return propertyDescriptors;
}
public EventPropertyDescriptor getWritableProperty(String propertyName) {
for (EventPropertyDescriptor desc : propertyDescriptors) {
if (desc.getPropertyName().equals(propertyName)) {
return desc;
}
}
Property property = PropertyParser.parseAndWalkLaxToSimple(propertyName);
if (property instanceof MappedProperty) {
EventPropertyWriter writer = getWriter(propertyName);
if (writer == null) {
return null;
}
MappedProperty mapProp = (MappedProperty) property;
return new EventPropertyDescriptor(mapProp.getPropertyNameAtomic(), Object.class, null, false, true, false, true, false);
}
if (property instanceof IndexedProperty) {
EventPropertyWriter writer = getWriter(propertyName);
if (writer == null) {
return null;
}
IndexedProperty indexedProp = (IndexedProperty) property;
return new EventPropertyDescriptor(indexedProp.getPropertyNameAtomic(), Object.class, null, true, false, true, false, false);
}
return null;
}
public EventBeanCopyMethod getCopyMethod(String[] properties) {
return new AvroEventBeanCopyMethod(this, eventAdapterService);
}
public EventBeanWriter getWriter(String[] properties) {
boolean allSimpleProps = true;
AvroEventBeanPropertyWriter[] writers = new AvroEventBeanPropertyWriter[properties.length];
List<Integer> indexes = new ArrayList<Integer>();
for (int i = 0; i < properties.length; i++) {
AvroEventBeanPropertyWriter writer = getWriter(properties[i]);
if (propertyItems.containsKey(properties[i])) {
writers[i] = writer;
indexes.add(avroSchema.getField(properties[i]).pos());
} else {
writers[i] = getWriter(properties[i]);
if (writers[i] == null) {
return null;
}
allSimpleProps = false;
}
}
if (allSimpleProps) {
return new AvroEventBeanWriterSimpleProps(CollectionUtil.intArray(indexes));
}
return new AvroEventBeanWriterPerProp(writers);
}
public EventBeanReader getReader() {
return null; // use the default reader
}
public boolean equalsCompareType(EventType other) {
if (!(other instanceof AvroEventType)) {
return false;
}
AvroEventType otherAvro = (AvroEventType) other;
if (!otherAvro.getName().equals(metadata.getPrimaryName())) {
return false;
}
return otherAvro.avroSchema.equals(avroSchema);
}
public Object getSchema() {
return avroSchema;
}
public Schema getSchemaAvro() {
return avroSchema;
}
private void init() {
propertyNames = new String[avroSchema.getFields().size()];
propertyDescriptors = new EventPropertyDescriptor[propertyNames.length];
int fieldNum = 0;
for (Schema.Field field : avroSchema.getFields()) {
propertyNames[fieldNum] = field.name();
Class propertyType = AvroTypeUtil.propertyType(field.schema());
Class componentType = null;
boolean indexed = false;
boolean mapped = false;
FragmentEventType fragmentEventType = null;
if (field.schema().getType() == Schema.Type.ARRAY) {
componentType = AvroTypeUtil.propertyType(field.schema().getElementType());
indexed = true;
if (field.schema().getElementType().getType() == Schema.Type.RECORD) {
fragmentEventType = getFragmentEventTypeForField(field.schema(), eventAdapterService);
}
} else if (field.schema().getType() == Schema.Type.MAP) {
mapped = true;
componentType = AvroTypeUtil.propertyType(field.schema().getValueType());
} else {
fragmentEventType = getFragmentEventTypeForField(field.schema(), eventAdapterService);
}
AvroEventBeanGetterSimple getter = new AvroEventBeanGetterSimple(field.pos(), fragmentEventType == null ? null : fragmentEventType.getFragmentType(), eventAdapterService);
EventPropertyDescriptor descriptor = new EventPropertyDescriptor(field.name(), propertyType, componentType, false, false, indexed, mapped, fragmentEventType != null);
PropertySetDescriptorItem item = new PropertySetDescriptorItem(descriptor, propertyType, getter, fragmentEventType);
propertyItems.put(field.name(), item);
propertyDescriptors[fieldNum] = descriptor;
fieldNum++;
}
}
}