First discussion - api/impl pattern

Stephen McConnell mcconnell at dpml.net
Tue Oct 5 21:09:19 EDT 2004



> -----Original Message-----
> From: support-dpml-bounces at lists.ibiblio.org [mailto:support-dpml-
> bounces at lists.ibiblio.org] On Behalf Of David Leangen
> Sent: 05 October 2004 11:44
> To: Support
> Subject: RE: First discussion - api/impl pattern
> 
> 
> Hi, Peter,
> 
> Ok, let me run with your example, then.
> 
> First off, I do not dispute at all the benefits of "Metro-izing"
> ("Metrizing"?) the various components. 

Metrofication?

> This provides an excellent service
> adapter to the various Java classes. In fact, this expands the
api/impl
> pattern to api/spi/impl. I also do not dispute that there are serveral
> benefits, including the ability to search for the appropriate
> dependencies.
> 
> My concern lies on a different, perhaps more abstract level. I'm
having
> trouble intellectually (ok, what else is new?) reconciling how to make
a
> clean separation of api/impl.
> 
> So, taking your example, there is an api, and, in reality, the impl is
> mixed
> up with the spi. The api is the DatabaseService class. The
implementation
> of
> this class is HsqlServer. The service adapter is HsqlServiceProvider.

The impl and api/spi classes need not be mixed.  Consider the following
classloader chain:

  |-------------------|
  | api classes       |
  |-------------------|
        |
        |
    ----------------------------------
    |                                |
|---------------------|      |---------------------|
| HsqlServiceProvider |      | WidgetProvider      |
|---------------------|      |---------------------|

You can structure a classloader hierarchy like the one described above
by nesting containers.  The root container can include the shared api
classes (implemented by the HsqlServiceProvider and used by the
WidgetProvider) but neither of the implementation classloaders need
visibility into each other. Instead an API or SPI is simply a _view_ on
an implementation.


> Obviously, both in impl and spi depend somehow on the api. In this
case,
> the spi does not actually directly implement the api per se, but
> it does provide the services required by the api. 

Not necessarily.

Typically a SPI makes use of an API but in actual fact both are just
views of an implementation.  An SPI will often provide services directed
to a client acting in a role that is different to the role of a client
using the API.

> The impl must implement both the api and spi.

Yep.

> In the case of the spi, I have no trouble understanding how to
completely
> abstract it out from the implementation. Metro provides a nice way of
> obtaining a component, and the rest works like magic.
> 
> Do you see what I'm trying to say so far? If you do, then so far so
good.
> 
> 
> So, the problem I'm having trouble getting over is using the api/impl
> without the spi. 

OK - I think I understand the assumption you may be making about SPIs.
If we looking at something like the repository package we see some
patterns similar to what your describing - namley SPI classes that
expose factories and API used by SPI.  You will also find this pattern
inside the composition system.  In this context the api/spi/impl
separation is like this because we don't have the existing IoC
infrastructure - instead these packages are parts of that
infrastructure.

If we look at packages such as the http facility we start to see a
different interpretation of API, SPI, impl, etc.  APIs and SPIs and
[any-character]PIs are much more aligned with functional views of an
implementation. Typically APIs are describing a more passive client
contract as compared to an SPI that is declaring functions more related
to management.  You could throw in a BCI, DCI and ECI or whatever - they
are just additional views of an implementation targeting an identifiable
usage scenario.

> So, for a moment, put aside Metro. Imagine I'm just
> building some component for which I'll eventually provide a service
> provider. How do I do this without having to "know" the
implementation? 

By delegating the responsibility of "knowing" to the container (which
takes you back to the subject of strategies used by the container to
discover implementations):

          |---> defines classloader
          |       |
          |       |--> enables type discovery (type scanning)
          |       |
block --->|       |---> enables profile discovery (xprofile scanning)
          |
          |--> defines composition
          |
          |--> declare service export

It's not a great diagram but it does detail the primary functions of a
block.  Firstly the definition of a classloader which enables the
discovery of component types and deployment scenarios, secondly aspects
concerning composition enabling the creation of composites and lastly,
the ability to control what is and is not exported from the composite.

Cheers, Steve.


> If
> we really wanted to use the api/impl pattern to its full potential, we
> should be able to do so without even having published the
implementation.
> 
> Somehow I don't feel like I'm expressing the point well... Do you get
an
> idea of what I'm trying to say, though?
> 
> If not, I'll make up some simple example that should better explain
the
> concept.
> 
> 
> Dave
> 
> 
> 
> 
> > -----Original Message-----
> > From: support-dpml-bounces at lists.ibiblio.org
> > [mailto:support-dpml-bounces at lists.ibiblio.org]On Behalf Of Peter
> Neubauer
> > Sent: 5 October 2004 16:02
> > To: support-dpml at lists.ibiblio.org
> > Subject: Re: First discussion - api/impl pattern
> >
> >
> > Hi David,
> > I am just a user, too, but I think the real potential with the
> > separattion of IMPL/API is first realized when you actually
> > package the components. If you do not, you will ahve to know
> > about the implementation in your <component class="..."/>. If you
> > package them, that is handled by the <inculde ..../> statement,
> > and the included .block  will have it's own classloader, know
> > what impl classes to intantiate and what to expose.
> >
> > I found a very neat example of that in the /planet/facilities/db
> > hsql server example, and the Console/Reflector/other newer
> > facilities. You just include it, then it downloads it's
> > dependencies and aeverything runs.
> >
> > THat means that it is most "pure" to go the whole way and
> > generate blocks of ryou components that make them includeable as
> > subcontainers exposing the components API.
> >
> >
> > /peter
> > -----Original message-----
> > From: "David Leangen" dleangen at canada.com
> > Date: Tue,  5 Oct 2004 08:21:56 +0200
> > To: support-dpml at lists.ibiblio.org
> > Subject: First discussion - api/impl pattern
> >
> > >
> > > Well, the title "support" just attracts people like me with all my
> > > questions!
> > >
> > > I wanted to inaugurate the list by kicking of a discussion about
the
> > > api/impl pattern, which is so central to Metro. There are still
> > a few points
> > > about the pattern that I haven't "got" yet, even when looking
> > at the Metro
> > > code base.
> > >
> > > First off, IIUC, the user should only _need_ the api, right? In
> > other words,
> > > even without the Javadoc for the impl, the user should have no
> > problems. The
> > > implementation classes should be obtained though factory methods
(for
> > > example) that are published in the api.
> > >
> > > So, ideally, the user should never need to see classes such as
> > DoThisImpl or
> > > DefaultContextFactory. At least, that's my understanding of the
> > pattern. If
> > > this isn't so, then I don't see the point in going to all the
trouble
> to
> > > separate the two.
> > >
> > >
> > > So, what is really tormenting me is how to achieve this very
strict
> > > separation of api/impl. At some point, there must obviously be a
way
> of
> > > loading the impl classes, but how to do this?
> > >
> > > One way, which to me appears to seriously violate the api/impl
> > principle, is
> > > to do this:
> > >
> > >   SomeClass someClass = new SomeClassImpl();
> > >
> > > or maybe even this:
> > >
> > >   SomeClass someClass =
> > > SomeClassFactoryImpl.getInstance().getObject(SomeClass.class);
> > >
> > > or whatever.
> > >
> > >
> > > The problem with this is that the user has to be aware of
> > what's inside the
> > > impl package. Ok, so that means it must be published. Ok, so
> > that means that
> > > it should be part of the API. Doh!
> > >
> > >
> > > So, it seems to me like the only way to acheive real api/impl
> > separation is
> > > to have some kind of classloader included with the api (maybe
> > in a factory
> > > method) that can load the impl classes. This would at least
> > achieve api/impl
> > > separation as far as the user is concerned.
> > >
> > >
> > > But...
> > >
> > >
> > > There would have to be some kind of contract between this class
> > loader and
> > > the impl package. So, there would have to be an impl api, which
kind
> of
> > > disturbs me somehow. Or at the very least, there has to be some
kind
> of
> > > convention. For example, the convention could simply be that
> > the impl for
> > > each class appends the letters "Impl" to the class name.
> > >
> > >
> > > Anyway, these are some of the things that are bothering me.
> > What's more is
> > > that it appears that even the Metro code violates the api/impl
> pattern,
> > > strictly speaking.
> > >
> > >
> > > What are your thoughts on this?
> > >
> > >
> > >
> > > Dave
> > >
> > >
> > > _______________________________________________
> > > support-dpml mailing list
> > > support-dpml at lists.ibiblio.org
> > > http://lists.ibiblio.org/mailman/listinfo/support-dpml
> > >
> > >
> > >
> > _______________________________________________
> > support-dpml mailing list
> > support-dpml at lists.ibiblio.org
> > http://lists.ibiblio.org/mailman/listinfo/support-dpml
> 
> _______________________________________________
> support-dpml mailing list
> support-dpml at lists.ibiblio.org
> http://lists.ibiblio.org/mailman/listinfo/support-dpml




More information about the support-dpml mailing list