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.servlet; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.lang3.exception.ExceptionUtils; import org.kawanfw.commons.api.server.CommonsConfigurator; import org.kawanfw.commons.server.util.ServerLogger; import org.kawanfw.commons.util.FrameworkDebug; import org.kawanfw.commons.util.Tag; import org.kawanfw.commons.util.TransferStatus; import org.kawanfw.file.api.server.FileConfigurator; import org.kawanfw.file.servlet.KawanNotifier; import org.kawanfw.file.servlet.ServerFileDispatch; import org.kawanfw.file.servlet.ServerFileUploadAction; import org.kawanfw.file.servlet.ServerUserThrowable; import org.kawanfw.file.util.parms.Action; import org.kawanfw.file.util.parms.Parameter; import org.kawanfw.file.util.parms.ReturnCode; import org.kawanfw.sql.api.server.SqlConfigurator; import org.kawanfw.sql.servlet.connection.ConnectionInfoUtil; import org.kawanfw.sql.servlet.connection.ConnectionStore; import org.kawanfw.sql.servlet.connection.ConnectionStoreCleaner; import org.kawanfw.sql.servlet.connection.SavepointUtil; import org.kawanfw.sql.servlet.connection.TransactionUtil; import org.kawanfw.sql.servlet.executor.ServerBatchPrepStatementExecutorNew; import org.kawanfw.sql.servlet.executor.ServerBatchStatementExecutorNew; import org.kawanfw.sql.servlet.executor.ServerSqlExecutorCallable; import org.kawanfw.sql.servlet.executor.ServerSqlExecutorNew; import org.kawanfw.sql.util.ConnectionParms; import org.kawanfw.sql.util.SqlAction; import org.kawanfw.sql.util.SqlActionCallable; import org.kawanfw.sql.util.SqlActionTransaction; import org.kawanfw.sql.util.SqlReturnCode; import org.kawanfw.sql.version.VersionValues; /** * @author Nicolas de Pomereu * * The method executeRequest() is to to be called from the SqlHttpServer * Servlet and Class. <br> * It will execute a client side request with a RemoteConnection * connection. * */ public class ServerSqlDispatch { private static boolean DEBUG = FrameworkDebug.isSet(ServerSqlDispatch.class); // Errors in SqlHttpServer private static final String ERR_ACTION_NOT_SET = "ERR_ACTION_NOT_SET"; /** * Constructor */ public ServerSqlDispatch() { // Does nothing } /** * Execute the client sent sql request * * @param request * the http request * @param response * the http response * @param servletContextTempDir * The temp dir used by Servlets * @param commonsConfigurator * the client commons http configurator specific class * @param fileConfigurator * the client file http configurator specific class * @param sqlConfigurator * the client sql http configurator specific class * @param connection * the Sql Jdbc Connection * @throws IOException * if any IOException occurs */ public void executeRequest(HttpServletRequest request, HttpServletResponse response, File servletContextTempDir, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator) throws IOException { // Immediate catch if we are asking a file upload, because parameters // are // in unknown sequence. We know it's a upload action if it's mime // multipart if (ServletFileUpload.isMultipartContent(request)) { ServerFileUploadAction serverFileUploadAction = new ServerFileUploadAction(); serverFileUploadAction.executeAction(request, response, servletContextTempDir, commonsConfigurator, fileConfigurator); return; } OutputStream out = null; try { debug("executeRequest Start"); // Prepare the response response.setContentType("text/html"); // Get the send string debug("ACTION retrieval"); String action = null; // We must trap the IllegalArgumentException to rethrow properly to // client // This happens if there is an encryption problem try { action = request.getParameter(Parameter.ACTION); } catch (IllegalArgumentException e) { debug("IllegalArgumentException : " + e.toString()); out = response.getOutputStream(); throw e; } String username = request.getParameter(Parameter.USERNAME); debug("Before if (action.equals(Action.LOGIN_ACTION"); if (action.equals(Action.LOGIN_ACTION) || action.equals(Action.BEFORE_LOGIN_ACTION)) { ServerLoginActionSql serverLoginActionSql = new ServerLoginActionSql(); serverLoginActionSql.executeAction(request, response, commonsConfigurator, sqlConfigurator, action); return; } debug("ACTION : " + action); // Redirect to Awake FILE if it's a File request (Blobs/Clobs) if (isActionForAwakeFile(action)) { ServerFileDispatch serverFileDispatch = new ServerFileDispatch(); serverFileDispatch.executeRequest(request, response, servletContextTempDir, commonsConfigurator, fileConfigurator); return; } debug("After isActionForAwakeFile"); out = response.getOutputStream(); if (action == null || action.equals("")) { // out.println(HttpTransferOne.SEND_FAILED + SPACE + // ERR_ACTION_NOT_SET); // out.println(TransferStatus.SEND_FAILED); // out.println(ERR_ACTION_NOT_SET); ServerSqlManager.writeLine(out, TransferStatus.SEND_FAILED); ServerSqlManager.writeLine(out, ERR_ACTION_NOT_SET); return; } debug("Before if (! ServerFileDispatch.isTokenValid(username, token, commonsConfigurator"); String token = request.getParameter(Parameter.TOKEN); if (!ServerFileDispatch.isTokenValid(username, token, commonsConfigurator)) { //out.println(TransferStatus.SEND_OK); //out.println(ReturnCode.INVALID_LOGIN_OR_PASSWORD); ServerSqlManager.writeLine(out, TransferStatus.SEND_OK); ServerSqlManager.writeLine(out, ReturnCode.INVALID_LOGIN_OR_PASSWORD); return; } String connectionId = request.getParameter(ConnectionParms.CONNECTION_ID); // If we are in normal mode (not server stateless mode), transaction // id is > 0 // So Extract a Connection from the pool and store it memory if (action.equals(SqlActionTransaction.ACTION_SQL_INIT_REMOTE_CONNECTION) && !connectionId.equals("0")) { // Create the Connection & store it ConnectionStore connectionStore = new ConnectionStore(username, connectionId); Connection connection = commonsConfigurator.getConnection(); connectionStore.put(connection); debug("ACTION_SQL_INIT_REMOTE_CONNECTION"); debug("username :" + username + ":"); debug("connectionId :" + connectionId + ":"); debug("connection :" + connection + ":"); //out.println(TransferStatus.SEND_OK); ServerSqlManager.writeLine(out, TransferStatus.SEND_OK); return; } // If we are not in stateless mode, clean old connections with a // Thread if (!connectionId.equals("0") && !ConnectionStoreCleaner.IS_RUNNING) { ConnectionStoreCleaner cleaner = new ConnectionStoreCleaner(sqlConfigurator); cleaner.start(); } // Notify to Kawan in async mode using a secured Thread that // the user has successfully logged (done once in JVM session per // username). // No notification is done if user.home/.kawansoft/no_notify.txt exists // or web server name is localhost or 127.0.0.1 if (!KawanNotifier.existsNoNotifyTxt() && !KawanNotifier.usernameAlreadyLogged(username) && !KawanNotifier.serverNameIsLocalhost()) { KawanNotifier kawanNotifier = new KawanNotifier(username, "AceQL_" + VersionValues.VERSION); kawanNotifier.start(); } if (action.equals(SqlAction.ACTION_SQL_STATEMENT)) { executeStatement(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlAction.ACTION_SQL_STATEMENT_BATCH)) { executeStatementBatch(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlAction.ACTION_SQL_PREP_STATEMENT_BATCH)) { executePrepStatementBatch(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlAction.ACTION_SQL_GET_METADATA)) { executeGetMetadata(request, commonsConfigurator, sqlConfigurator, out); } else if (action.equals(SqlAction.ACTION_SQL_EXECUTE_RAW)) { executeRaw(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlActionTransaction.ACTION_SQL_GET_TRANSACTION_ISOLATION)) { getTransactionIsolation(request, commonsConfigurator, sqlConfigurator, out); } else if (action.equals(SqlActionCallable.ACTION_SQL_CALLABLE_EXECUTE_RAW)) { callableExecute(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlActionCallable.ACTION_SQL_CALLABLE_EXECUTE_QUERY)) { callableExecuteQuery(request, commonsConfigurator, fileConfigurator, sqlConfigurator, out); } else if (action.equals(SqlActionTransaction.ACTION_SQL_COMMIT) || action.equals(SqlActionTransaction.ACTION_SQL_ROLLBACK) || action.equals(SqlActionTransaction.ACTION_SQL_CON_CLOSE) ) { setCommitRollbackCloseExecute(request, commonsConfigurator, sqlConfigurator, out, action); } else if (action.equals(SqlActionTransaction.ACTION_SQL_SET_AUTOCOMMIT) || action.equals(SqlActionTransaction.ACTION_SQL_SET_READ_ONLY) || action.equals(SqlActionTransaction.ACTION_SQL_SET_HOLDABILITY) || action.equals(SqlActionTransaction.ACTION_SQL_SET_TRANSACTION_ISOLATION) ) { setAutocommitReadOnlyHoldabilityTransactionInsolationExecute(request, commonsConfigurator, out, action); } else if (action.equals(SqlActionTransaction.ACTION_SQL_IS_READ_ONLY) || action.equals(SqlActionTransaction.ACTION_SQL_GET_HOLDABILITY) || action.equals(SqlActionTransaction.ACTION_SQL_GET_AUTOCOMMIT)) { getAutocommitReadOnlyHoldabilityExecute(request, commonsConfigurator, out, action); } else if (action.equals(SqlActionTransaction.ACTION_SQL_SET_SAVEPOINT) || action.equals(SqlActionTransaction.ACTION_SQL_SET_SAVEPOINT_NAME) || action.equals(SqlActionTransaction.ACTION_SQL_SET_ROLLBACK_SAVEPOINT) || action.equals(SqlActionTransaction.ACTION_SQL_SET_RELEASE_SAVEPOINT)) { setSavepointExecute(request, commonsConfigurator, out, action); } else if (action.equals(SqlAction.ACTION_SQL_IS_VALID) || action.equals(SqlAction.ACTION_SQL_SET_CLIENT_INFO_NAME) || action.equals(SqlAction.ACTION_SQL_SET_CLIENT_INFO_PROP) || action.equals(SqlAction.ACTION_SQL_GET_CLIENT_INFO_NAME) || action.equals(SqlAction.ACTION_SQL_GET_CLIENT_INFO) || action.equals(SqlAction.ACTION_SQL_CREATE_ARRAY_OF)) { connectionInfoExecute(request, commonsConfigurator, out, action); } else { throw new IllegalArgumentException("Invalid Sql Action: " + action); } } catch (Exception e) { // out.println(TransferStatus.SEND_FAILED); // out.println(e.getClass().getName()); // out.println(ServerUserThrowable.getMessage(e)); // out.println(ExceptionUtils.getStackTrace(e)); ServerSqlManager.writeLine(out, TransferStatus.SEND_FAILED); ServerSqlManager.writeLine(out, e.getClass().getName()); ServerSqlManager.writeLine(out, ServerUserThrowable.getMessage(e)); ServerSqlManager.writeLine(out, ExceptionUtils.getStackTrace(e)); try { ServerLogger.getLogger().log(Level.WARNING, Tag.PRODUCT_EXCEPTION_RAISED + " " + ServerUserThrowable.getMessage(e)); ServerLogger.getLogger().log(Level.WARNING, Tag.PRODUCT_EXCEPTION_RAISED + " " + ExceptionUtils.getStackTrace(e)); } catch (Exception e1) { e1.printStackTrace(); e1.printStackTrace(System.out); } } } /** * Returns to client the Connection.getTransactionIsolation() value * * @param out * the servlet print writer */ private void getTransactionIsolation(HttpServletRequest request, CommonsConfigurator commonsConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws SQLException, IOException { String connectionId = request.getParameter(ConnectionParms.CONNECTION_ID); int transactionIsolation = -1; if (connectionId.equals("0")) { // Server Stateless Mode Connection connection = null; try { connection = commonsConfigurator.getConnection(); transactionIsolation = connection.getTransactionIsolation(); } finally { // Release the connection ConnectionCloser.freeConnection(connection, sqlConfigurator); } } else { String username = request.getParameter(Parameter.USERNAME); ConnectionStore connectionStore = new ConnectionStore(username, connectionId); Connection connection = connectionStore.get(); if (connection == null) { //out.println(TransferStatus.SEND_OK); //out.println(SqlReturnCode.SESSION_INVALIDATED); ServerSqlManager.writeLine(out, TransferStatus.SEND_OK); ServerSqlManager.writeLine(out, SqlReturnCode.SESSION_INVALIDATED); return; } else { transactionIsolation = connection.getTransactionIsolation(); } } debug("transactionIsolation: " + transactionIsolation); //out.println(TransferStatus.SEND_OK); //out.println("" + transactionIsolation); ServerSqlManager.writeLine(out, TransferStatus.SEND_OK); ServerSqlManager.writeLine(out, "" + transactionIsolation); } /** * Calls a commit(), rollback() or close() on a Connection * * @param request * @param commonsConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentException */ private void setCommitRollbackCloseExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, SqlConfigurator sqlConfigurator, OutputStream out, String action) throws IOException, SQLException, IllegalArgumentException { TransactionUtil.setCommitRollbackCloseExecute(request, commonsConfigurator, sqlConfigurator, out, action); } /** * Calls a setAutocommit, setReadOnly(), setHoldbility, * setTransactionIsolation * * @param request * @param commonsConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentException */ private void setAutocommitReadOnlyHoldabilityTransactionInsolationExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, OutputStream out, String action) throws IOException, SQLException, IllegalArgumentException { TransactionUtil.setAutocommitReadOnlyHoldabilityTransactionInsolationExecute(request, commonsConfigurator, out, action); } /** * Calls a getAutocommit(), isReadOnly(), getHoldability( * * @param request * @param commonsConfigurator * @param out * @param action */ private void getAutocommitReadOnlyHoldabilityExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, OutputStream out, String action) throws IOException, SQLException, IllegalArgumentException { TransactionUtil.getAutocommitReadOnlyHoldabilityExecute(request, commonsConfigurator, out, action); } /** * Calls a getAutocommit(), isReadOnly(), getHoldability( * * @param request * @param commonsConfigurator * @param out * @param action */ private void setSavepointExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, OutputStream out, String action) throws IOException, SQLException, IllegalArgumentException { SavepointUtil.setSavepointExecute(request, commonsConfigurator, out, action); } private void connectionInfoExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, OutputStream out, String action) throws IOException, SQLException, IllegalArgumentException { ConnectionInfoUtil.connectionInfoExecute(request, commonsConfigurator, out, action); } /** * Execute a CallableStatement.executeQuery() * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentExceptionn */ private void callableExecuteQuery(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { // Actions that trigger a (Pre)Statement.executeQuery()/executeUppdate() ServerSqlExecutorCallable serverSqlExecutorCallable = new ServerSqlExecutorCallable(request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverSqlExecutorCallable.executeQuery(); } /** * Executes a raw CallableStatement.execute() * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentExceptionn */ private void callableExecute(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { // Actions that trigger a (Pre)Statement.executeQuery()/executeUppdate() ServerSqlExecutorCallable serverSqlExecutorCallable = new ServerSqlExecutorCallable(request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverSqlExecutorCallable.execute(); } /** * Executes a Statement or a PreparedStatement * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentExceptionn */ private void executeStatement(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { // Actions that trigger a (Pre)Statement.executeQuery()/executeUppdate() ServerSqlExecutorNew serverSqlExecutor = new ServerSqlExecutorNew(request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverSqlExecutor.executeQueryOrUpdate(); } /** * Execute a Statement Batch * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentException * @throws SecurityException */ private void executeStatementBatch(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { // Actions that trigger a Statement batch ServerBatchStatementExecutorNew serverBatchStatementExecutor = new ServerBatchStatementExecutorNew(request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverBatchStatementExecutor.execute(); } /** * Execute a PreparedStatement Batch * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out * @throws IOException * @throws SQLException * @throws IllegalArgumentException */ private void executePrepStatementBatch(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { // Actions that trigger a PreparedStatement batch ServerBatchPrepStatementExecutorNew serverBatchPrepStatementExecutor = new ServerBatchPrepStatementExecutorNew( request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverBatchPrepStatementExecutor.execute(); } /** * Execute a DatabaseMetaData call * * @param request * @param commonsConfigurator * @param sqlConfigurator * @param out * @throws Exception */ private void executeGetMetadata(HttpServletRequest request, CommonsConfigurator commonsConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws Exception { // Metadata retrieval DatabaseMetaDataExecutor databaseMetaDataExecutor = new DatabaseMetaDataExecutor(request, out, commonsConfigurator, sqlConfigurator); databaseMetaDataExecutor.execute(); } /** * Execute a raw (Prepared)Statement.execute() * * @param request * @param commonsConfigurator * @param fileConfigurator * @param sqlConfigurator * @param out */ private void executeRaw(HttpServletRequest request, CommonsConfigurator commonsConfigurator, FileConfigurator fileConfigurator, SqlConfigurator sqlConfigurator, OutputStream out) throws IOException, SQLException, IllegalArgumentException { debug("Before ServerSqlExecutorNew.executeRaw()"); ServerSqlExecutorNew serverSqlExecutor = new ServerSqlExecutorNew(request, out, commonsConfigurator, fileConfigurator, sqlConfigurator); serverSqlExecutor.executeRaw(); debug("After ServerSqlExecutorNew.executeRaw()"); } /** * Says if an Action asked by the client is for Awake FILE * * @param action * the action asked by the client side * @return true if the action is for Awake FILE */ private boolean isActionForAwakeFile(String action) { if (action.startsWith(SqlAction.ACTION_SQL)) { return false; } else { return true; } } /** * Method called by children Servlet for debug purpose Println is done only * if class name name is in kawansoft-debug.ini */ public static void debug(String s) { if (DEBUG) { ServerLogger.getLogger().log(Level.WARNING, s); } } }