/*******************************************************************************
*
* 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.eventconsumer;
import com.flipkart.aesop.event.AbstractEvent;
import com.flipkart.aesop.event.EventFactory;
import com.flipkart.aesop.event.implementation.SourceEvent;
import com.flipkart.aesop.eventconsumer.implementation.DefaultEventConsumerImpl;
import com.flipkart.aesop.mapper.Mapper;
import com.flipkart.aesop.processor.DestinationEventProcessor;
import com.linkedin.databus.client.consumer.AbstractDatabusCombinedConsumer;
import com.linkedin.databus.client.pub.ConsumerCallbackResult;
import com.linkedin.databus.client.pub.DbusEventDecoder;
import com.linkedin.databus.core.DbusEvent;
import com.linkedin.databus.core.DbusOpcode;
import com.linkedin.databus2.core.DatabusException;
import org.trpr.platform.core.impl.logging.LogFactory;
import org.trpr.platform.core.spi.logging.Logger;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Extend this class to implement your Event Consumer, or use {@link DefaultEventConsumerImpl}.
* @author Jagadeesh Huliyar
* @author Prakhar Jain
* @see DefaultEventConsumerImpl
*/
public abstract class AbstractEventConsumer extends AbstractDatabusCombinedConsumer
{
/** Logger for this class */
public static final Logger LOGGER = LogFactory.getLogger(AbstractEventConsumer.class);
/** Factory which generates {@link SourceEvent} using {@link DbusEvent} and {@link DbusEventDecoder}. */
protected EventFactory sourceEventFactory;
/** Maps {@link SourceEvent} to {@link List of DestinationEvent}. */
protected Mapper mapper;
/** Map from {@link com.linkedin.databus.core.DbusOpcode} to the corresponding {@link DestinationEventProcessor} implementation. */
protected Map<DbusOpcode, ? extends DestinationEventProcessor> destinationProcessorMap;
/** Set of Group Ids which the event consumer should consume. */
protected Set<Integer> destinationGroupSet;
/**
* Total Destination Groups. This is used in case Group Id is not specified in the HOCON-config and hence, group id
* is figured out using the {@link SourceEvent} and this number.
*/
protected Integer totalDestinationGroups;
/**
* Abstract Builder for AbstractEventConsumer.
* @param <T> Event Consumer Implementation class
*/
public abstract static class Builder<T>
{
protected EventFactory sourceEventFactory;
protected Mapper mapper;
protected Map<DbusOpcode, ? extends DestinationEventProcessor> destinationProcessorMap;
protected Set<Integer> destinationGroupSet = new HashSet<Integer>();
protected Integer totalDestinationGroups = 1;
public Builder(EventFactory sourceEventFactory, Mapper mapper, Map<DbusOpcode, ? extends DestinationEventProcessor> destinationProcessorMap)
{
this.sourceEventFactory = sourceEventFactory;
this.mapper = mapper;
this.destinationProcessorMap = destinationProcessorMap;
}
public EventFactory getSourceEventFactory()
{
return sourceEventFactory;
}
public Mapper getMapper()
{
return mapper;
}
public Map<DbusOpcode, ? extends DestinationEventProcessor> getDestinationProcessorMap()
{
return destinationProcessorMap;
}
public Set<Integer> getDestinationGroupSet()
{
return destinationGroupSet;
}
public Integer getTotalDestinationGroups()
{
return totalDestinationGroups;
}
public Builder<T> withDestinationGroupSet(Set<Integer> destinationGroupSet)
{
this.destinationGroupSet = destinationGroupSet;
return this;
}
public Builder<T> withTotalDestinationGroups(Integer totalDestinationGroups)
{
this.totalDestinationGroups = totalDestinationGroups;
return this;
}
public abstract T build();
}
/**
* Overridden superclass method. Returns the result of calling
* {@link AbstractEventConsumer#processEvent(DbusEvent, DbusEventDecoder)}
* @see com.linkedin.databus.client.consumer.AbstractDatabusCombinedConsumer#onDataEvent(com.linkedin.databus.core.DbusEvent,
* com.linkedin.databus.client.pub.DbusEventDecoder)
*/
public ConsumerCallbackResult onDataEvent(DbusEvent event, DbusEventDecoder eventDecoder)
{
return processEvent(event, eventDecoder);
}
/**
* Overridden superclass method. Returns the result of calling
* {@link AbstractEventConsumer#processEvent(DbusEvent, DbusEventDecoder)}
* @see com.linkedin.databus.client.consumer.AbstractDatabusCombinedConsumer#onBootstrapEvent(com.linkedin.databus.core.DbusEvent,
* com.linkedin.databus.client.pub.DbusEventDecoder)
*/
public ConsumerCallbackResult onBootstrapEvent(DbusEvent event, DbusEventDecoder eventDecoder)
{
return processEvent(event, eventDecoder);
}
/**
* Helper method that prints out the attributes of the change event.
* @param dbusEvent the Databus change event
* @param eventDecoder the Event decoder
* @return {@link ConsumerCallbackResult#SUCCESS} if successful and {@link ConsumerCallbackResult#ERROR} in case of
* exceptions/errors
*/
private ConsumerCallbackResult processEvent(DbusEvent dbusEvent, DbusEventDecoder eventDecoder)
{
LOGGER.debug("Source Id is " + dbusEvent.getSourceId());
AbstractEvent event;
try
{
event = decodeSourceEvent(dbusEvent, eventDecoder);
LOGGER.info("Event : " + event.toString()); // Log Properly
}
catch (DatabusException ex)
{
LOGGER.error("error in consuming events", ex);
return ConsumerCallbackResult.ERROR;
}
return processSourceEvent(event);
}
/**
* Decodes the {@link DbusEvent} to {@link SourceEvent} using {@link DbusEventDecoder}
* @param event : databus event
* @param eventDecoder : databus Event Decoder
* @return Source Event
* @throws DatabusException : dataBus Exception thrown
*/
public abstract AbstractEvent decodeSourceEvent(DbusEvent event, DbusEventDecoder eventDecoder)
throws DatabusException;
/**
* Processes source event. Ideal implementation, firstly, maps the {@link SourceEvent} to {@link List of
* DestinationEvent} and then passes each {@code DestinationEvent} to the corresponding
* {@link DestinationEventProcessor}.
* @param event Source Event
* @return {@link ConsumerCallbackResult#SUCCESS} if successful and {@link ConsumerCallbackResult#ERROR} in case of
* exceptions/errors
*/
public abstract ConsumerCallbackResult processSourceEvent(AbstractEvent event);
/**
* Gets the group Id set to be processed for this event consumer.
* @return Set of Group Ids
*/
public Set<Integer> getDestinationGroupSet()
{
return destinationGroupSet;
}
/**
* Sets the group Id set to be processed for this event consumer.
* @param totalDestinationGroups
*/
public void setTotalDestinationGroups(Integer totalDestinationGroups)
{
this.totalDestinationGroups = totalDestinationGroups;
}
}