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

com.ebay.jetstream.event.support.AbstractEventSource 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.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NamedBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.jmx.export.annotation.ManagedOperation;

import com.ebay.jetstream.config.AbstractNamedBean;
import com.ebay.jetstream.config.ContextBeanChangedEvent;
import com.ebay.jetstream.counter.LongCounter;
import com.ebay.jetstream.event.EventException;
import com.ebay.jetstream.event.EventSink;
import com.ebay.jetstream.event.EventSinkList;
import com.ebay.jetstream.event.EventSource;
import com.ebay.jetstream.event.JetstreamErrorCodes;
import com.ebay.jetstream.event.JetstreamEvent;
import com.ebay.jetstream.event.support.channel.PauseEvent;
import com.ebay.jetstream.event.support.channel.ResumeEvent;

/**
 * @author shmurthy, xiaojuwu1
 */
public abstract class AbstractEventSource extends AbstractNamedBean implements
		EventSource, ApplicationListener, ErrorTracker {

	private boolean m_pauseIfAnyEventSinkPauses = true;
	private final AtomicBoolean m_isSourcePaused = new AtomicBoolean(false);
	private static final Logger LOGGER = LoggerFactory.getLogger("com.ebay.jetstream.event.support");
	private List m_pausedEventSink = new CopyOnWriteArrayList();
	private EventSinkList m_sinkList = new EventSinkList();
	private ErrorManager m_errors = new ErrorManager();
	private final LongCounter m_cloneFailedCounter = new LongCounter();

	protected void fireSendEvent(JetstreamEvent event) throws EventException {

		if (LOGGER.isDebugEnabled())
			event.log(this);

		if (m_sinkList.getSinks().size() <= 0
				&& getPausedEventSink().size() > 0) {
			throw new EventException("All Event Sinks are  paused.....",
					JetstreamErrorCodes.EVENT_SINKS_PAUSED.toString());
		}

		int index = 0;
		int lastIndex = m_sinkList.size() - 1;

		for (EventSink sink : m_sinkList.getSinks()) {
			// if we have more than 1 sink we need to clone the event to pass to
			// another sink so they can
			// independently modify the event concurrently
			JetstreamEvent fwdEvent = null;
			if (index < lastIndex) {
				try {
					fwdEvent = event.clone();
					if (fwdEvent == null)
						m_cloneFailedCounter.increment();
				} catch (CloneNotSupportedException e) {
					m_cloneFailedCounter.increment();
					LOGGER.error(
							"unable to clone event : "
									+ e.getLocalizedMessage());

				}
			} else {
				fwdEvent = event;
			}

			index++;
			try {
				if (fwdEvent != null)
					sink.sendEvent(fwdEvent);
			} catch (EventException e) {
				if (m_pauseIfAnyEventSinkPauses) {
					throw e;
				}
			}
		}
	}

	@Override
	public void addEventSink(EventSink sink) {
		m_sinkList.addSink(sink);
	}

	@Override
	public Collection getEventSinks() {
		return m_sinkList;
	}

	@Override
	public void removeEventSink(EventSink sink) {
		m_sinkList.remove(sink);
	}

	@Override
	public void setEventSinks(Collection sinks) {
		if (sinks instanceof EventSinkList) {
			m_sinkList = (EventSinkList) sinks;
		} else {
			for (EventSink s : sinks) {
				addEventSink(s);
			}
		}
	}

	/**
	 * @return the pausedEventSink
	 */
	public List getPausedEventSink() {
		return Collections.unmodifiableList(m_pausedEventSink);
	}

	private boolean isEventFromTheSink(List eventSinks,
			String beanName) {
		for (EventSink sink : eventSinks) {
			if (beanName.equalsIgnoreCase(sink.getBeanName())) {
				return true;
			}
		}
		return false;
	}

	public boolean isPauseIfAnyEventSinkPauses() {
		return m_pauseIfAnyEventSinkPauses;
	}

	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof PauseEvent) {
			processPauseEvent((PauseEvent) event);
		} else if (event instanceof ResumeEvent) {
			processResumeEvent((ResumeEvent) event);
		} else {
			applyConfig(event);
			processApplicationEvent(event);
		}
	}

	private void applyConfig(ApplicationEvent event) {
		if (event instanceof ContextBeanChangedEvent) {
			ContextBeanChangedEvent bcInfo = (ContextBeanChangedEvent) event;

			if (bcInfo.isChangedBean((EventSinkList) getEventSinks())) {
				setEventSinks(((Collection) ((bcInfo
						.getApplicationContext()).getBean(bcInfo.getBeanName()))));
			}

		}
	}

	public abstract void pause();

	protected abstract void processApplicationEvent(ApplicationEvent event);

	/**
	 * 
	 * @param pauseEvent
	 */
	public void processPauseEvent(PauseEvent pauseEvent) {
		Object eventSource = pauseEvent.getSource();
		NamedBean bean = (NamedBean) eventSource;
		Collection eventSinks = getEventSinks();
		if (eventSinks != null) {
			for (EventSink eventSink : eventSinks) {
				if (bean.getBeanName()
						.equalsIgnoreCase(eventSink.getBeanName())) {
					removeEventSink(eventSink);
					m_pausedEventSink.add(eventSink);
				}
			}
			if (isEventFromTheSink(getPausedEventSink(), bean.getBeanName())
					&& m_pauseIfAnyEventSinkPauses && !m_isSourcePaused.get()) {
				m_isSourcePaused.set(true);
				pause();
			} else if (isEventFromTheSink(getPausedEventSink(),
					bean.getBeanName())
					&& getEventSinks().size() == 0 && !m_isSourcePaused.get()) {
				m_isSourcePaused.set(true);
				pause();
			}
		}
	}

	/**
	 * 
	 * @param resumeEvent
	 */
	public void processResumeEvent(ResumeEvent resumeEvent) {
		Object eventSource = resumeEvent.getSource();
		NamedBean bean = (NamedBean) eventSource;
		List eventSinks = new ArrayList();
		eventSinks
				.addAll(Collections.unmodifiableCollection(m_pausedEventSink));
		if (eventSinks != null) {
			for (EventSink eventSink : eventSinks) {
				if (bean.getBeanName()
						.equalsIgnoreCase(eventSink.getBeanName())) {
					addEventSink(eventSink);
					m_pausedEventSink.remove(eventSink);
				}
			}
			if (isEventFromTheSink(eventSinks, bean.getBeanName())
					&& m_pauseIfAnyEventSinkPauses
					&& getPausedEventSink().size() == 0
					&& m_isSourcePaused.get()) {
				m_isSourcePaused.set(false);
				resume();
			} else if (isEventFromTheSink(eventSinks, bean.getBeanName())
					&& !m_pauseIfAnyEventSinkPauses
					&& getEventSinks().size() > 0 && m_isSourcePaused.get()) {
				m_isSourcePaused.set(false);
				resume();
			}
		}
	}

	@ManagedOperation
	@Override
	public void clearErrorList() {
		m_errors.clearErrorList();
	}

	@Override
	public String getErrors() {
		return m_errors.toString();
	}

	@Override
	public void registerError(Throwable t) {
		m_errors.registerError(t);
	}

	@Override
	public void registerError(Throwable t, JetstreamEvent evtCause) {
		m_errors.registerError(t, evtCause);
	}

	public abstract void resume();

	@Override
	public void setErrorListMax(int nSize) {
		m_errors.setErrorListMax(nSize);
	}

	/**
	 * @param pausedEventSink
	 *            the pausedEventSink to set
	 */
	public void setPausedEventSink(List pausedEventSink) {
		m_pausedEventSink = pausedEventSink;
	}

	public void setPauseIfAnyEventSinkPauses(boolean pauseIfAnyEventSinkPauses) {
		m_pauseIfAnyEventSinkPauses = pauseIfAnyEventSinkPauses;
	}

	@Override
	public String toString() {
		return getBeanName();

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy