OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

sca-j message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: [sca-j] [JAVA-1] Proposed styles of code for the SCAClientFactory



On Feb 20, 2009, at 5:27 AM, Simon Nash wrote:

> See comments inline.
>
>  Simon
>
> Jim Marino wrote:
>> Hi
>> I was going to bring up the same issues as Raymond w.r.t META-INF/ 
>> services and the TCCL...The JAXB API for example uses the TCCL for  
>> discovery which causes issues in OSGi where the TCCL is not  
>> defined. The JPA API, Hibernate and Axis also rely on behavior of  
>> the TCCL which often forces runtimes that rely on OSGi for  
>> classloading to use proprietary features such as the Equinox  
>> "buddy" mechanism to get around this (in Fabric3 we use a slightly  
>> different method but the concept is the same).
> Both JAXB and JAXP default to using TCCL while also allowing some  
> other
> classloader to be passed in.  Whichever classloader we choose by  
> default,
> I think it would be sensible to also allow a classloader to be  
> passed in
> to override the default.
>
>> I think injection is a better approach to solve the problem. For  
>> environments where injection is not possible, SCAClientFactory  
>> could do the following:
>> 1. Use the injected SCAClientFactory instance
>> 2. If no instance is injected, look for a JVM property specifying  
>> the concrete SCAClientFactory class and instantiate it through  
>> reflection using the classloader of the SCAClientFactory class and  
>> not Class.forName(..) since the latter has slightly different  
>> caching semantics which do not work well in OSGi. 3. If the JVM  
>> property is not set, look in META-INF/services for a concrete class  
>> name and instantiate the class using the classloader of  
>> SCAClientFactory. This is intended for the use case where a client  
>> runs from a Java main where the only setup needed is for vendor- 
>> specific jars to be on the classpath (i.e. no need to set a JVM  
>> property). If two vendor implementations are on the classpath,  
>> option 1 or 2 will be needed.
> Why does this step use the classloader of SCAClientFactory instead
> of TCCL?  For the given use case, I would expect TCCL to be suitable.

The TCCL is only really usable in a web application (WAR) where it is  
explicitly defined and application code is restricted from setting it.  
In a J2SE environment, if it is not set, it is the system classloader.  
Unfortunately, applications, libraries, and containers have a habit of  
setting the TCCL and this can result in unpredictable behavior for  
resolving which SCA client implementation is loaded.

>
>
>> Steps 2-3 won't work well in OSGi but option 1 will. This means  
>> that OSGi environments will need to either have vendor code perform  
>> the injection or use code do it via a BundleActivator.
> I'm confused by this, as I thought the purpose of using the  
> classloader
> of the SCAClientFactory class in steps 2 and 3 was to avoid problems  
> with
> OSGi and TCCL.  If these steps can't be used by OSGi even though they
> avoid using TCCL, I'm not sure why we would need these steps to avoid
> using TCCL by default.
>

Steps 2 and 3 will work in OSGi but it means the vendor implementation  
classes must be visible to the bundle classloader that loads  
SCAClientFactory. If the TCCL is used, this may or may not work. For  
example, because Equinox uses a proprietary mechanism to set the TCCL  
to the current executing bundle's classloader, it will attempt to load  
the vendor classes using the latter. In other OSGi runtimes different  
results may ensue depending on how they treat the TCCL. sing the  
SCAClientFactory classloader will at least provide consistent results  
in OSGi (and J2SE) whereas using the TCCL will not.

>> I believe this would eliminate the need to define an  
>> SCAClientFactoryFinder API and by extension a discovery algorithm.  
>> Is there a reason why SCA should define a mechanism?
> It provides an escape valve in case the lookup order that we choose
> isn't suitable for some environment that we haven't anticipated.
> Given the discussion around this, I think that's quite likely!
>

:-) Don't we already have an escape hatch with SCAClientFactory and  
the proposed injection method? In other words:

1. When using Injection, any resolution mechanism can be used

2. When not using injection, the only requirement is the concrete  
subclass of SCAClientFactory must be visible to the SCAClientFactory  
classloader. The concrete subclass can do whatever it likes to resolve  
an instance of SCAClient, even loading an implementation class from a  
classloader it has no visibility to.

In most cases #2 is reasonable and if it is not, #1 can be used. The  
only case that comes to mind where this would not be handled is if  
SCAClientFactory were included in the JRE and the vendor  
implementation was not. That is not very likely. Do you think I'm  
missing a scenario?

Jim

>  Simon
>
>> Also, one other comment I have is please don't consider the SDO  
>> (anti)pattern of using instance variables on interfaces. SCA used  
>> that approach in the past for a similar client API and it caused  
>> all sorts of havoc in managed environments where classloader  
>> isolation is essential.  It's also one of the reasons SDO is so  
>> difficult to use in managed environments.
>> Jim    On Feb 19, 2009, at 9:12 AM, Raymond Feng wrote:
>>> 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:
>>>
>>> public abstract class SCAClientFactory
>>> {
>>>    private static SCAClientFactory defaultFactory; // This  
>>> instance to be injected, if null, the finder will be used
>>>
>>>    public static void setDefaultSCAClientFactory(SCAClientFactory  
>>> factory) {
>>>        defaultFactory = factory;
>>>    }
>>>
>>>    public abstract SCAClient createSCAClient();
>>>     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?
>>> 2) Should we define if the SCAClientFactory is thread-safe or not?
>>>
>>> Thanks,
>>> Raymond
>>>
>>>
>>>
>>> From: 	"Mark Combellack" <mcombellack@avaya.com <mailto:mcombellack@avaya.com 
>>> >>
>>> To: 	<sca-j@lists.oasis-open.org <mailto: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_ 
>>>  <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_ 
>>>  <mailto:|mcombellack@avaya.com>
>>>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this mail list, you must leave the OASIS TC that
> generates this mail.  Follow this link to all your TCs in OASIS at:
> https://www.oasis-open.org/apps/org/workgroup/portal/my_workgroups.php



[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]