All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ebay.jetstream.event.support.AdviceProcessor Maven / Gradle / Ivy

/*******************************************************************************
 *  Copyright © 2012-2015 eBay Software Foundation
 *  This program is dual licensed under the MIT and Apache 2.0 licenses.
 *  Please see LICENSE for more information.
 *******************************************************************************/
package com.ebay.jetstream.event.support;

import java.util.ArrayList;
import java.util.Date;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;

import com.ebay.jetstream.application.JetstreamApplication;
import com.ebay.jetstream.counter.LongCounter;
import com.ebay.jetstream.event.EventException;
import com.ebay.jetstream.event.JetstreamEvent;
import com.ebay.jetstream.event.JetstreamReservedKeys;
import com.ebay.jetstream.event.RetryEventCode;
import com.ebay.jetstream.event.advice.Advice;
import com.ebay.jetstream.event.channel.InboundChannel;
import com.ebay.jetstream.event.support.channel.RemoteController;
import com.ebay.jetstream.management.Management;
import com.ebay.jetstream.messaging.MessageService;
import com.ebay.jetstream.messaging.messagetype.MapMessage;
import com.ebay.jetstream.messaging.topic.JetstreamTopic;
import com.ebay.jetstream.util.GuidGenerator;

/**
 * A generic advice listener, it have a configurable retry event codes, and it
 * just pass the retry event to the eventSinks configured to the processor.
 * 
 * If the retryEventCodes is null, all retry reasons will be passed to the
 * eventSinks.
 * 
 * The startReplay/stopRelay method will pause/resume inbound channels when configured,
 * it also send out the message when configured the replayNotificationTopic.
 * 
 * @author xingwang
 * 
 */
@ManagedResource(objectName = "Event/AdviceProcessor", description = "Advice processor")
public class AdviceProcessor extends AbstractEventProcessor implements Advice {
    private static final Logger LOGGER = LoggerFactory.getLogger(AdviceProcessor.class.getPackage().getName());
    private static final String SERVER_ID = "" + GuidGenerator.gen() + "@"
            + JetstreamApplication.getInstance().getApplicationInformation().getApplicationName();
    private static final int HISTORY_COUNT = 32;
    
    private List m_retryEventCodes;
    private List m_replayInboundChannels;
    private MessageService m_messageService;
    private String m_replayNotificationTopic;
    
    private List m_cmdHistory = new ArrayList(HISTORY_COUNT);
    private AtomicLong m_historySeq = new AtomicLong(0);
    
    private JetstreamEvent m_lastEvent;
    
    private final AtomicBoolean m_shutdownFlag = new AtomicBoolean(false);

    private final EnumMap m_counters = new EnumMap(
            RetryEventCode.class);

    private final ConcurrentMap m_countersByTopic = new ConcurrentHashMap();
    
    @Override
    public void abandon(JetstreamEvent event, int reasonCode, String reason) {
        // do nothing.
    }

    private void addToHistory(String msg) {
        synchronized (m_cmdHistory) {
            int location = (int)(m_historySeq.getAndIncrement() % HISTORY_COUNT);
            if (m_cmdHistory.size() < HISTORY_COUNT) {
                m_cmdHistory.add(new Date() + " : " + msg);
            } else {
                m_cmdHistory.set(location, new Date() + " : " + msg);
            }
        }
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        for (RetryEventCode v : RetryEventCode.values()) {
            m_counters.put(v, new LongCounter());
        }
        Management.addBean(getBeanName(), this);
        m_messageService = MessageService.getInstance();
    }

    @ManagedAttribute
    public List getCmdHistory() {
        ArrayList cmdHistory = new ArrayList(HISTORY_COUNT);
        synchronized (m_cmdHistory) {
            long l = m_historySeq.get();
            if (l <= HISTORY_COUNT) {
                cmdHistory.addAll(m_cmdHistory);
            } else {
                long pos = l - HISTORY_COUNT;
                for (int i = 0; i < HISTORY_COUNT; i++) {
                    cmdHistory.add(m_cmdHistory.get((int) pos % HISTORY_COUNT));
                    pos ++;
                }
            }
        }
        return cmdHistory;
    }
    
    @Override
    public int getPendingEvents() {
        return 0;
    }
    
    public String getReplayNotificationTopic() {
        return m_replayNotificationTopic;
    }

    @ManagedAttribute
    public EnumMap getRetryCountersByReason() {
        return m_counters;
    }

    @ManagedAttribute
    public Map getRetryCountersByTopic() {
        return m_countersByTopic;
    }
    
    @ManagedAttribute
    public String getServerId() {
        return SERVER_ID;
    }

    @Override
    @ManagedOperation
    public void pause() {
        if (isPaused()) {
            return;
        }

        changeState(ProcessorOperationState.PAUSE);
    }

    @Override
    protected void processApplicationEvent(ApplicationEvent event) {
        // do nothing.
    }

    @Override
    @ManagedOperation
    public void resume() {
        if (isPaused()) {
            changeState(ProcessorOperationState.RESUME);
        }
    }

    @Override
    public void retry(JetstreamEvent event, RetryEventCode reasonCode, String reason) {
        // If retryEventCodes is null, retry all.
        if (m_retryEventCodes != null && !m_retryEventCodes.contains(reasonCode)) {
            super.incrementEventDroppedCounter();
            return;
        }

        m_counters.get(reasonCode).increment();

        sendEvent(event);
    }

    private void sendCommand(String command) {
        if (m_messageService.isInitialized()) {
            try {
                MapMessage msg = new MapMessage();
                msg.add(RemoteController.KEY_COMMAND, command);
                msg.add(RemoteController.KEY_SERVER, SERVER_ID);
                m_messageService.publish(new JetstreamTopic(m_replayNotificationTopic), msg);
            } catch (Exception e) {
                LOGGER.info( "Fatal Error : Publish method failed to broadcast the message", e);
            }
        } else {
            LOGGER.info( "Fatal Error : Message Service Not initialized");
        }
    }

    @Override
    public void sendEvent(JetstreamEvent event) throws EventException {
    	m_lastEvent = event;
    	String replayTopic = (String) event.get(JetstreamReservedKeys.EventReplayTopic.toString());
    	if (replayTopic != null) {
    	    LongCounter counter = m_countersByTopic.get(replayTopic);
    	    if (counter == null) {
    	        counter = new LongCounter();
    	        LongCounter existedCounter = m_countersByTopic.putIfAbsent(replayTopic, counter);
    	        if (existedCounter != null) {
    	            counter = existedCounter;
    	        }
    	    }
    	    counter.increment();
    	}
        super.incrementEventRecievedCounter();
        if (isPaused() || m_shutdownFlag.get()) {
            super.incrementEventDroppedCounter();
            return;
        }
        // Use this to avoid infinite loop.
        super.fireSendEvent(event);
        super.incrementEventSentCounter();
    }

	/**
	 * @return
	 */
	public JetstreamEvent getLastEvent() {
		return m_lastEvent;
	}
	
    public void setReplayInboundChannels(List replayInboundChannels) {
        this.m_replayInboundChannels = replayInboundChannels;
    } 

    public void setReplayNotificationTopic(String replayNotificationTopic) {
        this.m_replayNotificationTopic = replayNotificationTopic;
    }

    public void setRetryEventCodes(List retryEventCodes) {
        this.m_retryEventCodes = retryEventCodes;
    }
    
    
    @Override
    public void shutDown() {
        m_shutdownFlag.compareAndSet(false, true);
    }
    

    @ManagedOperation
    @Override
    public void startReplay() {
        addToHistory(RemoteController.COMMAND_START);
        if (this.m_replayNotificationTopic != null) {
            sendCommand(RemoteController.COMMAND_START);
        }
        List channels = m_replayInboundChannels;
        if (channels != null) {
            for (InboundChannel c : channels) {
                c.resume();
            }
        }
    }

    @ManagedOperation
    @Override
    public void stopReplay() {
        addToHistory(RemoteController.COMMAND_STOP);
        if (this.m_replayNotificationTopic != null) {
            sendCommand(RemoteController.COMMAND_STOP);
        }
        List channels = m_replayInboundChannels;
        if (channels != null) {
            for (InboundChannel c : channels) {
                c.pause();
            }
        }
    }

    @Override
    public void success(JetstreamEvent event) {
        // do nothing.
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy