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/
