src-main.org.awakefw.sql.servlet.DatabaseMetaDataExecutor Maven / Gradle / Ivy
/*
* This file is part of Awake SQL.
* Awake SQL: Remote JDBC access over HTTP.
* Copyright (C) 2013, KawanSoft SAS
* (http://www.kawansoft.com). All rights reserved.
*
* Awake SQL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Awake SQL 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 General Public License
* along with this program; if not, see .
*
* If you develop commercial activities using Awake SQL, you must:
* a) disclose and distribute all source code of your own product,
* b) license your own product under the GNU General Public License.
*
* You can be released from the requirements of the license by
* purchasing a commercial license. Buying such a license will allow you
* to ship Awake SQL with your closed source products without disclosing
* the source code.
*
* For more information, please contact KawanSoft SAS at this
* address: [email protected]
*
* Any modifications to this file must keep this entire header
* intact.
*/
package org.awakefw.sql.servlet;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.awakefw.commons.api.server.AwakeCommonsConfigurator;
import org.awakefw.file.api.util.AwakeDebug;
import org.awakefw.file.api.util.HtmlConverter;
import org.awakefw.file.json.ListOfStringTransport;
import org.awakefw.file.util.AwakeClientLogger;
import org.awakefw.file.util.JavaValueBuilder;
import org.awakefw.file.util.Tag;
import org.awakefw.file.util.TransferStatus;
import org.awakefw.file.util.parms.Parameter;
import org.awakefw.sql.api.server.AwakeSqlConfigurator;
import org.awakefw.sql.json.no_obfuscation.DatabaseMetaDataHolder;
import org.awakefw.sql.json.no_obfuscation.DatabaseMetaDataHolderTransport;
import org.awakefw.sql.servlet.connection.ConnectionStore;
import org.awakefw.sql.servlet.sql.ResultSetMetaDataWriter;
import org.awakefw.sql.servlet.sql.ResultSetWriter;
import org.awakefw.sql.servlet.sql.ServerStatement;
import org.awakefw.sql.util.ConnectionParms;
import org.awakefw.sql.util.SqlReturnCode;
/**
* Execute MetaData requests.
*
* @author Nicolas de Pomereu
*
*/
public class DatabaseMetaDataExecutor {
private static boolean DEBUG = AwakeDebug
.isSet(DatabaseMetaDataExecutor.class);
public static String CR_LF = System.getProperty("line.separator");
private HttpServletRequest request = null;
private PrintWriter out = null;
private AwakeCommonsConfigurator awakeCommonsConfigurator = null;
private AwakeSqlConfigurator awakeSqlConfigurator = null;
/**
* Constructor
*
* @param request
* the servlet http request
* @param out
* the servlet output stream
* @param awakeCommonsConfigurator
* the Awake Commons Configurator
* @param awakeSqlConfigurator
* the Awake SQL Configurator
*/
public DatabaseMetaDataExecutor(HttpServletRequest request,
PrintWriter out, AwakeCommonsConfigurator awakeCommonsConfigurator,
AwakeSqlConfigurator awakeSqlConfigurator)
{
this.request = request;
this.out = out;
this.awakeCommonsConfigurator = awakeCommonsConfigurator;
this.awakeSqlConfigurator = awakeSqlConfigurator;
}
/**
* Execute the MetaData request
*/
public void execute() throws Exception {
// String action = request.getParameter(SqlAction.ACTION) ;
String username = request.getParameter(Parameter.USERNAME);
String methodName = request.getParameter(Parameter.METHOD_NAME);
String connectionId = request
.getParameter(ConnectionParms.CONNECTION_ID);
// methodName = HtmlConverter.fromHtml(methodName);
debug("Parameter.METHOD_NAME: " + methodName);
Connection connection = null;
if (connectionId.equals("0")) {
try {
connection = awakeCommonsConfigurator.getConnection();
boolean isAllowed = AwakeSqlConfiguratorCall.allowGetMetaData(
awakeSqlConfigurator, username, connection);
if (!isAllowed) {
String message = Tag.AWAKE_SECURITY
+ "Database Catalog Query not authorized.";
throw new SecurityException(message);
}
DatabaseMetaData databaseMetaData = connection.getMetaData();
// If methodName is getMetaData ==> just return the
// DatabaseMetaData
if (methodName.equals("getMetaData")) {
DatabaseMetaDataHolder databaseMetaDataHolder = new DatabaseMetaDataHolder();
databaseMetaDataHolder
.setDatabaseMetaDataHolder(databaseMetaData);
String jsonString = DatabaseMetaDataHolderTransport
.toJson(databaseMetaDataHolder);
jsonString = HtmlConverter.toHtml(jsonString);
out.println(TransferStatus.SEND_OK);
out.println(jsonString);
return;
} else if (methodName.equals("getCatalog")) {
String catalog = connection.getCatalog();
catalog = HtmlConverter.toHtml(catalog);
out.println(TransferStatus.SEND_OK);
out.println(catalog);
} else {
// Call the DatabaseMetaData.method with reflection:
callMetaDataFunction(request, out, connection);
}
} finally {
// Release the connection
ConnectionCloser.freeConnection(connection,
awakeSqlConfigurator);
}
} else {
ConnectionStore connectionStore = new ConnectionStore(username,
connectionId);
connection = connectionStore.get();
if (connection == null) {
out.println(TransferStatus.SEND_OK);
out.println(SqlReturnCode.SESSION_INVALIDATED);
return;
}
boolean isAllowed = AwakeSqlConfiguratorCall.allowGetMetaData(
awakeSqlConfigurator, username, connection);
if (!isAllowed) {
String message = Tag.AWAKE_SECURITY
+ "Database Catalog Query not authorized.";
throw new SecurityException(message);
}
DatabaseMetaData databaseMetaData = connection.getMetaData();
// If methodName is getMetaData ==> just return the
// DatabaseMetaData
if (methodName.equals("getMetaData")) {
DatabaseMetaDataHolder databaseMetaDataHolder = new DatabaseMetaDataHolder();
databaseMetaDataHolder
.setDatabaseMetaDataHolder(databaseMetaData);
String jsonString = DatabaseMetaDataHolderTransport
.toJson(databaseMetaDataHolder);
jsonString = HtmlConverter.toHtml(jsonString);
out.println(TransferStatus.SEND_OK);
out.println(jsonString);
return;
} else if (methodName.equals("getCatalog")) {
String catalog = connection.getCatalog();
catalog = HtmlConverter.toHtml(catalog);
out.println(TransferStatus.SEND_OK);
out.println(catalog);
} else {
// Call the DatabaseMetaData.method with reflection:
callMetaDataFunction(request, out, connection);
}
}
// Of, if the list is not empty, dump it to out on servlet out stream
// dumpFilesOnServletOutStream(tempFilesForResultSet);
}
/**
*
* Calls a remote method from the PC
* Please note that all invocation are trapped and routed as code string to
* the PC.
*
* @param request
* the http request
* @param awakeCommonsConfigurator
* the commons configurator defined by the user
* @param awakeFileConfigurator
* the file configurator defined by the user
* @param out
* the servlet output stream
* @param username
* the client login (for security check)
*
*
* @throws IOException
* all Awake, network, etc. errors
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws NoSuchMethodException
* @throws SecurityException
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
private void callMetaDataFunction(HttpServletRequest request,
PrintWriter out, Connection connection) throws SQLException,
IOException, ClassNotFoundException, InstantiationException,
IllegalAccessException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException
{
// The method name
String methodName = request.getParameter(Parameter.METHOD_NAME);
// methodName = HtmlConverter.fromHtml(methodName);
// The parms name
String paramsTypes = request.getParameter(Parameter.PARAMS_TYPES);
String paramsValues = request.getParameter(Parameter.PARAMS_VALUES);
// Make sure all values are not null and trimed
methodName = this.getTrimValue(methodName);
paramsTypes = this.getTrimValue(paramsTypes);
paramsValues = this.getTrimValue(paramsValues);
debug("actionInvokeRemoteMethod:methodName : " + methodName);
// paramsTypes = HtmlConverter.fromHtml(paramsTypes);
// paramsValues = HtmlConverter.fromHtml(paramsValues);
List listParamsTypes = ListOfStringTransport
.fromJson(paramsTypes);
List listParamsValues = ListOfStringTransport
.fromJson(paramsValues);
debug("actionInvokeRemoteMethod:listParamsTypes : "
+ listParamsTypes);
debug("actionInvokeRemoteMethod:listParamsValues : "
+ listParamsValues);
DatabaseMetaData databaseMetaData = connection.getMetaData();
// Trap DatabaseMetaData.getTables() & DatabaseMetaData.getUDTs()
// that have special array String[] or int[] parameters
if (methodName.equals("getTables") || methodName.equals("getUDTs")
|| methodName.equals("getPrimaryKeys")) {
DatabaseMetaDataSpecial databaseMetaDataSpecial = new DatabaseMetaDataSpecial(
databaseMetaData, methodName, listParamsValues);
ResultSet rs = databaseMetaDataSpecial.execute();
dumpResultSetOnServletOutStream(rs);
return;
}
@SuppressWarnings("rawtypes")
Class[] argTypes = new Class[listParamsTypes.size()];
Object[] values = new Object[listParamsValues.size()];
for (int i = 0; i < listParamsTypes.size(); i++) {
String value = listParamsValues.get(i);
String javaType = listParamsTypes.get(i);
JavaValueBuilder javaValueBuilder = new JavaValueBuilder(javaType,
value);
argTypes[i] = javaValueBuilder.getClassOfValue();
values[i] = javaValueBuilder.getValue();
// Trap NULL values
if (values[i].equals("NULL")) {
values[i] = null;
}
debug("argTypes[i]: " + argTypes[i]);
debug("values[i] : " + values[i]);
}
Class> c = Class.forName("java.sql.DatabaseMetaData");
Object theObject = databaseMetaData;
// Invoke the method
Method main = null;
Object resultObj = null;
// Get the Drvier Info
String database = "";
String productVersion = "";
String DriverName = "";
String DriverVersion = "";
String driverInfo = Tag.AWAKE;
// try {
// database = databaseMetaData.getDatabaseProductName();
// productVersion = databaseMetaData.getDatabaseProductVersion();
// DriverName = databaseMetaData.getDriverName();
// DriverVersion= databaseMetaData.getDriverVersion();
// driverInfo += database + " " + productVersion + " " + DriverName +
// " " + DriverVersion;
// } catch (Exception e1) {
// AwakeLogger.log(Tag.AWAKE + "Impossible to get User Driver info.");
// }
database = databaseMetaData.getDatabaseProductName();
productVersion = databaseMetaData.getDatabaseProductVersion();
DriverName = databaseMetaData.getDriverName();
DriverVersion = databaseMetaData.getDriverVersion();
driverInfo += database + " " + productVersion + " " + DriverName + " "
+ DriverVersion;
String methodParams = getMethodParams(values);
try {
main = c.getDeclaredMethod(methodName, argTypes);
} catch (SecurityException e) {
throw new SecurityException(
driverInfo
+ " - Security - Impossible to get declared DatabaseMetaData."
+ methodName + "(" + methodParams + ")");
} catch (NoSuchMethodException e) {
throw new NoSuchMethodException(
driverInfo
+ " - No Such Method - Impossible get declared DatabaseMetaData."
+ methodName + "(" + methodParams + ")");
}
try {
resultObj = main.invoke(theObject, values);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(driverInfo
+ " - Impossible to call DatabaseMetaData." + methodName
+ "(" + methodParams + ")");
} catch (IllegalAccessException e) {
throw new IllegalAccessException(driverInfo
+ " - Impossible to access DatabaseMetaData method."
+ methodName + "(" + methodParams + ")");
} catch (InvocationTargetException e) {
throw new InvocationTargetException(e, driverInfo
+ " - Impossible to invoke DatabaseMetaData method."
+ methodName + "(" + methodParams + ")");
}
if (resultObj instanceof ResultSet) {
ResultSet rs = (ResultSet) resultObj;
dumpResultSetOnServletOutStream(rs);
} else {
// All other formats are handled in String
String result = null;
if (resultObj != null)
result = resultObj.toString();
debug("actionInvokeRemoteMethod:result: " + result);
result = HtmlConverter.toHtml(result);
out.println(TransferStatus.SEND_OK);
out.println(result);
}
}
/**
* Returns the method parameters as (value1, value2, ...)
*
* @param values
* the value array
* @return the method parameters as (value1, value2, ...)
*/
private String getMethodParams(Object[] values) {
if (values.length == 0) {
return "";
}
String returnValue = "(";
for (int i = 0; i < values.length; i++) {
returnValue += values[i];
if (i < values.length - 1) {
returnValue += ", ";
}
}
returnValue += ")";
return returnValue;
}
/**
* Dump the result set, releasing it as soon as possible, on the output
* stream
*
* @param rs
* the resut set to dump
*
* @throws SQLException
* @throws IOException
* @throws SecurityException
*/
public void dumpResultSetOnServletOutStream(ResultSet rs)
throws SQLException, IOException {
BufferedWriter br = null;
File tempFileForResultSet = null;
try {
tempFileForResultSet = ServerStatement.createTempFileForResultSet();
br = new BufferedWriter(new FileWriter(tempFileForResultSet));
br.write(TransferStatus.SEND_OK + CR_LF);
ResultSetMetaData meta = rs.getMetaData();
ResultSetWriter resultSetWriter = new ResultSetWriter(request,
br, awakeCommonsConfigurator, null,
awakeSqlConfigurator, "ResultSetMetaData", "ResultSetMetaData", null);
resultSetWriter.write(rs);
// Write the separator between ResultSet & ResultSet.getMetaData()
br.write("ResultSet.getMetaData()" + CR_LF);
// Write also the associated ResultSet.getMetaData();
ResultSetMetaDataWriter resultSetMetaDataWriter = new ResultSetMetaDataWriter(
br, null, awakeCommonsConfigurator, awakeSqlConfigurator);
resultSetMetaDataWriter.write(meta);
IOUtils.closeQuietly(br);
dumpFileOnServletOutStream(tempFileForResultSet);
} finally {
if (rs != null) {
rs.close();
}
IOUtils.closeQuietly(br);
tempFileForResultSet.delete();
}
}
/**
* return a "" empty string if null or a trimed stgring if not null
*
* @param action
* the input string
* @return the empty stgring or trimed string
*/
private String getTrimValue(String string) {
if (string == null) {
return "";
} else {
return string.trim();
}
}
/**
* Dump the file with the result set on the servlet output stream
*
* @param tempFilesForResultSet
* @throws FileNotFoundException
* @throws IOException
*/
private void dumpFileOnServletOutStream(File tempFileForResultSet)
throws FileNotFoundException, IOException {
BufferedReader br = new BufferedReader(new FileReader(
tempFileForResultSet));
try {
IOUtils.copy(br, out);
} finally {
IOUtils.closeQuietly(br);
}
}
/**
* Method called by children Servlest for debug purpose Println is done only
* if class name name is in awake-debug.ini
*/
public static void debug(String s) {
if (DEBUG) {
AwakeClientLogger.log(s);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy