/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javax.sql.rowset.spi;

import java.util.logging.*;
import java.util.*;

import java.sql.*;
import javax.sql.*;

import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

import javax.naming.*;
import sun.reflect.misc.ReflectUtil;

The Service Provider Interface (SPI) mechanism that generates SyncProvider instances to be used by disconnected RowSet objects. The SyncProvider instances in turn provide the javax.sql.RowSetReader object the RowSet object needs to populate itself with data and the javax.sql.RowSetWriter object it needs to propagate changes to its data back to the underlying data source.

Because the methods in the SyncFactory class are all static, there is only one SyncFactory object per Java VM at any one time. This ensures that there is a single source from which a RowSet implementation can obtain its SyncProvider implementation.

1.0 Overview

The SyncFactory class provides an internal registry of available synchronization provider implementations (SyncProvider objects). This registry may be queried to determine which synchronization providers are available. The following line of code gets an enumeration of the providers currently registered.
    java.util.Enumeration e = SyncFactory.getRegisteredProviders();
All standard RowSet implementations must provide at least two providers:
  • an optimistic provider for use with a CachedRowSet implementation or an implementation derived from it
  • an XML provider, which is used for reading and writing XML, such as with WebRowSet objects
Note that the JDBC RowSet Implementations include the SyncProvider implementations RIOptimisticProvider and RIXmlProvider, which satisfy this requirement.

The SyncFactory class provides accessor methods to assist applications in determining which synchronization providers are currently registered with the SyncFactory.

Other methods let RowSet persistence providers be registered or de-registered with the factory mechanism. This allows additional synchronization provider implementations to be made available to RowSet objects at run time.

Applications can apply a degree of filtering to determine the level of synchronization that a SyncProvider implementation offers. The following criteria determine whether a provider is made available to a RowSet object:

  1. If a particular provider is specified by a RowSet object, and the SyncFactory does not contain a reference to this provider, a SyncFactoryException is thrown stating that the synchronization provider could not be found.
  2. If a RowSet implementation is instantiated with a specified provider and the specified provider has been properly registered, the requested provider is supplied. Otherwise a SyncFactoryException is thrown.
  3. If a RowSet object does not specify a SyncProvider implementation and no additional SyncProvider implementations are available, the reference implementation providers are supplied.

2.0 Registering SyncProvider Implementations

Both vendors and developers can register SyncProvider implementations using one of the following mechanisms.

  • Using the command line
    The name of the provider is supplied on the command line, which will add the provider to the system properties. For example:
       -Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider
    
  • Using the Standard Properties File
    The reference implementation is targeted to ship with J2SE 1.5, which will include an additional resource file that may be edited by hand. Here is an example of the properties file included in the reference implementation:
      #Default JDBC RowSet sync providers listing
      #
      # Optimistic synchronization provider
      rowset.provider.classname.0=com.sun.rowset.providers.RIOptimisticProvider
      rowset.provider.vendor.0=Oracle Corporation
      rowset.provider.version.0=1.0
      # XML Provider using standard XML schema
      rowset.provider.classname.1=com.sun.rowset.providers.RIXMLProvider
      rowset.provider.vendor.1=Oracle Corporation
      rowset.provider.version.1=1.0
    
    The SyncFactory checks this file and registers the SyncProvider implementations that it contains. A developer or vendor can add other implementations to this file. For example, here is a possible addition:
        rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider
        rowset.provider.vendor.2=Fred, Inc.
        rowset.provider.version.2=1.0
    
  • Using a JNDI Context
    Available providers can be registered on a JNDI context, and the SyncFactory will attempt to load SyncProvider implementations from that JNDI context. For example, the following code fragment registers a provider implementation on a JNDI context. This is something a deployer would normally do. In this example, MyProvider is being registered on a CosNaming namespace, which is the namespace used by J2EE resources.
       import javax.naming.*;
       Hashtable svrEnv = new  Hashtable();
       srvEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
       Context ctx = new InitialContext(svrEnv);
       com.fred.providers.MyProvider = new MyProvider();
       ctx.rebind("providers/MyProvider", syncProvider);
    
Next, an application will register the JNDI context with the SyncFactory instance. This allows the SyncFactory to browse within the JNDI context looking for SyncProvider implementations.
   Hashtable appEnv = new Hashtable();
   appEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
   appEnv.put(Context.PROVIDER_URL, "iiop://hostname/providers");
   Context ctx = new InitialContext(appEnv);
   SyncFactory.registerJNDIContext(ctx);
If a RowSet object attempts to obtain a MyProvider object, the SyncFactory will try to locate it. First it searches for it in the system properties, then it looks in the resource files, and finally it checks the JNDI context that has been set. The SyncFactory instance verifies that the requested provider is a valid extension of the SyncProvider abstract class and then gives it to the RowSet object. In the following code fragment, a new CachedRowSet object is created and initialized with env, which contains the binding to MyProvider.
   Hashtable env = new Hashtable();
   env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "com.fred.providers.MyProvider");
   CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env);
Further details on these mechanisms are available in the javax.sql.rowset.spi package specification.
Author: Jonathan Bruce
See Also:
/** * The Service Provider Interface (SPI) mechanism that generates <code>SyncProvider</code> * instances to be used by disconnected <code>RowSet</code> objects. * The <code>SyncProvider</code> instances in turn provide the * <code>javax.sql.RowSetReader</code> object the <code>RowSet</code> object * needs to populate itself with data and the * <code>javax.sql.RowSetWriter</code> object it needs to * propagate changes to its * data back to the underlying data source. * <P> * Because the methods in the <code>SyncFactory</code> class are all static, * there is only one <code>SyncFactory</code> object * per Java VM at any one time. This ensures that there is a single source from which a * <code>RowSet</code> implementation can obtain its <code>SyncProvider</code> * implementation. * * <h3>1.0 Overview</h3> * The <code>SyncFactory</code> class provides an internal registry of available * synchronization provider implementations (<code>SyncProvider</code> objects). * This registry may be queried to determine which * synchronization providers are available. * The following line of code gets an enumeration of the providers currently registered. * <PRE> * java.util.Enumeration e = SyncFactory.getRegisteredProviders(); * </PRE> * All standard <code>RowSet</code> implementations must provide at least two providers: * <UL> * <LI>an optimistic provider for use with a <code>CachedRowSet</code> implementation * or an implementation derived from it * <LI>an XML provider, which is used for reading and writing XML, such as with * <code>WebRowSet</code> objects * </UL> * Note that the JDBC RowSet Implementations include the <code>SyncProvider</code> * implementations <code>RIOptimisticProvider</code> and <code>RIXmlProvider</code>, * which satisfy this requirement. * <P> * The <code>SyncFactory</code> class provides accessor methods to assist * applications in determining which synchronization providers are currently * registered with the <code>SyncFactory</code>. * <p> * Other methods let <code>RowSet</code> persistence providers be * registered or de-registered with the factory mechanism. This * allows additional synchronization provider implementations to be made * available to <code>RowSet</code> objects at run time. * <p> * Applications can apply a degree of filtering to determine the level of * synchronization that a <code>SyncProvider</code> implementation offers. * The following criteria determine whether a provider is * made available to a <code>RowSet</code> object: * <ol> * <li>If a particular provider is specified by a <code>RowSet</code> object, and * the <code>SyncFactory</code> does not contain a reference to this provider, * a <code>SyncFactoryException</code> is thrown stating that the synchronization * provider could not be found. * * <li>If a <code>RowSet</code> implementation is instantiated with a specified * provider and the specified provider has been properly registered, the * requested provider is supplied. Otherwise a <code>SyncFactoryException</code> * is thrown. * * <li>If a <code>RowSet</code> object does not specify a * <code>SyncProvider</code> implementation and no additional * <code>SyncProvider</code> implementations are available, the reference * implementation providers are supplied. * </ol> * <h3>2.0 Registering <code>SyncProvider</code> Implementations</h3> * <p> * Both vendors and developers can register <code>SyncProvider</code> * implementations using one of the following mechanisms. * <ul> * <LI><B>Using the command line</B><BR> * The name of the provider is supplied on the command line, which will add * the provider to the system properties. * For example: * <PRE> * -Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider * </PRE> * <li><b>Using the Standard Properties File</b><BR> * The reference implementation is targeted * to ship with J2SE 1.5, which will include an additional resource file * that may be edited by hand. Here is an example of the properties file * included in the reference implementation: * <PRE> * #Default JDBC RowSet sync providers listing * # * * # Optimistic synchronization provider * rowset.provider.classname.0=com.sun.rowset.providers.RIOptimisticProvider * rowset.provider.vendor.0=Oracle Corporation * rowset.provider.version.0=1.0 * * # XML Provider using standard XML schema * rowset.provider.classname.1=com.sun.rowset.providers.RIXMLProvider * rowset.provider.vendor.1=Oracle Corporation * rowset.provider.version.1=1.0 * </PRE> * The <code>SyncFactory</code> checks this file and registers the * <code>SyncProvider</code> implementations that it contains. A * developer or vendor can add other implementations to this file. * For example, here is a possible addition: * <PRE> * rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider * rowset.provider.vendor.2=Fred, Inc. * rowset.provider.version.2=1.0 * </PRE> * * <li><b>Using a JNDI Context</b><BR> * Available providers can be registered on a JNDI * context, and the <code>SyncFactory</code> will attempt to load * <code>SyncProvider</code> implementations from that JNDI context. * For example, the following code fragment registers a provider implementation * on a JNDI context. This is something a deployer would normally do. In this * example, <code>MyProvider</code> is being registered on a CosNaming * namespace, which is the namespace used by J2EE resources. * <PRE> * import javax.naming.*; * * Hashtable svrEnv = new Hashtable(); * srvEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming"); * * Context ctx = new InitialContext(svrEnv); * com.fred.providers.MyProvider = new MyProvider(); * ctx.rebind("providers/MyProvider", syncProvider); * </PRE> * </ul> * Next, an application will register the JNDI context with the * <code>SyncFactory</code> instance. This allows the <code>SyncFactory</code> * to browse within the JNDI context looking for <code>SyncProvider</code> * implementations. * <PRE> * Hashtable appEnv = new Hashtable(); * appEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming"); * appEnv.put(Context.PROVIDER_URL, "iiop://hostname/providers"); * Context ctx = new InitialContext(appEnv); * * SyncFactory.registerJNDIContext(ctx); * </PRE> * If a <code>RowSet</code> object attempts to obtain a <code>MyProvider</code> * object, the <code>SyncFactory</code> will try to locate it. First it searches * for it in the system properties, then it looks in the resource files, and * finally it checks the JNDI context that has been set. The <code>SyncFactory</code> * instance verifies that the requested provider is a valid extension of the * <code>SyncProvider</code> abstract class and then gives it to the * <code>RowSet</code> object. In the following code fragment, a new * <code>CachedRowSet</code> object is created and initialized with * <i>env</i>, which contains the binding to <code>MyProvider</code>. * <PRE> * Hashtable env = new Hashtable(); * env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "com.fred.providers.MyProvider"); * CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env); * </PRE> * Further details on these mechanisms are available in the * <code>javax.sql.rowset.spi</code> package specification. * * @author Jonathan Bruce * @see javax.sql.rowset.spi.SyncProvider * @see javax.sql.rowset.spi.SyncFactoryException */
public class SyncFactory {
Creates a new SyncFactory object, which is the singleton instance. Having a private constructor guarantees that no more than one SyncProvider object can exist at a time.
/** * Creates a new <code>SyncFactory</code> object, which is the singleton * instance. * Having a private constructor guarantees that no more than * one <code>SyncProvider</code> object can exist at a time. */
private SyncFactory() { }
The standard property-id for a synchronization provider implementation name.
/** * The standard property-id for a synchronization provider implementation * name. */
public static final String ROWSET_SYNC_PROVIDER = "rowset.provider.classname";
The standard property-id for a synchronization provider implementation vendor name.
/** * The standard property-id for a synchronization provider implementation * vendor name. */
public static final String ROWSET_SYNC_VENDOR = "rowset.provider.vendor";
The standard property-id for a synchronization provider implementation version tag.
/** * The standard property-id for a synchronization provider implementation * version tag. */
public static final String ROWSET_SYNC_PROVIDER_VERSION = "rowset.provider.version";
The standard resource file name.
/** * The standard resource file name. */
private static String ROWSET_PROPERTIES = "rowset.properties";
Permission required to invoke setJNDIContext and setLogger
/** * Permission required to invoke setJNDIContext and setLogger */
private static final SQLPermission SET_SYNCFACTORY_PERMISSION = new SQLPermission("setSyncFactory");
The initial JNDI context where SyncProvider implementations can be stored and from which they can be invoked.
/** * The initial JNDI context where <code>SyncProvider</code> implementations can * be stored and from which they can be invoked. */
private static Context ic;
The Logger object to be used by the SyncFactory.
/** * The <code>Logger</code> object to be used by the <code>SyncFactory</code>. */
private static volatile Logger rsLogger;
The registry of available SyncProvider implementations. See section 2.0 of the class comment for SyncFactory for an explanation of how a provider can be added to this registry.
/** * The registry of available <code>SyncProvider</code> implementations. * See section 2.0 of the class comment for <code>SyncFactory</code> for an * explanation of how a provider can be added to this registry. */
private static Hashtable<String, SyncProvider> implementations;
Adds the the given synchronization provider to the factory register. Guidelines are provided in the SyncProvider specification for the required naming conventions for SyncProvider implementations.

Synchronization providers bound to a JNDI context can be registered by binding a SyncProvider instance to a JNDI namespace.


SyncProvider p = new MySyncProvider();
InitialContext ic = new InitialContext();
ic.bind ("jdbc/rowset/MySyncProvider", p);
 
Furthermore, an initial JNDI context should be set with the SyncFactory using the setJNDIContext method. The SyncFactory leverages this context to search for available SyncProvider objects bound to the JNDI context and its child nodes.
Params:
  • providerID – A String object with the unique ID of the synchronization provider being registered
Throws:
See Also:
/** * Adds the the given synchronization provider to the factory register. Guidelines * are provided in the <code>SyncProvider</code> specification for the * required naming conventions for <code>SyncProvider</code> * implementations. * <p> * Synchronization providers bound to a JNDI context can be * registered by binding a SyncProvider instance to a JNDI namespace. * * <pre> * {@code * SyncProvider p = new MySyncProvider(); * InitialContext ic = new InitialContext(); * ic.bind ("jdbc/rowset/MySyncProvider", p); * } </pre> * * Furthermore, an initial JNDI context should be set with the * <code>SyncFactory</code> using the <code>setJNDIContext</code> method. * The <code>SyncFactory</code> leverages this context to search for * available <code>SyncProvider</code> objects bound to the JNDI * context and its child nodes. * * @param providerID A <code>String</code> object with the unique ID of the * synchronization provider being registered * @throws SyncFactoryException if an attempt is made to supply an empty * or null provider name * @see #setJNDIContext */
public static synchronized void registerProvider(String providerID) throws SyncFactoryException { ProviderImpl impl = new ProviderImpl(); impl.setClassname(providerID); initMapIfNecessary(); implementations.put(providerID, impl); }
Returns the SyncFactory singleton.
Returns:the SyncFactory instance
/** * Returns the <code>SyncFactory</code> singleton. * * @return the <code>SyncFactory</code> instance */
public static SyncFactory getSyncFactory() { /* * Using Initialization on Demand Holder idiom as * Effective Java 2nd Edition,ITEM 71, indicates it is more performant * than the Double-Check Locking idiom. */ return SyncFactoryHolder.factory; }
Removes the designated currently registered synchronization provider from the Factory SPI register.
Params:
  • providerID – The unique-id of the synchronization provider
Throws:
  • SyncFactoryException – If an attempt is made to unregister a SyncProvider implementation that was not registered.
/** * Removes the designated currently registered synchronization provider from the * Factory SPI register. * * @param providerID The unique-id of the synchronization provider * @throws SyncFactoryException If an attempt is made to * unregister a SyncProvider implementation that was not registered. */
public static synchronized void unregisterProvider(String providerID) throws SyncFactoryException { initMapIfNecessary(); if (implementations.containsKey(providerID)) { implementations.remove(providerID); } } private static String colon = ":"; private static String strFileSep = "/"; private static synchronized void initMapIfNecessary() throws SyncFactoryException { // Local implementation class names and keys from Properties // file, translate names into Class objects using Class.forName // and store mappings final Properties properties = new Properties(); if (implementations == null) { implementations = new Hashtable<>(); try { // check if user is supplying his Synchronisation Provider // Implementation if not using Oracle's implementation. // properties.load(new FileInputStream(ROWSET_PROPERTIES)); // The rowset.properties needs to be in jdk/jre/lib when // integrated with jdk. // else it should be picked from -D option from command line. // -Drowset.properties will add to standard properties. Similar // keys will over-write /* * Dependent on application */ String strRowsetProperties; try { strRowsetProperties = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("rowset.properties"); } }, null, new PropertyPermission("rowset.properties", "read")); } catch (Exception ex) { System.out.println("errorget rowset.properties: " + ex); strRowsetProperties = null; }; if (strRowsetProperties != null) { // Load user's implementation of SyncProvider // here. -Drowset.properties=/abc/def/pqr.txt ROWSET_PROPERTIES = strRowsetProperties; try (FileInputStream fis = new FileInputStream(ROWSET_PROPERTIES)) { properties.load(fis); } parseProperties(properties); } /* * Always available */ ROWSET_PROPERTIES = "javax" + strFileSep + "sql" + strFileSep + "rowset" + strFileSep + "rowset.properties"; ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { AccessController.doPrivileged((PrivilegedExceptionAction<Void>) () -> { try (InputStream stream = (cl == null) ? ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES) : cl.getResourceAsStream(ROWSET_PROPERTIES)) { if (stream == null) { throw new SyncFactoryException("Resource " + ROWSET_PROPERTIES + " not found"); } properties.load(stream); } return null; }); } catch (PrivilegedActionException ex) { Throwable e = ex.getException(); if (e instanceof SyncFactoryException) { throw (SyncFactoryException) e; } else { SyncFactoryException sfe = new SyncFactoryException(); sfe.initCause(ex.getException()); throw sfe; } } parseProperties(properties); // removed else, has properties should sum together } catch (FileNotFoundException e) { throw new SyncFactoryException("Cannot locate properties file: " + e); } catch (IOException e) { throw new SyncFactoryException("IOException: " + e); } /* * Now deal with -Drowset.provider.classname * load additional properties from -D command line */ properties.clear(); String providerImpls; try { providerImpls = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty(ROWSET_SYNC_PROVIDER); } }, null, new PropertyPermission(ROWSET_SYNC_PROVIDER, "read")); } catch (Exception ex) { providerImpls = null; } if (providerImpls != null) { int i = 0; if (providerImpls.indexOf(colon) > 0) { StringTokenizer tokenizer = new StringTokenizer(providerImpls, colon); while (tokenizer.hasMoreElements()) { properties.put(ROWSET_SYNC_PROVIDER + "." + i, tokenizer.nextToken()); i++; } } else { properties.put(ROWSET_SYNC_PROVIDER, providerImpls); } parseProperties(properties); } } }
The internal debug switch.
/** * The internal debug switch. */
private static boolean debug = false;
Internal registry count for the number of providers contained in the registry.
/** * Internal registry count for the number of providers contained in the * registry. */
private static int providerImplIndex = 0;
Internal handler for all standard property parsing. Parses standard ROWSET properties and stores lazy references into the the internal registry.
/** * Internal handler for all standard property parsing. Parses standard * ROWSET properties and stores lazy references into the the internal registry. */
private static void parseProperties(Properties p) { ProviderImpl impl = null; String key = null; String[] propertyNames = null; for (Enumeration<?> e = p.propertyNames(); e.hasMoreElements();) { String str = (String) e.nextElement(); int w = str.length(); if (str.startsWith(SyncFactory.ROWSET_SYNC_PROVIDER)) { impl = new ProviderImpl(); impl.setIndex(providerImplIndex++); if (w == (SyncFactory.ROWSET_SYNC_PROVIDER).length()) { // no property index has been set. propertyNames = getPropertyNames(false); } else { // property index has been set. propertyNames = getPropertyNames(true, str.substring(w - 1)); } key = p.getProperty(propertyNames[0]); impl.setClassname(key); impl.setVendor(p.getProperty(propertyNames[1])); impl.setVersion(p.getProperty(propertyNames[2])); implementations.put(key, impl); } } }
Used by the parseProperties methods to disassemble each property tuple.
/** * Used by the parseProperties methods to disassemble each property tuple. */
private static String[] getPropertyNames(boolean append) { return getPropertyNames(append, null); }
Disassembles each property and its associated value. Also handles overloaded property names that contain indexes.
/** * Disassembles each property and its associated value. Also handles * overloaded property names that contain indexes. */
private static String[] getPropertyNames(boolean append, String propertyIndex) { String dot = "."; String[] propertyNames = new String[]{SyncFactory.ROWSET_SYNC_PROVIDER, SyncFactory.ROWSET_SYNC_VENDOR, SyncFactory.ROWSET_SYNC_PROVIDER_VERSION}; if (append) { for (int i = 0; i < propertyNames.length; i++) { propertyNames[i] = propertyNames[i] + dot + propertyIndex; } return propertyNames; } else { return propertyNames; } }
Internal debug method that outputs the registry contents.
/** * Internal debug method that outputs the registry contents. */
private static void showImpl(ProviderImpl impl) { System.out.println("Provider implementation:"); System.out.println("Classname: " + impl.getClassname()); System.out.println("Vendor: " + impl.getVendor()); System.out.println("Version: " + impl.getVersion()); System.out.println("Impl index: " + impl.getIndex()); }
Returns the SyncProvider instance identified by providerID.
Params:
  • providerID – the unique identifier of the provider
Throws:
  • SyncFactoryException – If the SyncProvider cannot be found, the providerID is null, or some error was encountered when trying to invoke this provider.
Returns:a SyncProvider implementation
/** * Returns the <code>SyncProvider</code> instance identified by <i>providerID</i>. * * @param providerID the unique identifier of the provider * @return a <code>SyncProvider</code> implementation * @throws SyncFactoryException If the SyncProvider cannot be found, * the providerID is {@code null}, or * some error was encountered when trying to invoke this provider. */
public static SyncProvider getInstance(String providerID) throws SyncFactoryException { if(providerID == null) { throw new SyncFactoryException("The providerID cannot be null"); } initMapIfNecessary(); // populate HashTable initJNDIContext(); // check JNDI context for any additional bindings ProviderImpl impl = (ProviderImpl) implementations.get(providerID); if (impl == null) { // Requested SyncProvider is unavailable. Return default provider. return new com.sun.rowset.providers.RIOptimisticProvider(); } try { ReflectUtil.checkPackageAccess(providerID); } catch (java.security.AccessControlException e) { SyncFactoryException sfe = new SyncFactoryException(); sfe.initCause(e); throw sfe; } // Attempt to invoke classname from registered SyncProvider list Class<?> c = null; try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); /** * The SyncProvider implementation of the user will be in * the classpath. We need to find the ClassLoader which loads * this SyncFactory and try to load the SyncProvider class from * there. **/ c = Class.forName(providerID, true, cl); if (c != null) { return (SyncProvider) c.newInstance(); } else { return new com.sun.rowset.providers.RIOptimisticProvider(); } } catch (IllegalAccessException e) { throw new SyncFactoryException("IllegalAccessException: " + e.getMessage()); } catch (InstantiationException e) { throw new SyncFactoryException("InstantiationException: " + e.getMessage()); } catch (ClassNotFoundException e) { throw new SyncFactoryException("ClassNotFoundException: " + e.getMessage()); } }
Returns an Enumeration of currently registered synchronization providers. A RowSet implementation may use any provider in the enumeration as its SyncProvider object.

At a minimum, the reference synchronization provider allowing RowSet content data to be stored using a JDBC driver should be possible.

Throws:
Returns:Enumeration A enumeration of available synchronization providers that are registered with this Factory
/** * Returns an Enumeration of currently registered synchronization * providers. A <code>RowSet</code> implementation may use any provider in * the enumeration as its <code>SyncProvider</code> object. * <p> * At a minimum, the reference synchronization provider allowing * RowSet content data to be stored using a JDBC driver should be * possible. * * @return Enumeration A enumeration of available synchronization * providers that are registered with this Factory * @throws SyncFactoryException If an error occurs obtaining the registered * providers */
public static Enumeration<SyncProvider> getRegisteredProviders() throws SyncFactoryException { initMapIfNecessary(); // return a collection of classnames // of type SyncProvider return implementations.elements(); }
Sets the logging object to be used by the SyncProvider implementation provided by the SyncFactory. All SyncProvider implementations can log their events to this object and the application can retrieve a handle to this object using the getLogger method.

This method checks to see that there is an SQLPermission object which grants the permission setSyncFactory before allowing the method to succeed. If a SecurityManager exists and its checkPermission method denies calling setLogger, this method throws a java.lang.SecurityException.

Params:
  • logger – A Logger object instance
Throws:
See Also:
/** * Sets the logging object to be used by the <code>SyncProvider</code> * implementation provided by the <code>SyncFactory</code>. All * <code>SyncProvider</code> implementations can log their events to * this object and the application can retrieve a handle to this * object using the <code>getLogger</code> method. * <p> * This method checks to see that there is an {@code SQLPermission} * object which grants the permission {@code setSyncFactory} * before allowing the method to succeed. If a * {@code SecurityManager} exists and its * {@code checkPermission} method denies calling {@code setLogger}, * this method throws a * {@code java.lang.SecurityException}. * * @param logger A Logger object instance * @throws java.lang.SecurityException if a security manager exists and its * {@code checkPermission} method denies calling {@code setLogger} * @throws NullPointerException if the logger is null * @see SecurityManager#checkPermission */
public static void setLogger(Logger logger) { SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkPermission(SET_SYNCFACTORY_PERMISSION); } if(logger == null){ throw new NullPointerException("You must provide a Logger"); } rsLogger = logger; }
Sets the logging object that is used by SyncProvider implementations provided by the SyncFactory SPI. All SyncProvider implementations can log their events to this object and the application can retrieve a handle to this object using the getLogger method.

This method checks to see that there is an SQLPermission object which grants the permission setSyncFactory before allowing the method to succeed. If a SecurityManager exists and its checkPermission method denies calling setLogger, this method throws a java.lang.SecurityException.

Params:
  • logger – a Logger object instance
  • level – a Level object instance indicating the degree of logging required
Throws:
See Also:
/** * Sets the logging object that is used by <code>SyncProvider</code> * implementations provided by the <code>SyncFactory</code> SPI. All * <code>SyncProvider</code> implementations can log their events * to this object and the application can retrieve a handle to this * object using the <code>getLogger</code> method. * <p> * This method checks to see that there is an {@code SQLPermission} * object which grants the permission {@code setSyncFactory} * before allowing the method to succeed. If a * {@code SecurityManager} exists and its * {@code checkPermission} method denies calling {@code setLogger}, * this method throws a * {@code java.lang.SecurityException}. * * @param logger a Logger object instance * @param level a Level object instance indicating the degree of logging * required * @throws java.lang.SecurityException if a security manager exists and its * {@code checkPermission} method denies calling {@code setLogger} * @throws NullPointerException if the logger is null * @see SecurityManager#checkPermission * @see LoggingPermission */
public static void setLogger(Logger logger, Level level) { // singleton SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkPermission(SET_SYNCFACTORY_PERMISSION); } if(logger == null){ throw new NullPointerException("You must provide a Logger"); } logger.setLevel(level); rsLogger = logger; }
Returns the logging object for applications to retrieve synchronization events posted by SyncProvider implementations.
Throws:
Returns:The Logger that has been specified for use by SyncProvider implementations
/** * Returns the logging object for applications to retrieve * synchronization events posted by SyncProvider implementations. * @return The {@code Logger} that has been specified for use by * {@code SyncProvider} implementations * @throws SyncFactoryException if no logging object has been set. */
public static Logger getLogger() throws SyncFactoryException { Logger result = rsLogger; // only one logger per session if (result == null) { throw new SyncFactoryException("(SyncFactory) : No logger has been set"); } return result; }
Sets the initial JNDI context from which SyncProvider implementations can be retrieved from a JNDI namespace

This method checks to see that there is an SQLPermission object which grants the permission setSyncFactory before allowing the method to succeed. If a SecurityManager exists and its checkPermission method denies calling setJNDIContext, this method throws a java.lang.SecurityException.

Params:
  • ctx – a valid JNDI context
Throws:
See Also:
/** * Sets the initial JNDI context from which SyncProvider implementations * can be retrieved from a JNDI namespace * <p> * This method checks to see that there is an {@code SQLPermission} * object which grants the permission {@code setSyncFactory} * before allowing the method to succeed. If a * {@code SecurityManager} exists and its * {@code checkPermission} method denies calling {@code setJNDIContext}, * this method throws a * {@code java.lang.SecurityException}. * * @param ctx a valid JNDI context * @throws SyncFactoryException if the supplied JNDI context is null * @throws java.lang.SecurityException if a security manager exists and its * {@code checkPermission} method denies calling {@code setJNDIContext} * @see SecurityManager#checkPermission */
public static synchronized void setJNDIContext(javax.naming.Context ctx) throws SyncFactoryException { SecurityManager sec = System.getSecurityManager(); if (sec != null) { sec.checkPermission(SET_SYNCFACTORY_PERMISSION); } if (ctx == null) { throw new SyncFactoryException("Invalid JNDI context supplied"); } ic = ctx; }
Controls JNDI context initialization.
Throws:
  • SyncFactoryException – if an error occurs parsing the JNDI context
/** * Controls JNDI context initialization. * * @throws SyncFactoryException if an error occurs parsing the JNDI context */
private static synchronized void initJNDIContext() throws SyncFactoryException { if ((ic != null) && (lazyJNDICtxRefresh == false)) { try { parseProperties(parseJNDIContext()); lazyJNDICtxRefresh = true; // touch JNDI namespace once. } catch (NamingException e) { e.printStackTrace(); throw new SyncFactoryException("SPI: NamingException: " + e.getExplanation()); } catch (Exception e) { e.printStackTrace(); throw new SyncFactoryException("SPI: Exception: " + e.getMessage()); } } }
Internal switch indicating whether the JNDI namespace should be re-read.
/** * Internal switch indicating whether the JNDI namespace should be re-read. */
private static boolean lazyJNDICtxRefresh = false;
Parses the set JNDI Context and passes bindings to the enumerateBindings method when complete.
/** * Parses the set JNDI Context and passes bindings to the enumerateBindings * method when complete. */
private static Properties parseJNDIContext() throws NamingException { NamingEnumeration<?> bindings = ic.listBindings(""); Properties properties = new Properties(); // Hunt one level below context for available SyncProvider objects enumerateBindings(bindings, properties); return properties; }
Scans each binding on JNDI context and determines if any binding is an instance of SyncProvider, if so, add this to the registry and continue to scan the current context using a re-entrant call to this method until all bindings have been enumerated.
/** * Scans each binding on JNDI context and determines if any binding is an * instance of SyncProvider, if so, add this to the registry and continue to * scan the current context using a re-entrant call to this method until all * bindings have been enumerated. */
private static void enumerateBindings(NamingEnumeration<?> bindings, Properties properties) throws NamingException { boolean syncProviderObj = false; // move to parameters ? try { Binding bd = null; Object elementObj = null; String element = null; while (bindings.hasMore()) { bd = (Binding) bindings.next(); element = bd.getName(); elementObj = bd.getObject(); if (!(ic.lookup(element) instanceof Context)) { // skip directories/sub-contexts if (ic.lookup(element) instanceof SyncProvider) { syncProviderObj = true; } } if (syncProviderObj) { SyncProvider sync = (SyncProvider) elementObj; properties.put(SyncFactory.ROWSET_SYNC_PROVIDER, sync.getProviderID()); syncProviderObj = false; // reset } } } catch (javax.naming.NotContextException e) { bindings.next(); // Re-entrant call into method enumerateBindings(bindings, properties); } }
Lazy initialization Holder class used by getSyncFactory
/** * Lazy initialization Holder class used by {@code getSyncFactory} */
private static class SyncFactoryHolder { static final SyncFactory factory = new SyncFactory(); } }
Internal class that defines the lazy reference construct for each registered SyncProvider implementation.
/** * Internal class that defines the lazy reference construct for each registered * SyncProvider implementation. */
class ProviderImpl extends SyncProvider { private String className = null; private String vendorName = null; private String ver = null; private int index; public void setClassname(String classname) { className = classname; } public String getClassname() { return className; } public void setVendor(String vendor) { vendorName = vendor; } public String getVendor() { return vendorName; } public void setVersion(String providerVer) { ver = providerVer; } public String getVersion() { return ver; } public void setIndex(int i) { index = i; } public int getIndex() { return index; } public int getDataSourceLock() throws SyncProviderException { int dsLock = 0; try { dsLock = SyncFactory.getInstance(className).getDataSourceLock(); } catch (SyncFactoryException sfEx) { throw new SyncProviderException(sfEx.getMessage()); } return dsLock; } public int getProviderGrade() { int grade = 0; try { grade = SyncFactory.getInstance(className).getProviderGrade(); } catch (SyncFactoryException sfEx) { // } return grade; } public String getProviderID() { return className; } /* public javax.sql.RowSetInternal getRowSetInternal() { try { return SyncFactory.getInstance(className).getRowSetInternal(); } catch(SyncFactoryException sfEx) { // } } */ public javax.sql.RowSetReader getRowSetReader() { RowSetReader rsReader = null; try { rsReader = SyncFactory.getInstance(className).getRowSetReader(); } catch (SyncFactoryException sfEx) { // } return rsReader; } public javax.sql.RowSetWriter getRowSetWriter() { RowSetWriter rsWriter = null; try { rsWriter = SyncFactory.getInstance(className).getRowSetWriter(); } catch (SyncFactoryException sfEx) { // } return rsWriter; } public void setDataSourceLock(int param) throws SyncProviderException { try { SyncFactory.getInstance(className).setDataSourceLock(param); } catch (SyncFactoryException sfEx) { throw new SyncProviderException(sfEx.getMessage()); } } public int supportsUpdatableView() { int view = 0; try { view = SyncFactory.getInstance(className).supportsUpdatableView(); } catch (SyncFactoryException sfEx) { // } return view; } }