| /* |
| * Copyright (c) 2003, 2006, 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.Map; |
| import java.util.Hashtable; |
| import java.util.Enumeration; |
| import java.util.Vector; |
| import java.util.Properties; |
| import java.util.Collection; |
| import java.util.StringTokenizer; |
| import java.util.logging.*; |
| import java.util.*; |
| |
| import java.sql.*; |
| import javax.sql.*; |
| |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.FileNotFoundException; |
| |
| import javax.naming.*; |
| |
| /** |
| * 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. |
| * <p> |
| * <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> |
| * implemtations <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. |
| * <p> |
| * <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. |
| * <p> |
| * <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=Sun Microsystems Inc |
| * 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=Sun Microsystems Inc. |
| * 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> |
| * <p> |
| * <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 { |
| |
| /* |
| * The variable that represents the singleton instance |
| * of the <code>SyncFactory</code> class. |
| */ |
| private static SyncFactory syncFactory = null; |
| |
| /** |
| * 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. |
| */ |
| public static String ROWSET_SYNC_PROVIDER = |
| "rowset.provider.classname"; |
| |
| /** |
| * The standard property-id for a synchronization provider implementation |
| * vendor name. |
| */ |
| public static String ROWSET_SYNC_VENDOR = |
| "rowset.provider.vendor"; |
| |
| /** |
| * The standard property-id for a synchronization provider implementation |
| * version tag. |
| */ |
| public static String ROWSET_SYNC_PROVIDER_VERSION = |
| "rowset.provider.version"; |
| |
| /** |
| * The standard resource file name. |
| */ |
| private static String ROWSET_PROPERTIES = "rowset.properties"; |
| |
| /** |
| * The RI Optimistic Provider. |
| */ |
| private static String default_provider = |
| "com.sun.rowset.providers.RIOptimisticProvider"; |
| |
| /** |
| * The initial JNDI context where <code>SyncProvider</code> implementations can |
| * be stored and from which they can be invoked. |
| */ |
| private static Context ic; |
| |
| /** |
| * The <code>Logger</code> object to be used by the <code>SyncFactory</code>. |
| */ |
| private static Logger rsLogger; |
| |
| /** |
| * |
| */ |
| private static Level rsLevel; |
| |
| /** |
| * 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 implementations; |
| |
| /** |
| * Internal sync object used to maintain the SPI as a singleton |
| */ |
| private static Object logSync = new Object(); |
| |
| /** |
| * Internal PrintWriter field for logging facility |
| */ |
| private static java.io.PrintWriter logWriter = null; |
| |
| /** |
| * 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. |
| * <ul> |
| * <pre> |
| * SyncProvider p = new MySyncProvider(); |
| * InitialContext ic = new InitialContext(); |
| * ic.bind ("jdbc/rowset/MySyncProvider", p); |
| * </pre> |
| * </ul> |
| * 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 <code>SyncFactory</code> singleton. |
| * |
| * @return the <code>SyncFactory</code> instance |
| */ |
| public static SyncFactory getSyncFactory(){ |
| |
| // This method uses the Singleton Design Pattern |
| // with Double-Checked Locking Pattern for |
| // 1. Creating single instance of the SyncFactory |
| // 2. Make the class thread safe, so that at one time |
| // only one thread enters the synchronized block |
| // to instantiate. |
| |
| // if syncFactory object is already there |
| // don't go into synchronized block and return |
| // that object. |
| // else go into synchronized block |
| |
| if(syncFactory == null){ |
| synchronized(SyncFactory.class) { |
| if(syncFactory == null){ |
| syncFactory = new SyncFactory(); |
| } //end if |
| } //end synchronized block |
| } //end if |
| return syncFactory; |
| } |
| |
| /** |
| * 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 |
| Properties properties = new Properties(); |
| |
| if (implementations == null) { |
| implementations = new Hashtable(); |
| |
| try { |
| |
| // check if user is supplying his Synchronisation Provider |
| // Implementation if not use Sun'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 = System.getProperty("rowset.properties"); |
| if ( strRowsetProperties != null) { |
| // Load user's implementation of SyncProvider |
| // here. -Drowset.properties=/abc/def/pqr.txt |
| ROWSET_PROPERTIES = strRowsetProperties; |
| properties.load(new FileInputStream(ROWSET_PROPERTIES)); |
| parseProperties(properties); |
| } |
| |
| /* |
| * Always available |
| */ |
| ROWSET_PROPERTIES = "javax" + strFileSep + "sql" + |
| strFileSep + "rowset" + strFileSep + |
| "rowset.properties"; |
| // properties.load( |
| // ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES)); |
| |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| |
| properties.load(cl.getResourceAsStream(ROWSET_PROPERTIES)); |
| 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 = System.getProperty(ROWSET_SYNC_PROVIDER); |
| |
| 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 boolean switch that indicates whether a JNDI |
| * context has been established or not. |
| */ |
| private static boolean jndiCtxEstablished = false; |
| |
| /** |
| * The internal debug switch. |
| */ |
| private static boolean debug = false; |
| |
| /** |
| * 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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 <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 or |
| * some error was encountered when trying to invoke this provider. |
| */ |
| public static SyncProvider getInstance(String providerID) |
| throws SyncFactoryException { |
| 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(); |
| } |
| |
| // 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 laod 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 <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 |
| */ |
| 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 <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. |
| * |
| * @param logger A Logger object instance |
| */ |
| public static void setLogger(Logger logger) { |
| rsLogger = logger; |
| } |
| |
| /** |
| * 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. |
| * |
| * @param logger a Logger object instance |
| * @param level a Level object instance indicating the degree of logging |
| * required |
| */ |
| public static void setLogger(Logger logger, Level level) { |
| // singleton |
| |
| rsLogger = logger; |
| rsLogger.setLevel(level); |
| } |
| |
| /** |
| * Returns the logging object for applications to retrieve |
| * synchronization events posted by SyncProvider implementations. |
| * |
| * @throws SyncFactoryException if no logging object has been set. |
| */ |
| public static Logger getLogger() throws SyncFactoryException { |
| // only one logger per session |
| if(rsLogger == null){ |
| throw new SyncFactoryException("(SyncFactory) : No logger has been set"); |
| } |
| return rsLogger; |
| } |
| |
| /** |
| * Sets the initial JNDI context from which SyncProvider implementations |
| * can be retrieved from a JNDI namespace |
| * |
| * @param ctx a valid JNDI context |
| * @throws SyncFactoryException if the supplied JNDI context is null |
| */ |
| public static void setJNDIContext(javax.naming.Context ctx) |
| throws SyncFactoryException { |
| if (ctx == null) { |
| throw new SyncFactoryException("Invalid JNDI context supplied"); |
| } |
| ic = ctx; |
| jndiCtxEstablished = true; |
| } |
| |
| /** |
| * Controls JNDI context intialization. |
| * |
| * @throws SyncFactoryException if an error occurs parsing the JNDI context |
| */ |
| private static void initJNDIContext() throws SyncFactoryException { |
| |
| if (jndiCtxEstablished && (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. |
| */ |
| private static boolean lazyJNDICtxRefresh = false; |
| |
| /** |
| * 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. |
| */ |
| 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); |
| } |
| } |
| } |
| |
| /** |
| * 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; |
| } |
| |
| } |