All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.firebirdsql.jdbc.AbstractDriver Maven / Gradle / Ivy

There is a newer version: 2.2.15
Show newest version
/*
 * $Id$
 *
 * Firebird Open Source JavaEE Connector - JDBC Driver
 *
 * Distributable under LGPL license.
 * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * LGPL License for more details.
 *
 * This file was created by members of the firebird development team.
 * All individual contributions remain the Copyright (C) of those
 * individuals.  Contributors to this file are either listed here or
 * can be obtained from a source control history command.
 *
 * All rights reserved.
 */
package org.firebirdsql.jdbc;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import javax.resource.ResourceException;

import org.firebirdsql.gds.*;
import org.firebirdsql.gds.impl.*;
import org.firebirdsql.jca.*;
import org.firebirdsql.logging.Logger;
import org.firebirdsql.logging.LoggerFactory;

/**
 * The Jaybird JDBC Driver implementation for the Firebird database.
 *
 * @author David Jencks
 * @author Mark Rotteveel
 */
public abstract class AbstractDriver implements FirebirdDriver {

    private final static Logger log;

    public static final String CHARSET = "charSet";
    public static final String USE_TRANSLATION = "useTranslation";
    public static final String USER = "user";
    public static final String USER_NAME = "user_name";
    public static final String PASSWORD = "password";
    public static final String DATABASE = "database";
    public static final String BLOB_BUFFER_LENGTH = "blob_buffer_length";
    public static final String TPB_MAPPING = "tpb_mapping";
    
    /*
     * @todo implement the default subject for the
     * standard connection.
     */

    private final Map> mcfToDataSourceMap =
            new ConcurrentHashMap>();
    private final ReferenceQueue dataSourceReferenceQueue = new ReferenceQueue();
    private final Object createDataSourceLock = new Object();

    static {
        log = LoggerFactory.getLogger(AbstractDriver.class, false);
        try {
            DriverManager.registerDriver(new FBDriver());
        } catch (Exception ex) {
            if (log != null)
                log.error("Could not register with driver manager", ex);
        }
    }

    /**
     * Attempts to make a database connection to the given URL.
     * The driver should return "null" if it realizes it is the wrong kind
     * of driver to connect to the given URL.  This will be common, as when
     * the JDBC driver manager is asked to connect to a given URL it passes
     * the URL to each loaded driver in turn.
     *
     * 

The driver should raise a SQLException if it is the right * driver to connect to the given URL, but has trouble connecting to * the database. * *

The java.util.Properties argument can be used to passed arbitrary * string tag/value pairs as connection arguments. * Normally at least "user" and "password" properties should be * included in the Properties. * * @param url the URL of the database to which to connect * @param info a list of arbitrary string tag/value pairs as * connection arguments. Normally at least a "user" and * "password" property should be included. * @return a Connection object that represents a * connection to the URL * @exception SQLException if a database access error occurs */ public Connection connect(String url, final Properties info) throws SQLException { if (url == null) { throw new SQLException("url is null"); } final GDSType type = GDSFactory.getTypeForProtocol(url); if (type == null) { return null; } final Properties mergedProperties = mergeProperties(url, info); final Map normalizedInfo = FBDriverPropertyManager.normalize(url, mergedProperties); try { int qMarkIndex = url.indexOf('?'); if (qMarkIndex != -1) { url = url.substring(0, qMarkIndex); } FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(type); String databaseURL = GDSFactory.getDatabasePath(type, url); mcf.setDatabase(databaseURL); for (Object o : normalizedInfo.entrySet()) { Map.Entry entry = (Map.Entry) o; mcf.setNonStandardProperty((String) entry.getKey(), (String) entry.getValue()); } FBConnectionHelper.processTpbMapping(mcf.getGDS(), mcf, mergedProperties); mcf = mcf.canonicalize(); FBDataSource dataSource = createDataSource(mcf); return dataSource.getConnection(mcf.getUserName(), mcf.getPassword()); } catch(ResourceException resex) { throw new FBSQLException(resex); } catch(GDSException ex) { throw new FBSQLException(ex); } } private FBDataSource createDataSource(final FBManagedConnectionFactory mcf) throws ResourceException { final FBConnectionProperties cacheKey = mcf.getCacheKey(); FBDataSource dataSource = dataSourceFromCache(cacheKey); if (dataSource != null) return dataSource; synchronized (createDataSourceLock) { // Obtain again dataSource = dataSourceFromCache(cacheKey); if (dataSource == null) { dataSource = (FBDataSource) mcf.createConnectionFactory(); mcfToDataSourceMap.put(cacheKey, new SoftReference(dataSource, dataSourceReferenceQueue)); } } cleanDataSourceCache(); return dataSource; } /** * Removes cleared references from the {@link #mcfToDataSourceMap} cache. */ private void cleanDataSourceCache() { Reference reference; while ((reference = dataSourceReferenceQueue.poll()) != null) { mcfToDataSourceMap.values().remove(reference); } } private FBDataSource dataSourceFromCache(final FBConnectionProperties cacheKey) { final SoftReference dataSourceReference = mcfToDataSourceMap.get(cacheKey); return dataSourceReference != null ? dataSourceReference.get() : null; } public FirebirdConnection connect(FirebirdConnectionProperties properties) throws SQLException { GDSType type = GDSType.getType(properties.getType()); if (type == null) { type = GDSFactory.getDefaultGDS().getType(); } try { FBManagedConnectionFactory mcf = new FBManagedConnectionFactory(type); mcf = mcf.canonicalize(); FBDataSource dataSource = createDataSource(mcf); return (FirebirdConnection)dataSource.getConnection(mcf.getUserName(), mcf.getPassword()); } catch(ResourceException ex) { throw new FBSQLException(ex); } } public FirebirdConnectionProperties newConnectionProperties() { return new FBConnectionProperties(); } /** * Returns true if the driver thinks that it can open a connection * to the given URL. Typically drivers will return true if they * understand the subprotocol specified in the URL and false if * they don't. * * @param url the URL of the database * @return true if this driver can connect to the given URL * @exception SQLException if a database access error occurs */ public boolean acceptsURL(String url) throws SQLException { if (url == null) { throw new SQLException("url is null"); } Set protocols = GDSFactory.getSupportedProtocols(); for (Iterator iter = protocols.iterator(); iter.hasNext();) { String protocol = (String) iter.next(); if (url.startsWith(protocol)) return true; } return false; } /** * Gets information about the possible properties for this driver. *

The getPropertyInfo method is intended to allow a generic GUI tool to * discover what properties it should prompt a human for in order to get * enough information to connect to a database. Note that depending on * the values the human has supplied so far, additional values may become * necessary, so it may be necessary to iterate though several calls * to getPropertyInfo. * * @param url the URL of the database to which to connect * @param info a proposed list of tag/value pairs that will be sent on * connect open * @return an array of DriverPropertyInfo objects describing possible * properties. This array may be an empty array if no properties * are required. * @exception SQLException if a database access error occurs * TODO check the correctness of implementation * TODO convert parameters into constants */ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { return FBDriverPropertyManager.getDriverPropertyInfo(info); } /** * Gets the driver's major version number. Initially this should be 1. * @return this driver's major version number */ public int getMajorVersion() { return 2; } /** * Gets the driver's minor version number. Initially this should be 0. * @return this driver's minor version number */ public int getMinorVersion() { return 2; } /** * Reports whether this driver is a genuine JDBC * COMPLIANTTM driver. * A driver may only report true here if it passes the JDBC compliance * tests; otherwise it is required to return false. * * JDBC compliance requires full support for the JDBC API and full support * for SQL 92 Entry Level. It is expected that JDBC compliant drivers will * be available for all the major commercial databases. * * This method is not intended to encourage the development of non-JDBC * compliant drivers, but is a recognition of the fact that some vendors * are interested in using the JDBC API and framework for lightweight * databases that do not support full database functionality, or for * special databases such as document information retrieval where a SQL * implementation may not be feasible. */ public boolean jdbcCompliant() { return true; } /** * Merges the properties from the JDBC URL and properties object. *

* If a property is present in both, the property specified in the JDBC url takes precedence. *

* * @param jdbcUrl JDBC Url * @param connectionProperties Properties object * @return Map with connection properties */ private static Properties mergeProperties(String jdbcUrl, Properties connectionProperties) { Properties mergedProperties = new Properties(); if (connectionProperties != null) { for (String propertyName : connectionProperties.stringPropertyNames()) { mergedProperties.setProperty(propertyName, connectionProperties.getProperty(propertyName)); } } convertUrlParams(jdbcUrl, mergedProperties); return mergedProperties; } /** * Extract properties specified as URL parameter into the specified map of properties. * * @param url * specified URL. * @param info * instance of {@link Map} into which values should * be extracted. */ private static void convertUrlParams(String url, Properties info) { if (url == null) { return; } int iQuestionMark = url.indexOf("?"); if (iQuestionMark == -1) { return; } String propString = url.substring(iQuestionMark + 1); StringTokenizer st = new StringTokenizer(propString, "&;"); while (st.hasMoreTokens()) { String propertyString = st.nextToken(); int iIs = propertyString.indexOf("="); if (iIs > -1) { String property = propertyString.substring(0, iIs); String value = propertyString.substring(iIs + 1); info.setProperty(property, value); } else { info.setProperty(propertyString, ""); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy