
org.kawanfw.sql.api.server.DefaultDatabaseConfigurator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aceql-http Show documentation
Show all versions of aceql-http Show documentation
AceQL HTTP is a framework of REST like http APIs that allow to access to remote SQL databases over http from any device that supports http.
AceQL HTTP is provided with four client SDK:
- The AceQL C# Client SDK allows to wrap the HTTP APIs using Microsoft SQL Server like calls in their code, just like they would for a local database.
- The AceQL Java Client SDK allows to wrap the HTTP APIs using JDBC calls in their code, just like they would for a local database.
- The AceQL Python Client SDK allows SQL calls to be encoded with standard unmodified DB-API 2.0 syntax
/*
* Copyright (c)2022 KawanSoft S.A.S. All rights reserved.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-11-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
package org.kawanfw.sql.api.server;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import javax.sql.DataSource;
import org.apache.commons.lang3.StringUtils;
import org.kawanfw.sql.api.server.logging.DefaultLoggerCreator;
import org.kawanfw.sql.api.server.util.UsernameConverter;
import org.kawanfw.sql.servlet.injection.properties.PropertiesFileStore;
import org.kawanfw.sql.servlet.injection.properties.PropertiesFileUtil;
import org.kawanfw.sql.servlet.util.logging.LoggerWrapper;
import org.kawanfw.sql.tomcat.TomcatSqlModeStore;
import org.kawanfw.sql.util.Tag;
import org.slf4j.Logger;
/**
* Default implementation of server side configuration for AceQL.
*
* The two fully functional and secured methods are:
*
* - {@link #getConnection(String)} that extracts {@code Connections} from a
* Tomcat JDBC Connection Pool.
* - {@link #close(Connection)} that simplify closes the {@code Connection} and thus
* releases it into the pool.
*
*
* @author Nicolas de Pomereu
*/
public class DefaultDatabaseConfigurator implements DatabaseConfigurator {
/**
* If {@code true}, allows to "flatten" the log messages to make sure each log
* entry/message has only one line (CR/LF of the message will be suppressed).
* See {@link #getLogger()} code.
*/
protected boolean flattenLogMessages = true;
/** The map of (database, data sources) to use for connection pooling */
private Map dataSourceSet = new ConcurrentHashMap<>();
private Properties properties = null;
private static Logger ACEQL_LOGGER = null;
private static Map LOGGER_ELEMENTS = new ConcurrentHashMap<>();
/**
* Returns a {@code Connection} from
* Tomcat JDBC
* Connection Pool.
*
* the {@code Connection} is extracted from the {@code DataSource} created by
* the embedded Tomcat JDBC Pool. The JDBC parameters used to create the
* {@code DataSource} are defined in the properties file passed at start-up of
* AceQL.
*
* @param database the database name to extract the {@code Connection} for.
*
* @return the {@code Connection} extracted from Tomcat JDBC Connection Pool.
*/
@Override
public Connection getConnection(String database) throws SQLException {
DataSource dataSource = dataSourceSet.get(database);
if (dataSource == null) {
dataSource = TomcatSqlModeStore.getDataSource(database);
if (dataSource == null) {
if (TomcatSqlModeStore.isTomcatEmbedded()) {
String message = Tag.PRODUCT_USER_CONFIG_FAIL
+ " the \"driverClassName\" property is not defined in the properties file for database "
+ database + " or the Db Vendor is not supported in this version.";
// ServerLogger.getLogger().log(Level.WARNING, message);
throw new SQLException(message);
} else {
String message = Tag.PRODUCT_USER_CONFIG_FAIL
+ " the \"driverClassName\" property is not defined in the properties file for database "
+ database + " or the servlet name does not match the url pattern in your web.xml";
// ServerLogger.getLogger().log(Level.WARNING, message);
throw new SQLException(message);
}
}
dataSourceSet.put(database, dataSource);
}
Connection connection = dataSource.getConnection();
return connection;
}
/**
* Closes the connection acquired by
* {@link DatabaseConfigurator#getConnection(String)} with a call to
* Connection.close()
.
* Note that Exceptions are trapped to avoid client failure. Stack trace is
* printed on standard error stream.
*/
@Override
public void close(Connection connection) throws SQLException {
try {
if (connection != null) {
connection.close();
}
} catch (Exception e) {
try {
Logger logger = getLogger();
LoggerWrapper.log(logger, "Error on close(): ", e);
} catch (Exception io) {
// Should never happen
io.printStackTrace();
}
}
}
/**
* @return the value of the property {@code defaultDatabaseConfigurator.maxRows}
* defined in the {@code aceql-server.properties} file at server
* startup. If property does not exist, returns 0.
*/
@Override
public int getMaxRows(String username, String database) throws IOException, SQLException {
int maxRows = 0;
setProperties();
String maxRowsStr = properties.getProperty("defaultDatabaseConfigurator.maxRows");
// No limit if not set
if (maxRowsStr == null) {
return 0;
}
if (!StringUtils.isNumeric(maxRowsStr)) {
throw new IllegalArgumentException(
"The defaultDatabaseConfigurator.maxRows property is not numeric: " + maxRowsStr);
}
maxRows = Integer.parseInt(maxRowsStr);
return maxRows;
}
/**
* @return user.home/.aceql-server-root/username
. (
* {@code user.home} is the one of the servlet container).
*/
@Override
public File getBlobsDirectory(final String username) throws IOException, SQLException {
String userHome = System.getProperty("user.home");
if (!userHome.endsWith(File.separator)) {
userHome += File.separator;
}
// Escape invalid chars, mostly for Windows
String usernameNew = UsernameConverter.fromSpecialChars(username);
userHome += ".aceql-server-root" + File.separator + usernameNew;
File userHomeDir = new File(userHome);
userHomeDir.mkdirs();
return userHomeDir;
}
/**
* Creates a static default Logback/sl4fj Logger for main AceQL activity.
*
* Logger has default characteristics:
*
* - Name: {@code DefaultLoggerCreator}
* - Log directory: {@code user.home/.kawansoft/log}
* - File name pattern: {@code "aceql_%d.log.%i"} (example of file created:
* {@code aceql_2022-07-01.log.1}.)
* - Pattern of each line of log:
"%d{HH:mm:ss.SSS} [%thread] %-5level
* %logger{36} - %msg%n"}
* - Maximum File Size: 300Mb
* - Total Size Cap: 30Gb
*
* These default values may be superseded by creating a
* {@code DefaultLoggerCreator.properties} file in
* {@code user.home/.kawansoft/conf}.
*
*
* See the DefaultLoggerCreator.properties
* format.
*
*
*/
@Override
public Logger getLogger() throws IOException {
if (ACEQL_LOGGER != null) {
return ACEQL_LOGGER;
}
DefaultLoggerCreator defaultLoggerCreator = new DefaultLoggerCreator();
ACEQL_LOGGER = defaultLoggerCreator.getLogger();
LOGGER_ELEMENTS = defaultLoggerCreator.getElements();
return ACEQL_LOGGER;
}
/**
* Returns the Logger elements (for debug purpose)
*
* @return the lOGGER_ELEMENTS
*/
public static Map getLoggerElements() {
return LOGGER_ELEMENTS;
}
/**
* Sets in memory the Properties of the used {@code aceql-server.properties}
* file.
*
* @throws IOException
* @throws DatabaseConfigurationException
*/
private void setProperties() throws IOException, DatabaseConfigurationException {
if (properties == null) {
File file = PropertiesFileStore.get();
properties = PropertiesFileUtil.getProperties(file);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy