
rt.pipeline.pipe.PipeContext.xtend Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rts-pipeline Show documentation
Show all versions of rts-pipeline Show documentation
Framework to build reactive services for reactive application front-ends
The newest version!
package rt.pipeline.pipe
import java.util.HashMap
import java.util.Iterator
import org.eclipse.xtend.lib.annotations.Accessors
import org.slf4j.LoggerFactory
import rt.async.pubsub.IMessageBus
import rt.async.pubsub.Message
import rt.pipeline.IComponent
import rt.pipeline.UserInfo
class PipeContext {
static val logger = LoggerFactory.getLogger('PIPELINE')
@Accessors val Message message
@Accessors val PipeResource resource
boolean inFail = false
val Pipeline pipeline
val Iterator iter
val objects = new HashMap, Object>
def IMessageBus bus() { return pipeline.mb }
def object(Class> type, Object instance) { objects.put(type, instance) }
def T object(Class type) { return objects.get(type) as T }
package new(Pipeline pipeline, PipeResource resource, Message message, Iterator iter) {
this.pipeline = pipeline
this.resource = resource
this.message = message
this.iter = iter
}
/** Sends the context to the delivery destination. Normally this methods is called in the end of the pipeline process.
* So most of the time there is no need to call this.
*/
def void deliver() {
if(!inFail) {
try {
if (message.typ == Message.REPLY)
deliverReply
else
deliverRequest
} catch(RuntimeException ex) {
ex.printStackTrace
if (message.typ != Message.PUBLISH) fail(ex)
}
}
}
/** Used by interceptors, order the pipeline to execute the next interceptor. If no other interceptor exits, a delivery is proceed.
*/
def void next() {
if(!inFail) {
if(iter.hasNext) {
try {
iter.next.apply(this)
} catch(RuntimeException ex) {
ex.printStackTrace
fail(ex)
}
} else {
deliver
}
}
}
/** Send a message to the client resource
* @param msg Should be a new message to send
*/
def void send(Message msg) {
if(!inFail) {
resource.send(msg)
}
}
/** Interrupts the pipeline flow and sends an error message back to the original "from". After this, other calls to "next()" or "fail(..)" are useless.
* @param from The address that will be on reply "header.from".
* @param error The error descriptor message.
*/
def void fail(Throwable ex) {
if(!inFail) {
replyError(ex)
pipeline.fail(ex)
inFail = true
}
}
/** Does nothing to the pipeline flow and sends a reply back.
* @param reply Should be a new PipeMessage
*/
def void reply(Message reply) {
if(!inFail) {
reply => [
id = message.id
clt = message.clt
typ = Message.REPLY
]
resource.send(reply)
}
}
/** Does nothing to the pipeline flow and sends a OK reply back with a pre formatted JSON schema.
*/
def void replyOK() {
if(!inFail) {
val reply = new Message => [
cmd = Message.CMD_OK
]
reply(reply)
}
}
/** Does nothing to the pipeline flow and sends a OK reply back with a pre formatted JSON schema.
* @param value The address that will be on "from".
*/
def void replyOK(Object resultObj) {
if(!inFail) {
val reply = new Message => [
cmd = Message.CMD_OK
result = resultObj
]
reply(reply)
}
}
def void replyObservable(String uuid) {
if(!inFail) {
val reply = new Message => [
cmd = Message.CMD_OBSERVABLE
result = "evt:" + uuid
]
reply(reply)
}
}
/** Does nothing to the pipeline flow and sends a ERROR reply back with a pre formatted JSON schema.
* @param value The error descriptor message.
*/
def void replyError(Throwable ex) {
if(!inFail) {
val reply = new Message => [
cmd = Message.CMD_ERROR
result = ex
]
logger.error('REPLY-ERROR {}', ex)
reply(reply)
}
}
def void publish(Message pub) {
if(!inFail) {
pub => [
clt = message.clt
typ = Message.PUBLISH
]
resource.send(pub)
}
}
def void publishNext(String uuid, Object resultObj) {
if(!inFail) {
val pub = new Message => [
cmd = Message.CMD_OK
path = 'evt:' + uuid
result = resultObj
]
publish(pub)
}
}
def void publishComplete(String uuid) {
if(!inFail) {
val pub = new Message => [
cmd = Message.CMD_COMPLETE
path = 'evt:' + uuid
]
publish(pub)
}
}
def void publishError(String uuid, Throwable ex) {
if(!inFail) {
val pub = new Message => [
cmd = Message.CMD_ERROR
path = 'evt:' + uuid
result = ex
]
publish(pub)
}
}
/** Order the underlying resource channel to disconnect. But the client can be configured to reconnect, so most of the times a reconnection is made by the client.
* To avoid this, the method should only be used when the client orders the disconnection.
*/
def void disconnect() {
resource.disconnect
}
private def void deliverRequest() {
//validate authorization...
val user = object(UserInfo)
if (!pipeline.isAuthorized(message, user)) {
logger.error('Authorization failed on {}', message.path)
fail(new RuntimeException('Unauthorized user!'))
return
}
val srv = pipeline.getComponent(message.path)
if(srv != null) {
logger.debug('DELIVER {}', message.path)
srv.apply(this)
} else {
logger.info('PUBLISH {}', message.path)
pipeline.mb.publish(message.path, message)
}
}
private def void deliverReply() {
logger.debug('DELIVER-REPLY {} {}', message.clt, message.id)
pipeline.mb.reply(message)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy