/** * OrbisGIS is a java GIS application dedicated to research in GIScience. * OrbisGIS is developed by the GIS group of the DECIDE team of the * Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>. * * The GIS group of the DECIDE team is located at : * * Laboratoire Lab-STICC – CNRS UMR 6285 * Equipe DECIDE * UNIVERSITÉ DE BRETAGNE-SUD * Institut Universitaire de Technologie de Vannes * 8, Rue Montaigne - BP 561 56017 Vannes Cedex * * OrbisGIS is distributed under GPL 3 license. * * Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488) * Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285) * * This file is part of OrbisGIS. * * OrbisGIS is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * OrbisGIS 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along with * OrbisGIS. If not, see <http://www.gnu.org/licenses/>. * * For more information, please consult: <http://www.orbisgis.org/> * or contact directly: * info_at_ orbisgis.org */ package org.orbisgis.corejdbc; import org.h2gis.utilities.JDBCUrlParser; import org.h2gis.utilities.JDBCUtilities; import org.h2gis.utilities.SFSUtilities; import org.orbisgis.frameworkapi.CoreWorkspace; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.jdbc.DataSourceFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xnap.commons.i18n.I18n; import org.xnap.commons.i18n.I18nFactory; import javax.sql.DataSource; import java.io.PrintWriter; import java.sql.*; import java.util.HashMap; import java.util.Map; import java.util.Properties; /** * Using CoreWorkspace to declare the DataSource service in Declarative Service framework. * @author Nicolas Fortin */ @Component public class DataSourceService implements DataSource { private DataSource dataSource; private CoreWorkspace coreWorkspace; private Map<String, DataSourceFactory> dataSourceFactories = new HashMap<>(); private static final Map<String,String> URI_DRIVER_TO_OSGI_DRIVER = new HashMap<>(); private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceService.class); private static final I18n I18N = I18nFactory.getI18n(DataSourceService.class); private static final String H2_OSGI_DRIVER_NAME = "h2 jdbc driver"; static { URI_DRIVER_TO_OSGI_DRIVER.put("h2",H2_OSGI_DRIVER_NAME); URI_DRIVER_TO_OSGI_DRIVER.put("postgresql","postgresql"); } /** * @param coreWorkspace CoreWorkspace with valid connection */ @Reference public void setCoreWorkspace(CoreWorkspace coreWorkspace) { this.coreWorkspace = coreWorkspace; } /** * Create internal datasource using {@link #setCoreWorkspace(org.orbisgis.frameworkapi.CoreWorkspace)} and {@link * #addDataSourceFactory(org.osgi.service.jdbc.DataSourceFactory, java.util.Map)} * @throws SQLException If the DataSource could not be created */ @Activate public void activate() throws SQLException { // Build DataSource newDataSource(); } @Deactivate public void deactivate() throws SQLException { // Wait for H2 close try(Connection connection = getConnection(); Statement st = connection.createStatement()) { DatabaseMetaData metaData = connection.getMetaData(); if(JDBCUtilities.isH2DataBase(metaData) && !metaData.getURL().contains("tcp")) { st.execute("SHUTDOWN"); } } } private void newDataSource() throws SQLException { String jdbcConnectionReference = coreWorkspace.getJDBCConnectionReference(); if(!jdbcConnectionReference.isEmpty()) { Properties properties = JDBCUrlParser.parse(jdbcConnectionReference); String driverName = jdbcConnectionReference.split(":")[1]; properties.setProperty(DataSourceFactory.JDBC_USER,coreWorkspace.getDataBaseUser()); if(coreWorkspace.isRequirePassword()) { properties.setProperty(DataSourceFactory.JDBC_PASSWORD, coreWorkspace.getDataBasePassword()); } // Fetch requested Driver String osgiDriverName = URI_DRIVER_TO_OSGI_DRIVER.get(driverName); DataSourceFactory dataSourceFactory = dataSourceFactories.get(osgiDriverName); if(dataSourceFactory != null) { if(H2_OSGI_DRIVER_NAME.equals(osgiDriverName) && !properties.containsKey(DataSourceFactory.JDBC_SERVER_NAME)) { //;DATABASE_EVENT_LISTENER='org.orbisgis.h2triggers.H2DatabaseEventListener' // For local H2 Database link immediately with a database listener // as it will allow open a database event if some db objects cannot be initialised // see https://github.com/orbisgis/orbisgis/issues/793 properties.put("DATABASE_EVENT_LISTENER","'org.orbisgis.h2triggers.H2DatabaseEventListener'"); } dataSource = SFSUtilities.wrapSpatialDataSource(dataSourceFactory.createDataSource(properties)); // Init spatial try(Connection connection = dataSource.getConnection(); Statement st = connection.createStatement()) { if (JDBCUtilities.isH2DataBase(connection.getMetaData()) && !JDBCUtilities.tableExists(connection, "PUBLIC.GEOMETRY_COLUMNS")) { st.execute("CREATE ALIAS IF NOT EXISTS H2GIS_EXTENSION FOR\n" + " \"org.h2gis.ext.H2GISExtension.load\";\n" + "CALL H2GIS_EXTENSION();"); } } } else { throw new SQLException(String.format("The database driver %s is not available",driverName)); } } else { throw new SQLException("DataBase path not found"); } } public void unsetCoreWorkspace(CoreWorkspace coreWorkspace) { coreWorkspace = null; } /** * @param dataSourceFactory DataSourceFactory instance * @param serviceProperties Must contain DataSourceFactory.OSGI_JDBC_DRIVER_NAME entry. */ @Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY) public void addDataSourceFactory(DataSourceFactory dataSourceFactory, Map<String,String> serviceProperties) { LOGGER.debug("DataSourceFactory "+serviceProperties.get(DataSourceFactory.OSGI_JDBC_DRIVER_NAME)+" is available"); dataSourceFactories.put(serviceProperties.get(DataSourceFactory.OSGI_JDBC_DRIVER_NAME).toLowerCase(), dataSourceFactory); } /** * @param dataSourceFactory DataSourceFactory instance * @param serviceProperties Must contain DataSourceFactory.OSGI_JDBC_DRIVER_NAME entry. */ public void removeDataSourceFactory(DataSourceFactory dataSourceFactory, Map<String,String> serviceProperties) { dataSourceFactories.remove(serviceProperties.get(DataSourceFactory.OSGI_JDBC_DRIVER_NAME).toLowerCase()); } @Override public Connection getConnection() throws SQLException { return dataSource.getConnection(); } @Override public Connection getConnection(String username, String password) throws SQLException { return dataSource.getConnection(username, password); } @Override public PrintWriter getLogWriter() throws SQLException { return dataSource.getLogWriter(); } @Override public void setLogWriter(PrintWriter out) throws SQLException { dataSource.setLogWriter(out); } @Override public void setLoginTimeout(int seconds) throws SQLException { dataSource.setLoginTimeout(seconds); } @Override public int getLoginTimeout() throws SQLException { return dataSource.getLoginTimeout(); } @Override public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException { return dataSource.getParentLogger(); } @Override public <T> T unwrap(Class<T> iface) throws SQLException { return dataSource.unwrap(iface); } @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { return dataSource.isWrapperFor(iface); } }