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

com.ebay.jetstream.event.channel.file.OutboundFileChannel 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.channel.file;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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

import com.ebay.jetstream.counter.LongEWMACounter;
import com.ebay.jetstream.event.EventException;
import com.ebay.jetstream.event.JetstreamEvent;
import com.ebay.jetstream.event.channel.AbstractOutboundChannel;
import com.ebay.jetstream.management.Management;
import com.ebay.jetstream.messaging.MessageServiceTimer;
import com.ebay.jetstream.notification.AlertListener;

/**
 * OutboundFileChannel can be used in place of or along with OutboundMessage Channel. 
 * @author gjin
 *
 */

@ManagedResource(objectName = "Event/Channel", description = "Outbound file component")
public class OutboundFileChannel extends AbstractOutboundChannel {
	
	private static final String LINE_SEPARATOR = System.getProperty("line.separator");

	private Map m_streamTypeToHelperMap = new HashMap();
	private AlertListener m_AlertListener;
	
	private boolean m_stop = false;
	private boolean m_pause = false;
	private boolean m_restart = false;
	
	private static final Logger LOGGER = LoggerFactory.getLogger("com.ebay.jetstream.event.channel.file");
	
	public OutboundFileChannel() {
	}
	public void setAlertListener(AlertListener al) {
		if (al == null) {
			LOGGER.error( "AlertListener is null unexpectedly");
			return;
		}
		m_AlertListener = al;
	}
	public void afterPropertiesSet() throws Exception {
		
	}
	
	
	public void setStreamTypeToAddressMap(Map  typeToAddressMap) {
		if (typeToAddressMap == null) {
			throw new IllegalArgumentException("typeToFileChannelAddress Map is null unexpectedly");
		}
		
		for (Entry entry:typeToAddressMap.entrySet()) {
			m_streamTypeToHelperMap.put(entry.getKey(), new OutboundFileChannelHelper(entry.getValue()));
		}
		
		
	}
	

	public void close() throws EventException {
		
		LOGGER.info( "Closing Outbound File Chanel");
		
		/***### do not remove the bean so we can do restart ***/
  		//Management.removeBeanOrFolder(getBeanName(), this);
  		
		// m_eventsReceivedPerSec.destroy();
		//m_eventsSentPerSec.destroy();
  	  
  		/* close the files for each stream */
  		for (String type:m_streamTypeToHelperMap.keySet() ) {
  			m_streamTypeToHelperMap.get(type).closeForWrite();
  		}

	}


	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ebay.jetstream.event.channel.ChannelOperations#flush()
	 */
	public void flush() throws EventException {
		// This is a NOOP for this channel
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ebay.jetstream.event.channel.ChannelOperations#getAddress()
	 */
	
	/* let us return the first address if there is any */
	public FileChannelAddress getAddress() {
		
		Set types = m_streamTypeToHelperMap.keySet();
		if (types.size() == 0) {
			return null;
		}
		Iterator iter = types.iterator();
		
		return m_streamTypeToHelperMap.get(iter.next()).getAddress();
	}
	

	
	    


	
	/**
	 * ChannelBinging.afterPropertiesSet() calls channel.open()
	 */

	public void open() throws EventException {
		
		LOGGER.info(  "Opening Outbound File Channel");
  		
  		/* put my name Event/FileChannel to the page */
		if (!m_restart) {			
			Management.addBean(getBeanName(), this);
		}
  	    m_eventsReceivedPerSec = new LongEWMACounter(60, MessageServiceTimer.sInstance().getTimer());
  		m_eventsSentPerSec = new LongEWMACounter(60, MessageServiceTimer.sInstance().getTimer());
  	  

  		/* open the event file, be ready for writing*/
  		/* close the files for each stream */
  		
  		for (String type:m_streamTypeToHelperMap.keySet() ) {
  			try { 
  				m_streamTypeToHelperMap.get(type).openForWrite();
  			} catch (EventException ee) {
  				LOGGER.error( "open() get e=" + ee.getLocalizedMessage(), ee);
  	  	  		/*** instead of forcing application to exit, we choose to post an error status at dashboard */
  				if (m_AlertListener != null) {
  					m_AlertListener.sendAlert(getBeanName(),  "OutboundFileChannel open() get e=" + ee, AlertListener.AlertStrength.RED);
  				} else {
  					throw ee;
  				}
  			}
  		}

	}

		
	
	/**
	 * 
	 */
	@ManagedOperation
	public void resetStats() {
		super.resetStats();
	}


	/* create a line "v1,v2,,v4,v5\n" from the event
	 * if a value for a key is null then ",,". in the case above, v3 is null 
	 */
	private String createEventLine(JetstreamEvent e, String[] keys, String delimiter) {
		StringBuffer sb  = new StringBuffer();
		boolean isFirst = true;
		for (String key: keys) {
			if (isFirst) {
				isFirst = false;
			} else {
				sb.append(delimiter);
			}
			if (e.get(key) != null) {
				sb.append(e.get(key));
			}
		}
		sb.append(LINE_SEPARATOR);
		return sb.toString();
	}
	
	/*** this is the point where the data get into this class */
	public void sendEvent(JetstreamEvent event) throws EventException {
		if (m_stop || m_pause) {
			return;
		}
 		if (event == null) {
			return;
		}
		incrementEventRecievedCounter();
		
		String streamType = event.getEventType();
		
		if (!m_streamTypeToHelperMap.containsKey(streamType)) {
			/***#### INFO Logging here */
			//LOGGER.info(   "the stream type=" + streamType + " is not registered", getBeanName());
			incrementEventDroppedCounter();
			return;
		}
		
			
		OutboundFileChannelHelper helper = m_streamTypeToHelperMap.get(streamType);
		FileChannelAddress address = helper.getAddress();
		
		JetstreamEvent userEvent = null;
		
		/* remove those reserved keys (such as js_ev_type...which were added by jetstream) from the event */
		if (!address.isKeepReservedKeys()){
			userEvent = event.getFilteredEvent();
		} else {
			userEvent = new JetstreamEvent();
			userEvent.putAll(event);
			/* but should we still need to remove affinity key--- no
			userEvent.remove(JetstreamReservedKeys.MessageAffinityKey.toString());
			***/
		}
		
		/** empty event. drop it */
		if (userEvent.size() == 0) {
			LOGGER.info(   "the event is empty. Should not happen?");
			incrementEventDroppedCounter();
			return;
		}
		
		/*v1,v2,,,,,\r\n */
		String eventLineString = null;
		
		/* now the event must have at least one key 
		 * If columnname array is not predefined.
		 * it seems the first event of this stream. then we generate the keys from it and assume
		 * that all events of this stream have the same set of keys.
		 * */
		if (address.getColumnNameArray().length== 0) {
			synchronized (this) {
				if (address.getColumnNameArray().length== 0) {
					Set keys = userEvent.keySet();
					
					String[] keyArray = new String[keys.size()];
					keys.toArray(keyArray);
					address.setColumnNameArray(keyArray);
				}
			}

		} 
		/* now we have the column info */
		eventLineString = createEventLine(userEvent, address.getColumnNameArray(), address.getColumnDelimiter());

		if (helper.writeEvent(eventLineString)) {
			incrementEventSentCounter();
		} else {
			incrementEventDroppedCounter();
		}

	}


	public void shutDown() {
		close();
	}


	@Override
	public String toString() {

		return getBeanName();
	}

		

  	@Override
  	public void processApplicationEvent(ApplicationEvent event) {
  		/* we are not going to support for the time being */
  	}

	@Override
	public int getPendingEvents() {
		
		return 0;
	}
	@ManagedOperation
	public void stop() {
		m_stop = true;
		
		/* close all down load stream so we can detach the files from */
		close();
	}
	
	@ManagedOperation
	public void pause() {
		m_pause = true;
	}
	@ManagedOperation
	public void resume() {
		m_pause = false;
	}
	
	/* restart() to allow download more data if download files have more space */
	@ManagedOperation
	public void restart() {
		if (!m_stop) {
			return;
		}
		m_restart = true;
		open();
		m_restart = false;
		m_stop = false;
		m_pause = false;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy