You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2019/04/18 14:34:54 UTC
svn commit: r1857751 - in
/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model:
sql/ util/
Author: cbrisson
Date: Thu Apr 18 14:34:54 2019
New Revision: 1857751
URL: http://svn.apache.org/viewvc?rev=1857751&view=rev
Log:
[tools/model] Initial import: sql utilities
Added:
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/BasicDataSource.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionPool.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionWrapper.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Credentials.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/DriverInfos.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pool.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pooled.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/PooledStatement.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/RowValues.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/SqlUtils.java
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/StatementPool.java
Modified:
velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/util/TypeUtils.java
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/BasicDataSource.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/BasicDataSource.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/BasicDataSource.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/BasicDataSource.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,74 @@
+package org.apache.velocity.tools.model.sql;
+
+import javax.sql.DataSource;
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+
+public class BasicDataSource implements DataSource
+{
+ public BasicDataSource(String databaseURL)
+ {
+ this.databaseURL = databaseURL;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException
+ {
+ return DriverManager.getConnection(databaseURL);
+ }
+
+ @Override
+ public Connection getConnection(String user, String password) throws SQLException
+ {
+ return DriverManager.getConnection(databaseURL, user, password);
+ }
+
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException
+ {
+ return false;
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException
+ {
+ return logWriter;
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws SQLException
+ {
+ logWriter = out;
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws SQLException
+ {
+
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException
+ {
+ return 0;
+ }
+
+ @Override
+ public java.util.logging.Logger getParentLogger() throws SQLFeatureNotSupportedException
+ {
+ throw new SQLFeatureNotSupportedException("not using JDK logging");
+ }
+
+ private String databaseURL;
+
+ private PrintWriter logWriter = null;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionPool.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionPool.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionPool.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionPool.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,199 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.sql.DataSource;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Connection pool.
+ *
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ */
+public class ConnectionPool implements Serializable
+{
+ protected static Logger logger = LoggerFactory.getLogger(ConnectionPool.class);
+
+ /**
+ * Constructor.
+ * @param schema schema
+ * @param driverInfos infos on the driverInfos
+ * @param autocommit autocommit
+ * @param max max connections
+ * @throws SQLException
+ * /
+ public ConnectionPool(String schema, DriverInfos driverInfos, boolean autocommit, int max)
+ throws SQLException
+ {
+ this.schema = schema;
+ this.driverInfos = driverInfos;
+ this.autocommit = autocommit;
+ connections = new ArrayList<ConnectionWrapper>();
+ this.max = max;
+ }
+ */
+
+ /**
+ *
+ * @param dataSource
+ * @param schema
+ * @param max
+ * @throws SQLException
+ */
+ public ConnectionPool(DataSource dataSource, Credentials credentials, DriverInfos driverInfos, String schema, boolean autocommit, int max) throws SQLException
+ {
+ this.dataSource = dataSource;
+ this.credentials = credentials;
+ this.driverInfos = driverInfos;
+ this.schema = schema;
+ this.autocommit = autocommit;
+ this.max = max;
+ }
+
+ public DataSource getDataSource()
+ {
+ return dataSource;
+ }
+
+ public void setSchema(String schema)
+ {
+ this.schema = schema;
+ }
+
+ /**
+ * Get a connection.
+ * @return a connection
+ * @throws SQLException
+ */
+ public synchronized ConnectionWrapper getConnection() throws SQLException
+ {
+ for(Iterator it = connections.iterator(); it.hasNext(); )
+ {
+ ConnectionWrapper c = (ConnectionWrapper)it.next();
+
+ if(c.isClosed())
+ {
+ it.remove();
+ }
+ else if(!c.isBusy())
+ {
+ return c;
+ }
+ }
+ if(connections.size() == max)
+ {
+ logger.warn("Connection pool: max number of connections reached! ");
+
+ // return a busy connection...
+ return connections.get(0);
+ }
+
+ ConnectionWrapper newconn = createConnection();
+
+ connections.add(newconn);
+ return newconn;
+ }
+
+ /**
+ * Create a connection.
+ *
+ * @return connection
+ * @throws SQLException
+ */
+ private ConnectionWrapper createConnection() throws SQLException
+ {
+ logger.info("Creating a new connection.");
+
+ Connection connection = credentials.getConnection(dataSource);
+
+ // schema
+ if(schema != null && schema.length() > 0)
+ {
+ String schemaQuery = driverInfos.getSchemaQuery();
+
+ if(schemaQuery != null)
+ {
+ schemaQuery = schemaQuery.replace("$schema", schema);
+ Statement stmt = connection.createStatement();
+
+ stmt.executeUpdate(schemaQuery);
+ stmt.close();
+ }
+ }
+
+ // autocommit
+ connection.setAutoCommit(autocommit);
+ return new ConnectionWrapper(driverInfos, connection);
+ }
+
+/*
+ private String getSchema(Connection connection) throws SQLException
+ {
+ Statement stmt = connection.createStatement();
+ ResultSet rs = stmt.executeQuery("select sys_context('userenv','current_schema') from dual");
+ rs.next();
+ return rs.getString(1);
+ }*/
+
+ /**
+ * clear all connections.
+ */
+ public void clear()
+ {
+ for(Iterator it = connections.iterator(); it.hasNext(); )
+ {
+ ConnectionWrapper c = (ConnectionWrapper)it.next();
+
+ try
+ {
+ c.close();
+ }
+ catch(SQLException sqle) {}
+ }
+ }
+
+ private DataSource dataSource;
+
+ private Credentials credentials;
+
+ /** optional schema */
+ private String schema = null;
+
+ /** infos on the driverInfos */
+ private DriverInfos driverInfos = null;
+
+ /** autocommit flag */
+ private boolean autocommit = true;
+
+ /** list of all connections */
+ private List<ConnectionWrapper> connections = new ArrayList<>();
+
+ /** Maximum number of connections. */
+ private int max;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionWrapper.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionWrapper.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionWrapper.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/ConnectionWrapper.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,1029 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ * Connection wrapper class. Allows the handling of a busy state
+ *
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ */
+
+public class ConnectionWrapper
+ implements Connection, Serializable
+{
+
+ protected static Logger logger = LoggerFactory.getLogger(ConnectionWrapper.class);
+
+ /**
+ * Constructor.
+ * @param driverInfos infos on the driver
+ * @param connection connection to be wrapped
+ */
+ public ConnectionWrapper(DriverInfos driverInfos, Connection connection)
+ {
+ this.driverInfos = driverInfos;
+ this.connection = connection;
+ }
+
+ /**
+ * Unwrap the connection.
+ * @return the unwrapped connection
+ */
+ public Connection unwrap()
+ {
+ return connection;
+ }
+
+ /**
+ * Create a statement.
+ * @return created statement
+ * @throws SQLException
+ */
+ public synchronized Statement createStatement()
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createStatement();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a callable statement.
+ * @param s SQL query
+ * @return prepared callable statement
+ * @throws SQLException
+ */
+ public synchronized CallableStatement prepareCall(String s)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareCall(s);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Gets native SQL for a query.
+ * @param s query
+ * @return native SQL
+ * @throws SQLException
+ */
+ public synchronized String nativeSQL(String s)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.nativeSQL(s);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Set autocommit flag.
+ * @param flag autocommit
+ * @throws SQLException
+ */
+ public void setAutoCommit(boolean flag)
+ throws SQLException
+ {
+ connection.setAutoCommit(flag);
+ }
+
+ /**
+ * Get autocommit flag.
+ *
+ * @return autocommit flag
+ * @throws SQLException
+ */
+ public boolean getAutoCommit()
+ throws SQLException
+ {
+ return connection.getAutoCommit();
+ }
+
+ /**
+ * Commit.
+ *
+ * @throws SQLException
+ */
+ public synchronized void commit()
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ connection.commit();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Rollback.
+ *
+ * @throws SQLException
+ */
+ public synchronized void rollback()
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ connection.rollback();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Close.
+ *
+ * @throws SQLException
+ */
+ public void close()
+ throws SQLException
+ {
+ // since some sql drivers refuse to close a connection that has been interrupted,
+ // better handle this also ourselves
+ closed = true;
+ connection.close();
+ }
+
+ /**
+ * Check the closed state.
+ * @return closed state
+ * @throws SQLException
+ */
+ public boolean isClosed()
+ throws SQLException
+ {
+ return (closed || connection == null || connection.isClosed());
+ }
+
+ /**
+ * Get meta data
+ * @return database meta data
+ * @throws SQLException
+ */
+ public DatabaseMetaData getMetaData()
+ throws SQLException
+ {
+ return connection.getMetaData();
+ }
+
+ /**
+ * set read-only flag
+ * @param flag read-only
+ * @throws SQLException
+ */
+ public void setReadOnly(boolean flag)
+ throws SQLException
+ {
+ connection.setReadOnly(flag);
+ }
+
+ /**
+ * Check the read-only state.
+ * @return read-only state
+ * @throws SQLException
+ */
+ public boolean isReadOnly()
+ throws SQLException
+ {
+ return connection.isReadOnly();
+ }
+
+ /**
+ * Catalog setter.
+ * @param s catalog
+ * @throws SQLException
+ */
+ public void setCatalog(String s)
+ throws SQLException
+ {
+ connection.setCatalog(s);
+ }
+
+ /**
+ * Catalog getter.
+ * @return catalog
+ * @throws SQLException
+ */
+
+ public String getCatalog()
+ throws SQLException
+ {
+ return connection.getCatalog();
+ }
+ /**
+ * Transaction isolation setter.
+ * @param i transaction isolation
+ * @throws SQLException
+ */
+
+ public void setTransactionIsolation(int i)
+ throws SQLException
+ {
+ connection.setTransactionIsolation(i);
+ }
+
+ /**
+ * Transaction isolation getter.
+ * @return transaction isolation
+ * @throws SQLException
+ */
+ public int getTransactionIsolation()
+ throws SQLException
+ {
+ return connection.getTransactionIsolation();
+ }
+
+ /**
+ * Get SQL warnings.
+ * @return next SQL Warning.
+ * @throws SQLException
+ */
+ public SQLWarning getWarnings()
+ throws SQLException
+ {
+ return connection.getWarnings();
+ }
+
+ /**
+ * Clear SQL warnings.
+ * @throws SQLException
+ */
+ public void clearWarnings()
+ throws SQLException
+ {
+ connection.clearWarnings();
+ }
+
+ /**
+ * Create a statement.
+ *
+ * @param i result set type
+ * @param j result set concurrency
+ * @return new statement
+ * @throws SQLException
+ */
+ public synchronized Statement createStatement(int i, int j)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createStatement(i, j);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @param i result set type
+ * @param j result set concurrency
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s, int i, int j)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s, i, j);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a call.
+ * @param s SQL query
+ * @param i result set type
+ * @param j result set concurrency
+ * @return callable statement
+ * @throws SQLException
+ */
+ public synchronized CallableStatement prepareCall(String s, int i, int j)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareCall(s, i, j);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Get type map.
+ * @return type map
+ * @throws SQLException
+ */
+ public Map getTypeMap()
+ throws SQLException
+ {
+ return connection.getTypeMap();
+ }
+
+ /**
+ * Set type map.
+ * @param map type map
+ * @throws SQLException
+ */
+ public void setTypeMap(Map map)
+ throws SQLException
+ {
+ connection.setTypeMap(map);
+ }
+
+ /**
+ * Set holdability.
+ * @param i holdability
+ * @throws SQLException
+ */
+ public void setHoldability(int i)
+ throws SQLException
+ {
+ connection.setHoldability(i);
+ }
+
+ /**
+ * Get holdability.
+ * @return holdability
+ * @throws SQLException
+ */
+ public int getHoldability()
+ throws SQLException
+ {
+ return connection.getHoldability();
+ }
+
+ /**
+ * Savepoint setter.
+ * @return save point
+ * @throws SQLException
+ */
+ public synchronized Savepoint setSavepoint()
+ throws SQLException
+ {
+ return connection.setSavepoint();
+ }
+
+ /**
+ * Set named savepoint.
+ * @param s savepoint name
+ * @return savepoint
+ * @throws SQLException
+ */
+ public synchronized Savepoint setSavepoint(String s)
+ throws SQLException
+ {
+ return connection.setSavepoint(s);
+ }
+
+ /**
+ * Rollback.
+ * @param savepoint savepoint
+ * @throws SQLException
+ */
+ public synchronized void rollback(Savepoint savepoint)
+ throws SQLException
+ {
+ connection.rollback(savepoint);
+ }
+ /**
+ * Release savepoint.
+ *
+ * @param savepoint savepoint
+ * @throws SQLException
+ */
+ public synchronized void releaseSavepoint(Savepoint savepoint)
+ throws SQLException
+ {
+ connection.releaseSavepoint(savepoint);
+ }
+
+ /**
+ * Create a statement.
+ * @param i result set type
+ * @param j result set concurrency
+ * @param k result set holdability
+ * @return created statement
+ * @throws SQLException
+ */
+ public synchronized Statement createStatement(int i, int j, int k)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createStatement(i, j, k);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @param i result set type
+ * @param j result set concurrency
+ * @param k result set holdability
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s, int i, int j, int k)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s, i, j, k);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a callable statement.
+ * @param s SQL query
+ * @param i result set type
+ * @param j result set concurrency
+ * @param k result set holdability
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized CallableStatement prepareCall(String s, int i, int j, int k)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareCall(s, i, j, k);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @param i autogenerated keys
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s, int i)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s, i);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @param ai autogenerated keys column indexes
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s, int[] ai)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s, ai);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Prepare a statement.
+ * @param s SQL query
+ * @param as autogenerated keys column names
+ * @return prepared statement
+ * @throws SQLException
+ */
+ public synchronized PreparedStatement prepareStatement(String s, String[] as)
+ throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.prepareStatement(s,as);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ /**
+ * Enter busy state.
+ */
+ public synchronized void enterBusyState()
+ {
+ //Logger.trace("connection #"+toString()+": entering busy state.");
+ busy++;
+ }
+
+ /**
+ * Leave busy state.
+ */
+ public synchronized void leaveBusyState()
+ {
+ lastUse = System.currentTimeMillis();
+ busy--;
+ //Logger.trace("connection #"+toString()+": leaving busy state.");
+ }
+
+ /**
+ * Check busy state.
+ * @return busy state
+ */
+ public boolean isBusy()
+ {
+ return busy > 0;
+ }
+
+ /**
+ * Get last use timestamp
+ *
+ * @return last use
+ */
+ public long getLastUse()
+ {
+ return lastUse;
+ }
+
+ public DriverInfos getDriverInfos()
+ {
+ return driverInfos;
+ }
+
+ /**
+ * Get last inserted ID.
+ *
+ * @param statement
+ * @return last inserted id
+ * @throws SQLException
+ */
+ public long getLastInsertId(Statement statement, String keyColumn) throws SQLException
+ {
+ long ret = -1;
+ switch (driverInfos.getLastInsertIdPolicy())
+ {
+ case METHOD:
+ {
+ if (lastInsertIdMethod == null)
+ {
+ synchronized(this)
+ {
+ if (lastInsertIdMethod == null)
+ {
+ try
+ {
+ lastInsertIdMethod = statement.getClass().getMethod(driverInfos.getLastInsertIdMethodName());
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ throw new SQLException("cannot get last insert id", nsme);
+ }
+ }
+ }
+ }
+ try
+ {
+ ret = ((Long)lastInsertIdMethod.invoke(statement)).longValue();
+ }
+ catch (IllegalAccessException | InvocationTargetException e)
+ {
+ throw new SQLException("cannot get last insert id", e);
+ }
+ break;
+ }
+ case GENERATED_KEYS:
+ {
+ ResultSet rs = statement.getGeneratedKeys();
+ ResultSetMetaData meta = rs.getMetaData();
+ int colNum = meta.getColumnCount();
+ if (rs.next())
+ {
+ ret = colNum == 1 ? rs.getLong(1) : rs.getLong(keyColumn);
+ if (rs.wasNull())
+ {
+ ret = -1;
+ }
+ }
+ rs.close();
+ }
+ case QUERY:
+ {
+ ResultSet rs = statement.getConnection().createStatement().executeQuery(driverInfos.getLastInsertIdQuery());
+ rs.next();
+ ret = rs.getLong(1);
+ if (rs.wasNull())
+ {
+ ret = -1;
+ }
+ rs.close();
+ }
+ case RETURNING:
+ {
+ throw new SQLException("not implemented");
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Check connection.
+ *
+ * @return true if the connection is ok
+ */
+ public synchronized boolean check()
+ {
+ try
+ {
+ String checkQuery = driverInfos.getPingQuery();
+ if (checkQuery == null)
+ {
+ // at least, call isClosed
+ return !isClosed();
+ }
+ else
+ {
+ if (checkStatement == null)
+ {
+ checkStatement = prepareStatement(checkQuery);
+ }
+ checkStatement.executeQuery();
+ }
+ return true;
+ }
+ catch (Exception e)
+ {
+ logger.warn("Exception while checking connection. Refreshing...");
+ return false;
+ }
+ }
+
+ /** Infos on the driver. */
+ private DriverInfos driverInfos = null;
+
+ private Method lastInsertIdMethod = null;
+
+ /** Wrapped connection. */
+ private transient Connection connection = null;
+
+ /** Busy state. */
+ private int busy = 0;
+
+ /** Last use */
+ private long lastUse = System.currentTimeMillis();
+
+ /** Closed state. */
+ private boolean closed = false;
+
+ /** statement used to check connection ("select 1").
+ */
+ private transient PreparedStatement checkStatement = null;
+
+ /*
+ * 1.6 API
+ */
+
+ public Clob createClob() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createClob();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public Blob createBlob() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createBlob();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public NClob createNClob() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createNClob();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public SQLXML createSQLXML() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createSQLXML();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public boolean isValid(int timeout) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.isValid(timeout);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public void setClientInfo(String name,String value) throws SQLClientInfoException
+ {
+ try
+ {
+ enterBusyState();
+ connection.setClientInfo(name, value);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public void setClientInfo(Properties properties) throws SQLClientInfoException
+ {
+ try
+ {
+ enterBusyState();
+ connection.setClientInfo(properties);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public Properties getClientInfo() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.getClientInfo();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public String getClientInfo(String name) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.getClientInfo(name);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createArrayOf(typeName, elements);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.createStruct(typeName, attributes);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public boolean isWrapperFor(Class<?> iface) throws SQLException
+ {
+ throw new SQLException("Unsupported method.");
+ }
+
+ public <T> T unwrap(Class<T> iface) throws SQLException
+ {
+ throw new SQLException("Unsupported method.");
+ }
+
+ /*
+ * 1.7 API
+ */
+
+ public void setSchema(String schema) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ connection.setSchema(schema);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public String getSchema() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.getSchema();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public void abort(Executor executor) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ connection.abort(executor);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ connection.setNetworkTimeout(executor, milliseconds);
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+ public int getNetworkTimeout() throws SQLException
+ {
+ try
+ {
+ enterBusyState();
+ return connection.getNetworkTimeout();
+ }
+ finally
+ {
+ leaveBusyState();
+ }
+ }
+
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Credentials.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Credentials.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Credentials.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Credentials.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,45 @@
+package org.apache.velocity.tools.model.sql;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+public final class Credentials
+{
+ public Credentials() {}
+
+ public String getUser()
+ {
+ return user;
+ }
+
+ public boolean hasCredentials()
+ {
+ return user != null && password != null;
+ }
+
+ public void setUser(String user)
+ {
+ this.user = user;
+ }
+
+ public void setPassword(String password)
+ {
+ this.password = password;
+ }
+
+ public Connection getConnection(DataSource dataSource) throws SQLException
+ {
+ if (hasCredentials())
+ {
+ return dataSource.getConnection(user, password);
+ }
+ else
+ {
+ return dataSource.getConnection();
+ }
+ }
+
+ private String user = null;
+ private String password = null;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/DriverInfos.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/DriverInfos.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/DriverInfos.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/DriverInfos.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,381 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import org.apache.velocity.tools.config.ConfigurationException;
+import org.apache.velocity.tools.model.config.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.function.UnaryOperator;
+import java.util.regex.Pattern;
+
+/**
+ * <p>Contains specific description and behaviour of jdbc drivers.</p>
+ *
+ * <p>Main sources:
+ * <ul><li>http://www.schemaresearch.com/products/srtransport/doc/modules/jdbcconf.html
+ * <li>http://db.apache.org/torque/ and org.apache.torque.adapter classes
+ * </ul></p>
+ *
+ * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
+ */
+public class DriverInfos implements Constants, Serializable
+{
+ protected static Logger logger = LoggerFactory.getLogger(DriverInfos.class);
+
+ /*
+ * Constructors
+ */
+
+ public DriverInfos()
+ {
+ }
+
+ public void setDefaults(DriverInfos other)
+ {
+ setTag(Optional.ofNullable(getTag()).orElse(other.getTag()));
+ setCatalog(Optional.ofNullable(getCatalog()).orElse(other.getCatalog()));
+ setPingQuery(Optional.ofNullable(getPingQuery()).orElse(other.getPingQuery()));
+ setTablesCaseSensitivity(Optional.ofNullable(getTablesCaseSensitivity()).orElse(other.getTablesCaseSensitivity()));
+ setSchemaQuery(Optional.ofNullable(getSchemaQuery()).orElse(other.getSchemaQuery()));
+ setLastInsertIdPolicy(Optional.ofNullable(getLastInsertIdPolicyString()).orElse(Optional.ofNullable(other.getLastInsertIdPolicyString()).orElse("none")));
+ setPedanticColumnTypes(Optional.ofNullable(isPedanticColumnTypes()).orElse(Optional.ofNullable(other.isPedanticColumnTypes()).orElse(false)));
+ setColumnMarkers(Optional.ofNullable(hasColumnMarkers()).orElse(Optional.ofNullable(other.hasColumnMarkers()).orElse(false)));
+ Pattern ignoreTablesPattern = Optional.ofNullable(getIgnoreTablesPattern()).orElse(other.getIgnoreTablesPattern());
+ setIgnoreTablesPattern(ignoreTablesPattern == null ? null : ignoreTablesPattern.toString());
+ Character idQuoteChar = Optional.of(getIdentifierQuoteChar()).orElse(other.getIdentifierQuoteChar());
+ setIdentifierQuoteChar(idQuoteChar == null ? null : String.valueOf(idQuoteChar));
+ }
+
+ /*
+ * Getters and setters
+ */
+
+ public String getTag()
+ {
+ return tag;
+ }
+
+ public void setTag(String tag)
+ {
+ this.tag = tag;
+ }
+
+ public String getCatalog()
+ {
+ return catalog;
+ }
+
+ public void setCatalog(String catalog)
+ {
+ this.catalog = catalog;
+ }
+
+ public String getPingQuery()
+ {
+ return pingQuery;
+ }
+
+ public void setPingQuery(String query)
+ {
+ this.pingQuery = pingQuery;
+ }
+
+ public CaseSensitivity getTablesCaseSensitivity()
+ {
+ return tablesCaseSensitivity;
+ }
+
+ public void setTablesCaseSensitivity(CaseSensitivity tablesCaseSensitivity)
+ {
+ this.tablesCaseSensitivity = tablesCaseSensitivity;
+ switch (tablesCaseSensitivity)
+ {
+ case LOWERCASE: filterTableName = t -> t.toLowerCase(Locale.ROOT); break;
+ case UPPERCASE: filterTableName = t -> t.toUpperCase(Locale.ROOT); break;
+ default: filterTableName = t -> t;
+ }
+ }
+
+ public String getSchemaQuery()
+ {
+ return schemaQuery;
+ }
+
+ public void setSchemaQuery(String schemaQuery)
+ {
+ this.schemaQuery = schemaQuery;
+ }
+
+ public LastInsertIdPolicy getLastInsertIdPolicy()
+ {
+ return lastInsertIdPolicy;
+ }
+
+ public String getLastInsertIdPolicyString()
+ {
+ if (lastInsertIdPolicy == null)
+ {
+ return null;
+ }
+ switch (lastInsertIdPolicy)
+ {
+ case NONE: return "none";
+ case GENERATED_KEYS: return "generated_keys";
+ case METHOD: return "method:" + getLastInsertIdMethodName();
+ case QUERY: return "query:" + getLastInsertIdQuery();
+ default: return null;
+ }
+ }
+
+ public void setLastInsertIdPolicy(String policy)
+ {
+ if (policy.startsWith("query:"))
+ {
+ lastInsertIdPolicy = LastInsertIdPolicy.QUERY;
+ lastInsertIdQuery = policy.substring(6).trim();
+ }
+ else if (policy.startsWith("method:"))
+ {
+ lastInsertIdPolicy = LastInsertIdPolicy.METHOD;
+ lastInsertIdMethodName = policy.substring(7).trim();
+ }
+ else
+ {
+ lastInsertIdPolicy = LastInsertIdPolicy.valueOf(policy.toUpperCase());
+ if (lastInsertIdPolicy == LastInsertIdPolicy.RETURNING)
+ {
+ throw new ConfigurationException("'returning' last insert id policy is not yet supported");
+ }
+ }
+ }
+
+ public String getLastInsertIdQuery()
+ {
+ return lastInsertIdQuery;
+ }
+
+ public String getLastInsertIdMethodName()
+ {
+ return lastInsertIdMethodName;
+ }
+
+ public Boolean isPedanticColumnTypes()
+ {
+ return pedanticColumnTypes;
+ }
+
+ public void setPedanticColumnTypes(boolean pedanticColumnTypes)
+ {
+ this.pedanticColumnTypes = pedanticColumnTypes;
+ }
+
+ public Pattern getIgnoreTablesPattern()
+ {
+ return ignoreTablesPattern;
+ }
+
+ public void setIgnoreTablesPattern(String pattern)
+ {
+ if (pattern != null && pattern.length() > 0)
+ {
+ ignoreTablesPattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
+ }
+ else
+ {
+ ignoreTablesPattern = null;
+ }
+ }
+
+ public Character getIdentifierQuoteChar()
+ {
+ return identifierQuoteChar;
+ }
+
+ public void setIdentifierQuoteChar(String identifierQuoteChar)
+ {
+ identifierQuoteChar = identifierQuoteChar.trim();
+ if (identifierQuoteChar.length() > 0)
+ {
+ this.identifierQuoteChar = identifierQuoteChar.charAt(0);
+ }
+ }
+
+ public Boolean hasColumnMarkers()
+ {
+ return columnMarkers;
+ }
+
+ public void setColumnMarkers(boolean columnMarkers)
+ {
+ this.columnMarkers = columnMarkers;
+ }
+
+ /*
+ * Operations
+ */
+
+ public String getTableName(String entityName)
+ {
+ return filterTableName.apply(entityName);
+ }
+
+ public String quoteIdentifier(String id)
+ {
+ if (identifierQuoteChar == ' ')
+ {
+ return id;
+ }
+ else
+ {
+ return identifierQuoteChar + id + identifierQuoteChar;
+ }
+ }
+
+ /**
+ * Check whether to ignore or not this table.
+ *
+ * @param name table name
+ * @return whether to ignore this table
+ */
+ public boolean ignoreTable(String name)
+ {
+ return ignoreTablesPattern != null && ignoreTablesPattern.matcher(name).matches();
+ }
+
+ /**
+ * Driver-specific value filtering
+ *
+ * @param value value to be filtered
+ * @return filtered value
+ */
+ public Object filterValue(Object value)
+ {
+ if(value instanceof Calendar && "mysql".equals(tag))
+ {
+ value = ((Calendar)value).getTime();
+ }
+ return value;
+ }
+
+ /*
+ * Members
+ */
+
+ /** jdbc tag of the database vendor */
+ private String tag = "unknown";
+
+ private String catalog = null;
+
+ /** ping SQL query */
+ private String pingQuery = null;
+
+ /** case-sensivity */
+ public enum CaseSensitivity { UNKNOWN, SENSITIVE, LOWERCASE, UPPERCASE }
+ private CaseSensitivity tablesCaseSensitivity = null;
+ private UnaryOperator<String> filterTableName = t -> t;
+
+ /** SQL query to set the current schema */
+ private String schemaQuery = null;
+
+ /** ID generation method */
+ public enum LastInsertIdPolicy { NONE, GENERATED_KEYS, RETURNING, QUERY, METHOD }
+ private LastInsertIdPolicy lastInsertIdPolicy = null;
+ private String lastInsertIdQuery = null;
+ private String lastInsertIdMethodName = null;
+
+ /** whether the JDBC driver is pedantic about column types */
+ private Boolean pedanticColumnTypes = null;
+
+ /** ignore tables matching this pattern */
+ private Pattern ignoreTablesPattern = null;
+
+ /** quoteIdentifier quote character */
+ private Character identifierQuoteChar = null;
+
+ /** whether driver supports ::varchar etc... */
+ private Boolean columnMarkers = null;
+
+ /**
+ * Get the last inserted id.
+ * @param statement source statement
+ * @param keyColumn key column name
+ * @return last inserted id (or -1)
+ * @throws SQLException
+ * /
+ public long getLastInsertId(Statement statement, String keyColumn) throws SQLException
+ {
+ long ret = -1;
+
+ if("mysql".equalsIgnoreCase(getTag()))
+ { /* MySql * /
+ try
+ {
+ Method lastInsertId = statement.getClass().getMethod("getLastInsertID", new Class[0]);
+ ret = ((Long) lastInsertId.invoke(statement, new Object[0])).longValue();
+ }
+ catch (Throwable e)
+ {
+ logger.error("Could not find last insert id", e);
+ }
+ }
+ else if (getUsesGeneratedKeys())
+ {
+ int col = 1;
+ ResultSet rs = statement.getGeneratedKeys();
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int numberOfColumns = rsmd.getColumnCount();
+ if (rs.next())
+ {
+ if (numberOfColumns > 1)
+ {
+ ret = rs.getLong(keyColumn);
+ if (rs.wasNull()) ret = -1;
+ }
+ else
+ {
+ ret = rs.getLong(1);
+ if (rs.wasNull()) ret = -1;
+ }
+ }
+ }
+ else
+ {
+ if (lastInsertIDQuery == null)
+ {
+ logger.error("getLastInsertID is not [yet] implemented for your dbms... Contribute!");
+ }
+ else
+ {
+ ResultSet rs = statement.getConnection().createStatement().executeQuery(lastInsertIDQuery);
+ rs.next();
+ ret = rs.getLong(1);
+ if (rs.wasNull()) ret = -1;
+ }
+ }
+ return ret;
+ }
+ */
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pool.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pool.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pool.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pool.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,32 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.Serializable;
+
+/**
+ * This interface represents a generic pool of objects - no real need for now.
+ *
+ * @author <a href='mailto:claude.brisson@gmail.com'>Claude Brisson</a>
+ *
+ */
+public interface Pool extends Serializable
+{
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pooled.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pooled.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pooled.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/Pooled.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,156 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * This abstract class represents a pooled object with a potential encapsulated resultset.
+ *
+ * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public abstract class Pooled implements Serializable
+{
+ /**
+ * build a new pooled object.
+ */
+ public Pooled()
+ {
+ tagTime = System.currentTimeMillis();
+ }
+
+ /**
+ * get the time tag of this pooled object.
+ *
+ * @return the time tag
+ */
+ public long getTagTime()
+ {
+ return tagTime;
+ }
+
+ /**
+ * reset the time tag.
+ */
+ public void resetTagTime()
+ {
+ tagTime = System.currentTimeMillis();
+ }
+
+ /**
+ * notify this object that it is in use.
+ */
+ public void notifyInUse()
+ {
+ inUse = true;
+ resetTagTime();
+ }
+
+ /**
+ * notify this object that it is no more in use.
+ */
+ public void notifyOver()
+ {
+ try
+ {
+ if(resultSet != null && !resultSet.isClosed())
+ {
+ resultSet.close();
+ }
+ }
+ catch(SQLException sqle) {} // ignore
+ resultSet = null;
+ inUse = false;
+ }
+
+ /**
+ * check whether this pooled object is in use.
+ *
+ * @return whether this object is in use
+ */
+ public boolean isInUse()
+ {
+ return inUse;
+ }
+
+ /**
+ * check whether this pooled object is marked as valid or invalid.
+ * (used in the recovery execute)
+ *
+ * @return whether this object is in use
+ */
+ public boolean isValid()
+ {
+ return valid;
+ }
+
+ /**
+ * definitely mark this statement as meant to be deleted.
+ */
+ public void setInvalid()
+ {
+ valid = false;
+ }
+
+ /**
+ * get the connection used by this statement.
+ *
+ * @return the connection used by this statement
+ */
+ public abstract ConnectionWrapper getConnection();
+
+ /**
+ * close this pooled object.
+ *
+ * @exception SQLException when thrown by the database engine
+ */
+ public abstract void close() throws SQLException;
+
+ /**
+ * time tag.
+ */
+ private long tagTime = 0;
+
+ // states (inUse - useOver) : (false-false) -> (true-false) -> (true-true) -> [delay] (false-false)
+
+ /**
+ * valid statement?
+ */
+ private boolean valid = true;
+
+ /**
+ * is this object in use?
+ */
+ private boolean inUse = false;
+
+ /**
+ * database connection.
+ */
+ protected ConnectionWrapper connection = null;
+
+ /**
+ * result set.
+ */
+ protected transient ResultSet resultSet = null;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/PooledStatement.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/PooledStatement.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/PooledStatement.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/PooledStatement.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,231 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * this class encapsulates a jdbc PreparedStatement (and a potential ResultSet encapsulated by its base class).
+ *
+ * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public class PooledStatement extends Pooled implements RowValues
+{
+ protected static Logger logger = LoggerFactory.getLogger(PooledStatement.class);
+
+ /** org.apache.velocity.tools.generic.ValueParser$ValueParserSub class, if found in the classpath. */
+ private static Class valueParserSubClass = null;
+
+ static
+ {
+ try
+ {
+ valueParserSubClass = Class.forName("org.apache.velocity.tools.generic.ValueParser$ValueParserSub");
+ }
+ catch(ClassNotFoundException cnfe) {}
+ }
+
+ /**
+ * build a new PooledStatement.
+ *
+ * @param connection database connection
+ * @param preparedStatement wrapped prepared statement
+ */
+ public PooledStatement(ConnectionWrapper connection, PreparedStatement preparedStatement)
+ {
+ this.connection = connection;
+ this.preparedStatement = preparedStatement;
+ }
+
+ /**
+ * check whether this pooled object is marked as valid or invalid.
+ * (used in the recovery execute)
+ *
+ * @return whether this object is in use
+ */
+ public boolean isValid()
+ {
+ return super.isValid() && preparedStatement != null;
+ }
+
+ public synchronized ResultSet executeQuery(Serializable... paramValues) throws SQLException
+ {
+ try
+ {
+ setParamValues(paramValues);
+ getConnection().enterBusyState();
+ return resultSet = preparedStatement.executeQuery();
+ }
+ finally
+ {
+ getConnection().leaveBusyState();
+ }
+ }
+
+ public synchronized int executeUpdate(Serializable... paramValues) throws SQLException
+ {
+ try
+ {
+ setParamValues(paramValues);
+ getConnection().enterBusyState();
+ return preparedStatement.executeUpdate();
+ }
+ finally
+ {
+ getConnection().leaveBusyState();
+ }
+ }
+
+
+ private void setParamValues(Serializable[] paramValues) throws SQLException
+ {
+ for (int i = 0; i < paramValues.length; ++i)
+ {
+ preparedStatement.setObject(i + 1, paramValues[i]);
+ }
+ }
+
+ /**
+ * issue the modification query of this prepared statement.
+ *
+ * @param params parameter values
+ * @exception SQLException thrown by the database engine
+ * @return the numer of affected rows
+ */
+ public synchronized int update(List params) throws SQLException
+ {
+ try
+ {
+ logger.trace("update-params={}", params);
+ setParams(params);
+ connection.enterBusyState();
+
+ int rows = preparedStatement.executeUpdate();
+
+ return rows;
+ }
+ finally
+ {
+ connection.leaveBusyState();
+ notifyOver();
+ }
+ }
+
+ /**
+ * get the object value of the specified resultset column.
+ *
+ * @param key the name of the resultset column
+ * @exception SQLException thrown by the database engine
+ * @return the object value returned by jdbc
+ */
+ public synchronized Serializable get(Object key) throws SQLException
+ {
+ if(!(key instanceof String) || resultSet == null)
+ {
+ return null;
+ }
+
+ Serializable ret = (Serializable)resultSet.getObject((String)key);
+
+ /*
+ if(entity != null && entity.isObfuscated((String)key))
+ {
+ ret = entity.obfuscate((ret));
+ }
+ */
+ return ret;
+ }
+
+ public Set<String> keySet() throws SQLException
+ {
+ if(resultSet == null) return new HashSet<String>();
+ return new HashSet<String>(SqlUtils.getColumnNames(resultSet));
+ }
+
+ /**
+ * get the last insert id.
+ *
+ * @exception SQLException thrown by the database engine
+ * @return the last insert id
+ */
+ public synchronized long getLastInsertID(String keyColumn) throws SQLException
+ {
+ return connection.getLastInsertId(preparedStatement, keyColumn);
+ }
+
+ /**
+ * close this statement.
+ *
+ * @exception SQLException thrown by the database engine
+ */
+ public synchronized void close() throws SQLException
+ {
+ if(preparedStatement != null)
+ {
+ preparedStatement.close();
+ }
+ }
+
+ /**
+ * get statement Connection.
+ *
+ * @return the Connection object (usually a ConnectionWrapper object)
+ */
+ public ConnectionWrapper getConnection()
+ {
+ return connection;
+ }
+
+ /**
+ * set prepared parameter values.
+ *
+ * @param params parameter values
+ * @exception SQLException thrown by the database engine
+ */
+ private void setParams(List params) throws SQLException
+ {
+ for(int i = 0; i < params.size(); i++)
+ {
+ Object param = params.get(i);
+
+ if(valueParserSubClass != null && valueParserSubClass.isAssignableFrom(param.getClass()))
+ {
+ param = param.toString();
+ }
+ preparedStatement.setObject(i + 1, param);
+ }
+ }
+
+ /**
+ * wrapped prepared statement.
+ */
+ private transient PreparedStatement preparedStatement = null;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/RowValues.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/RowValues.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/RowValues.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/RowValues.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,47 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.Set;
+
+/**
+ * This interface represents objects having read-only properties
+ *
+ * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public interface RowValues
+{
+ /**
+ * get the property named key.
+ *
+ * @param key the name of the property to return
+ * @return the value of the property, or null if not found
+ */
+ Serializable get(Object key) throws SQLException;
+
+ /**
+ * Get keys set.
+ * @return keys set
+ */
+ Set<String> keySet() throws SQLException;
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/SqlUtils.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/SqlUtils.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/SqlUtils.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/SqlUtils.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,75 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * various SQL-related helpers.
+ *
+ * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public class SqlUtils
+{
+ protected static Logger logger = LoggerFactory.getLogger(SqlUtils.class);
+
+ // that's crazy to have to code such a method...
+ // in Ruby for instance, it's :
+ // '*' * n
+ private static String stars(int length)
+ {
+ StringBuilder ret = new StringBuilder(length);
+ for(int i = 0; i < length; i++)
+ {
+ ret.append('*');
+ }
+ return ret.toString();
+ }
+
+ /**
+ * get the column nams of a result set
+ * @param resultSet result set
+ * @return list of columns
+ * @throws SQLException
+ */
+ public static List<String> getColumnNames(ResultSet resultSet) throws SQLException
+ {
+ List<String> columnNames = new ArrayList<String>();
+ ResultSetMetaData meta = resultSet.getMetaData();
+ int count = meta.getColumnCount();
+
+ for(int c = 1; c <= count; c++)
+ {
+ // see http://jira.springframework.org/browse/SPR-3541
+ // columnNames.add(meta.getColumnName(c));
+ columnNames.add(meta.getColumnLabel(c));
+ }
+ return columnNames;
+ }
+}
Added: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/StatementPool.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/StatementPool.java?rev=1857751&view=auto
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/StatementPool.java (added)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/sql/StatementPool.java Thu Apr 18 14:34:54 2019
@@ -0,0 +1,285 @@
+package org.apache.velocity.tools.model.sql;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+import org.apache.velocity.tools.model.util.HashMultiMap;
+import org.apache.velocity.tools.model.util.MultiMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class is a pool of PooledPreparedStatements.
+ *
+ * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
+ *
+ */
+public class StatementPool implements /* Runnable, */ Pool
+{
+ protected Logger logger = LoggerFactory.getLogger(StatementPool.class);
+
+ public StatementPool(ConnectionPool connectionPool)
+ {
+ this(connectionPool, false, 0);
+ }
+
+ /**
+ * build a new pool.
+ *
+ * @param connectionPool connection pool
+ */
+ public StatementPool(ConnectionPool connectionPool, boolean checkConnections, long checkInterval)
+ {
+ this.connectionPool = connectionPool;
+ this.checkConnections = checkConnections;
+ this.checkInterval = checkInterval;
+
+// if(checkConnections) checkTimeoutThread = new Thread(this);
+// checkTimeoutThread.start();
+ }
+
+ /**
+ * get a PooledStatement associated with this query.
+ *
+ * @param query an SQL query
+ * @exception SQLException thrown by the database engine
+ * @return a valid statement
+ */
+ protected synchronized PooledStatement prepareStatement(String query, boolean update) throws SQLException
+ {
+ logger.trace("prepare-" + query);
+
+ PooledStatement statement = null;
+ ConnectionWrapper connection = null;
+ List available = statementsMap.get(query);
+
+ for(Iterator it = available.iterator(); it.hasNext(); )
+ {
+ statement = (PooledStatement)it.next();
+ if(statement.isValid())
+ {
+ if(!statement.isInUse() &&!(connection = statement.getConnection()).isBusy())
+ {
+ // check connection
+ if(!connection.isClosed() && (!checkConnections || System.currentTimeMillis() - connection.getLastUse() < checkInterval || connection.check()))
+ {
+ statement.notifyInUse();
+ return statement;
+ }
+ else
+ {
+ dropConnection(connection);
+ it.remove();
+ }
+ }
+ }
+ else
+ {
+ it.remove();
+ }
+ }
+ if(count == maxStatements)
+ {
+ throw new SQLException("Error: Too many opened prepared statements!");
+ }
+ connection = connectionPool.getConnection();
+ statement = new PooledStatement(connection,
+ update ?
+ connection.prepareStatement(
+ query, connection.getDriverInfos().getLastInsertIdPolicy() == DriverInfos.LastInsertIdPolicy.GENERATED_KEYS ?
+ Statement.RETURN_GENERATED_KEYS :
+ Statement.NO_GENERATED_KEYS) :
+ connection.prepareStatement(query, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY));
+ statementsMap.put(query, statement);
+ statement.notifyInUse();
+ return statement;
+ }
+
+ public synchronized PooledStatement prepareQuery(String query) throws SQLException
+ {
+ return prepareStatement(query, false);
+ }
+
+ public synchronized PooledStatement prepareUpdate(String query) throws SQLException
+ {
+ return prepareStatement(query, true);
+ }
+
+ /**
+ * cycle through statements to check and recycle them.
+ *
+ * public void run() {
+ * while (running) {
+ * try {
+ * Thread.sleep(checkDelay);
+ * } catch (InterruptedException e) {}
+ * long now = System.currentTimeMillis();
+ * PooledStatement statement = null;
+ * for (Iterator it=statementsMap.keySet().iterator();it.hasNext();)
+ * for (Iterator jt=statementsMap.get(it.next()).iterator();jt.hasNext();) {
+ * statement = (PooledStatement)jt.next();
+ * if (statement.isInUse() && now-statement.getTagTime() > timeout)
+ * statement.notifyOver();
+ * }
+ * }
+ * }
+ */
+
+ /**
+ * close all statements.
+ */
+ public void clear()
+ {
+ // close all statements
+ for(Iterator it = statementsMap.keySet().iterator(); it.hasNext(); )
+ {
+ for(Iterator jt = statementsMap.get(it.next()).iterator(); jt.hasNext(); )
+ {
+ try
+ {
+ ((PooledStatement)jt.next()).close();
+ }
+ catch(SQLException e)
+ { // don't care now...
+ logger.error("error while clearing pool", e);
+ }
+ }
+ }
+ statementsMap.clear();
+ }
+
+ /*
+ * drop all statements relative to a specific connection
+ * @param connection the connection
+ */
+ private void dropConnection(ConnectionWrapper connection)
+ {
+ for(Iterator it = statementsMap.keySet().iterator(); it.hasNext(); )
+ {
+ for(Iterator jt = statementsMap.get(it.next()).iterator(); jt.hasNext(); )
+ {
+ PooledStatement statement = (PooledStatement)jt.next();
+
+ if(statement.getConnection() == connection)
+ {
+ try
+ {
+ statement.close();
+ }
+ catch(SQLException sqle) {}
+ statement.setInvalid();
+ }
+ }
+ }
+ try
+ {
+ connection.close();
+ }
+ catch(SQLException sqle) {}
+ }
+
+ /**
+ * clear statements on exit.
+ */
+ protected void finalize()
+ {
+ clear();
+ }
+
+ /**
+ * debug - get usage statistics.
+ *
+ * @return an int array : [nb of statements in use , total nb of statements]
+ */
+ public int[] getUsageStats()
+ {
+ int[] stats = new int[] { 0, 0 };
+
+ for(Iterator it = statementsMap.keySet().iterator(); it.hasNext(); )
+ {
+ for(Iterator jt = statementsMap.get(it.next()).iterator(); jt.hasNext(); )
+ {
+ if(!((PooledStatement)jt.next()).isInUse())
+ {
+ stats[0]++;
+ }
+ }
+ }
+ stats[1] = statementsMap.size();
+ return stats;
+ }
+
+ /**
+ * connection pool.
+ */
+ private ConnectionPool connectionPool;
+
+ /**
+ * statements getCount.
+ */
+ private int count = 0;
+
+ /**
+ * map queries -> statements.
+ */
+ private MultiMap statementsMap = new HashMultiMap(); // query -> PooledStatement
+
+ /**
+ * running thread.
+ */
+ private Thread checkTimeoutThread = null;
+
+ /**
+ * true if running.
+ */
+ private boolean running = true;
+
+ /**
+ * do we need to check connections?
+ */
+ private boolean checkConnections = true;
+
+ /**
+ * minimal check interval
+ */
+ private long checkInterval;
+
+ /**
+ * check delay.
+ */
+
+// private static final long checkDelay = 30*1000;
+
+ /**
+ * after this timeout, statements are recycled even if not closed.
+ */
+// private static final long timeout = 60*60*1000;
+
+ /**
+ * max number of statements.
+ */
+ private static final int maxStatements = 50;
+}
Modified: velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/util/TypeUtils.java
URL: http://svn.apache.org/viewvc/velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/util/TypeUtils.java?rev=1857751&r1=1857750&r2=1857751&view=diff
==============================================================================
--- velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/util/TypeUtils.java (original)
+++ velocity/tools/branches/model/velocity-tools-model/src/main/java/org/apache/velocity/tools/model/util/TypeUtils.java Thu Apr 18 14:34:54 2019
@@ -21,8 +21,6 @@ package org.apache.velocity.tools.model.
import org.apache.commons.codec.binary.Base64;
-import java.io.Serializable;
-import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.Date;