Java tutorial
/* * 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.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.jdbc.util.zip.HttpTransferZip; 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<Connection, DatabaseMetaData> databaseMetaDataMap = new HashMap<Connection, DatabaseMetaData>(); /** 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<File> localFiles = new Vector<File>(); /** * The list of input streams to delete (in fire and forget mode) at commit */ List<InputStream> localInputStreams = new Vector<InputStream>(); /** The length of each InputStream */ List<Long> localInputStreamLengths = new Vector<Long>(); /** * The list of remote uploaded files delete (in fire and forget mode) at at * commit */ List<String> remoteFiles = new Vector<String>(); /** * 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; /** Says if Result Set must be GZIP before download */ private boolean zipResultSet; /** * 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 * @param zipResultSet * says if ResultSet must be zipped by server size */ public ConnectionHttp(String url, String username, Proxy proxy, PasswordAuthentication passwordAuthentication, SessionParameters sessionParameters, RemoteSession remoteSession, boolean statelessMode, boolean joinResultSetMetaData, boolean zipResultSet) { 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; this.zipResultSet = zipResultSet; String urlHttpOnly = JdbcUrlHeader.getUrlHttpOnly(url); httpTransfer = new HttpTransferZip(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 * @param zipResultSet * says if ResultSet must be zipped by server size * @throws IllegalArgumentException * if url, username, password is null * @throws SQLException * if any <code>Exception</code> occurs. The * <code>SQLException</code> wraps the original * <code>Exception</code> 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, boolean zipResultSet) 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; this.zipResultSet = zipResultSet; httpTransfer = new HttpTransferZip(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 {@code true} if server ResultSet Meta Data must be downloaded along with * the server ResultSet, else {@code false} * @since 3.0 */ public boolean isJoinResultSetMetaData() { return joinResultSetMetaData; } /** * Returns the boolean that says if server {@code ResultSet} must be GZIPed * before download. * * @return {@code true} if server {@code ResultSet} must be GZIPed before download * * @since 4.1 */ public boolean isZipResultSet() { return zipResultSet; } /** * Says if server {@code ResultSet} must be GZIPed before download * @param {@code true} if server {@code ResultSet} must be GZIPed before download, else {@code false} * * Defaults to {@code true} * @since 4.1 */ public void setZipResultSet(boolean zipResultSet) { this.zipResultSet = zipResultSet; } /** * 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<File>(); this.remoteFiles = new Vector<String>(); } } testIfUploadInterrupted(); JdbcHttpStatementTransfer jdbcHttpStatementTransfer = new JdbcHttpStatementTransfer(this, authenticationToken); String result = jdbcHttpStatementTransfer.getStringFromExecuteUpdateListOnServer(statementHolderFileList); testIfUploadInterrupted(); return result; } /** * Creates a <code>Statement</code> object for sending SQL statements to the * database. SQL statements without parameters are normally executed using * <code>Statement</code> objects. If the same SQL statement is executed * many times, it may be more efficient to use a * <code>PreparedStatement</code> object. * <P> * Result sets created using the returned <code>Statement</code> object will * by default be type <code>TYPE_FORWARD_ONLY</code> and have a concurrency * level of <code>CONCUR_READ_ONLY</code>. * * @return a new default <code>Statement</code> 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 <code>Statement</code> object that will generate * <code>ResultSet</code> objects with the given type and concurrency. This * method is the same as the <code>createStatement</code> 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 * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * a concurrency type; one of * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @return a new <code>Statement</code> object that will generate * <code>ResultSet</code> 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 * <code>ResultSet</code> 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 <code>Statement</code> object that will generate * <code>ResultSet</code> objects with the given type, concurrency, and * holdability. This method is the same as the <code>createStatement</code> * method above, but it allows the default result set type, concurrency, and * holdability to be overridden. * * @param resultSetType * one of the following <code>ResultSet</code> constants: * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * one of the following <code>ResultSet</code> constants: * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @param resultSetHoldability * one of the following <code>ResultSet</code> constants: * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @return a new <code>Statement</code> object that will generate * <code>ResultSet</code> 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 * <code>ResultSet</code> 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 <code>CallableStatement</code> object for calling database * stored procedures. The <code>CallableStatement</code> object provides * methods for setting up its IN and OUT parameters, and methods for * executing the call to a stored procedure. * * <P> * <B>Note:</B> This method is optimized for handling stored procedure call * statements. Some drivers may send the call statement to the database when * the method <code>prepareCall</code> is done; others may wait until the * <code>CallableStatement</code> object is executed. This has no direct * effect on users; however, it does affect which method throws certain * SQLExceptions. * <P> * Result sets created using the returned <code>CallableStatement</code> * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a * concurrency level of <code>CONCUR_READ_ONLY</code>. * * @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 <code>CallableStatement</code> 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 <code>CallableStatement</code> object that will generate * <code>ResultSet</code> objects with the given type and concurrency. This * method is the same as the <code>prepareCall</code> method above, but it * allows the default result set type and concurrency to be overridden. * * @param sql * a <code>String</code> 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 * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * a concurrency type; one of * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @return a new <code>CallableStatement</code> object containing the * pre-compiled SQL statement that will produce * <code>ResultSet</code> objects with the given type and * concurrency * @exception SQLException * if a database access error occurs or the given parameters * are not <code>ResultSet</code> 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 <code>CallableStatement</code> object that will generate * <code>ResultSet</code> objects with the given type and concurrency. This * method is the same as the <code>prepareCall</code> method above, but it * allows the default result set type, result set concurrency type and * holdability to be overridden. * * @param sql * a <code>String</code> object that is the SQL statement to be * sent to the database; may contain on or more ? parameters * @param resultSetType * one of the following <code>ResultSet</code> constants: * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * one of the following <code>ResultSet</code> constants: * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @param resultSetHoldability * one of the following <code>ResultSet</code> constants: * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @return a new <code>CallableStatement</code> object, containing the * pre-compiled SQL statement, that will generate * <code>ResultSet</code> objects with the given type, concurrency, * and holdability * @exception SQLException * if a database access error occurs or the given parameters * are not <code>ResultSet</code> 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 <code>PreparedStatement</code> object for sending parameterized * SQL statements to the database. * <P> * A SQL statement with or without IN parameters can be pre-compiled and * stored in a <code>PreparedStatement</code> object. This object can then * be used to efficiently execute this statement multiple times. * * <P> * <B>Note:</B> This method is optimized for handling parametric SQL * statements that benefit from precompilation. If the driver supports * precompilation, the method <code>prepareStatement</code> 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 <code>PreparedStatement</code> object is executed. * This has no direct effect on users; however, it does affect which methods * throw certain <code>SQLException</code> objects. * <P> * Result sets created using the returned <code>PreparedStatement</code> * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a * concurrency level of <code>CONCUR_READ_ONLY</code>. * * @param sql * an SQL statement that may contain one or more '?' IN parameter * placeholders * @return a new default <code>PreparedStatement</code> 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 <code>PreparedStatement</code> object that will generate * <code>ResultSet</code> objects with the given type and concurrency. This * method is the same as the <code>prepareStatement</code> 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 <code>String</code> 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 * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * a concurrency type; one of * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @return a new PreparedStatement object containing the pre-compiled SQL * statement that will produce <code>ResultSet</code> 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 * <code>ResultSet</code> 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 <code>PreparedStatement</code> object that will generate * <code>ResultSet</code> objects with the given type, concurrency, and * holdability. * <P> * This method is the same as the <code>prepareStatement</code> method * above, but it allows the default result set type, concurrency, and * holdability to be overridden. * * @param sql * a <code>String</code> 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 <code>ResultSet</code> constants: * <code>ResultSet.TYPE_FORWARD_ONLY</code>, * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code> * @param resultSetConcurrency * one of the following <code>ResultSet</code> constants: * <code>ResultSet.CONCUR_READ_ONLY</code> or * <code>ResultSet.CONCUR_UPDATABLE</code> * @param resultSetHoldability * one of the following <code>ResultSet</code> constants: * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @return a new <code>PreparedStatement</code> object, containing the * pre-compiled SQL statement, that will generate * <code>ResultSet</code> 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 * <code>ResultSet</code> 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 <code>PreparedStatement</code> 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 * <code>INSERT</code> statement, or an SQL statement able to return * auto-generated keys (the list of such statements is vendor-specific). * <P> * <B>Note:</B> This method is optimized for handling parametric SQL * statements that benefit from precompilation. If the driver supports * precompilation, the method <code>prepareStatement</code> 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 <code>PreparedStatement</code> object is executed. * This has no direct effect on users; however, it does affect which methods * throw certain SQLExceptions. * <P> * Result sets created using the returned <code>PreparedStatement</code> * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a * concurrency level of <code>CONCUR_READ_ONLY</code>. 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 <code>Statement.RETURN_GENERATED_KEYS</code> * or <code>Statement.NO_GENERATED_KEYS</code> * @return a new <code>PreparedStatement</code> 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 * <code>Statement</code> 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 <code>PreparedStatement</code> 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 <code>INSERT</code> * statement, or an SQL statement able to return auto-generated keys (the * list of such statements is vendor-specific). * <p> * An SQL statement with or without IN parameters can be pre-compiled and * stored in a <code>PreparedStatement</code> object. This object can then * be used to efficiently execute this statement multiple times. * <P> * <B>Note:</B> This method is optimized for handling parametric SQL * statements that benefit from precompilation. If the driver supports * precompilation, the method <code>prepareStatement</code> 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 <code>PreparedStatement</code> object is executed. * This has no direct effect on users; however, it does affect which methods * throw certain SQLExceptions. * <P> * Result sets created using the returned <code>PreparedStatement</code> * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a * concurrency level of <code>CONCUR_READ_ONLY</code>. 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 <code>PreparedStatement</code> 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 <code>PreparedStatement</code> 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 <code>INSERT</code> statement, * or an SQL statement able to return auto-generated keys (the list of such * statements is vendor-specific). * <P> * An SQL statement with or without IN parameters can be pre-compiled and * stored in a <code>PreparedStatement</code> object. This object can then * be used to efficiently execute this statement multiple times. * <P> * <B>Note:</B> This method is optimized for handling parametric SQL * statements that benefit from precompilation. If the driver supports * precompilation, the method <code>prepareStatement</code> 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 <code>PreparedStatement</code> object is executed. * This has no direct effect on users; however, it does affect which methods * throw certain SQLExceptions. * <P> * Result sets created using the returned <code>PreparedStatement</code> * object will by default be type <code>TYPE_FORWARD_ONLY</code> and have a * concurrency level of <code>CONCUR_READ_ONLY</code>. 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 <code>PreparedStatement</code> 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 <code>Blob</code> interface. The * object returned initially contains no data. The * <code>setBinaryStream</code> and <code>setBytes</code> methods of the * <code>Blob</code> interface may be used to add data to the * <code>Blob</code>. * * @return An object that implements the <code>Blob</code> interface * @throws SQLException * if an object that implements the <code>Blob</code> 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 <code>Clob</code> interface. The * object returned initially contains no data. The * <code>setAsciiStream</code>, <code>setCharacterStream</code> and * <code>setString</code> methods of the <code>Clob</code> interface may be * used to add data to the <code>Clob</code>. * * @return An object that implements the <code>Clob</code> interface * @throws SQLException * if an object that implements the <code>Clob</code> 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 <code>Connection</code> * object. * * @return the current state of this <code>Connection</code> 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 <code>commit</code> or the method <code>rollback</code> * . By default, new connections are in auto-commit mode. * <P> * The commit occurs when the statement completes or the next execute * occurs, whichever comes first. In the case of statements returning a * <code>ResultSet</code> object, the statement completes when the last row * of the <code>ResultSet</code> object has been retrieved or the * <code>ResultSet</code> 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. * <P> * <B>NOTE:</B> If this method is called during a transaction, the * transaction is committed. * * @param autoCommit * <code>true</code> to enable auto-commit mode; * <code>false</code> 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 * <code>Connection</code> object. This method should be used only when * auto-commit mode has been disabled. * * @exception SQLException * if a database access error occurs or this * <code>Connection</code> 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 <code>Connection</code> object. * This method should be used only when auto-commit mode has been disabled. * * @exception SQLException * if a database access error occurs or this * <code>Connection</code> 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 <code>Savepoint</code> object that represents it. * * @return the new <code>Savepoint</code> object * @exception SQLException * if a database access error occurs or this * <code>Connection</code> 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 <code>Savepoint</code> object that represents it. * * @param name * a <code>String</code> containing the name of the savepoint * @return the new <code>Savepoint</code> object * @exception SQLException * if a database access error occurs or this * <code>Connection</code> 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 <code>Savepoint</code> object was * set. * <P> * This method should be used only when auto-commit has been disabled. * * @param savepoint * the <code>Savepoint</code> object to roll back to * @exception SQLException * if a database access error occurs, the * <code>Savepoint</code> object is no longer valid, or this * <code>Connection</code> 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 <code>Savepoint</code> object was * set. * <P> * This method should be used only when auto-commit has been disabled. * * @param savepoint * the <code>Savepoint</code> 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 * <code>Savepoint</code> object is no longer valid, or this * <code>Connection</code> 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 <code>Connection</code> object's database and JDBC * resources immediately instead of waiting for them to be automatically * released. * <P> * Calling the method <code>close</code> on a <code>Connection</code> object * that is already closed is a no-op. * <P> * <B>Note:</B> A <code>Connection</code> object is automatically closed * when it is garbage collected. Certain fatal errors also close a * <code>Connection</code> 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 <code>Connection</code> object has been closed. A * connection is closed if the method <code>close</code> has been called on * it or if certain fatal errors have occurred. This method is guaranteed to * return <code>true</code> only when it is called after the method * <code>Connection.close</code> has been called. * <P> * 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 <code>true</code> if this <code>Connection</code> object is * closed; <code>false</code> 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. * * <P> * <B>Note:</B> This method cannot be called during a transaction. * * @param readOnly * <code>true</code> enables read-only mode; <code>false</code> * 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 <code>Connection</code> object is in read-only * mode. * * @return <code>true</code> if this <code>Connection</code> object is * read-only; <code>false</code> 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 <code>DatabaseMetaData</code> object that contains metadata * about the database to which this <code>Connection</code> 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 <code>DatabaseMetaData</code> object for this * <code>Connection</code> 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 * <code>Connection</code> object's database in which to work. * <P> * If the driver does not support catalogs, it will silently ignore this * request. * * @param catalog * the name of a catalog (subspace in this * <code>Connection</code> 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 <code>Connection</code> object's current catalog name. * * @return the current catalog name or <code>null</code> 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 * <code>Connection</code> object to the one given. The constants defined in * the interface <code>Connection</code> are the possible transaction * isolation levels. * <P> * <B>Note:</B> If this method is called during a transaction, the result is * implementation-defined. * * @param level * one of the following <code>Connection</code> constants: * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, * <code>Connection.TRANSACTION_READ_COMMITTED</code>, * <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or * <code>Connection.TRANSACTION_SERIALIZABLE</code>. (Note that * <code>Connection.TRANSACTION_NONE</code> 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 <code>Connection</code> 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 * <code>Connection</code> 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 <code>SQLWarning.getNextWarning</code> on the * warning that was retrieved previously. * <P> * This method may not be called on a closed connection; doing so will cause * an <code>SQLException</code> to be thrown. * * <P> * <B>Note:</B> Subsequent warnings will be chained to this SQLWarning. * * @return the first <code>SQLWarning</code> object or <code>null</code> 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 <code>Connection</code> object. * After a call to this method, the method <code>getWarnings</code> returns * <code>null</code> until a new warning is reported for this * <code>Connection</code> object. * * @exception SQLException * if a database access error occurs */ @Override public void clearWarnings() throws SQLException { // Does nothing } /** * Retrieves this <code>Connection</code> object's current transaction * isolation level. * * @return the current transaction isolation level, which will be one of the * following constants: * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, * <code>Connection.TRANSACTION_READ_COMMITTED</code>, * <code>Connection.TRANSACTION_REPEATABLE_READ</code>, * <code>Connection.TRANSACTION_SERIALIZABLE</code>, or * <code>Connection.TRANSACTION_NONE</code>. * @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 <code>ResultSet</code> objects created * using this <code>Connection</code> object to the given holdability. The * default holdability of <code>ResultSet</code> objects can be be * determined by invoking {@link DatabaseMetaData#getResultSetHoldability}. * * @param holdability * a <code>ResultSet</code> holdability constant; one of * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @throws SQLException * if a database access occurs, this method is called on a * closed connection, or the given parameter is not a * <code>ResultSet</code> 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 <code>ResultSet</code> objects * created using this <code>Connection</code> object. * * @return the holdability, one of * <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or * <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code> * @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. * <p> * 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. * <p> * @return true if the connection is valid, false otherwise * @exception SQLException * if the value supplied for <code>timeout</code> is less * then 0 * @since 1.6 * <p> * @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. * <p> * Applications may use the * <code>DatabaseMetaData.getClientInfoProperties</code> method to determine * the client info properties supported by the driver and the maximum length * that may be specified for each property. * <p> * 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. * <p> * The driver shall generate a warning if the client info name specified is * not recognized by the driver. * <p> * 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 <code>SQLClientInfoException</code>. If the driver * generates a <code>SQLClientInfoException</code>, the value specified was * not set on the connection. * <p> * 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. * <p> * <ul> * <li>ApplicationName - The name of the application currently utilizing the * connection</li> * <li>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.</li> * <li>ClientHostname - The hostname of the computer the application using * the connection is running on.</li> * </ul> * <p> * * @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. * <p> * @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 * <p> * @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 * <code>Properties</code> 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 * <code>setClientInfo (String, String)</code> for more information. * <p> * If an error occurs in setting any of the client info properties, a * <code>SQLClientInfoException</code> is thrown. The * <code>SQLClientInfoException</code> 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. * <p> * * @param properties * the list of client info properties to set * <p> * @see java.sql.Connection#setClientInfo(String, String) * setClientInfo(String, String) * @since 1.6 * <p> * @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 * <p> */ @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. * <p> * Applications may use the * <code>DatabaseMetaData.getClientInfoProperties</code> method to determine * the client info properties supported by the driver. * <p> * * @param name * The name of the client info property to retrieve * <p> * @return The value of the client info property specified * <p> * @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 * <p> * @since 1.6 * <p> * @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. * <p> * * @return A <code>Properties</code> object that contains the name and * current value of each of the client info properties supported by * the driver. * <p> * @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 * <p> * @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. * <P> * If the driver does not support schemas, it will silently ignore this * request. * <p> * 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 <code>Connection</code> object's current schema name. * * @return the current schema name or <code>null</code> 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 * <code>SQLException</code> 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 <code>Connection</code> * @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 <code>SessionParameters</code> instance in use for the * current session. * * @return the <code>SessionParameters</code> 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 <code>RemoteConnection</code>: 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, zipResultSet); 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 <code>RemoteSession</code> instance (used for file * transfers of Clobs and Blobs). * <p> * * @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