History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/sql/rowset/spi/SyncFactory.java (1 of 18352 files). Show all

Unified · Split

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