My brain is now overloaded.

On Thu, Oct 28, 2010 at 7:33 AM, Tom van Dijk <[email protected]> wrote:
> Hi,
>
> I'm discovering some interesting implications of dynamic services.
>
> In hibernate-core, building dynamic services causes at least two services to
> be realized.
>
> Let us assume that dynamic services are created based upon a contribution to
> a service.
> For example, dynamic services of hibernate-core are created based upon
> contributions to the service HibernateMarkerConfiguration. This service is
> injected into the dynamic contributor method (parameter injection)
> The use of a HibernateMarkerConfiguration service could be considered
> bending the semantics of a "service" a bit, since the service doesn't do
> anything apart from providing the markers.
> However, there really is only one way right now to contribute the markers,
> and that's by contributing them to a service.
>
> The real "problem", however, is not that I'm using a service.
>
> The real problem is that in order to realize the
> HibernateMarkerConfiguration service, other services have to be realized as
> well, in particular the MasterObjectProvider and ServiceOverride. This means
> that after the collectDynamicServices() and collectDynamicContributions()
> steps, no dynamic contributions can be done to MasterObjectProvider and
> ServiceOverride. Worse, if your contributions to ServiceOverride depend on
> HibernateMarkerConfiguration or something like that, there is a recursion
> error. Obviously, there's addInstance() to deal with this, but this will not
> solve the problem that no new contributions can be done by dynamic services.
> In our case it's even worse, since we have a static contribution to
> ServiceOverride which depends on HibernateMarkerConfiguration to figure out
> whether there are any markers. Voila, recursion. (See appendix below)
>
> The idea is that dynamic service contributors could use injected parameters
> for their building, to increase expressivity.
>
> The implication of this is that a combination of modules can cause errors,
> while each individual module works fine. Maybe module X depends on service S
> to dynamically create classes, and module Y wants to add (dynamic)
> contributions to service S. Independently, these modules can be in the
> registry, but their combination will fail, because the service is realized
> before the dynamic contribution is done. ((Note: in my current
> implementation, this won't even be noticed by the Registry, because there is
> no checking whether dynamic contributions are done to realized services))
>
> Fill in for X, Hibernate-core, for Y, Hibernate, and for S the
> ServiceOverride service (Where ServiceOverride elementOf dependencies(X),
> due to the injection of HibernateMarkerConfiguration depending on
> MasterObjectProvider to be realized which depends on ServiceOverride to be
> realized) and we nearly have our case**. It would even be a problem if X and
> Y are equal.
>
> There are several ways to cope with the issue.
>
>
>
> POSSIBLE SOLUTION 1
> A. Allow updating the configuration of services. Several possible strategies
> include: rebuilding the service when the configuration is updated; calling
> an updateConfiguration() method in the implementation class. Note that
> updating the configuration always means adding a new configuration entry.
> B. Generate an error when there is a dynamic contribution to a service that
> has already been realized and that is not update-able according to A.
> C. Allow injection of objects into Dynamic Service Contributors and Dynamic
> Contribution Contributors.
>
> This does not mean every service must be modified to allow
> rebuilding/updateConfiguration() calls. By default, services can be "not
> update-able". Then, whenever users have clashes, we could modify services to
> be update-able. For example, MasterObjectProvider and ServiceOverride could
> possibly be made update-able. We need to design the syntax for this update
> idea, possibly defining a new annotation to services or service
> implementations ("@Updateable", with an enum Updating.PROHIBIT,
> Updating.REBUILD, Updating.METHOD; in the last case exactly one public
> method in the implementation must have the @ConfigurationUpdate annotation
> OR be named updateConfiguration)
>
>
>
> POSSIBLE SOLUTION 2
> No injection of objects into Dynamic Service Contributors and Dynamic
> Contribution Contributors. A different mechanic must be found to contribute
> to dynamic services/contributions. Perhaps Dynamic Services/Contributions
> could be identified using a "Dynamic id" (which can be shared by different
> dynamic contributors) and which other classes can contribute to.
> This will severly limit the options for dynamic service/contribution
> contributions, as they may not have injected services (or something like the
> ObjectLocator) as parameters.
> This means no services will be realized during the dynamic part.
> This will not mean that a HibernateMarkerConfiguration service will not
> exist; it will still exist because there could be static services that may
> want to know which database configurations there are (e.g. HibernateUtil in
> my solution).
>
>
>
> With solution 1, this might mean more work and maintenance of existing
> services, although good test cases for every modified service will make this
> process much smoother.
> With solution 2, this might severely limit the options for dynamic services.
>
>
> The use case of our multiple database problem can be generalized to the
> problem of services with multiple configurations. Essentially that's what we
> have here: 6 services (hibernate-core) that have N configurations (e.g. Red
> and Blue in the appendix).
>
> Perhaps there are other use cases that need to be considered in the context
> of dynamic services/contributions. An example of this is Spring integration,
> which I have not looked into yet. (One problem there is that discovery of
> spring objects relies on the ServletContext object, which set in the
> application globals by tapestry-core during startup... but perhaps core
> could be modified to contribute the ServletContext object in some other way,
> so it can be discovered by a dynamic solution - until that is solved,
> tapestry-spring has to use a TapestyFilter subclass).
>
>
>
>
> POSSIBLE SOLUTION 3
>
> Alternatively, instead of this dynamic service jungle, we could consider
> only solving the "services with multiple configurations" problem by using a
> @MultipleConfigurations("MCid") annotation.
> Modules could statically contribute to a MCid using some syntax.
> (@ContributeMultipleConfiguration("MCid") Class[] contributeMarkers() {
> return new Class[] {Red.class, Blue.class} })
> If placed on a builder, this means "for every contributed marker, generate a
> service with additional marker; if no markers contributed, generate a
> service without additional markers;" and the marker (or null if no markers
> defined anywhere) would be injected into the build method.
> If placed on a contributor, this means exactly the same.
> Alternatively, contributors may also have the parameter
> ("MultipleConfiguration") (with subclasses MultipleMappedConfiguration,
> MultipleOrderedConfiguration....) which exposes the Class[] array of
> markers.
>
> We would have to consider what to do with the case where no markers are
> contributed to a MultipleConfiguration. In the solution I just described, it
> would fall back to generating a single service. However, maybe one would
> always want to create the "no markers" service, using ServiceOverride to set
> the default service implementation to the "null" service.... e.g. with
> multiple database, if {Red,Blue} are contributed, create Session, @Red
> SessionRed and @Blue SessionBlue; if no markers are defined, use Session.
> (My current implementation is: if {} is contributed, create Session; if
> {A,B,C...} is contributed, create @A SessionA, @B SessionB, @C SessionC,
> ...)
>
>
>
>
> TLDR;
> collecting dynamic services/contributions cause services to be realized,
> causing problems with contributions, as well as causing recursion.
> solution 1: allow services to be updated when there are new contributions
> solution 2: use a different mechanism to contribute configuration to dynamic
> service contributors and do not allow services to be realized during
> collection
> solution 3: do not allow dynamic services, instead create a syntax for the
> "services with multiple configurations" concept
>
>
> I would love feedback. Can't make all the decisions on my own, I'm too
> inexperienced for that.
> Also, there may be even more things I've overlooked. Please let me know if
> there are more issues.
>
> Tom.
>
>
>
> ** I say nearly, because my current implementation has
> HibernateMarkerConfiguration injected into contributeServiceOverride, which
> obviously won't work. I could modify this to create a dynamiccontribution,
> contributing to Service Override. In this case, the contribution will be
> lost.
>
>
> Appendix:
> Registry changes by dynamics
>                   AspectDecorator : DEFINED => VIRTUAL
>      HibernateMarkerConfiguration : DEFINED => REAL
>              MasterObjectProvider : DEFINED => REAL
>                   ServiceOverride : DEFINED => REAL
>                      SymbolSource : DEFINED => VIRTUAL
>                       TypeCoercer : DEFINED => VIRTUAL
>    DefaultHibernateConfigurerBlue :         => DEFINED
>     DefaultHibernateConfigurerRed :         => DEFINED
> HibernateEntityPackageManagerBlue :         => DEFINED
>  HibernateEntityPackageManagerRed :         => DEFINED
>       HibernateSessionManagerBlue :         => DEFINED
>        HibernateSessionManagerRed :         => DEFINED
>        HibernateSessionSourceBlue :         => DEFINED
>         HibernateSessionSourceRed :         => DEFINED
> PackageNameHibernateConfigurerBlue :         => DEFINED
> PackageNameHibernateConfigurerRed :         => DEFINED
>                     SessionBlue :         => DEFINED
>                      SessionRed :         => DEFINED
>
>
>
>
>
>
> Op 27-10-2010 2:15, Tom van Dijk schreef:
>>
>> For your pleasure, I implemented the "abstract class" alternative, as a
>> different branch.
>>
>>
>> There are now a number of branches on my git
>>
>>             trunk
>>               |
>>            fix1326 (fixes TAP5-1326)
>>               |
>> [2 commits without a branch] (fixes TAP5-1321 and TAP5-1320)
>>    /                 \
>>   /                   \
>> iocmod2               iocmod3     (fixes TAP5-1313, dynamic services)
>>   |                    |
>> [commit]              [commit]
>>   |                    |
>> hibmod2               hibmod3     (fixes TAP5-48, multiple databases)
>>
>> the "2" branch uses annotated services
>> the "3" branch uses the abstract class
>>
>> Maybe I should learn to "tag" instead of making a load of branches :)
>>
>> 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]
>
>



-- 
Howard M. Lewis Ship

Creator of Apache Tapestry

The source for Tapestry training, mentoring and support. Contact me to
learn how I can get you up and productive in Tapestry fast!

(971) 678-5210
http://howardlewisship.com

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to