Path: blob/master/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java
40948 views
/*1* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sql.rowset;2627import java.security.AccessController;28import java.security.PrivilegedAction;29import java.sql.SQLException;30import java.util.PropertyPermission;31import java.util.ServiceConfigurationError;32import java.util.ServiceLoader;33import sun.reflect.misc.ReflectUtil;3435/**36* A factory API that enables applications to obtain a37* {@code RowSetFactory} implementation that can be used to create different38* types of {@code RowSet} implementations.39* <p>40* Example:41* </p>42* <pre>43* RowSetFactory aFactory = RowSetProvider.newFactory();44* CachedRowSet crs = aFactory.createCachedRowSet();45* ...46* RowSetFactory rsf = RowSetProvider.newFactory("com.sun.rowset.RowSetFactoryImpl", null);47* WebRowSet wrs = rsf.createWebRowSet();48* </pre>49*<p>50* Tracing of this class may be enabled by setting the System property51* {@code javax.sql.rowset.RowSetFactory.debug} to any value but {@code false}.52* </p>53*54* @author Lance Andersen55* @since 1.756*/57public class RowSetProvider {5859private static final String ROWSET_DEBUG_PROPERTY = "javax.sql.rowset.RowSetProvider.debug";60private static final String ROWSET_FACTORY_IMPL = "com.sun.rowset.RowSetFactoryImpl";61private static final String ROWSET_FACTORY_NAME = "javax.sql.rowset.RowSetFactory";62/**63* Internal debug flag.64*/65private static boolean debug = true;666768static {69// Check to see if the debug property is set70String val = getSystemProperty(ROWSET_DEBUG_PROPERTY);71// Allow simply setting the prop to turn on debug72debug = val != null && !"false".equals(val);73}7475/**76* RowSetProvider constructor77*/78protected RowSetProvider () {79}8081/**82* <p>Creates a new instance of a <code>RowSetFactory</code>83* implementation. This method uses the following84* look up order to determine85* the <code>RowSetFactory</code> implementation class to load:</p>86* <ul>87* <li>88* The System property {@code javax.sql.rowset.RowSetFactory}. For example:89* <ul>90* <li>91* -Djavax.sql.rowset.RowSetFactory=com.sun.rowset.RowSetFactoryImpl92* </li>93* </ul>94* <li>95* The {@link ServiceLoader} API. The {@code ServiceLoader} API will look96* for a class name in the file97* {@code META-INF/services/javax.sql.rowset.RowSetFactory}98* in jars available to the runtime. For example, to have the RowSetFactory99* implementation {@code com.sun.rowset.RowSetFactoryImpl } loaded, the100* entry in {@code META-INF/services/javax.sql.rowset.RowSetFactory} would be:101* <ul>102* <li>103* {@code com.sun.rowset.RowSetFactoryImpl }104* </li>105* </ul>106* </li>107* <li>108* Platform default <code>RowSetFactory</code> instance.109* </li>110* </ul>111*112* <p>Once an application has obtained a reference to a {@code RowSetFactory},113* it can use the factory to obtain RowSet instances.</p>114*115* @return New instance of a <code>RowSetFactory</code>116*117* @throws SQLException if the default factory class cannot be loaded,118* instantiated. The cause will be set to actual Exception119*120* @see ServiceLoader121* @since 1.7122*/123public static RowSetFactory newFactory()124throws SQLException {125// Use the system property first126RowSetFactory factory = null;127String factoryClassName = null;128try {129trace("Checking for Rowset System Property...");130factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME);131if (factoryClassName != null) {132trace("Found system property, value=" + factoryClassName);133if (factoryClassName.equals(ROWSET_FACTORY_IMPL)) {134return defaultRowSetFactory();135}136// getFactoryClass takes care of adding the read edge if137// necessary138@SuppressWarnings("deprecation")139Object o = getFactoryClass(factoryClassName, null, false).newInstance();140factory = (RowSetFactory) o;141}142} catch (Exception e) {143throw new SQLException( "RowSetFactory: " + factoryClassName +144" could not be instantiated: ", e);145}146147// Check to see if we found the RowSetFactory via a System property148if (factory == null) {149// If the RowSetFactory is not found via a System Property, now150// look it up via the ServiceLoader API and if not found, use the151// Java SE default.152factory = loadViaServiceLoader();153}154return factory == null ? defaultRowSetFactory() : factory;155}156157private static RowSetFactory defaultRowSetFactory() {158return new com.sun.rowset.RowSetFactoryImpl();159}160161/**162* <p>Creates a new instance of a <code>RowSetFactory</code> from the163* specified factory class name.164* This function is useful when there are multiple providers in the classpath.165* It gives more control to the application as it can specify which provider166* should be loaded.</p>167*168* <p>Once an application has obtained a reference to a <code>RowSetFactory</code>169* it can use the factory to obtain RowSet instances.</p>170*171* @param factoryClassName fully qualified factory class name that172* provides an implementation of <code>javax.sql.rowset.RowSetFactory</code>.173*174* @param cl <code>ClassLoader</code> used to load the factory175* class. If <code>null</code> current <code>Thread</code>'s context176* classLoader is used to load the factory class.177*178* @return New instance of a <code>RowSetFactory</code>179*180* @throws SQLException if <code>factoryClassName</code> is181* <code>null</code>, or the factory class cannot be loaded, instantiated.182*183* @see #newFactory()184*185* @since 1.7186*/187public static RowSetFactory newFactory(String factoryClassName, ClassLoader cl)188throws SQLException {189190trace("***In newInstance()");191192if(factoryClassName == null) {193throw new SQLException("Error: factoryClassName cannot be null");194}195try {196ReflectUtil.checkPackageAccess(factoryClassName);197} catch (@SuppressWarnings("removal") java.security.AccessControlException e) {198throw new SQLException("Access Exception",e);199}200201try {202// getFactoryClass takes care of adding the read edge if203// necessary204Class<?> providerClass = getFactoryClass(factoryClassName, cl, false);205@SuppressWarnings("deprecation")206RowSetFactory instance = (RowSetFactory) providerClass.newInstance();207if (debug) {208trace("Created new instance of " + providerClass +209" using ClassLoader: " + cl);210}211return instance;212} catch (ClassNotFoundException x) {213throw new SQLException(214"Provider " + factoryClassName + " not found", x);215} catch (Exception x) {216throw new SQLException(217"Provider " + factoryClassName + " could not be instantiated: " + x,218x);219}220}221222/*223* Returns the class loader to be used.224* @return The ClassLoader to use.225*226*/227@SuppressWarnings("removal")228static private ClassLoader getContextClassLoader() throws SecurityException {229return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {230231public ClassLoader run() {232ClassLoader cl = null;233234cl = Thread.currentThread().getContextClassLoader();235236if (cl == null) {237cl = ClassLoader.getSystemClassLoader();238}239240return cl;241}242});243}244245/**246* Attempt to load a class using the class loader supplied. If that fails247* and fall back is enabled, the current (i.e. bootstrap) class loader is248* tried.249*250* If the class loader supplied is <code>null</code>, first try using the251* context class loader followed by the current class loader.252* @return The class which was loaded253*/254static private Class<?> getFactoryClass(String factoryClassName, ClassLoader cl,255boolean doFallback) throws ClassNotFoundException {256Class<?> factoryClass = null;257258try {259if (cl == null) {260cl = getContextClassLoader();261if (cl == null) {262throw new ClassNotFoundException();263} else {264factoryClass = cl.loadClass(factoryClassName);265}266} else {267factoryClass = cl.loadClass(factoryClassName);268}269} catch (ClassNotFoundException e) {270if (doFallback) {271// Use current class loader272factoryClass = Class.forName(factoryClassName, true, RowSetFactory.class.getClassLoader());273} else {274throw e;275}276}277278ReflectUtil.checkPackageAccess(factoryClass);279return factoryClass;280}281282/**283* Use the ServiceLoader mechanism to load the default RowSetFactory284* @return default RowSetFactory Implementation285*/286static private RowSetFactory loadViaServiceLoader() throws SQLException {287RowSetFactory theFactory = null;288try {289trace("***in loadViaServiceLoader():");290for (RowSetFactory factory : ServiceLoader.load(javax.sql.rowset.RowSetFactory.class)) {291trace(" Loading done by the java.util.ServiceLoader :" + factory.getClass().getName());292theFactory = factory;293break;294}295} catch (ServiceConfigurationError e) {296throw new SQLException(297"RowSetFactory: Error locating RowSetFactory using Service "298+ "Loader API: " + e, e);299}300return theFactory;301302}303304/**305* Returns the requested System Property. If a {@code SecurityException}306* occurs, just return NULL307* @param propName - System property to retrieve308* @return The System property value or NULL if the property does not exist309* or a {@code SecurityException} occurs.310*/311@SuppressWarnings("removal")312static private String getSystemProperty(final String propName) {313String property = null;314try {315property = AccessController.doPrivileged(new PrivilegedAction<String>() {316317public String run() {318return System.getProperty(propName);319}320}, null, new PropertyPermission(propName, "read"));321} catch (SecurityException se) {322trace("error getting " + propName + ": "+ se);323if (debug) {324se.printStackTrace();325}326}327return property;328}329330/**331* Debug routine which will output tracing if the System Property332* -Djavax.sql.rowset.RowSetFactory.debug is set333* @param msg - The debug message to display334*/335private static void trace(String msg) {336if (debug) {337System.err.println("###RowSets: " + msg);338}339}340}341342343