![JAR search and dependency download from the Maven repository](/logo.png)
org.kawanfw.sql.jdbc.ConnectionHttp Maven / Gradle / Ivy
/*
* This file is part of AceQL.
* AceQL: Remote JDBC access over HTTP.
* Copyright (C) 2015, KawanSoft SAS
* (http://www.kawansoft.com). All rights reserved.
*
* AceQL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* AceQL 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Any modifications to this file must keep this entire header
* intact.
*/
package org.kawanfw.sql.jdbc;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.PasswordAuthentication;
import java.net.Proxy;
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.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import org.apache.commons.io.FileUtils;
import org.kawanfw.commons.api.client.SessionParameters;
import org.kawanfw.commons.client.http.HttpTransfer;
import org.kawanfw.commons.client.http.HttpTransferOne;
import org.kawanfw.commons.jdbc.abstracts.AbstractConnection;
import org.kawanfw.commons.util.ClientLogger;
import org.kawanfw.commons.util.DefaultParms;
import org.kawanfw.commons.util.FrameworkDebug;
import org.kawanfw.commons.util.HtmlConverter;
import org.kawanfw.commons.util.KeepTempFilePolicyParms;
import org.kawanfw.commons.util.Tag;
import org.kawanfw.file.api.client.RemoteSession;
import org.kawanfw.file.api.util.client.FilesTransferWithProgress;
import org.kawanfw.sql.jdbc.http.JdbcHttpConnectionInfoTransfer;
import org.kawanfw.sql.jdbc.http.JdbcHttpMetaDataTransfer;
import org.kawanfw.sql.jdbc.http.JdbcHttpSavepointTransfer;
import org.kawanfw.sql.jdbc.http.JdbcHttpStatementTransfer;
import org.kawanfw.sql.jdbc.http.JdbcHttpTransactionTransfer;
import org.kawanfw.sql.jdbc.http.JdbcHttpTransferUtil;
import org.kawanfw.sql.jdbc.util.JdbcUtil;
import org.kawanfw.sql.jdbc.util.StatementHolderFileList;
import org.kawanfw.sql.json.StatementHolder;
import org.kawanfw.sql.json.no_obfuscation.DatabaseMetaDataHolder;
import org.kawanfw.sql.json.no_obfuscation.DatabaseMetaDataHolderTransport;
import org.kawanfw.sql.util.JdbcUrlHeader;
import org.kawanfw.sql.version.Version;
/**
* Creates and handle a HTTP Connection to SQLExecutor on Http Server.
*/
public class ConnectionHttp extends AbstractConnection implements Connection,
Cloneable {
public static final String FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE = Tag.PRODUCT
+ "This feature is not supported in stateless mode";
public static final String KAWANFW_NOT_SUPPORTED_METHOD = Tag.PRODUCT
+ "Method is not yet implemented.";
/** Set to true to display/log debug info */
private static boolean DEBUG = FrameworkDebug.isSet(ConnectionHttp.class);
/** The default maximum number of statement for transport in memory */
private static int DEFAULT_MAX_STATEMENTS_FOR_MEMORY_TRANSPORT = 100;
/**
* Map that stores DatabaseMetaData per Connection to avoid server
* re-contact if programmer calls many times Connection.getMetaData()
* instead of reusing the result value.
*/
private static Map databaseMetaDataMap = new HashMap();
/** The username */
private String username = null;
/** The Authentication Token */
private String authenticationToken = null;
/** The current RemoteSession instance used for file transfers */
private RemoteSession remoteSession = null;
/** The host to use */
private String url = null;
/** Proxy to use with HttpUrlConnection */
private Proxy proxy = null;
/** For authenticated proxy */
private PasswordAuthentication passwordAuthentication = null;
/** The Http Parameters instance */
private SessionParameters sessionParameters = null;
/**
* Set to true if the user has closed the connection by a explicit call to
* close()
*/
private boolean isClosed = false;
/**
* The supported holdability is only CLOSE_CURSORS_AT_COMMIT in
* statelessMode
*/
private int holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT;
/** Autocommit local state */
private boolean autoCommit = true;
/** The holdability, false if user does not change it */
private boolean readOnly = false;
/** The transaction isolation level, -1 if user does not change it */
private int transactionIsolation = -1;
/** The list of statement holder are stored on a file */
private StatementHolderFileList statementHolderFileList = null;
/** The maximum number of statement for transport in memory */
private int maxStatementsForMemoryTransport = DEFAULT_MAX_STATEMENTS_FOR_MEMORY_TRANSPORT;
/**
* if true, the Statement Parameters will be encrypted if the
* HttpProtocolParameter is set
*/
private boolean encryptStatementParameters = false;
/** Progress value between 0 and 100. Will be used by progress indicators. */
private AtomicInteger progress = new AtomicInteger();
/** Says if user has cancelled the blob/clob upload or download */
private AtomicBoolean cancelled = new AtomicBoolean();
/**
* The list of local files to uplaod and delete (in fire and forget mode) at
* commit
*/
List localFiles = new Vector();
/**
* The list of input streams to delete (in fire and forget mode) at commit
*/
List localInputStreams = new Vector();
/** The length of each InputStream */
List localInputStreamLengths = new Vector();
/**
* The list of remote uploaded files delete (in fire and forget mode) at at
* commit
*/
List remoteFiles = new Vector();
/**
* The result of the transfered ExecuteUpdate (last result if aucoCommit is
* off)
*/
String receiveFromExecuteUpdate = null;
//
// New fields for server stateless or connected mode
//
/** Says if we gare in stateless mode */
private boolean statelessMode = false;
/** The incremented number of Connections */
private static int MAX_CONNECTION_NUMBER = 0;
/** The connectionId Id to use */
private String connectionId = null;
/** The unique instance for transfer */
private HttpTransfer httpTransfer = null;
/**
* Says if ResultSet Meta Data must be downloaded from server along with
* ResultSet
*/
private boolean joinResultSetMetaData = false;
/**
* Public constructor for clone() - Must be public because RemoteConnection
* uses now composition)
*
* @param url
* the URL of the path to the ServerSqlManager Servlet
* @param username
* the user username
* @param proxy
* the proxy to use, null for direct access
* @param passwordAuthentication
* the proxy credentials, null if no proxy or if the proxy does not require authentication
* @param sessionParameters
* the http protocol parameters to set (maybe null if none)
* @param remoteSession
* the actual AceQL FILE Session
* @param statelessMode
* says if server is stateless for client side
* @param joinResultSetMetaData
* says if metadata must be downloaded along result set
*/
public ConnectionHttp(String url, String username, Proxy proxy,
PasswordAuthentication passwordAuthentication,
SessionParameters sessionParameters,
RemoteSession remoteSession, boolean statelessMode,
boolean joinResultSetMetaData) {
this.url = url;
this.username = username;
this.proxy = proxy;
this.passwordAuthentication = passwordAuthentication;
this.sessionParameters = sessionParameters;
this.remoteSession = remoteSession.clone();
this.authenticationToken = this.remoteSession.getAuthenticationToken();
// The file that will contain the statements, one per line added
this.statementHolderFileList = new StatementHolderFileList(this);
this.statelessMode = statelessMode;
this.joinResultSetMetaData = joinResultSetMetaData;
String urlHttpOnly = JdbcUrlHeader.getUrlHttpOnly(url);
httpTransfer = new HttpTransferOne(urlHttpOnly, proxy, passwordAuthentication,
sessionParameters);
if (statelessMode) {
this.connectionId = "0"; // Important , will be transmitted to
// server
} else {
this.connectionId = buildConnectionId();
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
try {
jdbcHttpTransactionTransfer.initRemoteConnection();
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
}
/**
* Constructor Build the SQL/JDBC http connection with a proxy and http
* protocol parameters, if necessary.
*
* @param url
* the URL of the path to the ServerSqlManager Servlet
* @param username
* the user username
* @param password
* the authentication password for username
* @param proxy
* the proxy to use, null for direct access
* @param passwordAuthentication
* the proxy credentials, null if proxy does not require
* authentication
*
* @param sessionParameters
* the http protocol parameters to set (maybe null if none)
* @param statelessMode
* if true, we are in stateless mode on the server
* @param joinResultSetMetaData
* if true, ResultSet.getMetaData() will be downloaded along with
* ResultSet when a SELECT is sent to the server
* @throws IllegalArgumentException
* if url, username, password is null
* @throws SQLException
* if any Exception
occurs. The
* SQLException
wraps the original
* Exception
that may be accessed using
* {@link SQLException#getCause()}.
*
*/
public ConnectionHttp(String url, String username, char[] password,
Proxy proxy, PasswordAuthentication passwordAuthentication,
SessionParameters sessionParameters,
boolean statelessMode, boolean joinResultSetMetaData)
throws SQLException {
if (username == null) {
throw new IllegalArgumentException("username can not be null!");
}
if (password == null) {
throw new IllegalArgumentException("password can not be null!");
}
if (url == null) {
throw new IllegalArgumentException("url can not be null!");
}
try {
this.url = url;
this.proxy = proxy;
this.passwordAuthentication = passwordAuthentication;
this.sessionParameters = sessionParameters;
this.username = username;
// The file that will contain the statements, one per line added
this.statementHolderFileList = new StatementHolderFileList(this);
String urlHttpOnly = JdbcUrlHeader.getUrlHttpOnly(url);
// Do the current username on the SQl Servlet
remoteSession = new RemoteSession(urlHttpOnly, username, password,
proxy, passwordAuthentication, sessionParameters);
// Because remoteSession.url may have been updated from http://
// to https://, update this.url:
// this.url = JdbcParms.JDBC_URL_HEADER + remoteSession.getUrl();
this.url = JdbcUrlHeader.prefixUrlWithJdbcProductName(remoteSession
.getUrl());
urlHttpOnly = JdbcUrlHeader.getUrlHttpOnly(url);
this.authenticationToken = remoteSession.getAuthenticationToken();
this.statelessMode = statelessMode;
this.joinResultSetMetaData = joinResultSetMetaData;
httpTransfer = new HttpTransferOne(urlHttpOnly, proxy, passwordAuthentication,
sessionParameters);
if (statelessMode) {
this.connectionId = "0"; // Important , will be transmitted to
// server
// if stateless mode ==> no chunking
// ==> force sessionParameters.setUploadChunkLength(0)
if (this.sessionParameters != null) {
this.sessionParameters.setUploadChunkLength(0);
}
} else {
this.connectionId = buildConnectionId();
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
try {
jdbcHttpTransactionTransfer.initRemoteConnection();
} catch (SQLException e) {
throw new IllegalStateException(e);
}
}
} catch (Exception e) {
JdbcHttpTransferUtil.wrapExceptionAsSQLException(e);
}
}
/**
* Returns the cancelled value set by the progress indicator
*
* @return the cancelled value set by the progress indicator
*
* @since 1.8
*/
public AtomicBoolean getCancelled() {
return cancelled;
}
/**
* Sets the shareable canceled variable that will be used by the progress
* indicator to notify this instance that the user has cancelled the current
* blob/clob upload or download.
*
* @param the
* shareable canceled variable that will be used by the progress
* indicator to notify this instance that the end user has
* cancelled the current blob/clob upload or download
*
* @since 1.8
*/
public void setCancelled(AtomicBoolean cancelled) {
this.cancelled = cancelled;
}
/**
* Returns the shareable progress variable that will store blob/clob upload
* or download progress between 0 and 100
*
* @return the shareable progress variable that will store blob/clob upload
* or download progress between 0 and 100
*
* @since 1.8
*/
public AtomicInteger getProgress() {
return progress;
}
/**
* Sets the shareable progress variable that will store blob/clob upload or
* download progress between 0 and 100. Will be used by progress indicators
* to show the progress.
*
* @param progress
* the shareable progress variable
*
* @since 1.8
*/
public void setProgress(AtomicInteger progress) {
this.progress = progress;
}
/**
* @return the httpTransfer
*/
public HttpTransfer getHttpTransfer() {
return httpTransfer;
}
/**
* Returns the boolean that says if server ResultSet Meta Data must be
* downloaded along with the server ResultSet
*
* @return true if server ResultSet Meta Data must be downloaded along with
* the server ResultSet, else false
* @since 3.0
*/
public boolean isJoinResultSetMetaData() {
return joinResultSetMetaData;
}
/**
* Generate a new incremented Transaction Id
*
* @return the new incremented Transaction Id
*/
private static synchronized int getNextConnectionNumber() {
MAX_CONNECTION_NUMBER++;
return MAX_CONNECTION_NUMBER;
}
/**
* Build a unique transaction Id for this username
*
* @return the built transaction Id
*/
private String buildConnectionId() {
String connectionId = getNextConnectionNumber() + "_"
+ JdbcUtil.getMacAddress();
return connectionId;
}
/**
* Says if Html Encoding is on for Clobs uploads/downloads
*
* @return true if Html Encoding is on
*/
boolean isHtmlEncodingOn() {
boolean htmlEncoding = DefaultParms.DEFAULT_HTML_ENCODING_ON;
if (sessionParameters != null) {
htmlEncoding = sessionParameters.isHtmlEncodingOn();
}
return htmlEncoding;
}
/**
* add a StatementHolder to the StatementHolder list to execute
*
* @param statementHolder
* the StatementHolder to add to the StatementHolder list to
* execute
*/
void addStatementHolder(StatementHolder statementHolder)
throws SQLException {
testIfClosed();
this.statementHolderFileList.add(statementHolder);
}
/**
* Reset the statement holder list
*/
void resetStatementHolderList() throws SQLException {
testIfClosed();
this.statementHolderFileList.delete(); // closes and delete the file
this.statementHolderFileList = new StatementHolderFileList(this);
}
/**
* Returns the maximum length authorized for a string
*
* @return
*/
int getMaxLengthForString() {
int maxLengthForString = DefaultParms.DEFAULT_MAX_LENGTH_FOR_STRING;
if (sessionParameters != null) {
maxLengthForString = sessionParameters.getMaxLengthForString();
}
return maxLengthForString;
}
/**
* Upload all the blob parameters
*/
private void uploadBlobParameters() throws SQLException {
// reinit progress
progress.set(0);
long totalLength = getLocalTotalLength();
try {
// for (int i = 0; i < localFiles.size(); i++) {
// // Do the upload
// debug("uploading file: " + localFiles.get(i));
// remoteSession.getFileTransferWrapper().upload(localFiles.get(i),
// remoteFiles.get(i));
// }
FilesTransferWithProgress filesTransferWithProgress = new FilesTransferWithProgress(
this.remoteSession, this.progress, this.cancelled);
filesTransferWithProgress.upload(localFiles, remoteFiles,
totalLength);
// 1) Upoad files
if (!localFiles.isEmpty()) {
filesTransferWithProgress.upload(localFiles, remoteFiles,
totalLength);
}
// 2) upload InputStreams
if (!localInputStreams.isEmpty()) {
filesTransferWithProgress.upload(localInputStreams,
localInputStreamLengths, remoteFiles, totalLength);
}
} catch (Exception e) {
JdbcHttpTransferUtil.wrapExceptionAsSQLException(e);
} finally {
// NO! We want to repeat the uploads, so stay at 99
// this.progress.set(100);
if (!KeepTempFilePolicyParms.KEEP_TEMP_FILE && !DEBUG) {
if (localFiles != null) {
for (File localFile : localFiles) {
localFile.delete();
}
}
}
}
}
/**
* Get the total length of the files to upload
*
* @return the total length of the files to upload
*/
private long getLocalTotalLength() {
long totalLength = 0;
for (File localFile : localFiles) {
totalLength += localFile.length();
}
for (Long localLength : localInputStreamLengths) {
totalLength += localLength;
}
return totalLength;
}
/**
* Test if user has hit cancel. if yes, throw a wrapped
* HttpTransferInterruptedException
*
* @throws SQLException
* the wrapped InterruptedException if user has hit cancel
*/
public void testIfUploadInterrupted() throws SQLException {
if (cancelled.get()) {
throw new SQLException(new InterruptedException(Tag.PRODUCT
+ " File upload interrupted by user."));
}
}
/**
* Execute a remote sql execute update statement and get the string
*
* @param sql
* @return the result of the execute update
*/
synchronized String getStringFromExecuteUpdateListOnServer()
throws SQLException {
testIfClosed();
if (isStatelessMode()) {
try {
// Upload each blob/clob parameters
if (!localFiles.isEmpty()) {
this.uploadBlobParameters();
}
} finally {
this.localFiles = new Vector();
this.remoteFiles = new Vector();
}
}
testIfUploadInterrupted();
JdbcHttpStatementTransfer jdbcHttpStatementTransfer = new JdbcHttpStatementTransfer(
this, authenticationToken);
String result = jdbcHttpStatementTransfer
.getStringFromExecuteUpdateListOnServer(statementHolderFileList);
testIfUploadInterrupted();
return result;
}
/**
* Creates a Statement
object for sending SQL statements to the
* database. SQL statements without parameters are normally executed using
* Statement
objects. If the same SQL statement is executed
* many times, it may be more efficient to use a
* PreparedStatement
object.
*
* Result sets created using the returned Statement
object will
* by default be type TYPE_FORWARD_ONLY
and have a concurrency
* level of CONCUR_READ_ONLY
.
*
* @return a new default Statement
object
* @exception SQLException
* if a database access error occurs
*/
@Override
public Statement createStatement() throws SQLException {
testIfClosed();
return new StatementHttp(this, ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
}
/**
* Creates a Statement
object that will generate
* ResultSet
objects with the given type and concurrency. This
* method is the same as the createStatement
method above, but
* it allows the default result set type and concurrency to be overridden.
* The holdability of the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param resultSetType
* a result set type; one of
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* a concurrency type; one of
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @return a new Statement
object that will generate
* ResultSet
objects with the given type and
* concurrency
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameters are not
* ResultSet
constants indicating type and
* concurrency
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this
* method is not supported for the specified result set type
* and result set concurrency.
* @since 1.2
*/
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
return new StatementHttp(this, resultSetType, resultSetConcurrency,
getHoldability());
}
/**
* Creates a Statement
object that will generate
* ResultSet
objects with the given type, concurrency, and
* holdability. This method is the same as the createStatement
* method above, but it allows the default result set type, concurrency, and
* holdability to be overridden.
*
* @param resultSetType
* one of the following ResultSet
constants:
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* one of the following ResultSet
constants:
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param resultSetHoldability
* one of the following ResultSet
constants:
* ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @return a new Statement
object that will generate
* ResultSet
objects with the given type, concurrency,
* and holdability
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameters are not
* ResultSet
constants indicating type,
* concurrency, and holdability
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this
* method is not supported for the specified result set type,
* result set holdability and result set concurrency.
* @see ResultSet
* @since 1.4
*/
@Override
public Statement createStatement(int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
// We support only ResultSet.CLOSE_CURSORS_AT_COMMIT
if (resultSetHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.HOLD_CURSORS_OVER_COMMIT is not supported.");
}
return new StatementHttp(this, resultSetType, resultSetConcurrency,
resultSetHoldability);
}
/**
* Creates a CallableStatement
object for calling database
* stored procedures. The CallableStatement
object provides
* methods for setting up its IN and OUT parameters, and methods for
* executing the call to a stored procedure.
*
*
* Note: This method is optimized for handling stored procedure call
* statements. Some drivers may send the call statement to the database when
* the method prepareCall
is done; others may wait until the
* CallableStatement
object is executed. This has no direct
* effect on users; however, it does affect which method throws certain
* SQLExceptions.
*
* Result sets created using the returned CallableStatement
* object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
.
*
* @param sql
* an SQL statement that may contain one or more '?' parameter
* placeholders. Typically this statement is a JDBC function call
* escape string.
* @return a new default CallableStatement
object containing
* the pre-compiled SQL statement
* @exception SQLException
* if a database access error occurs
*/
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
testIfClosed();
return new CallableStatementHttp(this, sql,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
}
/**
* Creates a CallableStatement
object that will generate
* ResultSet
objects with the given type and concurrency. This
* method is the same as the prepareCall
method above, but it
* allows the default result set type and concurrency to be overridden.
*
* @param sql
* a String
object that is the SQL statement to be
* sent to the database; may contain on or more ? parameters
* @param resultSetType
* a result set type; one of
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* a concurrency type; one of
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @return a new CallableStatement
object containing the
* pre-compiled SQL statement that will produce
* ResultSet
objects with the given type and
* concurrency
* @exception SQLException
* if a database access error occurs or the given parameters
* are not ResultSet
constants indicating type
* and concurrency
* @since 1.2
*/
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
return new CallableStatementHttp(this, sql, resultSetType,
resultSetConcurrency, getHoldability());
}
/**
* Creates a CallableStatement
object that will generate
* ResultSet
objects with the given type and concurrency. This
* method is the same as the prepareCall
method above, but it
* allows the default result set type, result set concurrency type and
* holdability to be overridden.
*
* @param sql
* a String
object that is the SQL statement to be
* sent to the database; may contain on or more ? parameters
* @param resultSetType
* one of the following ResultSet
constants:
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* one of the following ResultSet
constants:
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param resultSetHoldability
* one of the following ResultSet
constants:
* ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @return a new CallableStatement
object, containing the
* pre-compiled SQL statement, that will generate
* ResultSet
objects with the given type, concurrency,
* and holdability
* @exception SQLException
* if a database access error occurs or the given parameters
* are not ResultSet
constants indicating type,
* concurrency, and holdability
* @see ResultSet
* @since 1.4
*/
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
// We support only ResultSet.CLOSE_CURSORS_AT_COMMIT
if (resultSetHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.HOLD_CURSORS_OVER_COMMIT is not supported.");
}
return new CallableStatementHttp(this, sql, resultSetType,
resultSetConcurrency, resultSetHoldability);
}
/**
* Creates a PreparedStatement
object for sending parameterized
* SQL statements to the database.
*
* A SQL statement with or without IN parameters can be pre-compiled and
* stored in a PreparedStatement
object. This object can then
* be used to efficiently execute this statement multiple times.
*
*
* Note: This method is optimized for handling parametric SQL
* statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the
* statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to
* the database until the PreparedStatement
object is executed.
* This has no direct effect on users; however, it does affect which methods
* throw certain SQLException
objects.
*
* Result sets created using the returned PreparedStatement
* object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter
* placeholders
* @return a new default PreparedStatement
object containing
* the pre-compiled SQL statement
* @exception SQLException
* if a database access error occurs
*/
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
testIfClosed();
return new PreparedStatementHttp(this, sql,
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
ResultSet.CLOSE_CURSORS_AT_COMMIT);
}
/**
*
* Creates a PreparedStatement
object that will generate
* ResultSet
objects with the given type and concurrency. This
* method is the same as the prepareStatement
method above, but
* it allows the default result set type and concurrency to be overridden.
* The holdability of the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* a String
object that is the SQL statement to be
* sent to the database; may contain one or more '?' IN
* parameters
* @param resultSetType
* a result set type; one of
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* a concurrency type; one of
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @return a new PreparedStatement object containing the pre-compiled SQL
* statement that will produce ResultSet
objects with
* the given type and concurrency
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameters are not
* ResultSet
constants indicating type and
* concurrency
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this
* method is not supported for the specified result set type
* and result set concurrency.
* @since 1.2
*/
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
return new PreparedStatementHttp(this, sql, resultSetType,
resultSetConcurrency, getHoldability());
}
/**
* Creates a PreparedStatement
object that will generate
* ResultSet
objects with the given type, concurrency, and
* holdability.
*
* This method is the same as the prepareStatement
method
* above, but it allows the default result set type, concurrency, and
* holdability to be overridden.
*
* @param sql
* a String
object that is the SQL statement to be
* sent to the database; may contain one or more '?' IN
* parameters
* @param resultSetType
* one of the following ResultSet
constants:
* ResultSet.TYPE_FORWARD_ONLY
,
* ResultSet.TYPE_SCROLL_INSENSITIVE
, or
* ResultSet.TYPE_SCROLL_SENSITIVE
* @param resultSetConcurrency
* one of the following ResultSet
constants:
* ResultSet.CONCUR_READ_ONLY
or
* ResultSet.CONCUR_UPDATABLE
* @param resultSetHoldability
* one of the following ResultSet
constants:
* ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @return a new PreparedStatement
object, containing the
* pre-compiled SQL statement, that will generate
* ResultSet
objects with the given type, concurrency,
* and holdability
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameters are not
* ResultSet
constants indicating type,
* concurrency, and holdability
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method or this
* method is not supported for the specified result set type,
* result set holdability and result set concurrency.
* @see ResultSet
* @since 1.4
*/
@Override
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency, int resultSetHoldability)
throws SQLException {
testIfClosed();
// We support only ResultSet.CONCUR_READ_ONLY
if (resultSetConcurrency == ResultSet.CONCUR_UPDATABLE) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.CONCUR_UPDATABLE is not supported.");
}
// We support only ResultSet.HOLD_CURSORS_OVER_COMMIT
if (resultSetHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
throw new SQLFeatureNotSupportedException(
"Concurrency ResultSet.HOLD_CURSORS_OVER_COMMIT is not supported.");
}
return new PreparedStatementHttp(this, sql, resultSetType,
resultSetConcurrency, resultSetHoldability);
}
/**
* Creates a default PreparedStatement
object that has the
* capability to retrieve auto-generated keys. The given constant tells the
* driver whether it should make auto-generated keys available for
* retrieval. This parameter is ignored if the SQL statement is not an
* INSERT
statement, or an SQL statement able to return
* auto-generated keys (the list of such statements is vendor-specific).
*
* Note: This method is optimized for handling parametric SQL
* statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the
* statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to
* the database until the PreparedStatement
object is executed.
* This has no direct effect on users; however, it does affect which methods
* throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
* object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of
* the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter
* placeholders
* @param autoGeneratedKeys
* a flag indicating whether auto-generated keys should be
* returned; one of Statement.RETURN_GENERATED_KEYS
* or Statement.NO_GENERATED_KEYS
* @return a new PreparedStatement
object, containing the
* pre-compiled SQL statement, that will have the capability of
* returning auto-generated keys
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameter is not a
* Statement
constant indicating whether
* auto-generated keys should be returned
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method with a
* constant of Statement.RETURN_GENERATED_KEYS
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
throws SQLException {
if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS
&& autoGeneratedKeys != Statement.NO_GENERATED_KEYS) {
throw new SQLException(
"Invalid parameter autoGeneratedKeys value. Must be 1 or 2. Valus is: "
+ autoGeneratedKeys);
}
return new PreparedStatementHttp(this, sql, autoGeneratedKeys);
}
/**
* Creates a default PreparedStatement
object capable of
* returning the auto-generated keys designated by the given array. This
* array contains the indexes of the columns in the target table that
* contain the auto-generated keys that should be made available. The driver
* will ignore the array if the SQL statement is not an INSERT
* statement, or an SQL statement able to return auto-generated keys (the
* list of such statements is vendor-specific).
*
* An SQL statement with or without IN parameters can be pre-compiled and
* stored in a PreparedStatement
object. This object can then
* be used to efficiently execute this statement multiple times.
*
* Note: This method is optimized for handling parametric SQL
* statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the
* statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to
* the database until the PreparedStatement
object is executed.
* This has no direct effect on users; however, it does affect which methods
* throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
* object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of
* the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter
* placeholders
* @param columnIndexes
* an array of column indexes indicating the columns that should
* be returned from the inserted row or rows
* @return a new PreparedStatement
object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column
* indexes
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, int columnIndexes[])
throws SQLException {
if (columnIndexes == null) {
throw new SQLException("columnIndexes can not be null");
}
return new PreparedStatementHttp(this, sql, columnIndexes);
}
/**
* Creates a default PreparedStatement
object capable of
* returning the auto-generated keys designated by the given array. This
* array contains the names of the columns in the target table that contain
* the auto-generated keys that should be returned. The driver will ignore
* the array if the SQL statement is not an INSERT
statement,
* or an SQL statement able to return auto-generated keys (the list of such
* statements is vendor-specific).
*
* An SQL statement with or without IN parameters can be pre-compiled and
* stored in a PreparedStatement
object. This object can then
* be used to efficiently execute this statement multiple times.
*
* Note: This method is optimized for handling parametric SQL
* statements that benefit from precompilation. If the driver supports
* precompilation, the method prepareStatement
will send the
* statement to the database for precompilation. Some drivers may not
* support precompilation. In this case, the statement may not be sent to
* the database until the PreparedStatement
object is executed.
* This has no direct effect on users; however, it does affect which methods
* throw certain SQLExceptions.
*
* Result sets created using the returned PreparedStatement
* object will by default be type TYPE_FORWARD_ONLY
and have a
* concurrency level of CONCUR_READ_ONLY
. The holdability of
* the created result sets can be determined by calling
* {@link #getHoldability}.
*
* @param sql
* an SQL statement that may contain one or more '?' IN parameter
* placeholders
* @param columnNames
* an array of column names indicating the columns that should be
* returned from the inserted row or rows
* @return a new PreparedStatement
object, containing the
* pre-compiled statement, that is capable of returning the
* auto-generated keys designated by the given array of column names
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
*
* @since 1.4
*/
public PreparedStatement prepareStatement(String sql, String columnNames[])
throws SQLException {
if (columnNames == null) {
throw new SQLException("columnNames can not be null");
}
return new PreparedStatementHttp(this, sql, columnNames);
}
/**
* Constructs an object that implements the Blob
interface. The
* object returned initially contains no data. The
* setBinaryStream
and setBytes
methods of the
* Blob
interface may be used to add data to the
* Blob
.
*
* @return An object that implements the Blob
interface
* @throws SQLException
* if an object that implements the Blob
interface
* can not be constructed, this method is called on a closed
* connection or a database access error occurs.
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this data type
*
* @since 1.6
*/
@Override
public Blob createBlob() throws SQLException {
testIfClosed();
BlobHttp blob = new BlobHttp();
return blob;
}
/**
* Constructs an object that implements the Clob
interface. The
* object returned initially contains no data. The
* setAsciiStream
, setCharacterStream
and
* setString
methods of the Clob
interface may be
* used to add data to the Clob
.
*
* @return An object that implements the Clob
interface
* @throws SQLException
* if an object that implements the Clob
interface
* can not be constructed, this method is called on a closed
* connection or a database access error occurs.
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this data type
*
* @since 1.6
*/
@Override
public Clob createClob() throws SQLException {
testIfClosed();
ClobHttp clob = new ClobHttp();
return clob;
}
/**
* Retrieves the current auto-commit mode for this Connection
* object.
*
* @return the current state of this Connection
object's
* auto-commit mode
* @exception SQLException
* if a database access error occurs
* @see #setAutoCommit
*/
@Override
public boolean getAutoCommit() throws SQLException {
testIfClosed();
return this.autoCommit;
}
/**
* Sets this connection's auto-commit mode to the given state. If a
* connection is in auto-commit mode, then all its SQL statements will be
* executed and committed as individual transactions. Otherwise, its SQL
* statements are grouped into transactions that are terminated by a call to
* either the method commit
or the method rollback
* . By default, new connections are in auto-commit mode.
*
* The commit occurs when the statement completes or the next execute
* occurs, whichever comes first. In the case of statements returning a
* ResultSet
object, the statement completes when the last row
* of the ResultSet
object has been retrieved or the
* ResultSet
object has been closed. In advanced cases, a
* single statement may return multiple results as well as output parameter
* values. In these cases, the commit occurs when all results and output
* parameter values have been retrieved.
*
* NOTE: If this method is called during a transaction, the
* transaction is committed.
*
* @param autoCommit
* true
to enable auto-commit mode;
* false
to disable it
* @exception SQLException
* if a database access error occurs
* @see #getAutoCommit
*/
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
testIfClosed();
if (statelessMode) {
if (autoCommit && !this.statementHolderFileList.isEmpty()) {
try {
// Execute all pending statements
receiveFromExecuteUpdate = getStringFromExecuteUpdateListOnServer();
} finally {
resetStatementHolderList(); // Safety reset of list
}
}
} else {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.setAutoCommit(autoCommit);
}
this.autoCommit = autoCommit;
}
/**
* Makes all changes made since the previous commit/rollback permanent and
* releases any database locks currently held by this
* Connection
object. This method should be used only when
* auto-commit mode has been disabled.
*
* @exception SQLException
* if a database access error occurs or this
* Connection
object is in auto-commit mode
* @see #setAutoCommit
*/
@Override
public void commit() throws SQLException {
testIfClosed();
if (statelessMode) {
// Execute all pending statements
if (!this.statementHolderFileList.isEmpty()) {
try {
receiveFromExecuteUpdate = getStringFromExecuteUpdateListOnServer();
} finally {
resetStatementHolderList(); // Safety reset of list
}
}
} else {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.commit();
}
}
/**
* Undoes all changes made in the current transaction and releases any
* database locks currently held by this Connection
object.
* This method should be used only when auto-commit mode has been disabled.
*
* @exception SQLException
* if a database access error occurs or this
* Connection
object is in auto-commit mode
* @see #setAutoCommit
*/
@Override
public void rollback() throws SQLException {
testIfClosed();
if (statelessMode) {
resetStatementHolderList();
} else {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.rollback();
}
}
/**
* Creates an unnamed savepoint in the current transaction and returns the
* new Savepoint
object that represents it.
*
* @return the new Savepoint
object
* @exception SQLException
* if a database access error occurs or this
* Connection
object is currently in auto-commit
* mode
* @see Savepoint
* @since 1.4
*/
@Override
public Savepoint setSavepoint() throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpSavepointTransfer jdbcHttpSavepointTransfer = new JdbcHttpSavepointTransfer(
this, authenticationToken);
Savepoint savepoint = jdbcHttpSavepointTransfer.setSavepoint();
return savepoint;
}
}
/**
* Creates a savepoint with the given name in the current transaction and
* returns the new Savepoint
object that represents it.
*
* @param name
* a String
containing the name of the savepoint
* @return the new Savepoint
object
* @exception SQLException
* if a database access error occurs or this
* Connection
object is currently in auto-commit
* mode
* @see Savepoint
* @since 1.4
*/
@Override
public Savepoint setSavepoint(String name) throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpSavepointTransfer jdbcHttpSavepointTransfer = new JdbcHttpSavepointTransfer(
this, authenticationToken);
Savepoint savepoint = jdbcHttpSavepointTransfer.setSavepoint(name);
return savepoint;
}
}
/**
* Undoes all changes made after the given Savepoint
object was
* set.
*
* This method should be used only when auto-commit has been disabled.
*
* @param savepoint
* the Savepoint
object to roll back to
* @exception SQLException
* if a database access error occurs, the
* Savepoint
object is no longer valid, or this
* Connection
object is currently in auto-commit
* mode
* @see Savepoint
* @see #rollback
* @since 1.4
*/
@Override
public void rollback(Savepoint savepoint) throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpSavepointTransfer jdbcHttpSavepointTransfer = new JdbcHttpSavepointTransfer(
this, authenticationToken);
jdbcHttpSavepointTransfer.rollback(savepoint);
return;
}
}
/**
* Undoes all changes made after the given Savepoint
object was
* set.
*
* This method should be used only when auto-commit has been disabled.
*
* @param savepoint
* the Savepoint
object to roll back to
* @exception SQLException
* if a database access error occurs, this method is called
* while participating in a distributed transaction, this
* method is called on a closed connection, the
* Savepoint
object is no longer valid, or this
* Connection
object is currently in auto-commit
* mode
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
* @see Savepoint
* @see #rollback
* @since 1.4
*/
@Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpSavepointTransfer jdbcHttpSavepointTransfer = new JdbcHttpSavepointTransfer(
this, authenticationToken);
jdbcHttpSavepointTransfer.releaseSavepoint(savepoint);
return;
}
}
/**
* Releases this Connection
object's database and JDBC
* resources immediately instead of waiting for them to be automatically
* released.
*
* Calling the method close
on a Connection
object
* that is already closed is a no-op.
*
* Note: A Connection
object is automatically closed
* when it is garbage collected. Certain fatal errors also close a
* Connection
object.
*
* @exception SQLException
* if a database access error occurs
*/
@Override
public void close() throws SQLException {
if (this.isClosed) {
return;
}
debug("Before jdbcHttpTransactionTransfer.close()");
if (!statelessMode) {
final ConnectionHttp theConnection = this;
try {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
theConnection, authenticationToken);
jdbcHttpTransactionTransfer.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
debug("After jdbcHttpTransactionTransfer.close()");
this.username = null;
this.authenticationToken = null;
this.sessionParameters = null;
this.authenticationToken = null;
this.statementHolderFileList = null;
if (httpTransfer != null) {
httpTransfer.close();
httpTransfer = null;
}
if (remoteSession != null) {
remoteSession.logoff();
remoteSession = null;
}
debug("databaseMetaDataMap: " + databaseMetaDataMap);
databaseMetaDataMap.remove(this);
debug("databaseMetaDataMap: " + databaseMetaDataMap);
this.isClosed = true;
}
/**
* Retrieves whether this Connection
object has been closed. A
* connection is closed if the method close
has been called on
* it or if certain fatal errors have occurred. This method is guaranteed to
* return true
only when it is called after the method
* Connection.close
has been called.
*
* This method generally cannot be called to determine whether a connection
* to a database is valid or invalid. A typical client can determine that a
* connection is invalid by catching any exceptions that might be thrown
* when an operation is attempted.
*
* @return true
if this Connection
object is
* closed; false
if it is still open
* @exception SQLException
* if a database access error occurs
*/
@Override
public boolean isClosed() throws SQLException {
return this.isClosed;
}
/**
* Puts this connection in read-only mode as a hint to the driver to enable
* database optimizations.
*
*
* Note: This method cannot be called during a transaction.
*
* @param readOnly
* true
enables read-only mode; false
* disables it
* @exception SQLException
* if a database access error occurs or this method is called
* during a transaction
*/
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
testIfClosed();
if (!statelessMode) {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.setReadOnly(readOnly);
}
this.readOnly = readOnly;
}
/**
* Retrieves whether this Connection
object is in read-only
* mode.
*
* @return true
if this Connection
object is
* read-only; false
otherwise
* @exception SQLException
* if a database access error occurs
*/
@Override
public boolean isReadOnly() throws SQLException {
testIfClosed();
if (!statelessMode) {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
this.readOnly = jdbcHttpTransactionTransfer.isReadOnly();
}
return this.readOnly;
}
/**
* Retrieves a DatabaseMetaData
object that contains metadata
* about the database to which this Connection
object
* represents a connection. The metadata includes information about the
* database's tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, and so on.
*
* @return a DatabaseMetaData
object for this
* Connection
object
* @exception SQLException
* if a database access error occurs
*/
@Override
public DatabaseMetaData getMetaData() throws SQLException {
testIfClosed();
DatabaseMetaData databaseMetaDataLocal = databaseMetaDataMap.get(this);
if (databaseMetaDataLocal != null) {
debug("getMetaData(): return DatabaseMetaData from cache.");
return databaseMetaDataLocal;
}
debug("getMetaData(): contacting server. ");
// Retrieve the JSON formated DatabaseMetaDataHolder from host
JdbcHttpMetaDataTransfer jdbcHttpMetaDataTransfer = new JdbcHttpMetaDataTransfer(
this, this.getAuthenticationToken());
File file = jdbcHttpMetaDataTransfer
.getFileFromCallMetaDataFunction("getMetaData");
String databaseMetaDataHolderString = null;
try {
databaseMetaDataHolderString = FileUtils.readFileToString(file);
databaseMetaDataHolderString = HtmlConverter
.fromHtml(databaseMetaDataHolderString);
} catch (IOException e) {
JdbcHttpTransferUtil.wrapExceptionAsSQLException(e);
}
if (!DEBUG && !KeepTempFilePolicyParms.KEEP_TEMP_FILE) {
file.delete();
}
// Format the DatabaseMetaDataHolder from JSON String
DatabaseMetaDataHolder databaseMetaDataHolder = DatabaseMetaDataHolderTransport
.fromJson(databaseMetaDataHolderString);
// Build the final DatabaseMetaDataHttp instance
DatabaseMetaDataHttp databaseMetaData = new DatabaseMetaDataHttp(this,
databaseMetaDataHolder);
databaseMetaDataMap.put(this, databaseMetaData);
return databaseMetaData;
}
/**
* Sets the given catalog name in order to select a subspace of this
* Connection
object's database in which to work.
*
* If the driver does not support catalogs, it will silently ignore this
* request.
*
* @param catalog
* the name of a catalog (subspace in this
* Connection
object's database) in which to work
* @exception SQLException
* if a database access error occurs
* @see #getCatalog
*/
@Override
public void setCatalog(String catalog) throws SQLException {
// Do Nothing ==> Ignore silently
}
/**
* Retrieves this Connection
object's current catalog name.
*
* @return the current catalog name or null
if there is none
* @exception SQLException
* if a database access error occurs
* @see #setCatalog
*/
@Override
public String getCatalog() throws SQLException {
// Retrieve the JSON formated DatabaseMetaDataHolder from host
JdbcHttpMetaDataTransfer jdbcHttpMetaDataTransfer = new JdbcHttpMetaDataTransfer(
this, this.getAuthenticationToken());
File file = jdbcHttpMetaDataTransfer
.getFileFromCallMetaDataFunction("getCatalog");
String catalog = null;
try {
catalog = FileUtils.readFileToString(file);
if (catalog != null) {
catalog = catalog.trim();
}
catalog = HtmlConverter.fromHtml(catalog);
} catch (IOException e) {
JdbcHttpTransferUtil.wrapExceptionAsSQLException(e);
}
if (catalog.equals("null")) {
catalog = null;
}
file.delete();
return catalog;
}
/**
* Attempts to change the transaction isolation level for this
* Connection
object to the one given. The constants defined in
* the interface Connection
are the possible transaction
* isolation levels.
*
* Note: If this method is called during a transaction, the result is
* implementation-defined.
*
* @param level
* one of the following Connection
constants:
* Connection.TRANSACTION_READ_UNCOMMITTED
,
* Connection.TRANSACTION_READ_COMMITTED
,
* Connection.TRANSACTION_REPEATABLE_READ
, or
* Connection.TRANSACTION_SERIALIZABLE
. (Note that
* Connection.TRANSACTION_NONE
cannot be used
* because it specifies that transactions are not supported.)
* @exception SQLException
* if a database access error occurs, this method is called
* on a closed connection or the given parameter is not one
* of the Connection
constants
* @see DatabaseMetaData#supportsTransactionIsolationLevel
* @see #getTransactionIsolation
*/
@Override
public void setTransactionIsolation(int level) throws SQLException {
testIfClosed();
if (level != Connection.TRANSACTION_READ_UNCOMMITTED
&& level != Connection.TRANSACTION_READ_COMMITTED
&& level != Connection.TRANSACTION_REPEATABLE_READ
&& level != Connection.TRANSACTION_SERIALIZABLE) {
throw new SQLException("Illegal transaction isolation level: "
+ level);
}
if (!statelessMode) {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.setTransactionIsolation(level);
}
this.transactionIsolation = level;
}
/**
* Retrieves the first warning reported by calls on this
* Connection
object. If there is more than one warning,
* subsequent warnings will be chained to the first one and can be retrieved
* by calling the method SQLWarning.getNextWarning
on the
* warning that was retrieved previously.
*
* This method may not be called on a closed connection; doing so will cause
* an SQLException
to be thrown.
*
*
* Note: Subsequent warnings will be chained to this SQLWarning.
*
* @return the first SQLWarning
object or null
if
* there are none
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @see SQLWarning
*/
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
/**
* Clears all warnings reported for this Connection
object.
* After a call to this method, the method getWarnings
returns
* null
until a new warning is reported for this
* Connection
object.
*
* @exception SQLException
* if a database access error occurs
*/
@Override
public void clearWarnings() throws SQLException {
// Does nothing
}
/**
* Retrieves this Connection
object's current transaction
* isolation level.
*
* @return the current transaction isolation level, which will be one of the
* following constants:
* Connection.TRANSACTION_READ_UNCOMMITTED
,
* Connection.TRANSACTION_READ_COMMITTED
,
* Connection.TRANSACTION_REPEATABLE_READ
,
* Connection.TRANSACTION_SERIALIZABLE
, or
* Connection.TRANSACTION_NONE
.
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @see #setTransactionIsolation
*/
@Override
public int getTransactionIsolation() throws SQLException {
testIfClosed();
// Ok, now get the default isolation level
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
this.transactionIsolation = jdbcHttpTransactionTransfer
.getTransactionIsolation();
return this.transactionIsolation;
}
// --------------------------JDBC 3.0-----------------------------
/**
* Changes the default holdability of ResultSet
objects created
* using this Connection
object to the given holdability. The
* default holdability of ResultSet
objects can be be
* determined by invoking {@link DatabaseMetaData#getResultSetHoldability}.
*
* @param holdability
* a ResultSet
holdability constant; one of
* ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @throws SQLException
* if a database access occurs, this method is called on a
* closed connection, or the given parameter is not a
* ResultSet
constant indicating holdability
* @exception SQLFeatureNotSupportedException
* if the given holdability is not supported
* @see #getHoldability
* @see DatabaseMetaData#getResultSetHoldability
* @see ResultSet
* @since 1.4
*/
@Override
public void setHoldability(int holdability) throws SQLException {
testIfClosed();
if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT
&& holdability != ResultSet.CLOSE_CURSORS_AT_COMMIT) {
throw new SQLException("Illegal holdability: " + holdability);
}
if (!statelessMode) {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
jdbcHttpTransactionTransfer.setHoldability(holdability);
} else {
if (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT) {
throw new SQLFeatureNotSupportedException(
"holdability ResultSet.HOLD_CURSORS_OVER_COMMIT is not supported");
}
}
this.holdability = holdability;
}
/**
* Retrieves the current holdability of ResultSet
objects
* created using this Connection
object.
*
* @return the holdability, one of
* ResultSet.HOLD_CURSORS_OVER_COMMIT
or
* ResultSet.CLOSE_CURSORS_AT_COMMIT
* @throws SQLException
* if a database access error occurs or this method is called on
* a closed connection
* @see #setHoldability
* @see DatabaseMetaData#getResultSetHoldability
* @see ResultSet
* @since 1.4
*/
@Override
public int getHoldability() throws SQLException {
testIfClosed();
if (!statelessMode) {
JdbcHttpTransactionTransfer jdbcHttpTransactionTransfer = new JdbcHttpTransactionTransfer(
this, authenticationToken);
this.holdability = jdbcHttpTransactionTransfer.getHoldability();
}
return holdability;
}
/**
* Returns true if the connection has not been closed and is still valid.
* The driver shall submit a query on the connection or use some other
* mechanism that positively verifies the connection is still valid when
* this method is called.
*
* The query submitted by the driver to validate the connection shall be
* executed in the context of the current transaction.
*
* @param timeout
* - The time in seconds to wait for the database operation used
* to validate the connection to complete. If the timeout period
* expires before the operation completes, this method returns
* false. A value of 0 indicates a timeout is not applied to the
* database operation.
*
* @return true if the connection is valid, false otherwise
* @exception SQLException
* if the value supplied for timeout
is less
* then 0
* @since 1.6
*
* @see java.sql.DatabaseMetaData#getClientInfoProperties
*/
@Override
public boolean isValid(int timeout) throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
boolean isValid = jdbcHttpConnectionInfoTransfer.isValid(timeout);
return isValid;
}
}
/**
* Sets the value of the client info property specified by name to the value
* specified by value.
*
* Applications may use the
* DatabaseMetaData.getClientInfoProperties
method to determine
* the client info properties supported by the driver and the maximum length
* that may be specified for each property.
*
* The driver stores the value specified in a suitable location in the
* database. For example in a special register, session parameter, or system
* table column. For efficiency the driver may defer setting the value in
* the database until the next time a statement is executed or prepared.
* Other than storing the client information in the appropriate place in the
* database, these methods shall not alter the behavior of the connection in
* anyway. The values supplied to these methods are used for accounting,
* diagnostics and debugging purposes only.
*
* The driver shall generate a warning if the client info name specified is
* not recognized by the driver.
*
* If the value specified to this method is greater than the maximum length
* for the property the driver may either truncate the value and generate a
* warning or generate a SQLClientInfoException
. If the driver
* generates a SQLClientInfoException
, the value specified was
* not set on the connection.
*
* The following are standard client info properties. Drivers are not
* required to support these properties however if the driver supports a
* client info property that can be described by one of the standard
* properties, the standard property name should be used.
*
*
* - ApplicationName - The name of the application currently utilizing the
* connection
* - ClientUser - The name of the user that the application using the
* connection is performing work for. This may not be the same as the user
* name that was used in establishing the connection.
* - ClientHostname - The hostname of the computer the application using
* the connection is running on.
*
*
*
* @param name
* The name of the client info property to set
* @param value
* The value to set the client info property to. If the value is
* null, the current value of the specified property is cleared.
*
* @throws SQLClientInfoException
* if the database server returns an error while setting the
* client info value on the database server or this method is
* called on a closed connection
*
* @since 1.6
*/
@Override
public void setClientInfo(String name, String value)
throws SQLClientInfoException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
jdbcHttpConnectionInfoTransfer.setClientInfo(name, value);
}
/**
* Sets the value of the connection's client info properties. The
* Properties
object contains the names and values of the
* client info properties to be set. The set of client info properties
* contained in the properties list replaces the current set of client info
* properties on the connection. If a property that is currently set on the
* connection is not present in the properties list, that property is
* cleared. Specifying an empty properties list will clear all of the
* properties on the connection. See
* setClientInfo (String, String)
for more information.
*
* If an error occurs in setting any of the client info properties, a
* SQLClientInfoException
is thrown. The
* SQLClientInfoException
contains information indicating which
* client info properties were not set. The state of the client information
* is unknown because some databases do not allow multiple client info
* properties to be set atomically. For those databases, one or more
* properties may have been set before the error occurred.
*
*
* @param properties
* the list of client info properties to set
*
* @see java.sql.Connection#setClientInfo(String, String)
* setClientInfo(String, String)
* @since 1.6
*
* @throws SQLClientInfoException
* if the database server returns an error while setting the
* clientInfo values on the database server or this method is
* called on a closed connection
*
*/
@Override
public void setClientInfo(Properties properties)
throws SQLClientInfoException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
jdbcHttpConnectionInfoTransfer.setClientInfo(properties);
}
/**
* Returns the value of the client info property specified by name. This
* method may return null if the specified client info property has not been
* set and does not have a default value. This method will also return null
* if the specified client info property name is not supported by the
* driver.
*
* Applications may use the
* DatabaseMetaData.getClientInfoProperties
method to determine
* the client info properties supported by the driver.
*
*
* @param name
* The name of the client info property to retrieve
*
* @return The value of the client info property specified
*
* @throws SQLException
* if the database server returns an error when fetching the
* client info value from the database or this method is called
* on a closed connection
*
* @since 1.6
*
* @see java.sql.DatabaseMetaData#getClientInfoProperties
*/
@Override
public String getClientInfo(String name) throws SQLException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
String clientInfo = jdbcHttpConnectionInfoTransfer.getClientInfo(name);
return clientInfo;
}
/**
* Returns a list containing the name and current value of each client info
* property supported by the driver. The value of a client info property may
* be null if the property has not been set and does not have a default
* value.
*
*
* @return A Properties
object that contains the name and
* current value of each of the client info properties supported by
* the driver.
*
* @throws SQLException
* if the database server returns an error when fetching the
* client info values from the database or this method is called
* on a closed connection
*
* @since 1.6
*/
@Override
public Properties getClientInfo() throws SQLException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
Properties clientInfo = jdbcHttpConnectionInfoTransfer.getClientInfo();
return clientInfo;
}
@Override
public Array createArrayOf(String typeName, Object[] elements)
throws SQLException {
if (statelessMode) {
throw new SQLException(FEATURE_NOT_SUPPORTED_IN_STATELESS_MODE);
} else {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
Array array = jdbcHttpConnectionInfoTransfer.createArrayOf(
typeName, elements);
return array;
}
}
// Java 1.7 only Methods - No Overloading because we must stay compatible
// with Java 6
/**
* Sets the given schema name to access.
*
* If the driver does not support schemas, it will silently ignore this
* request.
*
* Calling {@code setSchema} has no effect on previously created or prepared
* {@code Statement} objects. It is implementation defined whether a DBMS
* prepare operation takes place immediately when the {@code Connection}
* method {@code prepareStatement} or {@code prepareCall} is invoked. For
* maximum portability, {@code setSchema} should be called before a
* {@code Statement} is created or prepared.
*
* @param schema
* the name of a schema in which to work
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @see #getSchema
* @since 1.7
*/
@Override
public void setSchema(String schema) throws SQLException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
jdbcHttpConnectionInfoTransfer.setSchema(schema);
}
/**
* Retrieves this Connection
object's current schema name.
*
* @return the current schema name or null
if there is none
* @exception SQLException
* if a database access error occurs or this method is called
* on a closed connection
* @see #setSchema
* @since 1.7
*/
@Override
public String getSchema() throws SQLException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
String schema = jdbcHttpConnectionInfoTransfer.getSchema();
return schema;
}
/**
* Retrieves the number of milliseconds the driver will wait for a database
* request to complete. If the limit is exceeded, a
* SQLException
is thrown.
*
* @return the current timeout limit in milliseconds; zero means there is no
* limit
* @throws SQLException
* if a database access error occurs or this method is called on
* a closed Connection
* @exception SQLFeatureNotSupportedException
* if the JDBC driver does not support this method
* @see #setNetworkTimeout
* @since 1.7
*/
@Override
public int getNetworkTimeout() throws SQLException {
JdbcHttpConnectionInfoTransfer jdbcHttpConnectionInfoTransfer = new JdbcHttpConnectionInfoTransfer(
this, authenticationToken);
int networkTimeout = jdbcHttpConnectionInfoTransfer.getNetworkTimeout();
return networkTimeout;
}
//
// Utility dedicated methods for raw ConnectionHttp class that are not
// Connection
//
/**
* Returns the current Version.
*
* @return the current Version
*/
public String getVersion() {
return Version.getVersion();
}
/**
* Returns the URL of the path to the ServerSqlManager Servlet.
*
* @return the URL of the path to the ServerSqlManager Servlet
*/
public String getUrl() {
return url;
}
/**
* Returns the username in use.
*
* @return the username in use
*/
public String getUsername() {
return this.username;
}
/**
* Returns the Authentication Token
*
* @return the Authentication Token
*/
String getAuthenticationToken() {
return authenticationToken;
}
/**
* Returns the SessionParameters
instance in use for the
* current session.
*
* @return the SessionParameters
instance in use for the
* current session
*/
public SessionParameters getSessionParameters() {
return this.sessionParameters;
}
/**
* Returns the {@code Proxy} instance in use for this File Session.
*
* @return the {@code Proxy} instance in use for this File Session
*/
public Proxy getProxy() {
return this.proxy;
}
/**
* Returns the proxy credentials
* @return the proxy credentials
*/
public PasswordAuthentication getPasswordAuthentication() {
return passwordAuthentication;
}
/**
* Allows to get a copy of the current RemoteConnection
: use it
* to do some simultaneous operations in a different thread (in order to
* avoid conflicts).
*/
@Override
public Connection clone() {
Connection connectionHttp = new ConnectionHttp(this.url, this.username,
this.proxy, this.passwordAuthentication, this.sessionParameters, remoteSession,
statelessMode, joinResultSetMetaData);
return connectionHttp;
}
/**
* Returns the http status code of the last executed JDBC command that
* called the remote server.
*
* @return the http status code of the last executed JDBC command that
* called the remote server. 0 means the status could not be
* returned.
*/
public int getHttpStatusCode() {
if (remoteSession != null) {
return remoteSession.getHttpStatusCode();
} else {
return 0;
}
}
/**
* Gets the current RemoteSession
instance (used for file
* transfers of Clobs and Blobs).
*
*
* @return the remoteSession instance (to be used for file transfers, per
* example)
*/
public RemoteSession getRemoteSession() {
return remoteSession;
}
/**
* Returns true if the statement are to be encrypted.
*
* @return true if the statement are to be encrypted. (Default to false).
*/
public boolean isEncryptStatementParameters() {
return this.encryptStatementParameters;
}
/**
* Set if the statement parameters are to be encrypted
*
* @param encryptStatementParameters
* true if the statement parameters are to be encrypted, else
* false
*/
public void setEncryptStatementParameters(boolean encryptStatementParameters) {
this.encryptStatementParameters = encryptStatementParameters;
}
/**
* Returns the maximum Number Of Statements that may be transported in
* memory. If maximum is reached, transport is done using a file.
*
* @return the maximum Number Of Statements that may be transported in
* memory.
*/
public int getMaxStatementsForMemoryTransport() {
return this.maxStatementsForMemoryTransport;
}
/**
* Sets the maximum Number Of Statements that may be transported in memory
* from client to server. if maximum is reached, transport is done using a
* file.
*
* @param maxStatementsForMemoryTransport
* the maximum Number Of Statements that may be transported in
* memory.
*
*/
public void setMaxStatementsForMemoryTransport(
int maxStatementsForMemoryTransport) {
this.maxStatementsForMemoryTransport = maxStatementsForMemoryTransport;
}
/**
* Test if a connection is still open
*
* @throws SQLException
* it the Connection is closed
*/
private void testIfClosed() throws SQLException {
if (isClosed()) {
throw new SQLException("This RemoteConnection is closed!");
}
}
/**
* Says if session is in stateless mode when connecting to the server.
*
* @return true if session is in stateless mode when connecting to the
* server
*/
public boolean isStatelessMode() {
return statelessMode;
}
/**
* @return the connectionId
*/
public String getConnectionId() {
return connectionId;
}
/**
* Debug tool
*
* @param s
*/
private void debug(String s) {
if (DEBUG) {
ClientLogger.getLogger().log(Level.WARNING, s);
}
}
}
// En