
reactor.groovy.config.ReactorBuilder.groovy Maven / Gradle / Ivy
The newest version!
package reactor.groovy.config
import groovy.transform.CompileStatic
import reactor.convert.Converter
import reactor.core.Environment
import reactor.core.Reactor
import reactor.core.composable.Deferred
import reactor.core.composable.Stream
import reactor.core.composable.spec.Streams
import reactor.core.spec.Reactors
import reactor.event.Event
import reactor.event.dispatch.Dispatcher
import reactor.event.routing.ArgumentConvertingConsumerInvoker
import reactor.event.routing.ConsumerInvoker
import reactor.event.routing.EventRouter
import reactor.event.selector.ObjectSelector
import reactor.event.selector.Selector
import reactor.event.selector.Selectors
import reactor.event.support.CallbackEvent
import reactor.filter.Filter
import reactor.filter.FirstFilter
import reactor.filter.PassThroughFilter
import reactor.filter.RandomFilter
import reactor.filter.RoundRobinFilter
import reactor.function.Consumer
import reactor.function.Predicate
import reactor.function.Supplier
import reactor.groovy.support.ClosureEventConsumer
/**
* @author Stephane Maldini
*/
@CompileStatic
class ReactorBuilder implements Supplier {
static final private Selector noSelector = Selectors.anonymous()
static final private Filter DEFAULT_FILTER = new PassThroughFilter()
static final String ROUND_ROBIN = 'round-robin'
static final String PUB_SUB = 'all'
static final String RANDOM = 'random'
static final String FIRST = 'first'
Environment env
Converter converter
EventRouter router
ConsumerInvoker consumerInvoker
Dispatcher dispatcher
Filter filter
boolean override = false
private String dispatcherName
final String name
private final SortedSet streams = new TreeSet()
private final Map ext = [:]
private final Map> consumers = [:]
private final Map reactorMap
private final List childNodes = []
private Reactor reactor
ReactorBuilder(String name, Map reactorMap) {
this.reactorMap = reactorMap
this.name = name
}
ReactorBuilder(String name, Map reactorMap, Reactor reactor) {
this(name, reactorMap)
this.reactor = reactor
}
void rehydrate(ReactorBuilder r) {
converter = converter ?: r.converter
filter = filter ?: r.filter
dispatcher = dispatcher ?: r.dispatcher
dispatcherName = dispatcherName ?: r.dispatcherName
router = router ?: r.router
consumerInvoker = consumerInvoker ?: r.consumerInvoker
if (!override) {
streams.addAll r.streams
childNodes.addAll r.childNodes
}
for (entry in r.ext) {
if (!ext[((Map.Entry) entry).key]) ext[((Map.Entry) entry).key] =
((Map.Entry) entry).value
}
}
void init() {
if (name) {
def r = reactorMap[name]
if (r) {
rehydrate r
addConsumersFrom r
}
reactorMap[name] = this
}
}
def ext(String k) {
ext[k]
}
void ext(String k, v) {
ext[k] = v
}
void exts(Map map) {
ext.putAll map
}
Filter routingStrategy(String strategy) {
switch (strategy) {
case ROUND_ROBIN:
filter = new RoundRobinFilter()
break
case RANDOM:
filter = new RandomFilter()
break
case FIRST:
filter = new FirstFilter()
break
case PUB_SUB:
default:
filter = DEFAULT_FILTER
}
}
ReactorBuilder dispatcher(String dispatcher) {
this.dispatcherName = dispatcher
this.dispatcher = env?.getDispatcher(dispatcher)
this
}
ReactorBuilder on(@DelegatesTo(strategy = Closure.DELEGATE_FIRST,
value = ClosureEventConsumer.ReplyDecorator) Closure closure) {
on noSelector, new ClosureEventConsumer((Closure) closure.clone())
}
ReactorBuilder on(String selector, @DelegatesTo(strategy = Closure.DELEGATE_FIRST,
value = ClosureEventConsumer.ReplyDecorator) Closure closure) {
on Selectors.object(selector), new ClosureEventConsumer((Closure) closure.clone())
}
ReactorBuilder on(Consumer consumer) {
on noSelector, consumer
}
ReactorBuilder on(String selector, Consumer closure) {
on Selectors.object(selector), closure
}
ReactorBuilder on(Selector selector, @DelegatesTo(strategy = Closure.DELEGATE_FIRST,
value = ClosureEventConsumer.ReplyDecorator) Closure closure) {
on selector, new ClosureEventConsumer((Closure) closure.clone())
}
ReactorBuilder on(Selector selector, Consumer closure) {
consumers[selector] = consumers[selector] ?: (List) []
consumers[selector] << closure
this
}
void stream(@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = Stream) Closure closure) {
stream((Selector) null, closure)
}
void stream(Deferred, Stream>> head, Stream> tail) {
stream((Selector) null, head, tail)
}
void stream(String selector, @DelegatesTo(strategy = Closure.DELEGATE_FIRST,
value = Stream) Closure closure) {
stream Selectors.$(selector), closure
}
void stream(Selector selector, @DelegatesTo(strategy = Closure.DELEGATE_FIRST,
value = Stream) Closure closure) {
Deferred, Stream>> head = Streams.> defer().get()
Stream newTail = DSLUtils.delegateFirstAndRun(head.compose(), closure)
stream selector, head, newTail
}
void stream(Selector selector, Deferred, Stream>> head, Stream> tail) {
if (tail) {
streams << new HeadAndTail(head, tail, selector)
}
}
@Override
Reactor get() {
if (reactor)
return reactor
def spec = Reactors.reactor().env(env)
if (dispatcherName) {
spec.dispatcher(dispatcherName)
} else {
spec.dispatcher(dispatcher)
}
if (converter) {
spec.converters(converter)
}
if (router) {
spec.eventRouter(router)
} else if (streams) {
Deferred, Stream>> deferred = null
Stream> tail = null
HeadAndTail stream
HeadAndTail anticipatedStream
Iterator it = streams.iterator()
boolean first = true
while (it.hasNext() || anticipatedStream) {
stream = anticipatedStream ?: it.next()
anticipatedStream = null
if (first) {
first = false
deferred = Streams.> defer().get()
tail = deferred.compose()
}
if (stream.selector) {
if (it.hasNext()) {
anticipatedStream = it.next()
} else {
def finalDeferred = Streams.> defer().get()
anticipatedStream = new HeadAndTail(finalDeferred, finalDeferred.compose(), null)
}
tail.filter(new EventRouterPredicate(stream.selector), anticipatedStream.tail).connect(stream.head.compose())
} else {
tail.connect(stream.head.compose())
}
tail = stream.tail
}
tail.consumeEvent(new Consumer() {
@Override
void accept(Event eventEvent) {
if (eventEvent.class == CallbackEvent)
((CallbackEvent) eventEvent).callback()
}
})
spec.eventRouter(new StreamEventRouter(filter ?: DEFAULT_FILTER,
consumerInvoker ?: new ArgumentConvertingConsumerInvoker(converter), deferred))
} else {
if (filter) {
spec.eventFilter(filter)
}
if (consumerInvoker) {
spec.consumerInvoker(consumerInvoker)
}
}
reactor = spec.get()
if (childNodes) {
for (childNode in childNodes) {
childNode.get()
}
}
if (consumers) {
for (perSelectorConsumers in consumers.entrySet()) {
for (consumer in perSelectorConsumers.value) {
reactor.on((Selector) perSelectorConsumers.key, consumer)
}
}
}
reactor
}
void addConsumersFrom(ReactorBuilder from) {
Map> fromConsumers = from.consumers
Map.Entry> consumerEntry
for (_consumerEntry in fromConsumers) {
consumerEntry = (Map.Entry>) _consumerEntry
for (consumer in consumerEntry.value) {
on consumerEntry.key, (Consumer) consumer
}
}
}
/**
* initialize a Reactor
* @param c DSL
*/
ReactorBuilder reactor(
@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = NestedReactorBuilder)
Closure c
) {
reactor(null, c)
}
ReactorBuilder reactor(String reactorName,
@DelegatesTo(strategy = Closure.DELEGATE_FIRST, value = NestedReactorBuilder)
Closure c
) {
def builder = new NestedReactorBuilder(reactorName, this, reactor)
builder.init()
DSLUtils.delegateFirstAndRun builder, c
childNodes << builder
builder
}
@CompileStatic
private final class EventRouterPredicate implements Predicate> {
final Selector sel
EventRouterPredicate(Selector sel) {
this.sel = sel
}
@Override
boolean test(Event> event) {
sel.matches(event.headers.get(StreamEventRouter.KEY_HEADER))
}
}
@CompileStatic
final class HeadAndTail implements Comparable {
final Deferred, Stream>> head
final Stream> tail
final Selector selector
HeadAndTail(Deferred, Stream>> head, Stream> tail, Selector selector) {
this.head = head
this.tail = tail
this.selector = selector
}
@Override
int compareTo(HeadAndTail o) {
selector ? 1 : 0
}
}
@CompileStatic
final class NestedReactorBuilder extends ReactorBuilder {
NestedReactorBuilder(String reactorName, ReactorBuilder parent, Reactor reactor) {
super(reactorName, parent.reactorMap, reactor)
rehydrate parent
env = parent.env
consumers.putAll(parent.consumers)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy