Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2015-2018 Rocket Partners, LLC
* https://github.com/inversion-api
*
* 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 io.inversion.jdbc;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.inversion.*;
import io.inversion.Collection;
import io.inversion.Api.ApiListener;
import io.inversion.jdbc.JdbcUtils.SqlListener;
import io.inversion.rql.Term;
import io.inversion.utils.Config;
import io.inversion.utils.Rows.Row;
import io.inversion.utils.Utils;
import org.apache.commons.configuration2.Configuration;
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;
/**
* Exposes the tables of a JDBC data source as REST Collections.
*/
public class JdbcDb extends Db {
static final Map DEFAULT_DRIVERS = new HashMap<>();
static final Map pools = new Hashtable<>();
static {
DEFAULT_DRIVERS.put("h2", "org.h2.Driver");
DEFAULT_DRIVERS.put("mysql", "com.mysql.cj.jdbc.Driver");
DEFAULT_DRIVERS.put("postgres", "org.postgresql.Driver");
DEFAULT_DRIVERS.put("sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
}
static {
JdbcUtils.addSqlListener(new SqlListener() {
final ch.qos.logback.classic.Logger log = (ch.qos.logback.classic.Logger) org.slf4j.LoggerFactory.getLogger(JdbcDb.class);
@Override
public void onError(String method, String sql, Object args, Exception ex) {
if (method != null && method.equals("selectRows")) {
log.error("SQL error in '" + method + "' [" + sql.replace("\r\n", "") + "] " + ex.getMessage());
} else {
log.warn(ex.getMessage(), ex);
}
}
@Override
public void beforeStmt(String method, String sql, Object args) {
}
@Override
public void afterStmt(String method, String sql, Object args, Exception ex, Object result) {
String debugPrefix = "SqlDb: ";
String debugType = "unknown";
if (Chain.peek() != null) {
Collection coll = Chain.top().getRequest().getCollection();
if (coll != null && coll.getDb() != null) {
Db db = coll.getDb();
debugType = db.getType().toLowerCase();
}
}
debugPrefix += debugType;
args = (args != null && args.getClass().isArray() ? Arrays.asList((Object[]) args) : args);
sql = sql.replaceAll("\r", "");
sql = sql.replaceAll("\n", " ");
sql = sql.trim().replaceAll(" +", " ");
StringBuilder buff = new StringBuilder();
buff.append(debugPrefix).append(" -> '").append(sql).append("'").append(" args=").append(args).append(" error='").append(ex != null ? ex.getMessage() : "").append("'");
String msg = buff.toString();
Chain.debug(msg);
}
});
}
/**
* Urls to DDL files that should be executed on startup of this Db.
*/
protected final List ddlUrls = new ArrayList<>();
protected char stringQuote = '\'';
protected char columnQuote = '"';
/**
* The JDBC driver class name.
*/
protected String driver = null;
/**
* The JDBC url.
*
* Generally you will want to have this value dependency inject this at runtime by setting "${name}.url=${MY_DB_URL}" somewhere
* where it can be discovered by Config...for example as an environment variable or in an inversion.properties file.
*
* @see Config
* @see Configuration
*/
protected String url = null;
/**
* The JDBC username.
*
* Generally you will want to have this value dependency inject this at runtime by setting "${name}.user=${MY_DB_USER_NAME}" somewhere
* where it can be discovered by Config...for example as an environment variable or in an inversion.properties file.
*
* @see Config
* @see Configuration
*/
protected String user = null;
/**
* The JDBC password.
*
* Generally you will want to have this value dependency inject this at runtime by setting "${name}.user=${MY_DB_USER_NAME}" somewhere
* where it can be discovered by Config...for example as an environment variable or in an inversion.properties file.
*
* @see Config
* @see Configuration
*/
protected String pass = null;
/**
* The maximum number of connections in the JDBC Connection pool, defaults to 50.
*/
protected int poolMax = 50;
protected int idleConnectionTestPeriod = 3600; // in seconds
/**
* Should the JDBC connection be set to autoCommit.
*
* By default, autoCommit is false because the system is setup to execute all sql statements for a single Request
* inside of one transaction that commits just before the root Response is returned to the caller.
*/
protected boolean autoCommit = false;
/**
* For MySQL only, set this to false to turn off SQL_CALC_FOUND_ROWS and SELECT FOUND_ROWS()
*/
protected boolean calcRowsFound = true;
public JdbcDb() {
//System.out.println("JdbcDb() ");
}
public JdbcDb(String name) {
withName(name);
}
public JdbcDb(String name, String driver, String url, String user, String pass, String... ddlUrls) {
withName(name);
withDriver(driver);
withUrl(url);
withUser(user);
withPass(pass);
withDdlUrl(ddlUrls);
}
public JdbcDb(String url, String user, String pass) {
withUrl(url);
withUser(user);
withPass(pass);
}
@Override
protected void doStartup(Api api) {
if (isType("mysql"))
withColumnQuote('`');
super.doStartup(api);
api.withApiListener(new ApiListener() {
@Override
public void onStartup(Api api) {
}
@Override
public void onShutdown(Api api) {
}
@Override
public void afterRequest(Request req, Response res) {
try {
JdbcConnectionLocal.commit();
} catch (Exception ex) {
throw ApiException.new500InternalServerError(ex, "Error committing tansaction");
}
}
@Override
public void afterError(Request req, Response res) {
try {
JdbcConnectionLocal.rollback();
} catch (Throwable t) {
log.warn("Error rollowing back transaction.", t);
}
}
@Override
public void beforeFinally(Request req, Response res) {
try {
JdbcConnectionLocal.close();
} catch (Throwable t) {
log.warn("Error closing connections.", t);
}
}
});
}
protected void doShutdown() {
if (isType("h2") && getUrl() != null) {
try {
String url = getUrl().toUpperCase();
if (url.indexOf(":MEM:") > 0 && url.indexOf("DB_CLOSE_DELAY=-1") > 0) {
JdbcUtils.execute(getConnection(), "SHUTDOWN");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
DataSource pool = pools.get(this);
if (pool != null) {
System.out.println("CLOSING CONNECTION POOL : " + getUrl());
((HikariDataSource) pool).close();
}
}
@Override
public String getType() {
if (type != null)
return type;
String url = getUrl();
url = url != null ? url : getDriver();
if (url != null) {
if (url.contains("mysql"))
return "mysql";
if (url.contains("postgres"))
return "postgres";
if (url.contains("redshift"))
return "redshift";
if (url.contains("sqlserver"))
return "sqlserver";
if (url.contains("h2"))
return "h2";
}
log.warn("Unable to determine db type. type='{}', driver='{}', url='{}'", this.type, this.driver, this.url);
if(Chain.peek() != null) {
Chain.peek().getResponse().debug("Unable to determine db type. type='{}', driver='{}', url='{}'", this.type, this.driver, this.url);
}
return "UNKNOWN";
}
@Override
public Results doSelect(Collection coll, List columnMappedTerms) throws ApiException {
SqlQuery query = new SqlQuery<>(this, coll, columnMappedTerms);
return query.doSelect();
}
@Override
public List doUpsert(Collection table, List