Maybe you now have time to take a look at this. I have no idea if
attaching a PDF file works, but I'll just try!
I will also just paste it here but I have the feeling that the result
will look ugly but anyway, here goes...
*Multiple Configurations extension to Tapestry IoC*
_*Goal*_
Create services with the same implementation but with a different
configuration.
_*Description*_
With an annotation a service implementation can be assigned to a
configuration group. This group is represented by a /Class/. (Just like
markers.)
Tapestry Modules can contribute configuration markers (represented by a
/class/) to a configuration group. The configuration marker can also be
/null/.
If no markers are contributed, every service will be instantiated
without additional markers. If markers are contributed, every service
will be instantiated for each marker. If the /null/marker is
contributed, then there will also be a service without additional markers.
The different instantiated services will be automatically linked to
services within the same configuration group.
Configurations are contributed to a combination of service interface and
markers. For a given service, it will use the contributions to the
service /without the configuration marker/that has the
@MultipleConfigurations annotation, plus the contributions to the
service /with the configuration marker/.
_*Example*_
There are two services in the module ExampleModule, service One and Two,
with implementation OneImpl and TwoImpl. The OneImpl service has the
mark @Example to distinguish it from other services. OneImpl relies on
TwoImpl, which is a local implementation of a service that is also
implemented elsewhere.
Example code:
@Marker(Example.class) @ConfigurationGroup(ExampleGroup.class)
public class OneImpl implements One {
public OneImpl(@Local Two twoObject) {}
}
@ConfigurationGroup(ExampleGroup.class)
public class TwoImpl implements Two {
public TwoImpl() {}
}
@ContributeConfigurationMarker(ExampleGroup.class)
public static final void blablabla(Configuration<Class> cfg) {
cfg.add(...);
}
_Case 1: no markers_
If no markers are contributed, there will be two services, OneImpl with
marker @Example and TwoImpl.
_Case 2: markers @Red and @Blue_
In this case, there will be four services. OneImpl with markers @Example
and @Red, which uses TwoImpl with marker @Red; OneImpl with markers
@Example and @Blue, which uses TwoImpl with marker @Blue.
_Case 3: markers @Red and null_
In this case there will also be four services. OneImpl with markers
@Example and @Red, which uses TwoImpl with marker @Red; OneImpl with
marker @Example, which uses TwoImpl without markers.
_Configuration example_
For case 3, there may be three contributions:
@Contribution(One.class) @Marker({Red.class})
public static void firstContribution() ...
@Contribution(One.class)
public static void secondContribution() …
@Contribution(One.class) @MultipleConfigurations
public static void thirdContribution() …
In this example, the service with marker @Red will receive the first and
the third contributions. The service without markers will receive the
first and the second contributions.
_*Extra features*_
It is sometimes necessary to know the different configurations and
markers. One example is when contributing an object provider that has to
provide a different object for every configuration. It is also possible
to query the Registry for this information. Because this cannot be done
in the startup phase, the contributed markers can also be injected.
We define two additional resources:
*
a Class with the @ConfigurationGroup annotation will at runtime hold
the marker of this service or /null/ if it has none.
*
A Set or Collection with the @ConfigurationGroup annotation will
hold all contributed markers, including /null/ if it has been
contributed.
_*Naming*_
The names are not fixed yet so they are up to debate and preference.
*
the terms “configuration group” and “configuration marker”
*
the annotation @ConfigurationGroup
*
the annotation @MultipleConfigurations for contributions to all
services in the same group
*
the annotation @ContributeConfigurationMarker for contributions to
configuration groups
*
the injection marker @ConfigurationGroup
Op 19-7-2011 18:34, Thiago H. de Paula Figueiredo schreef:
Hi!
Unfortunately, currently I don't have to take a deep look and what
you're doing, but from reading its description, it seems something
that would be of great worth for Tapestry-IoC. Please keep up the good
work. ;)
On Mon, 18 Jul 2011 18:25:21 -0300, Tom van Dijk <[email protected]> wrote:
I thought it would be a good idea to explain this part again:
The extension is simple: it allows reusing existing (in-use) service
implementation, with a different marker. We can identify groups of
services that are tightly related and that all need to be properly
wired to eachother. They can be called "configuration groups"...
maybe someone has a better name, feel free to suggest one. With the
idea in mind that we would prefer to identify services using just
the interface they implement and additional markers, this is the
perfect way to get multiple services with the same implementation
and a different configuration.
The trick is that it might be useful to somehow reuse implementations
with a different configuration.
So how could we do it? We can't just create another instance of the
implementation and pray it goes well. There can be various reasons
why this would not work, for example, the service may use other
services and set their state depending on the configuration. If for
some reason the developer uses static fields, things would screw up.
There may be other reasons for failure. However, if developers would
annotate suitable classes, that actually can be instantiated for
multiple configurations, that would 'guarantee' that no such problems
exist. After all, these developers are then responsible for making
sure there are no strange effects and everything is neat and tidy.
Now, in the case where a service uses other closely related services
in a particular way, it is likely to be a good practice to create
multiple instances of these services as well. Also, some modules
(like the hibernate module) can provide objects and these should be
provided for every instantiation too.
For simplicity, we could assume that the instantiation is done by
means of contributing to the configuration group. For backward
compatibility, there is "default behavior" if no contributions are
done: just the normal behavior, as if there were no configuration group.
So what do we do with the hibernate and hibernate-core module? It
boils down to annotating the classes with a simple syntax, and then
making sure everything that used to be implemented well for the
single-configuration case, still works afterwards AND still works in
a multiple-configuration situation. I have done this for hibernate
and hibernate-core and the concept works.
Tom.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]