/*******************************************************************************
*
* Copyright 2012-2015, the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obta a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*******************************************************************************/
package com.flipkart.aesop.event;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
import org.apache.avro.generic.GenericRecord;
import com.flipkart.aesop.utils.AvroToMysqlMapper;
import com.flipkart.aesop.utils.MysqlDataTypes;
import com.linkedin.databus.client.pub.DbusEventDecoder;
import com.linkedin.databus.core.DbusConstants;
import com.linkedin.databus.core.DbusEvent;
import com.linkedin.databus.core.DbusOpcode;
import com.linkedin.databus2.core.DatabusException;
import com.linkedin.databus2.schemas.VersionedSchema;
import com.linkedin.databus2.schemas.utils.SchemaHelper;
/**
* Abstract Event Factory to be extended by the various types of Event Factory Classes.
* @author Prakhar Jain
* @param <T> Actual Event Class
*/
public abstract class AbstractEventFactory<T extends AbstractEvent> implements EventFactory
{
public static String PRIMARY_KEY_FIELD_NAME = "pk";
public static String META_FIELD_TYPE_NAME = "dbFieldType";
/**
* Generates primary key set using the schema.
* @param schema
* @return Primary key set
* @throws DatabusException
*/
private Set<String> getPrimaryKeysSetFromSchema(Schema schema) throws DatabusException
{
Set<String> primaryKeySet = new HashSet<String>();
String primaryKeyFieldName = SchemaHelper.getMetaField(schema, PRIMARY_KEY_FIELD_NAME);
if (primaryKeyFieldName == null)
{
throw new DatabusException("No primary key specified in the schema");
}
for (String primaryKey : primaryKeyFieldName.split(DbusConstants.COMPOUND_KEY_SEPARATOR))
{
primaryKeySet.add(primaryKey.trim());
}
assert (primaryKeySet.size() >= 1);
return primaryKeySet;
}
public AbstractEvent createEvent(DbusEvent dbusEvent, DbusEventDecoder eventDecoder) throws DatabusException
{
GenericRecord genericRecord = eventDecoder.getGenericRecord(dbusEvent, null);
VersionedSchema writerSchema = eventDecoder.getPayloadSchema(dbusEvent);
Schema schema = writerSchema.getSchema();
DbusOpcode eventType = dbusEvent.getOpcode();
Set<String> primaryKeysSet = getPrimaryKeysSetFromSchema(schema);
String namespaceName = schema.getNamespace();
String entityName = schema.getName();
Map<String, Object> fieldMap = new HashMap<String, Object>();
for (Field field : schema.getFields())
{
String mysqlType = SchemaHelper.getMetaField(field, META_FIELD_TYPE_NAME);
fieldMap.put(
field.name(),
AvroToMysqlMapper.avroToMysqlType(genericRecord.get(field.name()),
MysqlDataTypes.valueOf(mysqlType.toUpperCase())));
}
AbstractEvent event = createEventInstance(fieldMap, primaryKeysSet, entityName, namespaceName, eventType);
return event;
}
/**
* To be implemented by the Actual Event class. Generates Event instance using all the mandatory fields.
* @param fieldsMap
* @param primaryKeysSet
* @param entityName
* @param namespaceName
* @param eventType
* @return Actual Event instance.
*/
protected abstract AbstractEvent createEventInstance(Map<String, Object> fieldsMap, Set<String> primaryKeysSet,
String entityName, String namespaceName, DbusOpcode eventType);
public AbstractEvent createEvent(Schema schema, Map<String, Object> keyValuePairs, DbusOpcode eventType)
throws DatabusException
{
String entityName = schema.getName();
String namespaceName = schema.getNamespace();
Set<String> primaryKeysSet = getPrimaryKeysSetFromSchema(schema);
AbstractEvent event = createEventInstance(keyValuePairs, primaryKeysSet, entityName, namespaceName, eventType);
return event;
}
public AbstractEvent createEvent(Map<String, Object> fieldsMap, Set<String> primaryFieldsSet, String entityName,
String namespaceName, DbusOpcode eventType)
{
AbstractEvent event = createEventInstance(fieldsMap, primaryFieldsSet, entityName, namespaceName, eventType);
return event;
}
}