> From: Stephen McConnell [mailto:[EMAIL PROTECTED]]
>
> Leo Sutic wrote:
> > I was about to ask you how you would handle the selection among
> > several components for a role where some components are thread-safe
> > and some poolable: Do you pool the selectors or do you select among
> > several maybe-pools? But the ServiceChooser interface does that,
> > albeit in a very ugly way (pools everything).
>
> Firstly, I'm not recommending the simplification of interfaces such that
> situation could occur. Your example case is a good example of the
> conflicts
> that
> can be introduced when mixing concerns. The approach I have taken is that
> the client uses a manager to get the selection provider. If the selection
> provider is an instance of SelectionChooser, the client is now
> aware of its
> obligations concerning release of pooled resources. Code is therefore
> required to meet those responsibilities.
Right. And then we are back into having to explicitly test for poolable
components when retrieving them. Which is a step backwards.
It means that I have to do this:
Object component = manager.lookup (role);
if (component instanceof ServiceChooser) {
realComponent = ((ServiceChooser) component).checkout (...);
}
instead of just looking up the component.
> > Plus the lifestyle interfaces for the above.
>
> Small correction - "lifecycle interface" (singular). The interfaces as
> presented in the response resolved the issue of multiple composition
> mechanisms by requiring that a client that is using pooled resources
> narrow to an interface that supports pooling (hence the separation of
> the ServiceReclaimer interface).
And that is bad. If every lookup must be followed by a test-for-poolable
then that code should belong in the lookup method.
> Which bit is too much?
Too much repetitive code, too many interfaces, too much responsibility
shifted to the client.
> > My proposal is:
> >
> > interface ServiceManager {
> > public Object lookup (String role);
> > public Object lookup (String role, Object policy);
> > public void release (Object component);
> > }
> >
> > interface ServiceSelector {
> > public Object select (Object policy);
> > }
> >
> > interface ServiceHandler {
> > public Object lookup ();
> > public Object release ();
> > }
> >
> > Does everything you need:
> >
> > ServiceManager:
> >
> > public Object lookup (String role);
> > Looks up a role.
>
> But more correctly, you should add that the semantics "requires" that the
> client release this service even if the manager doesn't not need to be
> notified of the release.
Yes. This is to provide a unified interface for both poolable and
non-poolable
components.
> > public Object lookup (String role, Object policy);
> > Looks up a role, and gives the policy object to the selector if any.
>
> This is a reasonable convenience operation provided that we totally ignore
> the entire thread concerning token based release of pooled resources.
I'll state my position regarding tokens now: They are good if we can fit
them
into the interface, but I can do just as well without them. All they provide
is a releaseAll method, and that is non-critical, and orthogonal to
what we are discussing now.
I could easily refit the interface to support tokens:
public Object lookup (Token token, String role);
public Object lookup (Token token, String role, Object policy);
public void releaseAll (Token token);
What I am concerned with is the use of the ServiceManager/Resolver
interface -
I want *one* way to obtain *any* service - pooled or not. I want
one method call, and I do not want to have to test for a ServiceChooser
to handle pooled components as a special case.
> > ServiceSelector:
> > Intended to be implemented by the client, to provide
> > selection policies for components. The selector
> > selects among several ServiceHandlers and calls lookup()
> > on the selected one.
>
> Can you clarify for me the comment "implemented by the client". My
> understanding is that a ServiceSelector is implemented by the
> provider. It
> takes as an input argument of an object that specifies the selection
> criteria,
> and based on that criteria, attempts to resolve an appropriate service. If
> the
> object were implemented by the client then we don't need pass via an
> interface
> for that behaviour (because it's in the client implementation).
Situation: You want to select component based on a Color object.
Solution: Create a class that implements ServiceSelector. Specify
this class (ColorSelector) in the configuration to the ServiceManager,
The need for an interface is becuase the ServiceManager will use
this class - not the client directly.
> > So the lookup is:
> >
> > ServiceManager ---- Picks among several, based on role ----> Selectors
> > *or* Handlers
>
> Do you mean that ServiceHandler *only* returns either a Selector or a
> Handler
> and explicitly not direct service - which would imply that the general
> return
> object is a Handler ? If this is correct, then yes, that simplifies the
> interfaces because pooled services get pushed down to handlers but at the
> same
> time it negates the simplicity of the current CM interface - lookup and
> forget
> about the manager.
No. I wasn't too clear on this, but this is what happens:
I call ServiceManager.lookup (role);
Object ServiceManager.lookup (String role) {
return lookup (role, null); // null policy means "gimme default", which if
there is no
// Selector, the single impl.
}
Object ServiceManager.lookup (String role, Object policy) {
Object instance = getMappingFor (role);
// component may be either a ServiceSelector or a ServiceHandler
ServiceHandler handler = null;
// Optionally select between several
if (instance instanceof ServiceSelector) {
handler = ((ServiceSelector) instance).select (policy);
} else {
handler = (ServiceHandler) instance;
}
Object component = handler.lookup ();
// So we can return it.
handlerMap.put (component, handler);
return component;
}
void ServiceManager.release (Object instance) {
ComponentHandler handler = (ComponentHandler) handlerMap.get (instance);
handler.release (instance);
handlerMap.remove (instance);
}
The simplicity I talk about is that there is no need to narrow the SM,
test for poolable components, etc. That is a huge advantage. With
tokens things are just as simple. I do not consider a 6 method interface
overloaded.
/LS
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>