You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Howard Lewis Ship <hl...@gmail.com> on 2007/05/18 20:15:18 UTC

Re: tapestry-ioc remarks and questions

On 5/9/07, Ognen Ivanovski <og...@netcetera.com.mk> wrote:
>
> Hi there!
>
> I'm very impatient to get my hands on tapestry 5, especially the IUC
> container. I really like the major points there. However, some remarks:
>
> 1. having the IOC container recognize the builder/contributor methods
> by method name is cool, but it might be confusing for someone that
> has a first time look. I noticed that you've removed the @Contribute
> and @Id annotations to support that. Perhaps they should be left as
> optional. Some people might like the extra verbosity for
> documentation purposes.



The verbosity of the method names is sufficient, I think.


2. Contributions are great (myself a long time Eclipse-RCP developer,
> *really* like the idea, especially combined with module autoloading).
> Is there a possibility to have a tree-like configuration for
> services? Let's say a site-map service (or a UI-menu service)
> collects various important links from contributed modules and
> displays them in a navigation UI component. The contributors could
> like some fine grained control about where these links appear (in/
> before/after something?). Of course this can be modeled like in
> Eclipse (with path-like strings) or with lists of lists (which would
> be too coarse), but still...



Or with additional services to represent the sub nodes.  I'm not sure what a
tree-like contribution would look like.  The contributions don't have to be
the raw data nodes; they could be objects that *build* the ultimate tree. So
the contribution could be a [path, value] tuple, combined with the logic to,
when passed the Tree, navigate to the right node and set the value.  That's
the advantage of contributing real Java objects rather than dumb XML data
... it doesn't have to be just setters and getters.  Alternately, dumb data,
but the service does the tree building from the [path, value] tuples inside
its constructor.

3. AFAIK, injections can be performed only on services built/
> controlled by modules. On the other hand I've seen that tapestry
> components can be injected with services based on the @Inject/
> @InjectService annotations on members (probably via the tapestry
> class loader). Can/How this be used on domain objects?


This is possible because such objects are only created by Tapestry, and the
magic with the fields is due to some complex bytecode AOP going on, inside
Tapestry. This is OK for Tapestry because the classes being enhanced (or,
perhaps "mangled" would be a better adjective) have a very specific purpose.
Domain objects are not so contrained.

The general pattern is to define a domain object Factory, within the IoC
container.  The Factory is injected with the service dependencies, and can
pass those along to domain objects created by the factory.  You can see some
examples of this with Assets and the AssetFactory, inside Tapestry.

Spring has the ability, based on AspectJ, to perform this kind of injection
(directly into domain objects). Ultimately, it comes down, I believe, to a
static and/or thread local that stores the Spring BeanContext plus an Aspect
that leverages the BeanContext to do the injection.  (This isn't based on
any real research, so I suspect the real implementation differs).  Anyway, I
think AspectJ is cool, but not good for everyone, and not something average
users should ever see, which is why Tapestry 5 is the way it is (home grown
AOP that is focus on Tapestry's needs, rather than generic requirements).


In my experience I've done a considerable amount of advisor web
> applications. These are basically wizard-like apps where you start an
> advising session, go through the wizard steps, fill some data,
> possibly go back to a previous step and change something and at the
> end display advice or calculations.
>
> I usually like to have a nice domain model that sits in the HTTP
> session throughout the wizard's life cycle which I feed with the data
> and ask for the advice / calculations. These domain objects often
> need to access some internal/external service to perform some
> calculation or get some reference data.
>
> Ideally these services should be injected. I can address this by
> creating the domain model from a IOC controlled service and pass
> along the external services from there.
>
> The problem occurs when this model gets serialized (along with the
> http session) or persisted to a RDBMS: when deserializing/restoring
> from db I have no control over the object's creation (and cannot re-
> inject the services back).
>
> So my current idea is to use your class loader trick (or an aspect)
> to do this. The question is, how easy is this with the tapestry-ioc
> or (eventually the classloader)?


Right now I'm targeting Spring Web Flow to supply this kind of behavior. Its
mature, well supported and seems like it will be a good fit. My current plan
is to have a special @Flow annotation for variables that are, in fact,
defined and manipulated within the Flow.


4. More service scopes (e.g. http-session scope)? Also defining your
> own scopes and scope control (think spring 2.0). Is this on the roadmap?


This is already possible, there's a service configuration for this purpose.
I'm not sure of the value of storing a service inside the Session, when you
can instead inject the Session and store data there.  It also raises some
other issues, such as the fact that IoC service implementations are likely
not serializable, and dynamically-generated proxies (to other services) are
very much not serializable.  HiveMind had a solution to this, but due to
limitations of the Servlet API, I was never satisfied.


5. Autobuilding: I really prefer the module builder. Reason:
> decoupling implementation classes from the IOC container. If the
> service class is not annotated with tapestry-ioc annotations I can
> freely use it in another ioc without even the need to recompile (the
> module class never gets loaded). This is not the case with an
> autobuilt service that contains tapestry-ioc annotations (ok, not
> entirely true, but I will need to have tapestry-ioc as a dependency
> just for the annotations.



But you have the choice. In most cases, you just establish a linkage between
an interface and an implementation class and IoC determines the correct
constructor and parameters. I don't go as far a Guice (which can annotate
the interface with the implementation class, and which will invoke other
methods, not just the constructor, to establish depenencies).

When Tapestry can't determine the right values, you either annotate the
parameters of the constructor, or define the service using a service builder
method.


Well, that's all (for now). :)
>
> Cheers,
> Ognen
> --
> Meet us at Jazoon'07: 24 - 28 June - http://jazoon.com
>
> Ognen Ivanovski | ognen.ivanovski@netcetera.com.mk
> phone +389 -2- 30 64 532 | fax +389 -2- 30 79 495
> Netcetera | 1000 Skopje | Macedonia | http://netcetera.com.mk
>
>
>


-- 
Howard M. Lewis Ship
TWD Consulting, Inc.
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Apache HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com