2740N/A/*
2740N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2740N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2740N/A *
2740N/A * This code is free software; you can redistribute it and/or modify it
2740N/A * under the terms of the GNU General Public License version 2 only, as
2740N/A * published by the Free Software Foundation. Oracle designates this
2740N/A * particular file as subject to the "Classpath" exception as provided
2740N/A * by Oracle in the LICENSE file that accompanied this code.
2740N/A *
2740N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2740N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2740N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2740N/A * version 2 for more details (a copy is included in the LICENSE file that
2740N/A * accompanied this code).
2740N/A *
2740N/A * You should have received a copy of the GNU General Public License version
2740N/A * 2 along with this work; if not, write to the Free Software Foundation,
2740N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2740N/A *
2740N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2740N/A * or visit www.oracle.com if you need additional information or have any
2740N/A * questions.
2740N/A */
2740N/A
2740N/Apackage javax.sql.rowset;
2740N/A
2740N/Aimport java.security.AccessController;
2740N/Aimport java.security.PrivilegedAction;
2740N/Aimport java.sql.SQLException;
2881N/Aimport java.util.ServiceConfigurationError;
2740N/Aimport java.util.ServiceLoader;
2740N/A
2740N/A/**
2740N/A * A factory API that enables applications to obtain a
2740N/A * {@code RowSetFactory} implementation that can be used to create different
2740N/A * types of {@code RowSet} implementations.
2740N/A * <p>
2740N/A * Example:
2740N/A * </p>
2740N/A * <pre>
2740N/A * RowSetFactory aFactory = RowSetProvider.newFactory();
2740N/A * CachedRowSet crs = aFactory.createCachedRowSet();
2740N/A * ...
2740N/A * RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);
2740N/A * WebRowSet wrs = rsf.createWebRowSet();
2740N/A * </pre>
2740N/A *<p>
2740N/A * Tracing of this class may be enabled by setting the System property
2740N/A * {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}.
2740N/A * </p>
2740N/A *
2740N/A * @author Lance Andersen
2740N/A * @since 1.7
2740N/A */
2740N/Apublic class RowSetProvider {
2740N/A
2740N/A private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug";
2740N/A private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl";
2740N/A private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory";
2740N/A /**
2740N/A * Internal debug flag.
2740N/A */
2740N/A private static boolean debug = true;
2740N/A
2740N/A
2740N/A static {
2740N/A // Check to see if the debug property is set
2740N/A String val = getSystemProperty(ROWSET_DEBUG_PROPERTY);
2740N/A // Allow simply setting the prop to turn on debug
2740N/A debug = val != null && !"false".equals(val);
2740N/A }
2740N/A
2740N/A
2740N/A protected RowSetProvider () {
2740N/A }
2740N/A
2740N/A /**
2740N/A * <p>Creates a new instance of a <code>RowSetFactory</code>
2740N/A * implementation. This method uses the following
2740N/A * look up order to determine
2740N/A * the <code>RowSetFactory</code> implementation class to load:</p>
2740N/A * <ul>
2740N/A * <li>
2798N/A * The System property {@code javax.sql.rowset.RowSetFactory}. For example:
2740N/A * <ul>
2740N/A * <li>
2798N/A * -Djavax.sql.rowset.RowSetFactory=com.sun.rowset.RowSetFactoryImpl
2740N/A * </li>
2740N/A * </ul>
2740N/A * <li>
2815N/A * The {@link ServiceLoader} API. The {@code ServiceLoader} API will look
2815N/A * for a class name in the file
2740N/A * {@code META-INF/services/javax.sql.rowset.RowSetFactory}
2740N/A * in jars available to the runtime. For example, to have the the RowSetFactory
2740N/A * implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the
2740N/A * entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be:
2740N/A * <ul>
2740N/A * <li>
2740N/A * {@code com.sun.rowset.RowSetFactoryImpl }
2740N/A * </li>
2740N/A * </ul>
2740N/A * </li>
2740N/A * <li>
2740N/A * Platform default <code>RowSetFactory</code> instance.
2740N/A * </li>
2740N/A * </ul>
2740N/A *
2740N/A * <p>Once an application has obtained a reference to a {@code RowSetFactory},
2740N/A * it can use the factory to obtain RowSet instances.</p>
2740N/A *
2740N/A * @return New instance of a <code>RowSetFactory</code>
2740N/A *
2740N/A * @throws SQLException if the default factory class cannot be loaded,
2740N/A * instantiated. The cause will be set to actual Exception
2740N/A *
2740N/A * @see ServiceLoader
2740N/A * @since 1.7
2740N/A */
2740N/A public static RowSetFactory newFactory()
2740N/A throws SQLException {
2740N/A // Use the system property first
2740N/A RowSetFactory factory = null;
2740N/A String factoryClassName = null;
2740N/A try {
2740N/A trace("Checking for Rowset System Property...");
2740N/A factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME);
2740N/A if (factoryClassName != null) {
2740N/A trace("Found system property, value=" + factoryClassName);
2740N/A factory = (RowSetFactory) getFactoryClass(factoryClassName, null, true).newInstance();
2740N/A }
2740N/A } catch (ClassNotFoundException e) {
2740N/A throw new SQLException(
2740N/A "RowSetFactory: " + factoryClassName + " not found", e);
2740N/A } catch (Exception e) {
2740N/A throw new SQLException(
2740N/A "RowSetFactory: " + factoryClassName + " could not be instantiated: " + e,
2740N/A e);
2740N/A }
2740N/A
2740N/A // Check to see if we found the RowSetFactory via a System property
2740N/A if (factory == null) {
2740N/A // If the RowSetFactory is not found via a System Property, now
2740N/A // look it up via the ServiceLoader API and if not found, use the
2740N/A // Java SE default.
2740N/A factory = loadViaServiceLoader();
2740N/A factory =
2740N/A factory == null ? newFactory(ROWSET_FACTORY_IMPL, null) : factory;
2740N/A }
2740N/A return (factory);
2740N/A }
2740N/A
2740N/A /**
2740N/A * <p>Creates a new instance of a <code>RowSetFactory</code> from the
2740N/A * specified factory class name.
2740N/A * This function is useful when there are multiple providers in the classpath.
2740N/A * It gives more control to the application as it can specify which provider
2740N/A * should be loaded.</p>
2740N/A *
2740N/A * <p>Once an application has obtained a reference to a <code>RowSetFactory</code>
2740N/A * it can use the factory to obtain RowSet instances.</p>
2740N/A *
2740N/A * @param factoryClassName fully qualified factory class name that
2740N/A * provides an implementation of <code>javax.sql.rowset.RowSetFactory</code>.
2740N/A *
2740N/A * @param cl <code>ClassLoader</code> used to load the factory
2740N/A * class. If <code>null</code> current <code>Thread</code>'s context
2740N/A * classLoader is used to load the factory class.
2740N/A *
2740N/A * @return New instance of a <code>RowSetFactory</code>
2740N/A *
2740N/A * @throws SQLException if <code>factoryClassName</code> is
2740N/A * <code>null</code>, or the factory class cannot be loaded, instantiated.
2740N/A *
2740N/A * @see #newFactory()
2740N/A *
2740N/A * @since 1.7
2740N/A */
2740N/A public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl)
2740N/A throws SQLException {
2740N/A
2740N/A trace("***In newInstance()");
2740N/A try {
2740N/A Class providerClass = getFactoryClass(factoryClassName, cl, false);
2740N/A RowSetFactory instance = (RowSetFactory) providerClass.newInstance();
2740N/A if (debug) {
2740N/A trace("Created new instance of " + providerClass +
2740N/A " using ClassLoader: " + cl);
2740N/A }
2740N/A return instance;
2740N/A } catch (ClassNotFoundException x) {
2740N/A throw new SQLException(
2740N/A "Provider " + factoryClassName + " not found", x);
2740N/A } catch (Exception x) {
2740N/A throw new SQLException(
2740N/A "Provider " + factoryClassName + " could not be instantiated: " + x,
2740N/A x);
2740N/A }
2740N/A }
2740N/A
2740N/A /*
2740N/A * Returns the class loader to be used.
2740N/A * @return The ClassLoader to use.
2740N/A *
2740N/A */
2740N/A static private ClassLoader getContextClassLoader() throws SecurityException {
3999N/A return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
2740N/A
3999N/A public ClassLoader run() {
2740N/A ClassLoader cl = null;
2740N/A
2740N/A cl = Thread.currentThread().getContextClassLoader();
2740N/A
2740N/A if (cl == null) {
2740N/A cl = ClassLoader.getSystemClassLoader();
2740N/A }
2740N/A
2740N/A return cl;
2740N/A }
2740N/A });
2740N/A }
2740N/A
2740N/A /**
2740N/A * Attempt to load a class using the class loader supplied. If that fails
2740N/A * and fall back is enabled, the current (i.e. bootstrap) class loader is
2740N/A * tried.
2740N/A *
2740N/A * If the class loader supplied is <code>null</code>, first try using the
2740N/A * context class loader followed by the current class loader.
2740N/A * @return The class which was loaded
2740N/A */
2740N/A static private Class getFactoryClass(String factoryClassName, ClassLoader cl,
2740N/A boolean doFallback) throws ClassNotFoundException {
2740N/A try {
2740N/A if (cl == null) {
2740N/A cl = getContextClassLoader();
2740N/A if (cl == null) {
2740N/A throw new ClassNotFoundException();
2740N/A } else {
2740N/A return cl.loadClass(factoryClassName);
2740N/A }
2740N/A } else {
2740N/A return cl.loadClass(factoryClassName);
2740N/A }
2740N/A } catch (ClassNotFoundException e) {
2740N/A if (doFallback) {
2740N/A // Use current class loader
2740N/A return Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());
2740N/A } else {
2740N/A throw e;
2740N/A }
2740N/A }
2740N/A }
2740N/A
2740N/A /**
2740N/A * Use the ServiceLoader mechanism to load the default RowSetFactory
2740N/A * @return default RowSetFactory Implementation
2740N/A */
2881N/A static private RowSetFactory loadViaServiceLoader() throws SQLException {
2740N/A RowSetFactory theFactory = null;
2881N/A try {
2881N/A trace("***in loadViaServiceLoader():");
2881N/A for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) {
2881N/A trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName());
2881N/A theFactory = factory;
2881N/A break;
2881N/A }
2881N/A } catch (ServiceConfigurationError e) {
2881N/A throw new SQLException(
2881N/A "RowSetFactory: Error locating RowSetFactory using Service "
2881N/A + "Loader API: " + e, e);
2740N/A }
2740N/A return theFactory;
2740N/A
2740N/A }
2740N/A
2740N/A /**
2740N/A * Returns the requested System Property. If a {@code SecurityException}
2740N/A * occurs, just return NULL
2798N/A * @param propName - System property to retrieve
2740N/A * @return The System property value or NULL if the property does not exist
2740N/A * or a {@code SecurityException} occurs.
2740N/A */
2740N/A static private String getSystemProperty(final String propName) {
2740N/A String property = null;
2740N/A try {
3999N/A property = AccessController.doPrivileged(new PrivilegedAction<String>() {
2740N/A
3999N/A public String run() {
2740N/A return System.getProperty(propName);
2740N/A }
2740N/A });
2740N/A } catch (SecurityException se) {
2740N/A if (debug) {
2740N/A se.printStackTrace();
2740N/A }
2740N/A }
2740N/A return property;
2740N/A }
2740N/A
2740N/A /**
2740N/A * Debug routine which will output tracing if the System Property
2740N/A * -Djavax.sql.rowset.RowSetFactory.debug is set
2740N/A * @param msg - The debug message to display
2740N/A */
2740N/A private static void trace(String msg) {
2740N/A if (debug) {
2740N/A System.err.println("###RowSets: " + msg);
2740N/A }
2740N/A }
2740N/A}