On 9/2/07, Brian McCallister <[EMAIL PROTECTED]> wrote:
> As I am wrapping up a project which uses Cameland Hiram asked me to
> send my feedback to the list so... :-)

Awesome - feedback == good!


> Firstly, Camel has proven really nice to work with for the most part.
> It simplified a much nastier first take on my project!

Great!


> So, to the details:
>
> * The async exchange stuff in trunk is pretty much required. I needed
> guaranteed delivery in-memory and wanted to just use the fie
> component, but the inability for it to handle async delivery was a
> deal breaker. I wound up writing a spool component, which was much
> like the file component except that it took urls of the form "spool:/
> var/baz/spool:store" and "spool:*:delete" and things were delivered
> to the "delete" variant when I wanted the file removed. Ugly, but it
> worked.

Yeah. Its nice to know you can easily workaround any missing pieces in
Camel; and hopefully these workarounds can make their way back into
the core so fewer and fewer users need workarounds etc...


> * Failure to convert a type should raise an exception, a clear type
> conversion exception which provides enough details to solve the
> problem.

Yeah; there's a JIRA for this one..
https://issues.apache.org/activemq/browse/CAMEL-84

the main reason I didn't just go a head and fix this one is wondering
where/when this exception should occur. e.g. currently the Type
Converter APIs under the covers don't throw a type conversion
exception; am wondering if we should add exceptions all the way
through? Or should we just add exceptions to the convertBody() style
APIs in the DSL?



> The conversions expected by the existing components need to
> be documented clearly on the components.

Definitely.

Also I really want a maven plugin to document the type conversions
supported natively by each maven module...
https://issues.apache.org/activemq/browse/CAMEL-11

i.e. so you can see visually what type conversions are available per jar.


> * Speaking of documentation, any method that is part of the fluent
> API really needs javadocs.

Agreed


> * So, as to what I did -- I defined a bunch of routes and created a
> number of components. Specifically I replaced the file and seda
> components, and created several "end" components which were the final
> destinations of messages in the system. I used the fluent API, and
> avoided the magic (see later point).
>
> * The use extensive of discovery magic is a bit troublesome. It is
> nice and all for the demo, but I want something which I can see how
> it works, and more importantly the next person to come along can
> understand without needing to know about the properties file which
> mentions the classes which are interpreted out by some strings
> somewhere else. This applies to both components and type conversion.

Yeah. In Camel we've tried to be Rails-ish, with convention over
configuration. So you only should have to describe what you want, not
necessarily write all the Java code or XML configuration file stuff to
make every single thing involved in what you want explicit.

So there's some magic; just like there is in Rails; if you wanna grok
that magic, its pretty straightforward to look into (and am sure we
can do a better job of visualising the magic - e.g. like above,
generating reports for type conversions, components etc).

However if you are magic-averse, you can just ignore that bit and wire
everything by hand. e.g. create whatever endpoints / components you
want and pop them into JNDI or a Spring ApplicationContext then let
Camel do wiring by names (rather like Spring/JNDI do anyway).

If you want you could avoid the implicit type conversion and just
invoke explicit bean method calls to do any conversions you want.

from("file://bar").beanRef("myBean", "myConversionMethod").to("blah")

So all magic can be avoided on the wiring of components/endpoints and
the type conversion methods if you want it to be?


> * Producer vs Consumer: The naming right now makes sense if you are
> implementing the routing system (or JMS as Hiram has pointed out to
> me). It does not make sense if you are implementing components. Users
> of Camel will likely implement components, and will almost surely not
> re-implement the routing system.

We've taken much of the naming conventions from the Enterprise
Integration Patterns themselves...
http://activemq.apache.org/camel/enterprise-integration-patterns.html

which given that they are message-centric, does map more closely to
messaging terminology such as used in JMS...

In Camel we support both Event Driven Consumer...
http://activemq.apache.org/camel/event-driven-consumer.html

and Polling Consumer
http://activemq.apache.org/camel/polling-consumer.html

which is where the 'Consumer' name came from. EIP doesn't much talk
about Producer; but that name is typically the opposite of Consumer :)

You could argue we should rename 'Consumer' to 'EventDrivenConsumer'
to be completely EIP naming precise.


> It is also the opposite of JBI,
> which implies it is the opposite of some WS standard thing that JBI
> is based on.

FWIW in JBI only JBI components can create and send exchanges to
components and then a component is-a consumer. So the producing and
consuming roles are kinda merged - and the main artifact - the
endpoint - is actually invisible in the JBI 1.0 API :).



> As it is also undocumented, this is triply painful.

It was documented a little in the EIP catalogue. I've just updated the
Developer docs
http://cwiki.apache.org/CAMEL/developers.html

in particular I added more detail to
http://cwiki.apache.org/CAMEL/writing-components.html

to hopefully explain more on the Producer / Consumer / PollingConsumer
front. Contributions always welcome though!


> So, looking to improve Camel:
>
> * Exception and dead letter channel handling needs to be clarified.
> This may just be a documentation issue, but even after exploring it
> in tests I am unsure of exact semantics.

Yeah.


> * Async exchange handling should always be assumed.

I'm not totally sure about this one. One of the reasons JBI is so
complex to work with is that it assumes all the hard stuff is always
the case. e.g. if you want to use transactions, being async is a major
nightmare. One of the major reasons why declarative transactions in
spring are so easy to use is that it assumes a single threaded,
synchronous programming model like servlets / EJB3 which simplifies
the developers job tremendously.



> * Thread semantics need to be cleaned up. I believe all built in
> components should be single-thread oriented (ie, only one message at
> a time coming out).

Isn't that conflicting with the previous async comment? :)

It all depends really; there's many different use cases, so its kinda
hard to be too sweeping. e.g. folks might want to use efficient,
parallel consumption of JMS messages with Camel; using Spring's JMS
MessageListenerContainers in the component/endpoints, which do pooling
and support concurrent message dispatch.

I would definitely agree that one of the responsibilities of a
component/endpoint is to clearly define its threading semantics so
users can understand the threading model; its just I can see different
users wanting different threading requirements.


> * Corollary -- the seda component should go away and be replaced with
> a thread pool policy. This should be done as a policy/interceptor as
> it is not an endpoint unto itself, it just controls how messages make
> their way between. Given:
>
>         from("file:foo").threadPool(10).to("wombat:nugget")
>           or
>         from("file:foo").threads(10).to("wombat:nugget")

FWIW you could do the same with URIs too...

from("file:foo").to("seda:mythreadpool?size=10").to("wombat:nugget")

i.e. use a URI to define named thread pools of different sizes &
configurations (min/max size etc)

Its worth noting too that some components need to deeply control
thread pools; e.g. the Spring based MessageListenerContainer stuff for
pooled JMS / JCA consuption, the thread pooling and the
endpoint/component are deeply entwined & its not that easy or useful
to separate the threading.

Though I agree it might be nice to enhance the DSL with threading
semantics; similarly we might want to be able to define pooling
semantics for processors/transformers when used in a highly concurrent
route.


>   The file component would push to a blocking queue which ten threads
> pull from and pass on to "wombat:nugget" This provides clear control
> over how threads are allocated and used to the developer -- a Good
> Thing(r).

Yeah - though the seda equivalent (assuming the seda component is
sufficiently documented) could also be just as clear I'd hope?


> More to say, but need to run and this email has been gathering for
> too long so will send it out incomplete.

Awesome stuff Brian! Keep it coming!

-- 
James
-------
http://macstrac.blogspot.com/

Reply via email to