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

org.zdevra.sparrow.AbstractSparrowEngine Maven / Gradle / Ivy

/*****************************************************************************
 * Copyright 2012 Zdenko Vrabel
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************/
package org.zdevra.sparrow;

import org.zdevra.sparrow.actor.*;
import org.zdevra.sparrow.adapter.AbstractAdapterBuilder;
import org.zdevra.sparrow.adapter.AdapterBuilder;
import org.zdevra.sparrow.adapter.InboundAdapter;
import org.zdevra.sparrow.aggregator.AggregatorBuilder;
import org.zdevra.sparrow.aggregator.AggregatorBuilderImpl;
import org.zdevra.sparrow.chain.ChainBuilder;
import org.zdevra.sparrow.channel.*;
import org.zdevra.sparrow.dsl.FromDsl;
import org.zdevra.sparrow.dsl.SparrowDsl;
import org.zdevra.sparrow.filter.FilterBuilder;
import org.zdevra.sparrow.filter.HeaderFilterRuleBuilder;
import org.zdevra.sparrow.filter.PayloadFilterRuleBuilder;
import org.zdevra.sparrow.smartproxy.BaseSmartProxyBuilder;
import org.zdevra.sparrow.smartproxy.SmartProxy;
import org.zdevra.sparrow.smartproxy.SmartProxyBuilder;
import org.zdevra.sparrow.splitter.SplitterBuilder;
import org.zdevra.sparrow.splitter.SplitterBuilderImpl;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Abstract sparrow engine could be used as standalone engine without any dependencies to Guice or anything else.
 * What you need to do is just extend this class, implement the {@link org.zdevra.sparrow.AbstractSparrowEngine#configureSparrow()}
 * method where you place your own sparrow configuration of message system.
 *
 * 

* AbstractSparrowEngine has some limitations. First of all is no dependency injection what means that annotations like * ChannelNamed etc doesn't work. Also you could create actors/channels only from instances, not from classes. * *
*

How to configure/build/use your own messaging system

*
* *
 *    public class MyMessagingSystem extends AbstractSparrowEngine
 *    {
 *       public void configureSparrow() {
 *          ...
 *          channel("fib-ch").asInstance(new DirectChannel());
 *
 *          actor("fibonacci-1")
 *             .input("fib-ch")
 *             .output("log-ch")
 *             .actorOf(new FibonacciActor());
 *
 *          channel("log-ch").asInstance(new DirectChannel());
 *          ...
 *       }
 *    }
 * 
* * The engine's implementation above build simple actor that computes fibonacci numbers for messages with input and * output channel. In {@code configureSparrow()} method you could use any of entities that Sparrow offers you like * {@link org.zdevra.sparrow.splitter.SplitterActorHandler splitters}, {@link org.zdevra.sparrow.aggregator.AggregatorActorHandler aggregators} * etc. via protected methods. * *

* If you have defined you messaging system, you will want start it and use it then. * *

*

 *    SparrowEngine engine = new MyMessagingSystem();
 *    engine.start();
 *    ...
 *    MessageChannel ch = engine.getMessageChannel("fib-ch");
 *    ch.send(message);
 *    ...
 *    engine.shutdown();
 * 
* * Example code prepare, initialize and start all entities defined in {@code MyMessagingSystem} implementation. You * could access to any channel defined inside system and as you can see in example, you cold send the message into * system through this channel. At the end the engine goes shutdown. * *
*

Supported entities by Sparrow

*
* * Sparrow follows similar style of configuration as is used in Guice. There are several builders and methods that * creates concrete entities like channels, actors etc. *

*

 *    channel("input").asInstance(new LoadBalancerChannel());
 * 
* This statement creates load balanced channel named as 'input'. Into method {@code asInstance} you could forward * any message implementation you want. Sparrow engine then bind the concrete instance of channel with channel's name. * *

*
 *    ActorHandler handler = ...;
 *    actor("act1")
 *       .input("input-ch")
 *       .mailbox(new FifoMailbox(10))
 *       .actorOf(handler);
 * 
* This code fragment creates actor 'act1' that receive messages from 'input-ch' and with processing procedure * implemented in {@code handler}. InputOutputActor is using different implementation of mailbox that is {@code FifoMailbox} * with capacity 10. Because handler isn't extending {@link org.zdevra.sparrow.actor.OutputActorHandler}, you don't * need specify output channel. * * * * @author Zdenko Vrabel ([email protected]) */ public abstract class AbstractSparrowEngine implements SparrowEngine, SparrowDsl { //------------------------------------------------------------------------------------------------------------------- // members //------------------------------------------------------------------------------------------------------------------- /** collection of all channels with names */ private final Map channels; /** collection of all units */ private final List units; /** temporary list of all other builders. Exists during 'configureSparrow()' calling */ private List preBuilders; /** temporary list of all channels builders. Exists during 'configureSparrow()' calling */ private List channelBuilders; /** temporary list of all actor builders. Exists during 'configureSparrow()' calling */ private List actorBuilders; //------------------------------------------------------------------------------------------------------------------- // constructor //------------------------------------------------------------------------------------------------------------------- /** * Constructor */ public AbstractSparrowEngine() { channels = new HashMap(); units = new LinkedList(); } //------------------------------------------------------------------------------------------------------------------- // abstract & protected methods //------------------------------------------------------------------------------------------------------------------- /** * Here you will place configuration of your message system. */ public abstract void configureSparrow(); /** * Create/register new actor into engine's context * * @return */ @Override public ActorBuilder actor(ActorHandlerBuilder actor) { return new StandaloneActorBuilder(actor); } /** * Create/register new actor into engine's context * * @return */ @Override public ActorBuilder actor(ActorHandler actor) { return new StandaloneActorBuilder(new InstanceActorHandlerBuilder(actor)); } /** * Create/register new actor into engine's context * * @return */ @Override public ActorBuilder actor(Class actor) { return new StandaloneActorBuilder(new ClassActorHandlerBuilder(actor)); } /** * Create/register new channel into engine's context * * @return */ @Override public ChannelBuilder channel(String channelName) { ChannelBuilder b = new StandaloneChannelBuilder(); b.namedAs(channelName); channelBuilders.add(b); return b; } /** * Create reference to channel * * @param name * @return */ @Override public ChannelReference channelRef(String name) { return new NamedChannelReference(name); } /** * Create/register new inbound adapter into engine's context * * @return */ @Override public AdapterBuilder inboundAdapter() { AdapterBuilder b = new StandaloneAdapterBuilder(); return b; } /** * Create/register smart {@link SmartProxy proxy} which is more complex entity. * * @param name * name for smart proxy */ @Override public SmartProxyBuilder smartProxy(String name) { BaseSmartProxyBuilder b = new BaseSmartProxyBuilder(name, this); preBuilders.add(b); return b; } /** * builds {@link org.zdevra.sparrow.aggregator.AggregatorStrategy aggregator} * * @return aggregator builder */ @Override public AggregatorBuilder aggregator() { return new AggregatorBuilderImpl(); } /** * builds {@link org.zdevra.sparrow.splitter.SplitterStrategy splitter} * * @return aggregator builder */ @Override public SplitterBuilder splitter() { return new SplitterBuilderImpl(); } /** * Builds filter that can be used as actor * @return */ @Override public FilterBuilder filter() { return new FilterBuilder(); } /** * Builds filter-rule for {@code filter()} that filter message where condition is * header data * * @param header * @return */ @Override public HeaderFilterRuleBuilder header(String header) { return new HeaderFilterRuleBuilder(header); } /** * Builds filter-rule for {@code filter()} that filter message where condition is * payload data * * @return */ @Override public PayloadFilterRuleBuilder payload() { return new PayloadFilterRuleBuilder(); } @Override public FromDsl from(ChannelReference channel) { FromDslImpl fromBuilder = new FromDslImpl(); fromBuilder.setInputChannel(channel); return fromBuilder; } //------------------------------------------------------------------------------------------------------------------- // inner builders //------------------------------------------------------------------------------------------------------------------- /** * Implementation of {@link org.zdevra.sparrow.dsl.FromDsl} for standalone engine */ private class FromDslImpl extends FromDsl { @Override public ChainBuilder chain(String name) { ChainBuilder b = new ChainBuilder(this.inputChannelRef, name, AbstractSparrowEngine.this); preBuilders.add(b); return b; } @Override public ActorBuilder actor(ActorHandler actor) { ActorBuilder b = new StandaloneActorBuilder(new InstanceActorHandlerBuilder(actor), this.inputChannelRef); return b; } @Override public ActorBuilder actor(ActorHandlerBuilder actor) { ActorBuilder b = new StandaloneActorBuilder(actor, this.inputChannelRef); return b; } @Override public ActorBuilder actor(Class actor) { ActorBuilder b = new StandaloneActorBuilder(new ClassActorHandlerBuilder(actor), this.inputChannelRef); return b; } } /** * Implementation of {@link AdapterBuilder} for standalone engine */ private class StandaloneAdapterBuilder extends AbstractAdapterBuilder { @Override public void asInstance(InboundAdapter adapter) { adapter.setOutputName(this.outputName); AbstractSparrowEngine.this.units.add(adapter); } @Override public void asClass(Class adapterClass) { throw new UnsupportedOperationException("asClass is supported only for Guice"); } } /** * Implementation of {@link ActorBuilder} for standalone engine */ private class StandaloneActorBuilder extends AbstractActorBuilder { /** * Constructor * @param builder */ public StandaloneActorBuilder(ActorHandlerBuilder builder) { this(builder, null); } /** * Constructor */ public StandaloneActorBuilder(ActorHandlerBuilder builder, ChannelReference from) { super(builder); from(from); actorBuilders.add(this); } @Override public void build() { AbstractActor actor = new StandaloneActor(handlerBuilder.build(), this.mailbox, this.exceptionHandler, this.inputChannel, this.outputChannel); addActor(this.actorName, actor); } } /** * Implementation of {@link ChannelBuilder} for standalone engine */ private class StandaloneChannelBuilder extends AbstractChannelBuilder { /** * {@inheritDoc} */ @Override public final ChannelBuilder exposed() { throw new UnsupportedOperationException("asClass is supported only for Guice"); } /** * {@inheritDoc} */ @Override public ChannelBuilder asClass(Class channelClass) { try { MessageChannel channel = channelClass.newInstance(); asInstance(channel); } catch (InstantiationException e) { //todo: change the exception handling e.printStackTrace(); } catch (IllegalAccessException e) { //todo: change the exception handling e.printStackTrace(); } return this; } @Override public void build() { if (channelInstance == null) { channelInstance = new DirectChannel(); } if (channelInstance instanceof Nameable) { ((Nameable)channelInstance).setName(this.channelName); } AbstractSparrowEngine.this.channels.put(this.channelName, channelInstance); if (channelInstance instanceof SparrowLifecycle) { AbstractSparrowEngine.this.units.add((SparrowLifecycle) channelInstance); } } } //------------------------------------------------------------------------------------------------------------------- // private methods //------------------------------------------------------------------------------------------------------------------- private void addActor(String actorName, AbstractActor actor) { actor.setName(actorName); channels.put(actorName, actor); this.units.add(actor); } //------------------------------------------------------------------------------------------------------------------- // public methods //------------------------------------------------------------------------------------------------------------------- /** * {@inheritDoc} */ @Override public MessageChannel getMessageChannel(ChannelReference channelRef) { String channelName = channelRef.name(); MessageChannel channel = channels.get(channelName); return channel; } /** * {@inheritDoc} */ @Override public void start() { configure(); for (SparrowLifecycle unit : units) { unit.onInit(this); } for (SparrowLifecycle unit : units) { unit.onStart(); } } /** * {@inheritDoc} */ @Override public void shutdown() throws InterruptedException { for (SparrowLifecycle unit : units) { unit.onStop(); } } /** * Method does configuration of message system and build all his entities as channels, actors etc */ private void configure() { preBuilders = new LinkedList(); channelBuilders = new LinkedList(); actorBuilders = new LinkedList(); configureSparrow(); for (SparrowBuilder preBuilder : this.preBuilders) { preBuilder.build(); } for (ChannelBuilder channelBuilder : this.channelBuilders) { channelBuilder.build(); } for (SparrowBuilder actorBuilder : this.actorBuilders) { actorBuilder.build(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy