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
26package javax.sql.rowset.spi;
27
28import java.util.logging.*;
29import java.util.*;
30
31import java.sql.*;
32import javax.sql.*;
33
34import java.io.FileInputStream;
35import java.io.InputStream;
36import java.io.IOException;
37import java.io.FileNotFoundException;
38
39import 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 */
199public 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 */
806class 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}