From:
Raymond Feng [mailto:rfeng@us.ibm.com]
Sent: 19 February 2009 17:13
To: sca-j@lists.oasis-open.org
Subject: Re: [sca-j] [JAVA-1]
Proposed styles of code for the SCAClientFactory
Hi, Mark.
The
abstract factory classes seems to be the widely-used pattern.
But
we have encountered various issues for this pattern in an OSGi-based runtime.
First, that the classloader-based discovery of META-INF/services doesn't work
well in OSGi as OSGi has a network of classloaders instead of a flat one.
Passing in the name of the factory impl class via system property also depends
on TCCL or the classloader of the SCAClientFactory class and it's not OSGi
friendly.
I
propose that we add a static setter or field on SCAClientFactory so that a
subclass of SCAClientFactory (class or instance) or an instance of
SCAClientFactoryFinder can be injected by the runtime. Something like:
[Mark Combellack] This seems to be a
reasonable compromise. In a managed environment, the vendor has the chance to
set the SCAClientFactory implementation that should be used. In an unmanaged
environment, we provide a standard way of discovering the implementation via
System Properties and META-INF/services.
public abstract class SCAClientFactory
{
private static SCAClientFactory defaultFactory; // This instance to be
injected, if null, the finder will be used
[Mark Combellack] Personally, I would like the
set method to not be public so that a user of the SCAClientFactory does not see
the method since there is no reason for them to call it. The method should be package
or protected.
public static
void setDefaultSCAClientFactory(SCAClientFactory factory) {
defaultFactory = factory;
}
public abstract SCAClient createSCAClient();
[Mark Combellack] If I understand things
correctly, we may have a threading issue with this approach since there is no
synchronization. The SCA Runtime may call the setDefaultSCAClientFactory()
method but there is no guarantee that the newInstance() method will see the new
value immediately.
public static
SCAClientFactory newInstance() {
if(defaultFactory == null) {
return SCAClientFactoryFinder.find();
} else {
return defaultFactory;
}
}
}
Two
more points:
1)
Do we really need to define the algorithm on how the subclass of the
SCAClientFactory is discovered?
[Mark Combellack] Personally, I think it
would be good to provide a reference implementation of how the subclass of the
SCAClientFactory is discovered. However, I am open to being convinced
otherwise.
2) Should we define if the SCAClientFactory is
thread-safe or not?
[Mark Combellack] Yes, this is a good
point. We need to clearly define the threading behaviour for SCAClientFactory
and the finder
Thanks,
Raymond
From:
|
"Mark Combellack"
<mcombellack@avaya.com>
|
To:
|
<sca-j@lists.oasis-open.org>
|
Date:
|
02/18/2009 07:51 AM
|
Subject:
|
[sca-j] [JAVA-1] Proposed styles of code for the
SCAClientFactory
|
Hi,
I took
an action item on Monday’s call to provide code fragments to show how we
could implement the SCAClientFactory code for
creating SCAClient instances in a
standard way but still allow Vendors to plug in Vendor specific code as
required by their runtime.
Overview of the Proposals
I have
written up the 4 proposals at the end of this email and they are:
Proposal
1: Follow style defined by SDO – instance variable on Interface set by a
separate finder class
Proposal
2: Follow style defined by JAXB – method on abstract class which delegates
to a separate finder class
Proposal
3: Follow style defined in Mark’s proposal – method on concrete
class
Proposal
4: Follow style defined in Mark’s proposal with a tweak from Simon
– method on a concrete class which delegates to a separate finder class
In the
following discussion Proposal 3 is not considered as it has been replaced by
Proposal 4
Comparison of the Proposals
In SCA
terms, the 3 proposals (1, 2 and 4) conceptually do the same thing (with a few
minor differences in how they do it). Conceptually, they all:
- Provide a SCAClientFactory
class/interface that is used to create concrete instances of SCAClient using
the SCAClientFactory
- SCAClientFactory
delegates to a separate class for actually creating the concrete instance
of SCAClient – such
as SCAClientFactoryFinder or HelperProvider
- SCA would provide a reference implementation of
the class that SCAClientFactory
delegates to a for creating the concrete instances of SCAClient
· The
reference implementation uses System Properties, META-INF/services and/or
ClassLoader to load the Vendor implementation of the SCAClientFactory
- Vendors are able to replace the reference
implementation of the finder with a vendor specific implementation that
will interact with their SCA Runtime as required.
Recommended Approach for moving forward
From
these proposals, which one is the best approach? My thoughts are:
- I think proposal 2 seems the best option (JAXB
style)
- I would suggest that we don’t do proposal
4 (Mark’s custom code) since there is little point in inventing
something new.
- I personally don’t like proposal 2 (SDO)
since it has an instance variable on an interface so I would not do
proposal 1.
What
does this all mean for SCA? The main points are listed below:
- SCAClient is an
interface and provided by the SCA Specification.
- SCAClientFactory is an
abstract class and provided by the SCA Specification.
- SCAClientFactory has a
static method called newInstance() that
delegates to the SCAClientFactoryFinder class
for creating the Vendor instance of SCAClientFactory
- The SCA Specification provides a reference implementation of SCAClientFactoryFinder that
uses a combination of a System Property and META-INF/services to
locate the correct Vendor specific implementation of the
SCAClientFactory
- Vendors MUST subclass SCAClientFactory and
implement the createSCAClient()method.
This will create and return a new instance of the Vendor specific SCAClient
implementation.
- Vendors MAY choose to replace the reference implementation of SCAClientFactoryFinder with
an alternative implementation which can be tailored to their own SCA
Runtime.
What would the SCA code look like when following the above
recommended approach?
From
all of the above, what code would a SCA User need to write in their code? They
would need to write:
SCAClient
scaClient = SCAClientFactory.newInstance().createSCAClient();
The SCAClientFactory would look
something like:
public
abstract class SCAClientFactory
{
public abstract SCAClient createSCAClient();
public static SCAClientFactory newInstance() {
return SCAClientFactoryFinder.find();
}
}
The SCAClientFactoryFinder would look
something like the following pseudo code:
public
class SCAClientFactoryFinder
{
public static SCAClientFactory find() throws SCARuntimeException {
// First look in the System Properties
String vendorImplClass =
getVendorImplClassNameFromSystemProperties();
if (vendorImplClass == null) {
// Secondly look in META-INF/services
vendorImplClass =
getVendorImplClassNameFromMETAINFServices();
}
if (vendorImplClass == null) {
throw new SCARuntimeException("No SCAClientFactory
implementation provided");
}
return
createInstanceOfVendorImplClassFromClassName(vendorImplClass);
}
}
I will
be interested in people’s opinion on this approach. Sorry this email is a
bit long but hopefully it will continue the discussion on JAVA-1.
Thanks,
Mark
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Note:
You may want to stop reading here if you are not really interested in the
details of the investigation into the 4 proposals.
My
original write up of the 4 proposals is shown below. I’ve included in the
email for completeness but it is probably not worth reading it unless you are
really interested.
These
patterns assume that SCAClient has the
following methods:
public
<T> T getService(Class<T> interfaze, String serviceURI, URI
domainURI)
throws NoSuchServiceException, NoSuchDomainException;
Proposal 1: Follow style defined by SDO – Instance
variable on Interface
SDO
uses the concept of an instance variable on an interface for obtaining the
default vendor implementation. In SCA terms, this would look like:
SCAClient
scaClient = SCAClientFactory.INSTANCE.createSCAClient();
In
this style SCAClient and SCAClientFactory are both
interfaces. The SCAClientFactory interface
would look like:
public
interface SCAClientFactory
{
SCAClient createSCAClient();
SCAClientFactory INSTANCE = HelperProvider.getSCAClientFactory();
}
This
interface delegates the creation of the SCAClientFactory instance to
the getSCAClientFactory() method on HelperProvider in the impl package.
SDO provides a reference implementation of the HelperProvider class but
Vendors may replace this class with their own implementation.
Following
this style, the SCA API should provide a reference implementation of the HelperProvider class but
Vendors are encourage to replace the class to meet the requirements of their
SCA Runtimes. The SCA Reference implementation of HelperProvider would
search the System Properties and META-INF/services for the
implementation of SCAClientFactory.
As an
example, the code for the Tuscany SDO HelperProvider can be seen
at http://svn.apache.org/viewvc/tuscany/java/sdo/sdo-api/src/main/java/commonj/sdo/impl/HelperProvider.java?view=markup&sortby=date
Proposal 2: Follow style defined by JAXB – method on
abstract interface
In
JAXB, the initial JAXBContext is looked
up by calling the newInstance() method on
the abstract JAXBContext class. The
abstract JAXBContext class delegates to
the ContextFinder class that will use the ClassLoaders to instantiate the
Vendor implementation that subclasses JAXBContext. In SCA terms, this would
look like:
SCAClientFactory
scaClientFactory = SCAClientFactory.newInstance();
SCAClient
scaClient = scaClientFactory.createSCAClient();
Or
combined as one statement:
SCAClient
scaClient = SCAClientFactory.newInstance().createSCAClient();
In
this style SCAClient is an
interface and SCAClientFactory is an
abstract class. The SCAClientFactory abstract
class would look like:
public
abstract class SCAClientFactory
{
public abstract SCAClient createSCAClient();
public static SCAClientFactory newInstance() {
return SCAClientFactoryFinder.find();
}
}
This
abstract class delegates the creation of the SCAClientFactory instance to
the find() method on SCAClientFactoryFinder. JAXB
provides a reference implementation of the JAXB Finder class but Vendors may
replace this class with their own implementation.
Following
this style, the SCA API should provide a reference implementation of the SCAClientFactoryFinder class
but Vendors are encourage to replace the class to meet the requirements of
their SCA Runtimes. The SCA Reference implementation of SCAClientFactoryFinder would
search the System Properties and META-INF/services for the
implementation of SCAClientFactory.
Proposal 3: Follow style defined in Mark’s original
code proposal for JAVA-1
Note:
This proposal has been superseded by Proposal 4 below.
The SCAClientFactory class is
responsible for providing the indirection from the user’s generic SCA
code and the vendor’s implementation of the SCA Runtime. The user’s
code will ask it for a SCAClient via the createSCAClient() method.
The SCAClientFactory class
provides this indirection to the vendor’s implementation by attempting to
discover the class name of the vendor’s implementation using:
- The org.oasisopen.sca.SCAClientFactory System
Property
- The META-INF/services/org.oasisopen.sca.SCAClientFactory
file.
It is
important to note that this class does not need to be updated by the Vendor to
include their implementation. All the Vendor needs to do is set the System
Property or provide the correct services file
The
difference here is that the SCA Specification provides the definitive
implementation of the SCAClientFactory lookup code
and Vendors cannot change this lookup code.
Proposal 4: Follow style defined in Mark’s original
code proposal for JAVA-1 with a tweak from Simon
Simon
pointed out that Vendors may want to override the way that the SCAClientFactory
implementation is discovered. Therefore, the code should be moved into a
separate class in a separate package so that Vendors can override this class if
they wish.
Mark Combellack| Software Developer| Avaya | Eastern Business
Park | St. Mellons | Cardiff | CF3 5EA | Voice: +44 (0) 29 2081 7624 | mcombellack@avaya.com