blob: dd9ff8223c8e2d72f63bcd274799d2fd24bc7c53 [file] [log] [blame]
----
Shadow Services
----
Shadow Services
The
{{{../apidocs/org/apache/tapestry5/ioc/services/PropertyShadowBuilder.html}PropertyShadowBuilder}}
service is used to build a special, delegating kind of service implementation.
Effectively, it is used to allow a property of another service to be exposed as its own service.
For example, the tapestry-core module provides a Request property as a shadow of the RequestGlobals
service's request property:
+----+
public Request build()
{
return _shadowBuilder.build(_requestGlobals, "request", Request.class);
}
+----+
This can be thought of as similar to:
+----+
public Request build()
{
return _requestGlobals.getRequest();
}
+----+
However there is a <critical> difference between the two: a shadow property is <re-evaluated on each method invocation>.
In the former case, the Request service will always obtain the current value of the request property from the
per-thread RequestGlobals service. The second example is more than likely broken, since it will expose whatever
value is in the request property of the RequestGlobals <at the time the Request service implementation is created>.
Notice that in this example, the Request service is a normal singleton. This service can be freely injected
into any service throughout the framework or application. Invoking methods on this service will always delegate
to the current thread's request. Callers don't have to be aware of this internal delegation; it just happens.
Non-Reflective
When the shadow is created, reflection is used to translate the property name to a method name.
This information is used to build a new class (at runtime) that is instantiated as the service implementation.
A typical method is implemented as (approximately):
+----+
private RequestGlobals _source;
public String getParameter(String name)
{
return _source.getRequest().getParameter(name);
}
+----+
That is, the shadow implementation holds onto the target object (in the above example,
the RequestGlobals service) and invokes a method on it directly, not using reflection, no differently
than you would if you wrote the code yourself.