> 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]>

Reply via email to