/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.constellation.metadata.io.filesystem.sql;
import org.apache.sis.util.logging.Logging;
import org.constellation.configuration.ConfigDirectory;
import org.constellation.util.Util;
import org.geotoolkit.internal.sql.DefaultDataSource;
import org.geotoolkit.util.sql.DerbySqlScriptRunner;
import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
/**
*
* @author Guilhem Legal (Geomatys)
*/
public class MetadataDatasource {
private static final Logger LOGGER = Logging.getLogger("org.constellation.metadata.io.filesystem.sql");
/**
* CSW database {@link DefaultDataSource} instance.
*/
private static final Map<String, DataSource> DATA_SOURCE = new HashMap<>();
/**
* Obtains a csw database {@link org.constellation.metadata.io.filesystem.sql.Session} instance.
*
* @param serviceID
* @return a {@link org.constellation.admin.dao.Session} instance
* @throws SQLException if a database access error occurs
*/
public static Session createSession(final String serviceID) throws SQLException {
final DataSource source = getOrCreateDataSource(serviceID);
return new Session(source.getConnection());
}
private static DataSource getOrCreateDataSource(final String serviceID) throws SQLException {
final DataSource source = DATA_SOURCE.get(serviceID);
synchronized(MetadataDatasource.class) {
if (source == null) {
return setup(serviceID);
}
}
return source;
}
/**
* Sets static connection variables and check if the csw schema named
* {@code "csw"} exists on the current {@link DataSource}.
* <p />
* If the schema is missing create it executing the {@code create-csw-db.sql} resource file.
*
* @throws SQLException if an error occurred while connecting to database or executing a SQL statement
*/
private static DataSource setup(final String serviceID) throws SQLException {
// Force loading driver because some container like tomcat 7.0.21+ disable drivers at startup.
try {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
} catch (ClassNotFoundException ex) {
LOGGER.log(Level.WARNING, ex.getMessage(), ex);
}
final File configDirectory = ConfigDirectory.getInstanceDirectory("CSW", serviceID);
// Read or create default configuration.
if (!configDirectory.exists()) {
configDirectory.mkdir();
}
// Initialize data source.
final String dbUrl = "jdbc:derby:" + configDirectory.getPath() + "/csw-db;create=true;";
LOGGER.log(Level.INFO, "connection to {0}", dbUrl);
final DataSource source = new DefaultDataSource(dbUrl);
// Establish connection and create schema if does not exist.
Connection con = null;
try {
con = source.getConnection();
if (!schemaExists(con, "csw")) {
// Load database schema SQL stream.
final InputStream stream = Util.getResourceAsStream("org/constellation/csw/filesystem/sql/v1/create-csw-db.sql");
// Create schema.
final DerbySqlScriptRunner runner = new DerbySqlScriptRunner(con);
runner.run(stream);
runner.close(false);
}
} catch (IOException unexpected) {
throw new IllegalStateException("Unexpected error occurred while trying to create csw database schema.", unexpected);
} finally {
if (con != null) {
con.close();
}
}
DATA_SOURCE.put(serviceID, source);
return source;
}
private static boolean schemaExists(final Connection connect, final String schemaName) throws SQLException {
ensureNonNull("schemaName", schemaName);
final ResultSet schemas = connect.getMetaData().getSchemas();
while (schemas.next()) {
if (schemaName.equals(schemas.getString(1))) {
return true;
}
}
return false;
}
public static void close(final String serviceID) {
final DefaultDataSource source = (DefaultDataSource) DATA_SOURCE.get(serviceID);
if (source != null) {
source.shutdown();
DATA_SOURCE.remove(serviceID);
}
}
}