1. /*
  2. * @(#)SyncFactory.java 1.13 04/07/17
  3. * @(#)SyncFactory.java 1.11 04/06/25
  4. *
  5. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  6. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  7. */
  8. package javax.sql.rowset.spi;
  9. import java.util.Map;
  10. import java.util.Hashtable;
  11. import java.util.Enumeration;
  12. import java.util.Vector;
  13. import java.util.Properties;
  14. import java.util.Collection;
  15. import java.util.StringTokenizer;
  16. import java.util.logging.*;
  17. import java.util.*;
  18. import java.sql.*;
  19. import javax.sql.*;
  20. import java.io.FileInputStream;
  21. import java.io.IOException;
  22. import java.io.FileNotFoundException;
  23. import javax.naming.*;
  24. /**
  25. * The Service Provider Interface (SPI) mechanism that generates <code>SyncProvider</code>
  26. * instances to be used by disconnected <code>RowSet</code> objects.
  27. * The <code>SyncProvider</code> instances in turn provide the
  28. * <code>javax.sql.RowSetReader</code> object the <code>RowSet</code> object
  29. * needs to populate itself with data and the
  30. * <code>javax.sql.RowSetWriter</code> object it needs to
  31. * propagate changes to its
  32. * data back to the underlying data source.
  33. * <P>
  34. * Because the methods in the <code>SyncFactory</code> class are all static,
  35. * there is only one <code>SyncFactory</code> object
  36. * per Java VM at any one time. This ensures that there is a single source from which a
  37. * <code>RowSet</code> implementation can obtain its <code>SyncProvider</code>
  38. * implementation.
  39. * <p>
  40. * <h3>1.0 Overview</h3>
  41. * The <code>SyncFactory</code> class provides an internal registry of available
  42. * synchronization provider implementations (<code>SyncProvider</code> objects).
  43. * This registry may be queried to determine which
  44. * synchronization providers are available.
  45. * The following line of code gets an enumeration of the providers currently registered.
  46. * <PRE>
  47. * java.util.Enumeration e = SyncFactory.getRegisteredProviders();
  48. * </PRE>
  49. * All standard <code>RowSet</code> implementations must provide at least two providers:
  50. * <UL>
  51. * <LI>an optimistic provider for use with a <code>CachedRowSet</code> implementation
  52. * or an implementation derived from it
  53. * <LI>an XML provider, which is used for reading and writing XML, such as with
  54. * <code>WebRowSet</code> objects
  55. * </UL>
  56. * Note that the JDBC RowSet Implementations include the <code>SyncProvider</code>
  57. * implemtations <code>RIOptimisticProvider</code> and <code>RIXmlProvider</code>,
  58. * which satisfy this requirement.
  59. * <P>
  60. * The <code>SyncFactory</code> class provides accessor methods to assist
  61. * applications in determining which synchronization providers are currently
  62. * registered with the <code>SyncFactory</code>.
  63. * <p>
  64. * Other methods let <code>RowSet</code> persistence providers be
  65. * registered or de-registered with the factory mechanism. This
  66. * allows additional synchronization provider implementations to be made
  67. * available to <code>RowSet</code> objects at run time.
  68. * <p>
  69. * Applications can apply a degree of filtering to determine the level of
  70. * synchronization that a <code>SyncProvider</code> implementation offers.
  71. * The following criteria determine whether a provider is
  72. * made available to a <code>RowSet</code> object:
  73. * <ol>
  74. * <li>If a particular provider is specified by a <code>RowSet</code> object, and
  75. * the <code>SyncFactory</code> does not contain a reference to this provider,
  76. * a <code>SyncFactoryException</code> is thrown stating that the synchronization
  77. * provider could not be found.
  78. * <p>
  79. * <li>If a <code>RowSet</code> implementation is instantiated with a specified
  80. * provider and the specified provider has been properly registered, the
  81. * requested provider is supplied. Otherwise a <code>SyncFactoryException</code>
  82. * is thrown.
  83. * <p>
  84. * <li>If a <code>RowSet</code> object does not specify a
  85. * <code>SyncProvider</code> implementation and no additional
  86. * <code>SyncProvider</code> implementations are available, the reference
  87. * implementation providers are supplied.
  88. * </ol>
  89. * <h3>2.0 Registering <code>SyncProvider</code> Implementations</h3>
  90. * <p>
  91. * Both vendors and developers can register <code>SyncProvider</code>
  92. * implementations using one of the following mechanisms.
  93. * <ul>
  94. * <LI><B>Using the command line</B><BR>
  95. * The name of the provider is supplied on the command line, which will add
  96. * the provider to the system properties.
  97. * For example:
  98. * <PRE>
  99. * -Drowset.provider.classname=com.fred.providers.HighAvailabilityProvider
  100. * </PRE>
  101. * <li><b>Using the Standard Properties File</b><BR>
  102. * The reference implementation is targeted
  103. * to ship with J2SE 1.5, which will include an additional resource file
  104. * that may be edited by hand. Here is an example of the properties file
  105. * included in the reference implementation:
  106. * <PRE>
  107. * #Default JDBC RowSet sync providers listing
  108. * #
  109. *
  110. * # Optimistic synchronization provider
  111. * rowset.provider.classname.0=com.sun.rowset.providers.RIOptimisticProvider
  112. * rowset.provider.vendor.0=Sun Microsystems Inc
  113. * rowset.provider.version.0=1.0
  114. *
  115. * # XML Provider using standard XML schema
  116. * rowset.provider.classname.1=com.sun.rowset.providers.RIXMLProvider
  117. * rowset.provider.vendor.1=Sun Microsystems Inc.
  118. * rowset.provider.version.1=1.0
  119. * </PRE>
  120. * The <code>SyncFactory</code> checks this file and registers the
  121. * <code>SyncProvider</code> implementations that it contains. A
  122. * developer or vendor can add other implementations to this file.
  123. * For example, here is a possible addition:
  124. * <PRE>
  125. * rowset.provider.classname.2=com.fred.providers.HighAvailabilityProvider
  126. * rowset.provider.vendor.2=Fred, Inc.
  127. * rowset.provider.version.2=1.0
  128. * </PRE>
  129. * <p>
  130. * <li><b>Using a JNDI Context</b><BR>
  131. * Available providers can be registered on a JNDI
  132. * context, and the <code>SyncFactory</code> will attempt to load
  133. * <code>SyncProvider</code> implementations from that JNDI context.
  134. * For example, the following code fragment registers a provider implementation
  135. * on a JNDI context. This is something a deployer would normally do. In this
  136. * example, <code>MyProvider</code> is being registered on a CosNaming
  137. * namespace, which is the namespace used by J2EE resources.
  138. * <PRE>
  139. * import javax.naming.*;
  140. *
  141. * Hashtable svrEnv = new Hashtable();
  142. * srvEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
  143. *
  144. * Context ctx = new InitialContext(svrEnv);
  145. * com.fred.providers.MyProvider = new MyProvider();
  146. * ctx.rebind("providers/MyProvider", syncProvider);
  147. * </PRE>
  148. * </ul>
  149. * Next, an application will register the JNDI context with the
  150. * <code>SyncFactory</code> instance. This allows the <code>SyncFactory</code>
  151. * to browse within the JNDI context looking for <code>SyncProvider</code>
  152. * implementations.
  153. * <PRE>
  154. * Hashtable appEnv = new Hashtable();
  155. * appEnv.put(Context.INITIAL_CONTEXT_FACTORY, "CosNaming");
  156. * appEnv.put(Context.PROVIDER_URL, "iiop://hostname/providers");
  157. * Context ctx = new InitialContext(appEnv);
  158. *
  159. * SyncFactory.registerJNDIContext(ctx);
  160. * </PRE>
  161. * If a <code>RowSet</code> object attempts to obtain a <code>MyProvider</code>
  162. * object, the <code>SyncFactory</code> will try to locate it. First it searches
  163. * for it in the system properties, then it looks in the resource files, and
  164. * finally it checks the JNDI context that has been set. The <code>SyncFactory</code>
  165. * instance verifies that the requested provider is a valid extension of the
  166. * <code>SyncProvider</code> abstract class and then gives it to the
  167. * <code>RowSet</code> object. In the following code fragment, a new
  168. * <code>CachedRowSet</code> object is created and initialized with
  169. * <i>env</i>, which contains the binding to <code>MyProvider</code>.
  170. * <PRE>
  171. * Hashtable env = new Hashtable();
  172. * env.put(SyncFactory.ROWSET_SYNC_PROVIDER, "com.fred.providers.MyProvider");
  173. * CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl(env);
  174. * </PRE>
  175. * Further details on these mechanisms are available in the
  176. * <code>javax.sql.rowset.spi</code> package specification.
  177. *
  178. * @author Jonathan Bruce
  179. * @see javax.sql.rowset.spi.SyncProvider
  180. * @see javax.sql.rowset.spi.SyncFactoryException
  181. */
  182. public class SyncFactory {
  183. /*
  184. * The variable that represents the singleton instance
  185. * of the <code>SyncFactory</code> class.
  186. */
  187. private static SyncFactory syncFactory = null;
  188. /**
  189. * Creates a new <code>SyncFactory</code> object, which is the singleton
  190. * instance.
  191. * Having a private constructor guarantees that no more than
  192. * one <code>SyncProvider</code> object can exist at a time.
  193. */
  194. private SyncFactory() {};
  195. /**
  196. * The standard property-id for a synchronization provider implementation
  197. * name.
  198. */
  199. public static String ROWSET_SYNC_PROVIDER =
  200. "rowset.provider.classname";
  201. /**
  202. * The standard property-id for a synchronization provider implementation
  203. * vendor name.
  204. */
  205. public static String ROWSET_SYNC_VENDOR =
  206. "rowset.provider.vendor";
  207. /**
  208. * The standard property-id for a synchronization provider implementation
  209. * version tag.
  210. */
  211. public static String ROWSET_SYNC_PROVIDER_VERSION =
  212. "rowset.provider.version";
  213. /**
  214. * The standard resource file name.
  215. */
  216. private static String ROWSET_PROPERTIES = "rowset.properties";
  217. /**
  218. * The RI Optimistic Provider.
  219. */
  220. private static String default_provider =
  221. "com.sun.rowset.providers.RIOptimisticProvider";
  222. /**
  223. * The initial JNDI context where <code>SyncProvider</code> implementations can
  224. * be stored and from which they can be invoked.
  225. */
  226. private static Context ic;
  227. /**
  228. * The <code>Logger</code> object to be used by the <code>SyncFactory</code>.
  229. */
  230. private static Logger rsLogger;
  231. /**
  232. *
  233. */
  234. private static Level rsLevel;
  235. /**
  236. * The registry of available <code>SyncProvider</code> implementations.
  237. * See section 2.0 of the class comment for <code>SyncFactory</code> for an
  238. * explanation of how a provider can be added to this registry.
  239. */
  240. private static Hashtable implementations;
  241. /**
  242. * Internal sync object used to maintain the SPI as a singleton
  243. */
  244. private static Object logSync = new Object();
  245. /**
  246. * Internal PrintWriter field for logging facility
  247. */
  248. private static java.io.PrintWriter logWriter = null;
  249. /**
  250. * Adds the the given synchronization provider to the factory register. Guidelines
  251. * are provided in the <code>SyncProvider</code> specification for the
  252. * required naming conventions for <code>SyncProvider</code>
  253. * implementations.
  254. * <p>
  255. * Synchronization providers bound to a JNDI context can be
  256. * registered by binding a SyncProvider instance to a JNDI namespace.
  257. * <ul>
  258. * <pre>
  259. * SyncProvider p = new MySyncProvider();
  260. * InitialContext ic = new InitialContext();
  261. * ic.bind ("jdbc/rowset/MySyncProvider", p);
  262. * </pre>
  263. * </ul>
  264. * Furthermore, an initial JNDI context should be set with the
  265. * <code>SyncFactory</code> using the <code>setJNDIContext</code> method.
  266. * The <code>SyncFactory</code> leverages this context to search for
  267. * available <code>SyncProvider</code> objects bound to the JNDI
  268. * context and its child nodes.
  269. *
  270. * @param providerID A <code>String</code> object with the unique ID of the
  271. * synchronization provider being registered
  272. * @throws SyncFactoryException if an attempt is made to supply an empty
  273. * or null provider name
  274. * @see #setJNDIContext
  275. */
  276. public static synchronized void registerProvider(String providerID)
  277. throws SyncFactoryException {
  278. ProviderImpl impl = new ProviderImpl();
  279. impl.setClassname(providerID);
  280. initMapIfNecessary();
  281. implementations.put(providerID, impl);
  282. }
  283. /**
  284. * Returns the <code>SyncFactory</code> singleton.
  285. *
  286. * @return the <code>SyncFactory</code> instance
  287. */
  288. public static SyncFactory getSyncFactory(){
  289. // This method uses the Singleton Design Pattern
  290. // with Double-Checked Locking Pattern for
  291. // 1. Creating single instance of the SyncFactory
  292. // 2. Make the class thread safe, so that at one time
  293. // only one thread enters the synchronized block
  294. // to instantiate.
  295. // if syncFactory object is already there
  296. // don't go into synchronized block and return
  297. // that object.
  298. // else go into synchronized block
  299. if(syncFactory == null){
  300. synchronized(SyncFactory.class) {
  301. if(syncFactory == null){
  302. syncFactory = new SyncFactory();
  303. } //end if
  304. } //end synchronized block
  305. } //end if
  306. return syncFactory;
  307. }
  308. /**
  309. * Removes the designated currently registered synchronization provider from the
  310. * Factory SPI register.
  311. *
  312. * @param providerID The unique-id of the synchronization provider
  313. * @throws SyncFactoryException If an attempt is made to
  314. * unregister a SyncProvider implementation that was not registered.
  315. */
  316. public static synchronized void unregisterProvider(String providerID)
  317. throws SyncFactoryException {
  318. initMapIfNecessary();
  319. if (implementations.containsKey(providerID)) {
  320. implementations.remove(providerID);
  321. }
  322. }
  323. private static String colon = ":";
  324. private static String strFileSep = "/";
  325. private static synchronized void initMapIfNecessary() throws SyncFactoryException {
  326. // Local implementation class names and keys from Properties
  327. // file, translate names into Class objects using Class.forName
  328. // and store mappings
  329. Properties properties = new Properties();
  330. if (implementations == null) {
  331. implementations = new Hashtable();
  332. try {
  333. // check if user is supplying his Synchronisation Provider
  334. // Implementation if not use Sun's implementation.
  335. // properties.load(new FileInputStream(ROWSET_PROPERTIES));
  336. // The rowset.properties needs to be in jdk/jre/lib when
  337. // integrated with jdk.
  338. // else it should be picked from -D option from command line.
  339. // -Drowset.properties will add to standard properties. Similar
  340. // keys will over-write
  341. /*
  342. * Dependent on application
  343. */
  344. String strRowsetProperties = System.getProperty("rowset.properties");
  345. if ( strRowsetProperties != null) {
  346. // Load user's implementation of SyncProvider
  347. // here. -Drowset.properties=/abc/def/pqr.txt
  348. ROWSET_PROPERTIES = strRowsetProperties;
  349. properties.load(new FileInputStream(ROWSET_PROPERTIES));
  350. parseProperties(properties);
  351. }
  352. /*
  353. * Always available
  354. */
  355. ROWSET_PROPERTIES = "javax" + strFileSep + "sql" +
  356. strFileSep + "rowset" + strFileSep +
  357. "rowset.properties";
  358. // properties.load(
  359. // ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES));
  360. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  361. properties.load(cl.getResourceAsStream(ROWSET_PROPERTIES));
  362. parseProperties(properties);
  363. // removed else, has properties should sum together
  364. } catch (FileNotFoundException e) {
  365. throw new SyncFactoryException("Cannot locate properties file: " + e);
  366. } catch (IOException e) {
  367. throw new SyncFactoryException("IOException: " + e);
  368. }
  369. /*
  370. * Now deal with -Drowset.provider.classname
  371. * load additional properties from -D command line
  372. */
  373. properties.clear();
  374. String providerImpls = System.getProperty(ROWSET_SYNC_PROVIDER);
  375. if (providerImpls != null) {
  376. int i = 0;
  377. if (providerImpls.indexOf(colon) > 0) {
  378. StringTokenizer tokenizer = new StringTokenizer(providerImpls, colon);
  379. while (tokenizer.hasMoreElements()) {
  380. properties.put(ROWSET_SYNC_PROVIDER + "." + i, tokenizer.nextToken());
  381. i++;
  382. }
  383. } else {
  384. properties.put(ROWSET_SYNC_PROVIDER, providerImpls);
  385. }
  386. parseProperties(properties);
  387. }
  388. }
  389. }
  390. /**
  391. * The internal boolean switch that indicates whether a JNDI
  392. * context has been established or not.
  393. */
  394. private static boolean jndiCtxEstablished = false;
  395. /**
  396. * The internal debug switch.
  397. */
  398. private static boolean debug = false;
  399. /**
  400. * Internal registry count for the number of providers contained in the
  401. * registry.
  402. */
  403. private static int providerImplIndex = 0;
  404. /**
  405. * Internal handler for all standard property parsing. Parses standard
  406. * ROWSET properties and stores lazy references into the the internal registry.
  407. */
  408. private static void parseProperties(Properties p) {
  409. ProviderImpl impl = null;
  410. String key = null;
  411. String[] propertyNames = null;
  412. for (Enumeration e = p.propertyNames(); e.hasMoreElements() ;) {
  413. String str = (String)e.nextElement();
  414. int w = str.length();
  415. if (str.startsWith(SyncFactory.ROWSET_SYNC_PROVIDER)) {
  416. impl = new ProviderImpl();
  417. impl.setIndex(providerImplIndex++);
  418. if (w == (SyncFactory.ROWSET_SYNC_PROVIDER).length()) {
  419. // no property index has been set.
  420. propertyNames = getPropertyNames(false);
  421. } else {
  422. // property index has been set.
  423. propertyNames = getPropertyNames(true, str.substring(w-1));
  424. }
  425. key = p.getProperty(propertyNames[0]);
  426. impl.setClassname(key);
  427. impl.setVendor(p.getProperty(propertyNames[1]));
  428. impl.setVersion(p.getProperty(propertyNames[2]));
  429. implementations.put(key, impl);
  430. }
  431. }
  432. }
  433. /**
  434. * Used by the parseProperties methods to disassemble each property tuple.
  435. */
  436. private static String[] getPropertyNames(boolean append) {
  437. return getPropertyNames(append, null);
  438. }
  439. /**
  440. * Disassembles each property and its associated value. Also handles
  441. * overloaded property names that contain indexes.
  442. */
  443. private static String[] getPropertyNames(boolean append,
  444. String propertyIndex) {
  445. String dot = ".";
  446. String[] propertyNames =
  447. new String[] {SyncFactory.ROWSET_SYNC_PROVIDER,
  448. SyncFactory.ROWSET_SYNC_VENDOR,
  449. SyncFactory.ROWSET_SYNC_PROVIDER_VERSION};
  450. if (append) {
  451. for (int i = 0; i < propertyNames.length; i++) {
  452. propertyNames[i] = propertyNames[i] +
  453. dot +
  454. propertyIndex;
  455. }
  456. return propertyNames;
  457. } else {
  458. return propertyNames;
  459. }
  460. }
  461. /**
  462. * Internal debug method that outputs the registry contents.
  463. */
  464. private static void showImpl(ProviderImpl impl) {
  465. System.out.println("Provider implementation:");
  466. System.out.println("Classname: " + impl.getClassname());
  467. System.out.println("Vendor: " + impl.getVendor());
  468. System.out.println("Version: " + impl.getVersion());
  469. System.out.println("Impl index: " + impl.getIndex());
  470. }
  471. /**
  472. * Returns the <code>SyncProvider</code> instance identified by <i>providerID</i>.
  473. *
  474. * @param providerID the unique identifier of the provider
  475. * @return a <code>SyncProvider</code> implementation
  476. * @throws SyncFactoryException If the SyncProvider cannot be found or
  477. * some error was encountered when trying to invoke this provider.
  478. */
  479. public static SyncProvider getInstance(String providerID)
  480. throws SyncFactoryException {
  481. initMapIfNecessary(); // populate HashTable
  482. initJNDIContext(); // check JNDI context for any additional bindings
  483. ProviderImpl impl = (ProviderImpl)implementations.get(providerID);
  484. if (impl == null) {
  485. // Requested SyncProvider is unavailable. Return default provider.
  486. return new com.sun.rowset.providers.RIOptimisticProvider();
  487. }
  488. // Attempt to invoke classname from registered SyncProvider list
  489. Class c = null;
  490. try {
  491. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  492. /**
  493. * The SyncProvider implementation of the user will be in
  494. * the classpath. We need to find the ClassLoader which loads
  495. * this SyncFactory and try to laod the SyncProvider class from
  496. * there.
  497. **/
  498. c = Class.forName(providerID, true, cl);
  499. if (c != null) {
  500. return (SyncProvider)c.newInstance();
  501. } else {
  502. return new com.sun.rowset.providers.RIOptimisticProvider();
  503. }
  504. } catch (IllegalAccessException e) {
  505. throw new SyncFactoryException("IllegalAccessException: " + e.getMessage());
  506. } catch (InstantiationException e) {
  507. throw new SyncFactoryException("InstantiationException: " + e.getMessage());
  508. } catch (ClassNotFoundException e) {
  509. throw new SyncFactoryException("ClassNotFoundException: " + e.getMessage());
  510. }
  511. }
  512. /**
  513. * Returns an Enumeration of currently registered synchronization
  514. * providers. A <code>RowSet</code> implementation may use any provider in
  515. * the enumeration as its <code>SyncProvider</code> object.
  516. * <p>
  517. * At a minimum, the reference synchronization provider allowing
  518. * RowSet content data to be stored using a JDBC driver should be
  519. * possible.
  520. *
  521. * @return Enumeration A enumeration of available synchronization
  522. * providers that are registered with this Factory
  523. */
  524. public static Enumeration<SyncProvider> getRegisteredProviders()
  525. throws SyncFactoryException {
  526. initMapIfNecessary();
  527. // return a collection of classnames
  528. // of type SyncProvider
  529. return implementations.elements();
  530. }
  531. /**
  532. * Sets the logging object to be used by the <code>SyncProvider</code>
  533. * implementation provided by the <code>SyncFactory</code>. All
  534. * <code>SyncProvider</code> implementations can log their events to
  535. * this object and the application can retrieve a handle to this
  536. * object using the <code>getLogger</code> method.
  537. *
  538. * @param logger A Logger object instance
  539. */
  540. public static void setLogger(Logger logger) {
  541. rsLogger = logger;
  542. }
  543. /**
  544. * Sets the logging object that is used by <code>SyncProvider</code>
  545. * implementations provided by the <code>SyncFactory</code> SPI. All
  546. * <code>SyncProvider</code> implementations can log their events
  547. * to this object and the application can retrieve a handle to this
  548. * object using the <code>getLogger</code> method.
  549. *
  550. * @param logger a Logger object instance
  551. * @param level a Level object instance indicating the degree of logging
  552. * required
  553. */
  554. public static void setLogger(Logger logger, Level level) {
  555. // singleton
  556. rsLogger = logger;
  557. rsLogger.setLevel(level);
  558. }
  559. /**
  560. * Returns the logging object for applications to retrieve
  561. * synchronization events posted by SyncProvider implementations.
  562. *
  563. * @throws SyncFactoryException if no logging object has been set.
  564. */
  565. public static Logger getLogger() throws SyncFactoryException {
  566. // only one logger per session
  567. if(rsLogger == null){
  568. throw new SyncFactoryException("(SyncFactory) : No logger has been set");
  569. }
  570. return rsLogger;
  571. }
  572. /**
  573. * Sets the initial JNDI context from which SyncProvider implementations
  574. * can be retrieved from a JNDI namespace
  575. *
  576. * @param ctx a valid JNDI context
  577. * @throws SyncFactoryException if the supplied JNDI context is null
  578. */
  579. public static void setJNDIContext(javax.naming.Context ctx)
  580. throws SyncFactoryException {
  581. if (ctx == null) {
  582. throw new SyncFactoryException("Invalid JNDI context supplied");
  583. }
  584. ic = ctx;
  585. jndiCtxEstablished = true;
  586. }
  587. /**
  588. * Controls JNDI context intialization.
  589. *
  590. * @throws SyncFactoryException if an error occurs parsing the JNDI context
  591. */
  592. private static void initJNDIContext() throws SyncFactoryException {
  593. if (jndiCtxEstablished && (ic != null) && (lazyJNDICtxRefresh == false)) {
  594. try {
  595. parseProperties(parseJNDIContext());
  596. lazyJNDICtxRefresh = true; // touch JNDI namespace once.
  597. } catch (NamingException e) {
  598. e.printStackTrace();
  599. throw new SyncFactoryException("SPI: NamingException: " + e.getExplanation());
  600. } catch (Exception e) {
  601. e.printStackTrace();
  602. throw new SyncFactoryException("SPI: Exception: " + e.getMessage());
  603. }
  604. }
  605. }
  606. /**
  607. * Internal switch indicating whether the JNDI namespace should be re-read.
  608. */
  609. private static boolean lazyJNDICtxRefresh = false;
  610. /**
  611. * Parses the set JNDI Context and passes bindings to the enumerateBindings
  612. * method when complete.
  613. */
  614. private static Properties parseJNDIContext() throws NamingException {
  615. NamingEnumeration bindings = ic.listBindings("");
  616. Properties properties = new Properties();
  617. // Hunt one level below context for available SyncProvider objects
  618. enumerateBindings(bindings, properties);
  619. return properties;
  620. }
  621. /**
  622. * Scans each binding on JNDI context and determines if any binding is an
  623. * instance of SyncProvider, if so, add this to the registry and continue to
  624. * scan the current context using a re-entrant call to this method until all
  625. * bindings have been enumerated.
  626. */
  627. private static void enumerateBindings(NamingEnumeration bindings,
  628. Properties properties) throws NamingException {
  629. boolean syncProviderObj = false; // move to parameters ?
  630. try {
  631. Binding bd = null;
  632. Object elementObj = null;
  633. String element = null;
  634. while (bindings.hasMore()) {
  635. bd = (Binding)bindings.next();
  636. element = bd.getName();
  637. elementObj = bd.getObject();
  638. if (!(ic.lookup(element) instanceof Context)) {
  639. // skip directories/sub-contexts
  640. if (ic.lookup(element) instanceof SyncProvider) {
  641. syncProviderObj = true;
  642. }
  643. }
  644. if (syncProviderObj) {
  645. SyncProvider sync = (SyncProvider)elementObj;
  646. properties.put(SyncFactory.ROWSET_SYNC_PROVIDER,
  647. sync.getProviderID());
  648. syncProviderObj = false; // reset
  649. }
  650. }
  651. } catch (javax.naming.NotContextException e) {
  652. bindings.next();
  653. // Re-entrant call into method
  654. enumerateBindings(bindings, properties);
  655. }
  656. }
  657. }
  658. /**
  659. * Internal class that defines the lazy reference construct for each registered
  660. * SyncProvider implementation.
  661. */
  662. class ProviderImpl extends SyncProvider {
  663. private String className = null;
  664. private String vendorName = null;
  665. private String ver = null;
  666. private int index;
  667. public void setClassname(String classname) {
  668. className = classname;
  669. }
  670. public String getClassname() {
  671. return className;
  672. }
  673. public void setVendor(String vendor) {
  674. vendorName = vendor;
  675. }
  676. public String getVendor() {
  677. return vendorName;
  678. }
  679. public void setVersion(String providerVer) {
  680. ver = providerVer;
  681. }
  682. public String getVersion() {
  683. return ver;
  684. }
  685. public void setIndex(int i) {
  686. index = i;
  687. }
  688. public int getIndex() {
  689. return index;
  690. }
  691. public int getDataSourceLock() throws SyncProviderException {
  692. int dsLock = 0;
  693. try
  694. {
  695. dsLock = SyncFactory.getInstance(className).getDataSourceLock();
  696. } catch(SyncFactoryException sfEx) {
  697. throw new SyncProviderException(sfEx.getMessage());
  698. }
  699. return dsLock;
  700. }
  701. public int getProviderGrade() {
  702. int grade = 0;
  703. try
  704. {
  705. grade = SyncFactory.getInstance(className).getProviderGrade();
  706. } catch(SyncFactoryException sfEx) {
  707. //
  708. }
  709. return grade;
  710. }
  711. public String getProviderID() {
  712. return className;
  713. }
  714. /*
  715. public javax.sql.RowSetInternal getRowSetInternal() {
  716. try
  717. {
  718. return SyncFactory.getInstance(className).getRowSetInternal();
  719. } catch(SyncFactoryException sfEx) {
  720. //
  721. }
  722. }
  723. */
  724. public javax.sql.RowSetReader getRowSetReader() {
  725. RowSetReader rsReader = null;;
  726. try
  727. {
  728. rsReader = SyncFactory.getInstance(className).getRowSetReader();
  729. } catch(SyncFactoryException sfEx) {
  730. //
  731. }
  732. return rsReader;
  733. }
  734. public javax.sql.RowSetWriter getRowSetWriter() {
  735. RowSetWriter rsWriter = null;
  736. try
  737. {
  738. rsWriter = SyncFactory.getInstance(className).getRowSetWriter();
  739. } catch(SyncFactoryException sfEx) {
  740. //
  741. }
  742. return rsWriter;
  743. }
  744. public void setDataSourceLock(int param)
  745. throws SyncProviderException {
  746. try
  747. {
  748. SyncFactory.getInstance(className).setDataSourceLock(param);
  749. } catch(SyncFactoryException sfEx) {
  750. throw new SyncProviderException(sfEx.getMessage());
  751. }
  752. }
  753. public int supportsUpdatableView() {
  754. int view = 0;
  755. try
  756. {
  757. view = SyncFactory.getInstance(className).supportsUpdatableView();
  758. } catch(SyncFactoryException sfEx) {
  759. //
  760. }
  761. return view;
  762. }
  763. }