You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@camel.apache.org by Claus Ibsen <cl...@gmail.com> on 2009/05/12 10:20:47 UTC

[DISCUSS - Camel 2.0]- Synchronization (UnitOfWork callbacks) and needed syntax DSL sugar

Hi

Now that the we had an internal API cleanup and the new Async API in place.
I thought I will take a look at the UnitOfWork and its synchronization hooks.

About synchronization
=================
org.apache.camel.spi.Synchronization is an interface defining 2
methods for callbacks when an Exchange is done.
- 1 callback for complete
- 1 callback for failure

This is really great and nice. What end users and Camel internally
actually need.

What you can do with this is for instance as some end users have
requirements for is to be able to send an email in case something goes
wrong.
Or log when a processing of the message is complete / finished etc.

Today you can do this with error handling and eg route to an additonal
endpoint when the route is at its end.
But what we would like is nice DSL syntax for this and the feature
implemented in a single logical execution wihtin Camel itself.

Some of the basis idea for the UnitOfWork constitutes this. That is a
context that abstracts the work an exchange undertakes during routing.
UnitOfWork is already integrated with  the Synchronization API and
thus it invokes the callback if any is registered.

But to use it today you need to access and register the callbacks on
the Exchange and thus you usually need a Processor and do the wiring
in Java code.
The code is not clean and nice so what is needed is some syntax sugar in the DSL

Syntax Sugar in DSL
===============
I have started experimenting with new DSL for registering callbacks.
But I am in doubt of naming and such.

For example I have:

        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                Processor complete = new Processor() {
                    public void process(Exchange exchange) throws Exception {
                        assertEquals("Bye World",
exchange.getIn().getBody(String.class));
                        SynchronizeTest.this.complete = true;
                    }
                };

                from("direct:start")
                    .synchronize(complete)
                    .transform(constant("Bye World"))
                    .to("mock:result");
            }
        };

This was just a quick prototype to allow to register a Processor with
the completion callback. Notice that we use the .synchronize DSL
keyword.

I am wondering what good names would be
- synchronize
- onComplete
- onFailure
- onDone (eg for a single DSL keyword for both complete/failure)

For instance with onComplete:
                from("direct:start")
                    .onComplete(complete)
                    .transform(constant("Bye World"))
                    .to("mock:result");

Not just a processor
===============
The processor thingy was just an experiment the idea is to be able to
route, eg to a bean for POJO, log for logging, smtp for email etc.

For instance something like this:
                from("direct:start")
                    .onFailure()

.to("log:damn?level=WARN").to("smtp://noone@somemailserver?subject=Damn&to=damn@damn.org")
                    // end to indicate end of onFailure route
                    .end()
                    // this is the original route that we route to
after from direct:start
                    .transform(constant("Bye World"))
                    .to("mock:result");

And it should be a route by itself just like the intercept() so you
can route it to multiple destinations and do other work as you like.

And we could consider having scope as well. So you can define
synchronization hooks at global level, so they apply for all.


Any thoughts?


-- 
Claus Ibsen
Apache Camel Committer

Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus
Apache Camel Reference Card:
http://refcardz.dzone.com/refcardz/enterprise-integration
Interview with me:
http://architects.dzone.com/articles/interview-claus-ibsen-about?mz=7893-progress

Re: [DISCUSS - Camel 2.0]- Synchronization (UnitOfWork callbacks) and needed syntax DSL sugar

Posted by Claus Ibsen <cl...@gmail.com>.
Hi

I have just committed the first cut to trunk.

I decided that onCompletion was a better DSL keyword than synchronize.

I have added a wiki page that shows how to use it and some background on it:
http://cwiki.apache.org/confluence/display/CAMEL/OnCompletion



Any thoughts?


-- 
Claus Ibsen
Apache Camel Committer

Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus
Apache Camel Reference Card:
http://refcardz.dzone.com/refcardz/enterprise-integration
Interview with me:
http://architects.dzone.com/articles/interview-claus-ibsen-about?mz=7893-progress

Re: [DISCUSS - Camel 2.0]- Synchronization (UnitOfWork callbacks) and needed syntax DSL sugar

Posted by Claus Ibsen <cl...@gmail.com>.
Hi

Update on this one. I gotta the internals sorted now and bumped into
some issues with Block but gotta that figured out as well.

Here is a snippet from an unit test.
                // START SNIPPET: e1
                from("direct:start")
                    .synchronize()
                        // this route is only invoked when the
original route is complete as a kind
                        // of completion callback
                        .to("log:sync")
                        .to("mock:sync")
                    // must use end to denote the end of the synchronize route
                    .end()
                    // here the original route contiues
                    .process(new MyProcessor())
                    .to("mock:result");
                // END SNIPPET: e1

Here you can see the synchronize sub-route that is executed when the
Exchange is complete.
You can qualify the synchronize to only run on either complete /
failure by adding
.onComplete() or .onFailure() to the DSL

for instance:
                    .synchronize().onFailure()

The Exchange that is routed in the synchronize route is a copy of the
original with its own UnitOfWork.
It does not use the same UnitOfWork as the original as its done. Its
also processed in another thread than the original
to not hold it up = its like a wiretap.

And finally if the original exchange failed with an exception, the
exception on the synchronize route is cleared as otherwise Camel
thinks the subroute is failed also. The original caused exception can
be fetched as a exchange property with the key
Exchange#EXCEPTION_CAUGHT.


I have kept the synchronize DSL for now as it was the API name. Do
anyone have a different / better name?
Is it clear what it means?


Any thoughts?


On Tue, May 12, 2009 at 10:20 AM, Claus Ibsen <cl...@gmail.com> wrote:
> Hi
>
> Now that the we had an internal API cleanup and the new Async API in place.
> I thought I will take a look at the UnitOfWork and its synchronization hooks.
>
> About synchronization
> =================
> org.apache.camel.spi.Synchronization is an interface defining 2
> methods for callbacks when an Exchange is done.
> - 1 callback for complete
> - 1 callback for failure
>
> This is really great and nice. What end users and Camel internally
> actually need.
>
> What you can do with this is for instance as some end users have
> requirements for is to be able to send an email in case something goes
> wrong.
> Or log when a processing of the message is complete / finished etc.
>
> Today you can do this with error handling and eg route to an additonal
> endpoint when the route is at its end.
> But what we would like is nice DSL syntax for this and the feature
> implemented in a single logical execution wihtin Camel itself.
>
> Some of the basis idea for the UnitOfWork constitutes this. That is a
> context that abstracts the work an exchange undertakes during routing.
> UnitOfWork is already integrated with  the Synchronization API and
> thus it invokes the callback if any is registered.
>
> But to use it today you need to access and register the callbacks on
> the Exchange and thus you usually need a Processor and do the wiring
> in Java code.
> The code is not clean and nice so what is needed is some syntax sugar in the DSL
>
> Syntax Sugar in DSL
> ===============
> I have started experimenting with new DSL for registering callbacks.
> But I am in doubt of naming and such.
>
> For example I have:
>
>        return new RouteBuilder() {
>            @Override
>            public void configure() throws Exception {
>                Processor complete = new Processor() {
>                    public void process(Exchange exchange) throws Exception {
>                        assertEquals("Bye World",
> exchange.getIn().getBody(String.class));
>                        SynchronizeTest.this.complete = true;
>                    }
>                };
>
>                from("direct:start")
>                    .synchronize(complete)
>                    .transform(constant("Bye World"))
>                    .to("mock:result");
>            }
>        };
>
> This was just a quick prototype to allow to register a Processor with
> the completion callback. Notice that we use the .synchronize DSL
> keyword.
>
> I am wondering what good names would be
> - synchronize
> - onComplete
> - onFailure
> - onDone (eg for a single DSL keyword for both complete/failure)
>
> For instance with onComplete:
>                from("direct:start")
>                    .onComplete(complete)
>                    .transform(constant("Bye World"))
>                    .to("mock:result");
>
> Not just a processor
> ===============
> The processor thingy was just an experiment the idea is to be able to
> route, eg to a bean for POJO, log for logging, smtp for email etc.
>
> For instance something like this:
>                from("direct:start")
>                    .onFailure()
>
> .to("log:damn?level=WARN").to("smtp://noone@somemailserver?subject=Damn&to=damn@damn.org")
>                    // end to indicate end of onFailure route
>                    .end()
>                    // this is the original route that we route to
> after from direct:start
>                    .transform(constant("Bye World"))
>                    .to("mock:result");
>
> And it should be a route by itself just like the intercept() so you
> can route it to multiple destinations and do other work as you like.
>
> And we could consider having scope as well. So you can define
> synchronization hooks at global level, so they apply for all.
>
>
> Any thoughts?
>
>
> --
> Claus Ibsen
> Apache Camel Committer
>
> Open Source Integration: http://fusesource.com
> Blog: http://davsclaus.blogspot.com/
> Twitter: http://twitter.com/davsclaus
> Apache Camel Reference Card:
> http://refcardz.dzone.com/refcardz/enterprise-integration
> Interview with me:
> http://architects.dzone.com/articles/interview-claus-ibsen-about?mz=7893-progress
>



-- 
Claus Ibsen
Apache Camel Committer

Open Source Integration: http://fusesource.com
Blog: http://davsclaus.blogspot.com/
Twitter: http://twitter.com/davsclaus
Apache Camel Reference Card:
http://refcardz.dzone.com/refcardz/enterprise-integration
Interview with me:
http://architects.dzone.com/articles/interview-claus-ibsen-about?mz=7893-progress