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

rt.pipeline.DefaultMessageBus.xtend Maven / Gradle / Ivy

package rt.pipeline

import java.util.HashMap
import java.util.HashSet
import java.util.Set
import java.util.concurrent.ConcurrentHashMap
import org.eclipse.xtend.lib.annotations.Accessors
import rt.async.pubsub.IMessageBus
import rt.async.pubsub.IObserver
import rt.async.pubsub.ISubscription
import rt.async.pubsub.Message

import static rt.async.AsyncUtils.*
import org.slf4j.LoggerFactory

class DefaultMessageBus implements IMessageBus {
	static val logger = LoggerFactory.getLogger('BUS')
	
	val subscriptions = new HashMap>
	val replyListeners = new ConcurrentHashMap void>
	
	val observers = new HashMap
	
	override publish(String address, String inCmd, Object inResult) {
		publish(address, address, inCmd, inResult)
	}
	
	override publish(String address, String inPath, String inCmd, Object inResult) {
		val msg = new Message => [ typ = Message.PUBLISH path = 'srv:' + inPath cmd = inCmd result = inResult ]
		subscriptions.get(address)?.forEach[ send(msg) ]
	}
	
	override publish(String address, Message msg) {
		if (msg.typ != null) msg.typ = Message.PUBLISH
		subscriptions.get(address)?.forEach[ send(msg) ]
	}
	
	override send(String address, Message msg, (Message) => void replyCallback) {
		val replyID = msg.replyID
		replyListener(replyID, replyCallback)
		
		msg.typ = Message.SEND
		subscriptions.get(address)?.forEach[ send(msg) ]
		
		timeout[
			val replyTimeoutMsg = new Message => [
				id=msg.id clt=msg.clt typ=Message.REPLY cmd=Message.CMD_ERROR
				result=new RuntimeException('''Timeout for «msg.path» -> «msg.cmd»''')
			]
			replyTimeoutMsg.reply
		]
	}
	
	override reply(Message msg) {
		val replyID = msg.replyID
		
		val replyOKBackFun = replyListeners.remove(replyID + '/reply-ok')
		val replyERRORBackFun = replyListeners.remove(replyID + '/reply-error')
		
		//process backward replies. In case of internal components need the information
		if (msg.cmd == Message.CMD_OK) {
			replyOKBackFun?.apply(msg)
		} else {
			replyERRORBackFun?.apply(msg)
		}
		
		val replyFun = replyListeners.remove(replyID)
		replyFun?.apply(msg)
	}
	
	override replyListener(String replyID, (Message) => void listener) {
		replyListeners.put(replyID, listener)
	}
	
	override subscribe(String address, (Message) => void listener) {
		logger.info('SUBSCRIBE {}', address)
		var holder = subscriptions.get(address)
		if (holder == null) {
			holder = new HashSet
			subscriptions.put(address, holder)
			observers.get(address)?.onCreate(address)
		}
		
		val sub = new DefaultSubscription(this, address, listener)
		holder.add(sub)
		
		return sub
	}
	
	override addObserver(String address, IObserver observer) {
		observers.put(address, observer)
	}
	
	static class DefaultSubscription implements ISubscription {
		@Accessors val String address
		
		val DefaultMessageBus parent
		val (Message) => void  callback
		
		package new(DefaultMessageBus parent, String address, (Message) => void callback) {
			this.parent = parent
			this.address = address
			this.callback = callback
		}
		
		def send(Message msg) {
			callback.apply(msg)
		}
		
		override remove() {
			logger.info('UNSUBSCRIBE {}', address)
			val holder = parent.subscriptions.get(address)
			if (holder != null) {
				holder.remove(this)
				
				if (holder.size == 0) {
					parent.observers.get(address)?.onDestroy(address)
					parent.subscriptions.remove(address)
				}	
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy