tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Josh Canfield <joshcanfi...@gmail.com>
Subject Injection calculation is difficult when building a service advisor
Date Thu, 03 Feb 2011 01:48:17 GMT
I started writing a long winded description of my problem, but let's
start with the gist and then get into the details and finally a
solution.

The gist:
I struggled for too long to figure out how to build a service advisor
that uses services, and is a service. Not due to recursion into my own
advisor, but due to recursion generated by the MasterObjectProvider
when it attempts to construct it's various ObjectProvider instances.

The details:

One form of the error:
[ERROR] Registry [ 1] Resolving object of type
org.apache.tapestry5.services.ApplicationGlobals using
MasterObjectProvider
[ERROR] Registry [ 2] Realizing service AssetObjectProvider
[ERROR] Registry [ 3] Invoking
org.apache.tapestry5.monitor.MonitorModule.adviseForMonitoredServices(MethodAdviceReceiver,
MonitorAdvisor) (at MonitorModule.java:52)
[ERROR] Registry [ 4] Reloading class
org.apache.tapestry5.internal.monitor.MonitorAdvisorImpl.
[ERROR] Registry [ 5] Determining injection value for parameter #2
(org.apache.tapestry5.monitor.MonitorNamingStrategy)
[ERROR] Registry [ 6] Resolving object of type
org.apache.tapestry5.monitor.MonitorNamingStrategy using
MasterObjectProvider
[ERROR] Registry [ 7] Realizing service AssetObjectProvider <---
AHHH!!!! I don't need an AssetObjectProvider

I can work around the problem by using 'InjectService("MyService")
MyService' because by default the service id maps to the simple name
of the service interface and the MasterObjectProvider isn't consulted
about getting my Service. But I'm hopefully not alone in thinking this
is silly.

I am building service advice based on an annotation, I haven't seen
anything in the system that puts all these together using the current
advice (as opposed to decoration), but if you have I'd love to see it.

This is what I have that works with the existing system.

    @Match("*")
    public static void adviceForMonitoredServices(
            MethodAdviceReceiver receiver,
            @InjectService("MonitorAdvisor") MonitorAdvisor monitorAdvisor) {
        monitorAdvisor.monitor(receiver);
    }

 public MonitorAdvisorImpl(
            Logger logger,
            @InjectService("MonitorNamingStrategy")
MonitorNamingStrategy monitorNamingStrategy,
            @InjectService("MonitorJmxObjectNamingStrategy")
MonitorJmxObjectNamingStrategy jmxObjectNamingStrategy,
            @InjectService("MBeanSupport") MBeanSupport mBeanSupport) {

The solution:

If I modify the InternalUtils.calculateInjection method so that it
checks for the simple name of the service before delegating to the
master object provider then I don't have to use the @InjectService
annotation anymore.

        // by default services are registered by their simple name,
see if we can get to it that way
        // although, if there is a marker annotation then you can't
load the service this way.
        if ( provider.getAnnotation(Marker.class) != null) {
            try
            {
                return
locator.getService(injectionType.getSimpleName(), injectionType);
            }
            catch (RuntimeException e)
            {
                // ignored, it will fall through to the master object provider
            }
        }

I've run the ioc,core, spring and hibernate unit tests and they pass.
The fact that the simple name is used as the default id is pervasive
so I don't imagine using it here breaks any encapsulation.

What use cases have I missed that will cause this code to break
something not covered in the unit tests?

Thanks,
Josh

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tapestry.apache.org
For additional commands, e-mail: dev-help@tapestry.apache.org


Mime
View raw message