/*
 * Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.util;

import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.h2.engine.Constants;
import org.h2.jdbcx.JdbcDataSource;
import org.osgi.framework.BundleContext;
import org.osgi.service.jdbc.DataSourceFactory;

This class implements the OSGi DataSourceFactory interface for the H2 JDBC driver. The following standard configuration properties are supported: JDBC_USER, JDBC_PASSWORD, JDBC_DESCRIPTION, JDBC_DATASOURCE_NAME, JDBC_NETWORK_PROTOCOL, JDBC_URL, JDBC_SERVER_NAME, JDBC_PORT_NUMBER. The following standard configuration properties are not supported: JDBC_ROLE_NAME, JDBC_DATABASE_NAME, JDBC_INITIAL_POOL_SIZE, JDBC_MAX_POOL_SIZE, JDBC_MIN_POOL_SIZE, JDBC_MAX_IDLE_TIME, JDBC_MAX_STATEMENTS, JDBC_PROPERTY_CYCLE. Any other property will be treated as a H2 specific option. If the JDBC_URL property is passed to any of the DataSource factories, the following properties will be ignored: JDBC_DATASOURCE_NAME, JDBC_NETWORK_PROTOCOL, JDBC_SERVER_NAME, JDBC_PORT_NUMBER.
Author:Per Otterstrom
/** * This class implements the OSGi DataSourceFactory interface for the H2 JDBC * driver. The following standard configuration properties are supported: * {@link #JDBC_USER}, {@link #JDBC_PASSWORD}, {@link #JDBC_DESCRIPTION}, * {@link #JDBC_DATASOURCE_NAME}, {@link #JDBC_NETWORK_PROTOCOL}, * {@link #JDBC_URL}, {@link #JDBC_SERVER_NAME}, {@link #JDBC_PORT_NUMBER}. The * following standard configuration properties are not supported: * {@link #JDBC_ROLE_NAME}, {@link #JDBC_DATABASE_NAME}, * {@link #JDBC_INITIAL_POOL_SIZE}, {@link #JDBC_MAX_POOL_SIZE}, * {@link #JDBC_MIN_POOL_SIZE}, {@link #JDBC_MAX_IDLE_TIME}, * {@link #JDBC_MAX_STATEMENTS}, {@link #JDBC_PROPERTY_CYCLE}. Any other * property will be treated as a H2 specific option. If the {@link #JDBC_URL} * property is passed to any of the DataSource factories, the following * properties will be ignored: {@link #JDBC_DATASOURCE_NAME}, * {@link #JDBC_NETWORK_PROTOCOL}, {@link #JDBC_SERVER_NAME}, * {@link #JDBC_PORT_NUMBER}. * * @author Per Otterstrom */
public class OsgiDataSourceFactory implements DataSourceFactory { private final org.h2.Driver driver; public OsgiDataSourceFactory(org.h2.Driver driver) { this.driver = driver; }
Creates a basic data source.
Params:
  • properties – the properties for the data source.
Throws:
  • SQLException – if unsupported properties are supplied, or if data source can not be created.
Returns:a new data source.
/** * Creates a basic data source. * * @param properties the properties for the data source. * @throws SQLException if unsupported properties are supplied, or if data * source can not be created. * @return a new data source. */
@Override public DataSource createDataSource(Properties properties) throws SQLException { // Make copy of properties Properties propertiesCopy = new Properties(); if (properties != null) { propertiesCopy.putAll(properties); } // Verify that no unsupported standard options are used rejectUnsupportedOptions(propertiesCopy); // Standard pool properties in OSGi not applicable here rejectPoolingOptions(propertiesCopy); JdbcDataSource dataSource = new JdbcDataSource(); setupH2DataSource(dataSource, propertiesCopy); return dataSource; }
Creates a pooled data source.
Params:
  • properties – the properties for the data source.
Throws:
  • SQLException – if unsupported properties are supplied, or if data source can not be created.
Returns:a new data source.
/** * Creates a pooled data source. * * @param properties the properties for the data source. * @throws SQLException if unsupported properties are supplied, or if data * source can not be created. * @return a new data source. */
@Override public ConnectionPoolDataSource createConnectionPoolDataSource( Properties properties) throws SQLException { // Make copy of properties Properties propertiesCopy = new Properties(); if (properties != null) { propertiesCopy.putAll(properties); } // Verify that no unsupported standard options are used rejectUnsupportedOptions(propertiesCopy); // The integrated connection pool is H2 is not configurable rejectPoolingOptions(propertiesCopy); JdbcDataSource dataSource = new JdbcDataSource(); setupH2DataSource(dataSource, propertiesCopy); return dataSource; }
Creates a pooled XA data source.
Params:
  • properties – the properties for the data source.
Throws:
  • SQLException – if unsupported properties are supplied, or if data source can not be created.
Returns:a new data source.
/** * Creates a pooled XA data source. * * @param properties the properties for the data source. * @throws SQLException if unsupported properties are supplied, or if data * source can not be created. * @return a new data source. */
@Override public XADataSource createXADataSource(Properties properties) throws SQLException { // Make copy of properties Properties propertiesCopy = new Properties(); if (properties != null) { propertiesCopy.putAll(properties); } // Verify that no unsupported standard options are used rejectUnsupportedOptions(propertiesCopy); // The integrated connection pool is H2 is not configurable rejectPoolingOptions(propertiesCopy); JdbcDataSource dataSource = new JdbcDataSource(); setupH2DataSource(dataSource, propertiesCopy); return dataSource; }
Returns a driver. The H2 driver does not support any properties.
Params:
  • properties – must be null or empty list.
Throws:
Returns:a driver.
/** * Returns a driver. The H2 driver does not support any properties. * * @param properties must be null or empty list. * @throws SQLException if any property is supplied. * @return a driver. */
@Override public java.sql.Driver createDriver(Properties properties) throws SQLException { if (properties != null && !properties.isEmpty()) { // No properties supported throw new SQLException(); } return driver; }
Checker method that will throw if any unsupported standard OSGi options is present.
Params:
  • p – the properties to check
Throws:
/** * Checker method that will throw if any unsupported standard OSGi options * is present. * * @param p the properties to check * @throws SQLFeatureNotSupportedException if unsupported properties are * present */
private static void rejectUnsupportedOptions(Properties p) throws SQLFeatureNotSupportedException { // Unsupported standard properties in OSGi if (p.containsKey(DataSourceFactory.JDBC_ROLE_NAME)) { throw new SQLFeatureNotSupportedException("The " + DataSourceFactory.JDBC_ROLE_NAME + " property is not supported by H2"); } if (p.containsKey(DataSourceFactory.JDBC_DATASOURCE_NAME)) { throw new SQLFeatureNotSupportedException("The " + DataSourceFactory.JDBC_DATASOURCE_NAME + " property is not supported by H2"); } }
Applies common OSGi properties to a H2 data source. Non standard properties will be applied as H2 options.
Params:
  • dataSource – the data source to configure
  • p – the properties to apply to the data source
/** * Applies common OSGi properties to a H2 data source. Non standard * properties will be applied as H2 options. * * @param dataSource the data source to configure * @param p the properties to apply to the data source */
private static void setupH2DataSource(JdbcDataSource dataSource, Properties p) { // Setting user and password if (p.containsKey(DataSourceFactory.JDBC_USER)) { dataSource.setUser((String) p.remove(DataSourceFactory.JDBC_USER)); } if (p.containsKey(DataSourceFactory.JDBC_PASSWORD)) { dataSource.setPassword((String) p .remove(DataSourceFactory.JDBC_PASSWORD)); } // Setting description if (p.containsKey(DataSourceFactory.JDBC_DESCRIPTION)) { dataSource.setDescription((String) p .remove(DataSourceFactory.JDBC_DESCRIPTION)); } // Setting URL StringBuilder connectionUrl = new StringBuilder(); if (p.containsKey(DataSourceFactory.JDBC_URL)) { // Use URL if specified connectionUrl.append(p.remove(DataSourceFactory.JDBC_URL)); // Remove individual properties p.remove(DataSourceFactory.JDBC_NETWORK_PROTOCOL); p.remove(DataSourceFactory.JDBC_SERVER_NAME); p.remove(DataSourceFactory.JDBC_PORT_NUMBER); p.remove(DataSourceFactory.JDBC_DATABASE_NAME); } else { // Creating URL from individual properties connectionUrl.append(Constants.START_URL); // Set network protocol (tcp/ssl) or DB type (mem/file) String protocol = ""; if (p.containsKey(DataSourceFactory.JDBC_NETWORK_PROTOCOL)) { protocol = (String) p.remove(DataSourceFactory.JDBC_NETWORK_PROTOCOL); connectionUrl.append(protocol).append(":"); } // Host name and/or port if (p.containsKey(DataSourceFactory.JDBC_SERVER_NAME)) { connectionUrl.append("//").append( p.remove(DataSourceFactory.JDBC_SERVER_NAME)); if (p.containsKey(DataSourceFactory.JDBC_PORT_NUMBER)) { connectionUrl.append(":").append( p.remove(DataSourceFactory.JDBC_PORT_NUMBER)); } connectionUrl.append("/"); } else if (p.containsKey( DataSourceFactory.JDBC_PORT_NUMBER)) { // Assume local host if only port was set connectionUrl .append("//localhost:") .append(p.remove(DataSourceFactory.JDBC_PORT_NUMBER)) .append("/"); } else if (protocol.equals("tcp") || protocol.equals("ssl")) { // Assume local host if network protocol is set, but no host or // port is set connectionUrl.append("//localhost/"); } // DB path and name if (p.containsKey(DataSourceFactory.JDBC_DATABASE_NAME)) { connectionUrl.append( p.remove(DataSourceFactory.JDBC_DATABASE_NAME)); } } // Add remaining properties as options for (Object option : p.keySet()) { connectionUrl.append(";").append(option).append("=") .append(p.get(option)); } if (connectionUrl.length() > Constants.START_URL.length()) { dataSource.setURL(connectionUrl.toString()); } }
Checker method that will throw if any pooling related standard OSGi options are present.
Params:
  • p – the properties to check
Throws:
/** * Checker method that will throw if any pooling related standard OSGi * options are present. * * @param p the properties to check * @throws SQLFeatureNotSupportedException if unsupported properties are * present */
private static void rejectPoolingOptions(Properties p) throws SQLFeatureNotSupportedException { if (p.containsKey(DataSourceFactory.JDBC_INITIAL_POOL_SIZE) || p.containsKey(DataSourceFactory.JDBC_MAX_IDLE_TIME) || p.containsKey(DataSourceFactory.JDBC_MAX_POOL_SIZE) || p.containsKey(DataSourceFactory.JDBC_MAX_STATEMENTS) || p.containsKey(DataSourceFactory.JDBC_MIN_POOL_SIZE) || p.containsKey(DataSourceFactory.JDBC_PROPERTY_CYCLE)) { throw new SQLFeatureNotSupportedException( "Pooling properties are not supported by H2"); } }
Register the H2 JDBC driver service.
Params:
  • bundleContext – the bundle context
  • driver – the driver
/** * Register the H2 JDBC driver service. * * @param bundleContext the bundle context * @param driver the driver */
static void registerService(BundleContext bundleContext, org.h2.Driver driver) { Properties properties = new Properties(); properties.put( DataSourceFactory.OSGI_JDBC_DRIVER_CLASS, org.h2.Driver.class.getName()); properties.put( DataSourceFactory.OSGI_JDBC_DRIVER_NAME, "H2 JDBC Driver"); properties.put( DataSourceFactory.OSGI_JDBC_DRIVER_VERSION, Constants.getFullVersion()); bundleContext.registerService( DataSourceFactory.class.getName(), new OsgiDataSourceFactory(driver), properties); } }