/* * This file is part of the openSCADA project * Copyright (C) 2010-2012 TH4 SYSTEMS GmbH (http://th4-systems.com) * * openSCADA is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * openSCADA 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 * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with openSCADA. If not, see * <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License. */ package org.openscada.external.postgresql; import java.sql.Driver; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.sql.ConnectionPoolDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; import org.osgi.service.jdbc.DataSourceFactory; import org.postgresql.ds.PGConnectionPoolDataSource; import org.postgresql.ds.PGSimpleDataSource; import org.postgresql.ds.common.BaseDataSource; import org.postgresql.ds.jdbc23.AbstractJdbc23ConnectionPoolDataSource; import org.postgresql.xa.PGXADataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A {@link DataSourceFactory} implemenation for PostgreSQL * @author Jens Reimann * */ public class DataSourceFactoryImpl implements DataSourceFactory { private final static Logger logger = LoggerFactory.getLogger ( DataSourceFactoryImpl.class ); private final org.postgresql.Driver driver = new org.postgresql.Driver (); private static abstract class Property<T extends BaseDataSource> { public abstract void apply ( T dataSource, Object value ) throws SQLException; } private static abstract class StringProperty<T extends BaseDataSource> extends Property<T> { @Override public void apply ( final T dataSource, final Object value ) throws SQLException { applyString ( dataSource, value != null ? value.toString () : null ); } protected abstract void applyString ( T dataSource, String string ) throws SQLException; } private static abstract class IntegerProperty<T extends BaseDataSource> extends Property<T> { @Override public void apply ( final T dataSource, final Object value ) throws SQLException { if ( value == null ) { applyInteger ( dataSource, null ); } else if ( value instanceof Number ) { applyInteger ( dataSource, ( (Number)value ).intValue () ); } else { try { applyInteger ( dataSource, Integer.parseInt ( value.toString () ) ); } catch ( final Exception e ) { throw new SQLException ( String.format ( "Unable to convert property value (%s) to integer", value ), e ); } } } protected abstract void applyInteger ( T dataSource, Integer string ) throws SQLException; } private static abstract class BooleanProperty<T extends BaseDataSource> extends Property<T> { @Override public void apply ( final T dataSource, final Object value ) throws SQLException { if ( value == null ) { applyBoolean ( dataSource, null ); } else if ( value instanceof Boolean ) { applyBoolean ( dataSource, (Boolean)value ); } else { try { applyBoolean ( dataSource, Boolean.parseBoolean ( value.toString () ) ); } catch ( final Exception e ) { throw new SQLException ( String.format ( "Unable to convert property value (%s) to boolean", value ), e ); } } } protected abstract void applyBoolean ( T dataSource, Boolean string ) throws SQLException; } private final Map<String, Property<BaseDataSource>> properties = new HashMap<String, Property<BaseDataSource>> (); private final Map<String, Property<AbstractJdbc23ConnectionPoolDataSource>> poolProperties = new HashMap<String, Property<AbstractJdbc23ConnectionPoolDataSource>> (); public DataSourceFactoryImpl () { this.properties.put ( "applicationName", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setApplicationName ( value ); } } ); this.properties.put ( "compatible", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setCompatible ( value ); } } ); this.properties.put ( "databaseName", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setDatabaseName ( value ); } } ); this.properties.put ( "loginTimeout", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setLoginTimeout ( value ); } } } ); this.properties.put ( "logLevel", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setLogLevel ( value ); } } } ); this.properties.put ( "password", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setPassword ( value ); } } ); this.properties.put ( "portNumber", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setPortNumber ( value ); } } } ); this.properties.put ( "prepareThreshold", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setPrepareThreshold ( value ); } } } ); this.properties.put ( "protocolVersion", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setProtocolVersion ( value ); } } } ); this.properties.put ( "serverName", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setServerName ( value ); } } ); this.properties.put ( "socketTimeout", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setSocketTimeout ( value ); } } } ); this.properties.put ( "ssl", new BooleanProperty<BaseDataSource> () { @Override protected void applyBoolean ( final BaseDataSource dataSource, final Boolean value ) throws SQLException { if ( value != null ) { dataSource.setSsl ( value ); } } } ); this.properties.put ( "sslFactory", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setSslfactory ( value ); } } ); this.properties.put ( "tcpKeepAlive", new BooleanProperty<BaseDataSource> () { @Override protected void applyBoolean ( final BaseDataSource dataSource, final Boolean value ) throws SQLException { if ( value != null ) { dataSource.setTcpKeepAlive ( value ); } } } ); this.properties.put ( "unknownLength", new IntegerProperty<BaseDataSource> () { @Override protected void applyInteger ( final BaseDataSource dataSource, final Integer value ) throws SQLException { if ( value != null ) { dataSource.setUnknownLength ( value ); } } } ); this.properties.put ( "user", new StringProperty<BaseDataSource> () { @Override protected void applyString ( final BaseDataSource dataSource, final String value ) throws SQLException { dataSource.setUser ( value ); } } ); // pool properties this.poolProperties.put ( "defaultAutoCommit", new BooleanProperty<AbstractJdbc23ConnectionPoolDataSource> () { @Override protected void applyBoolean ( final AbstractJdbc23ConnectionPoolDataSource dataSource, final Boolean value ) throws SQLException { if ( value != null ) { dataSource.setDefaultAutoCommit ( value ); } } } ); } @Override public DataSource createDataSource ( final Properties paramProperties ) throws SQLException { final PGSimpleDataSource dataSource = new PGSimpleDataSource (); setProperties ( dataSource, paramProperties, this.properties ); return dataSource; } @Override public ConnectionPoolDataSource createConnectionPoolDataSource ( final Properties paramProperties ) throws SQLException { final PGConnectionPoolDataSource dataSource = new PGConnectionPoolDataSource (); setProperties ( dataSource, paramProperties, this.properties ); setProperties ( dataSource, paramProperties, this.poolProperties ); return dataSource; } @Override public XADataSource createXADataSource ( final Properties paramProperties ) throws SQLException { final PGXADataSource dataSource = new PGXADataSource (); setProperties ( dataSource, paramProperties, this.properties ); return dataSource; } private <T extends BaseDataSource> void setProperties ( final T dataSource, final Properties properties, final Map<String, Property<T>> handlers ) throws SQLException { for ( final Map.Entry<Object, Object> entry : properties.entrySet () ) { logger.trace ( "Setting property - key: {}, value: {}", entry.getKey (), entry.getValue () ); if ( entry.getKey () == null ) { continue; } final Property<T> prop = handlers.get ( entry.getKey () ); if ( prop == null ) { logger.debug ( "Skipping property '{}' for now", entry.getKey () ); continue; } prop.apply ( dataSource, entry.getValue () ); } } @Override public Driver createDriver ( final Properties paramProperties ) throws SQLException { return this.driver; } }