On 8/9/07, Neil Thorne <[EMAIL PROTECTED]> wrote: > > Awesome stuff James.
Thanks for all the great feedback! :) > The idea of aspect oriented routes is very nice. Agreed! > In our current use cases we can classify the results of a endpoint delivery > into a few types. > > Success, exception1, exception2. > > The actions taking place on these exceptions are common. I can imagine others having that kinda scenario too. e.g. doing standard things with XML parsing errors/validation errors on messages etc. > We're found that we can classify our endpoint components according to a QoS > type of > > For idempotent endpoints > > intercept(error(SystemException.class)).maximumRedeliveries(-1) > > for "never retry - we need to manually intervene first" > > intercept(error(BusinessException.class)).to("jms:errors") > > how can we register these interceptors across multiple routes? So the nice thing is, stuff thats registered outside of a specific route, is shared by all of the routes defined by that RouteBuilder. So if you do all your interceptors/error handlers up front, before you define any routes - the error handlers / interceptors are shared on all routes. If you want to customize this; you can overload the error handler later on for other routes. Or its probably easier to just write another RouteBuilder maybe? > intercept(error(BusinessException.class)).to("jms:business.errors"); > intercept(error(SystemException.class)).maximumRedeliveries(-1); > intercept(error(*)).to("jms:uncaught.errors");//not sure how to specify a > catch all here > from("jms:bus").to("jms:dateservice").to("jms:paymentservice").to("jms.responseservice"); > > Read as: > > along the route bus->dateservice->paymentservice->responseservice > > if at any time a BusinessException occurs terminate the originating route > flow and redirect to business.errors. > if at any time a SystemException occurs retry until you can proceed > if at any time any other exception occurs redirect to uncaught.errors > > In our use case the payment service is a "retry when its a system exception > type", and a "never retry if it's a BusinessException type". > Both of the other services are idempotent and will always throw > SystemExceptions or potentially uncaught exceptions. > > Your new AOP concept should handle this nicely. We've got a clean route, and > the error handling aspect is nicely separated. > > Endpoints can be categorized in a few different ways in our app. > > * by the exeptions they throw > * by the retry policies (which can differ based on some exception type) > * by the kind of data they expect in and out (Message Translation) > > We also do some common message translation too. > > You've already talked about some kind of registry. What about a registry of > MessageTranslators registered by to and from types. BTW have you seen the registry of type converters? http://activemq.apache.org/camel/type-converter.html which is great at converting the body or a header into a well defined type you expect. It works great for different Classes (e.g. if you had a POJO representation of a business object, then wanted to turn it into a String or DOM or whatever). It doesn't work too well on more general-formatting/translation issues though. e.g. what if you have a number of different ways of marshalling a POJO to a stream; the existing type converter mechanism isn't quite ideal for that. So maybe we need a way to just define a registry of transformers maybe? Which could have a route to define exactly how they work (so they are kinda their own route?). > Eg. I could have a route defined as > > from("jms:bus").translate(from("canonical").into("component").andBack()). > to("jms:dateservice"); > from("jms:dateservice").translate(from("canonical").into("component").andBack()). > to("jms:paymentservice"); > from("jms:paymentservice").translate(from("canonical").into("component").andBack()). > to("jms:responseservice") > > If all of these are the same then I can use AOP style: > //leave out the jms:bus endpoint > intercept(except(endpoints("jms:bus")).translate(from("canonical").into("component").andBack()); > from("jms:bus").to("jms:dateservice").to("jms:paymentservice").to("jms.responseservice"); > > that means all of my endpoints have message translation to and from the > canonical format into component format along the route. Interesting idea. BTW what does ".andBack()" mean? Also "canonical" and "component" are just named formats right? So you could configure some route/translation that goes from A, B or C to X etc. > I can then easily change one translation for a new component: > > intercept(endpoints("jms:dateservice", > "jms:responseservice")).translate(from("canonical").into("component").andBack()); > intercept(endpoints("jms:paymentservice").translate(from("canonical").into("componentNew").andBack()); > from("jms:bus").to("jms:dateservice").to("jms:paymentservice").to("jms.responseservice"); > > We'd then just need to register the translators somewhere > > translate(from("component").to("canonical").andBack().with(componentToCanonicalMessageTranslator))); > translate(from("componentNew").to("canonical").andBack().with(componentNewToCanonicalMessageTranslator))); Interesting; its been one of those things on my list of things to ponder about, how to register custom translators easily etc. > intercept(endpoints("jms:dateservice", > "jms:responseservice")).translate(from("canonical").into("component").andBack()); > intercept(endpoints("jms:paymentservice").translate(from("canonical").into("componentNew").andBack()); > > from("jms:bus").to("jms:dateservice").to("jms:paymentservice").to("jms.responseservice"); > > the translator could be given access to the appropriate part of the exchange > body by the framework. > > hopefully some of this makes sense. Yes! Nice work. Still mulling over the translator stuff; I'll post more when I've had time to digest more fully -- James ------- http://macstrac.blogspot.com/