The Macaroni framework provides two basic abstractions – an Event and a Pipe.

  • An event is a change in a software module that happens inside or outside your application, significant enough to be noted. An event may signify a problem or impending problem, an opportunity, a threshold, or a deviation. Anything that “happens” might be considered as an event.
  • A Pipe is kind of a stream to propagate events. At abstract, some components put events into a pipe and some components get events from that pipe. The pipe transports events between event generators and downstream subscribers.

The occurrence of an event in a pipe triggers the invocation of one or many pipe subscribers. Upon generation, the event is immediately disseminated to all interested parties (human or automated). The interested parties evaluate the event, and optionally take action.

Contents:

1 Consuming(receiving) events 2 Producing events 3 Pipe Filters 4 Managing Pipes 5 Macaroni with Spring IoC 6 Macaroni with JSF

top 1 Consuming(receiving) events

If a component acts as a consumer, it should subscribe a named pipe and it should as well have annotated methods to process events it wants to receive. Let us consider the simple example:

								
package org.az.macaroni.example1;


import org.az.macaroni.Event;
import org.az.macaroni.EventPipe;
import org.az.macaroni.OnEvent;
import org.az.macaroni.sync.SyncPipeFactory;


public class NewsReader {

    public NewsReader() {
        //subscribing the "News" pipe. 
        //If no such pipe exists, a new one created
        //Actually, in real life it's better not doing this in constructors.
        SyncPipeFactory.instance().getPipe("News").addSubscriber(this);
    }

    //this method is invoked if a 
    //EVENT_GOOD_NEWS event occurs in the "News" pipe 
    @OnEvent(EVENT_GOOD_NEWS)
    public void onGoodNews(Event e, EventPipe pipe) {
        System.out.println("good news!");
        System.out.println("got " + e + " via " + pipe);
    }

    //this method is invoked if a 
    //EVENT_GOOD_NEWS or EVENT_BAD_NEWS event occurs in the "News" pipe
    @OnEvent( { EVENT_GOOD_NEWS, EVENT_BAD_NEWS })
    public void onBadNews(EventPipe pipe, Object e) {
        System.out.println("got " + e + " via " + pipe);
    }

    //this method is invoked if any event occurs in the "News" pipe
    @OnEvent(OnEvent.ANY_TYPE)
    public void onAnyNews(EventPipe pipe, Object e) {
        System.out.println("got " + e + " via " + pipe);
    }
}

the source is available here

This means that the NewsReader class subscribes on the “ News” pipe and it’s method onGoodNews is about to process all the events of type EVENT_GOOD_NEWS . Event types are just long values – in the example above the constant is used.

It’s important that the signature of such methods should not obey any conventions. Any public method of your component might be annotated with @OnEvent. All you should notice is that all the parameters will get null or default values if the method called due to an event occurrence in the pipe.  However, if a method declares a parameter of type EventPipe or Event, they receive the corresponding values.

top 2 Producing events

Look at the example:

								
package org.az.macaroni.example1;


import org.az.macaroni.EventBuilder;
import org.az.macaroni.EventPipe;
import org.az.macaroni.EventUtils;
import org.az.macaroni.sync.SyncPipeFactory;


public class NewsMaker {

    public void doSomething() {
        EventPipe pipe = SyncPipeFactory.instance().getPipe("News");
        pipe.putEvent(EventBuilder.create(this, EVENT_GOOD_NEWS, "A text of a good news"));
    }

    //OR THIS WAY:

    public void doSomethingElse() {
        EventUtils.postSyncEvent("News", this, EVENT_BAD_NEWS, "A text of a bad news");
    }
}

the source is available here

This means, that every consumer subscribed on the pipe ”News” receives a new event from the NewsMaker. The event bears “A text of a .. news” as a value.

top 3 Pipe Filters

								
package org.az.macaroni;

public interface Filter {
    public Event before(EventPipe pipe, Event event);

    public Event after(EventPipe pipe, Event event);
}						
						

In the simpliest implementation you typically do the following:

								
private static Filter whitespaceRemover = new BasicFilter() {
    @Override
    public Event before(EventPipe pipe, Event event) {
        char c = Character.toUpperCase((char)event.getType());
        if (Character.isWhitespace(c))
            return null;
        return event;
    }
};

//.....

pipe.setFilter(whitespaceRemover);

3.1 Filter chains


FilterChain filterChain = new FilterChain();
//now adding filters to the chain:
filterChain.addLastFilter(filter1);
filterChain.addLastFilter(filter2);
filterChain.addLastFilter(filter3);
filterChain.addLastFilter(filter1);

//.....
	
pipe.setFilter(filterChain);

top 4 Managing Pipes

4.1 Pipe factories

Normally, you don't have to iplement the EventPipe interface and you don't have to intantiate pipes. Use pipe factories for creating and obtaining pipes .

EventPipe pipe = SyncPipeFactory.instance().getPipe("Pipe Name");
pipe.putEvent( ... );

TODO: list all known factories here

4.2 Pipe scopes

TODO: application

TODO: thread local

top 5 Macaroni with Spring IoC

If your application runs under the Spring IoC, you can find useful the features Macaroni provides in support of Spring framework.

5.1 Auto subscription

As it shown in previous examples, you have to call EventPipe.addSubscriber() method to enable your components to receive events. This actually means that you have to decide at which stage it is better to subscribe, besides, it means that your components depend on the Macaroni API. The things can be simpler with @PipeAware annotation.

@PipeAware( {"pipeName1", "pipeName2"} ) 

Macaroni will automatically subscribe all the beans annotated with @PipeAware to the pipes listed by the annotation.

Example:

@Component
@PipeAware(MAIL_PIPE_NAME)
public class MailReceiver {

    @OnEvent(EVENT_MAIL)
    public void processMail(Event e, EventPipe pipe) {
        //System.out.println(toString() + ":\t got mail:" + e.getValue());
        pipe.putEvent(
            EventBuilder.create(this, EVENT_MAIL_DELIVERED, "mail received"));
    }
}
							
							

To enable auto-subscription feature, it's enough to put the following line in your Spring application context configuration file:

<beans>
    ..
    <bean class="org.az.macaroni.spring.AutoSubscription" />
    ..
<beans>
                            

Every time a bean created in the Spring context, the AutoSubscription component examines whether the bean has the @PipeAware annotation. If it has, the Macaroni's AutoSubscription binds the newly created bean with the pipes listed in its annotation.

TODO: refer to the example prvided

top5.2 Injecting pipes

If you run under Spring, it could be useful to have your pipes injected into your components with Spring wiring mechanisms.

As you may notice, you cannot instantiate a pipe directly as you should use pipe factories. However, it might be desirable to have pipes under Spring IoC container. For that purpose, Macaroni framework provides the special pipe-wrapper class PipeBean.

The snippet bellow demonstrates a typical bean definition:

  
<bean id="my.app.systemEventPipe"
class="org.az.macaroni.spring.PipeBean">
<property name="pipeName">
<value>mmEventPipe</value>
</property>
</bean>

However, in the normal scenario you don't have to mess with pipe objects (EventPipe), you might only operate with pipe names and the factories.

 

top 6 Macaroni with JSF

TODO:

TODO: