All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src-main.org.awakefw.sql.api.client.AwakeDriver Maven / Gradle / Ivy

/*
 * Awake File: Easy file upload & download through HTTP with Java
 * Awake SQL: Remote JDBC access through HTTP.                                    
 * Copyright (C) 2012, Kawan Softwares S.A.S.
 * (http://www.awakeframework.org). All rights reserved.                                
 *                                                                               
 * Awake File/SQL 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.            
 *                                                                               
 * Awake File/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 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.
 */

// 18/11/11 11:20 NDP : Driver: Create a java.sql.Driver implementation
// 18/11/11 22:25 NDP : Driver: Clean properties comments
// 19/11/11 16:05 NDP : Driver: Clean properties texts in Javadoc
// 22/11/11 13:20 NDP : Driver: Clean text
// 02/11/11 17:55 NDP : Driver: allow to pass all HttpProtocolParameters values
// 02/11/11 19:55 NDP : AwakerDriver: new name of Awake SQL Driver & Javadoc clean
// 02/11/11 20:15 NDP : AwakerDriver: clean Javadoc
// 17/02/12 16:30 NDP : AwakerDriver: add Java 7 Connection methods for source code
//		        compatibility in Java 6 & Java 7
// 01/03/12 23:25 NDP : AwakerDriver: add HtmlEncoding Driver property
// 02/03/12 13:50 NDP : AwakeDriver: clean Javadoc
// 03/03/12 13:15 NDP : AwakeDriver: clean Javadoc
// 04/03/12 21:15 NDP : AwakeDriver: clean Javadoc with new HttpProtocolParameters default values
// 11/03/12 14:05 NDP : AwakeDriver: Clean Javadoc

package org.awakefw.sql.api.client;

import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverPropertyInfo;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

import org.apache.commons.lang3.StringUtils;
import org.awakefw.commons.api.client.HttpProtocolParameters;
import org.awakefw.commons.api.client.HttpProxy;
import org.awakefw.file.api.util.AwakeDebug;
import org.awakefw.file.util.AwakeLogger;
import org.awakefw.file.util.JavaVersionUtil;

/**
 * 
 * The Awake SQL Driver class - Note that The preferred way to connect to a
 * remote database is {@link AwakeConnection}. 
*
* The Driver implementation is provided because it's necessary for usage with * third party programs as SQL client front end (SQuirreL, Netbeans IDE, etc.)
*
* user & password are the only required properties.
*
* Properties: *
    *
  • user: Username to connect to the remote database as.
  • *
  • password: Password to use when authenticating.
  • *
  • httpProxyAddress: Http proxy address to use.
  • *
  • httpProxyPort: Http proxy Port to use.
  • *
  • httpProxyUsername: Http proxy credential username.
  • *
  • httpProxyPassword: Http proxy credential password.
  • *
  • httpProxyWorkstation: For NTLM proxy: the workstation.
  • *
  • httpProxyDomain: For NTLM proxy: the domain.
  • *
  • maxLengthForString: Int for the maximum authorized length for a * string for upload or download Should be <= 2097152 (2Mb). Defaults to * 2097152.
  • *
  • uploadBufferSize: Int for the buffer size when uploading a * Blob/Clob. Defaults to 20480 (20 Kb).
  • *
  • downloadBufferSize: Int for the buffer size when downloading a * Blob/Clob. Defaults to 20480 (20 Kb).
  • *
  • encryptionPassword: The password to use to encrypt all request * parameter names and values. Defaults to null.
  • *
  • htmlEncodingOn: Boolean to say if the upload/download of Clob * using character stream or ASCII stream must be html encoded. *
* * You may also pass any Jakarta HttpClient parameter as with * {@link HttpProtocolParameters}:
*
*
    *
  • The name of the HttpClient parameter must be in the format: * 'http-client-<name>'.
  • *
  • The value of HttpClient parameter: *
      *
    • The String value for String parameters
    • *
    • The String: * '[value.getClass().ClassName(), value.toString()]' for * parameters of other Java type.
    • *
    *
  • *
* * Examples:
*
*
    *
  • To pass a 'http.socket.timeout' of 10 seconds, pass the * following property: *
      *
    • property name: 'http-client-http.socket.timeout'.
    • *
    • property value: '[java.lang.Integer, 10000]'.
    • *
    *
  • *
  • To pass a 'http.useragent' of * 'www.acme.org User-Agent', pass the following property: *
      *
    • property name: 'http-client-http.useragent'.
    • *
    • property value: 'www.acme.org User-Agent'.
    • *
    *
  • *
* * @author Nicolas de Pomereu * @since 1.0 * */ public class AwakeDriver implements java.sql.Driver { /** The debug flag */ private static boolean DEBUG = AwakeDebug.isSet(AwakeDriver.class); /** * Constructor. */ public AwakeDriver() { JavaVersionUtil.testJavaIsAtLeastJava6OrThrowException(); } /** * Attempts to make a database connection to the given URL. * * The Awake driver will return "null" if it realizes it is the wrong kind * of driver to connect to the given URL. {@link #acceptsURL} will return * null. * *

* The Awake driver will throwSQLException if it is the right * driver to connect to the given URL but has trouble connecting to the * database. * *

* The java.util.Properties argument can be used to pass * arbitrary string tag/value pairs as connection arguments. At least "user" * and "password" properties should be included in the * Properties object. * * @param url * the URL of the database to which to connect * @param info * a list of arbitrary string tag/value pairs as connection * arguments. At least a "user" and "password" property should be * included. * @return a Connection object that represents a connection to * the URL * @exception SQLException * if a database access error occurs */ @Override public Connection connect(String url, Properties info) throws SQLException { if (url == null) { throw new SQLException("url not set. Please provide an url."); } if (!acceptsURL(url)) { return null; } String username = info.getProperty("user"); String password = info.getProperty("password"); if (username == null) { throw new SQLException("user not set. Please provide a user."); } if (password == null) { throw new SQLException( "password not set. Please provide a password."); } // Add proxy lookup String httpProxyAddress = info.getProperty("httpProxyAddress"); String httpProxyPort = info.getProperty("httpProxyPort"); String httpProxyUsername = info.getProperty("httpProxyUsername"); String httpProxyPassword = info.getProperty("httpProxyPassword"); String httpProxyWorkstation = info.getProperty("httpProxyWorkstation"); String httpProxyDomain = info.getProperty("httpProxyDomain"); int port = -1; HttpProxy httpProxy = null; if (httpProxyAddress != null) { try { port = Integer.parseInt(httpProxyPort); } catch (NumberFormatException e) { throw new SQLException( "Invalid HttpProxy port. Port is not numeric: " + httpProxyPort); } if (httpProxyWorkstation != null) { httpProxy = new HttpProxy(httpProxyAddress, port, httpProxyUsername, httpProxyPassword, httpProxyWorkstation, httpProxyDomain); } else { httpProxy = new HttpProxy(httpProxyAddress, port, httpProxyUsername, httpProxyPassword); } } HttpProtocolParameters httpProtocolParameters = getHttpProtocolParameters(info); debug(httpProtocolParameters.toString()); Connection connection = new AwakeConnection(url, username, password.toCharArray(), httpProxy, httpProtocolParameters); return connection; } /** * Returns the HttpProtocolParameters from the passed Properties * * @param info * the properties * @return HttpProtocolParameters from the passed Properties */ private HttpProtocolParameters getHttpProtocolParameters(Properties info) throws SQLException { HttpProtocolParameters httpProtocolParameters = new HttpProtocolParameters(); String maxLengthForString = info.getProperty("maxLengthForString"); String uploadBufferSize = info.getProperty("uploadBufferSize"); String downloadBufferSize = info.getProperty("downloadBufferSize"); String encryptionPassword = info.getProperty("encryptionPassword"); String htmlEncoding = info.getProperty("htmlEncoding"); // debug(""); // debug("maxLengthForString: " + maxLengthForString); // debug("uploadBufferSize : " + uploadBufferSize); // debug("downloadBufferSize: " + downloadBufferSize); // debug("encryptionPassword: " + encryptionPassword); if (maxLengthForString != null) { int maxLengthForStringInteger; try { maxLengthForStringInteger = Integer .parseInt(maxLengthForString); httpProtocolParameters .setMaxLengthForString(maxLengthForStringInteger); } catch (NumberFormatException e) { throw new SQLException( "Invalid maxLengthForString. Not numeric: " + maxLengthForString); } } if (uploadBufferSize != null) { int uploadBufferSizeInteger; try { uploadBufferSizeInteger = Integer.parseInt(uploadBufferSize); httpProtocolParameters .setUploadBufferSize(uploadBufferSizeInteger); } catch (NumberFormatException e) { throw new SQLException( "Invalid uploadBufferSize. Not numeric: " + uploadBufferSize); } } if (downloadBufferSize != null) { int downloadBufferSizeInteger; try { downloadBufferSizeInteger = Integer .parseInt(downloadBufferSize); httpProtocolParameters .setDownloadBufferSize(downloadBufferSizeInteger); } catch (NumberFormatException e) { throw new SQLException( "Invalid downloadBufferSize. Not numeric: " + downloadBufferSize); } } if (encryptionPassword != null) { httpProtocolParameters.setEncryptionPassword(encryptionPassword .toCharArray()); } if (htmlEncoding != null) { httpProtocolParameters.setHtmlEncodingOn(Boolean .parseBoolean(htmlEncoding)); } // Set now the HttpClient parameters setHttpClientParameters(info, httpProtocolParameters); return httpProtocolParameters; } /** * Sets the HttpClient parameters on httpProtocolParameters * * @param info * the driver info * @param httpProtocolParameters * the HttpProtocolParameters to set * @throws SQLException * if any Exception occurs */ private void setHttpClientParameters(Properties info, HttpProtocolParameters httpProtocolParameters) throws SQLException { Map httpClientMap = new HashMap(); // First step: build the map httpClientParams for (Enumeration e = info.propertyNames(); e.hasMoreElements();) { String prop = (String) e.nextElement(); if (prop.startsWith("http-client-")) { String httpClientParam = StringUtils.substringAfter(prop, "http-client-"); String httpClientValue = info.getProperty(prop); httpClientMap.put(httpClientParam, httpClientValue); } } // Get the HttpClient epured properties Set keys = httpClientMap.keySet(); for (String key : keys) { String value = httpClientMap.get(key); if (value == null) { throw new SQLException( "HttpClient value is null for HttpClient parameter: http-client-" + key); } if (value.startsWith("[") && value.endsWith("]")) { // We must analyse the object type from the string // [value.getClass().getName(), value.toString()] setObjectHttpParameter(httpProtocolParameters, key, value); } else { httpProtocolParameters.setHttpClientParameter(key, value); } } } /** * Sets the HttpClient parameter value as an object value * * @param httpProtocolParameters * the HttpProtocolParameters to set * @param key * the HttpClient parameter name * @param value * the HttpClient parameter value * @throws SQLException * if any Exception occurs */ private void setObjectHttpParameter( HttpProtocolParameters httpProtocolParameters, String key, String value) throws SQLException { // We must analyse the object type from the string // [value.getClass().getName(), value.toString()] if (!value.contains(",")) { throw new IllegalArgumentException( "Invalid format for HttpClient parameter http-client-" + key + ". " + "Value does not contain a comma: " + value); } String originalValue = value; value = StringUtils.substringAfter(value, "["); value = StringUtils.substringBeforeLast(value, "]"); String className = StringUtils.substringBefore(value, ","); String stringValue = StringUtils.substringAfter(value, ","); className = className.trim(); stringValue = stringValue.trim(); Class c = null; try { c = Class.forName(className); } catch (ClassNotFoundException e) { throw new IllegalArgumentException( "Invalid format for HttpClient parameter http-client-" + key + ". " + "Value does not contain a valid Java class name: " + originalValue); } try { Constructor ctor = c.getDeclaredConstructor(String.class); ctor.setAccessible(true); Object objValue = ctor.newInstance(stringValue); httpProtocolParameters.setHttpClientParameter(key, objValue); } catch (Exception e) { throw new IllegalArgumentException( "Invalid format for HttpClient parameter http-client-" + key + ". " + "Java class name is not callable with the value: " + originalValue, e); } } /** * Retrieves whether the driver thinks that it can open a connection to the * given URL. Typically drivers will return true if they * understand the subprotocol specified in the URL and false if * they do not.
*
* Awake driver requires an URL which is an http url in the format:
* {@code http(s):///}
*
* Example:
* {@code http://www.acme.com/AwakeSqlManager} * * @param url * the URL of the database * @return true if this driver understands the given URL; * false otherwise * @exception SQLException * if a database access error occurs */ @Override public boolean acceptsURL(String url) throws SQLException { URL theUrl = null; try { theUrl = new URL(url); } catch (MalformedURLException e) { return false; } String protocol = theUrl.getProtocol(); if (protocol.equals("http") || protocol.equals("https")) { return true; } else { return false; } } /** * Gets information about the possible properties for this driver. *

* The getPropertyInfo method is intended to allow a generic * GUI tool to discover what properties it should prompt a human for in * order to get enough information to connect to a database. Note that * depending on the values the human has supplied so far, additional values * may become necessary, so it may be necessary to iterate though several * calls to the getPropertyInfo method. * * @param url * the URL of the database to which to connect * @param info * a proposed list of tag/value pairs that will be sent on * connect open * @return an array of DriverPropertyInfo objects describing * possible properties. * @exception SQLException * if a database access error occurs */ @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { DriverPropertyInfo[] arrayOfDriverPropertyInfo = new DriverPropertyInfo[13]; if (info != null) { info.remove("RemarksReporting"); } int i = 0; DriverPropertyInfo driverPropertyInfo = null; driverPropertyInfo = new DriverPropertyInfo("user", info.getProperty("user")); driverPropertyInfo.description = "Username to connect to the remote database as"; driverPropertyInfo.required = true; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("password", null); driverPropertyInfo.description = "Password to use when authenticating"; driverPropertyInfo.required = true; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyAddress", info.getProperty("httpProxyAddress")); driverPropertyInfo.description = "Http proxy address to use"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyPort", info.getProperty("httpProxyPort")); driverPropertyInfo.description = "Http proxy Port to use"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyUsername", info.getProperty("httpProxyUsername")); driverPropertyInfo.description = "Http proxy credential username"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyPassword", info.getProperty("httpProxyPassword")); driverPropertyInfo.description = "Http proxy credential password"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyWorkstation", info.getProperty("httpProxyWorkstation")); driverPropertyInfo.description = "For NTLM proxy: the workstation"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("httpProxyDomain", info.getProperty("httpProxyDomain")); driverPropertyInfo.description = "For NTLM proxy: the domain"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; // Size was 8 driverPropertyInfo = new DriverPropertyInfo("maxLengthForString", info.getProperty("maxLengthForString")); driverPropertyInfo.description = "Int for the maximum authorized length for a string for upload or download Should be <= 2097152 (2Mb). Defaults to 2097152."; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("uploadBufferSize", info.getProperty("uploadBufferSize")); driverPropertyInfo.description = "Int for the buffer size when uploading a Blob/Clob. Defaults to 20480 (20 Kb)"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("downloadBufferSize", info.getProperty("downloadBufferSize")); driverPropertyInfo.description = "Int for the buffer size when downloading a Blob/Clob. Defaults to 20480 (20 Kb)"; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("encryptionPassword", info.getProperty("encryptionPassword")); driverPropertyInfo.description = "The password to use to encrypt all request parameter names and values. Defaults to null (no encryption)."; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; driverPropertyInfo = new DriverPropertyInfo("htmlEncoding", info.getProperty("htmlEncoding")); driverPropertyInfo.description = "Boolean that says if the upload/download of Clob using character stream or ASCII stream must be html encoded. Defaults to true."; driverPropertyInfo.required = false; arrayOfDriverPropertyInfo[i++] = driverPropertyInfo; return arrayOfDriverPropertyInfo; } /** * Retrieves this driver's major version number. * * @return this driver's major version number */ @Override public int getMajorVersion() { return 1; } /** * Gets the driver's minor version number. * * @return this driver's minor version number */ @Override public int getMinorVersion() { return 0; } /** * Reports whether this driver is a genuine JDBC CompliantTM driver. A driver may only report * true here if it passes the JDBC compliance tests; otherwise * it is required to return false. *

* JDBC compliance requires full support for the JDBC API and full support * for SQL 92 Entry Level. *

* Because Awake driver is not a a genuine JDBC CompliantTM driver, method returns false * * @return false */ @Override public boolean jdbcCompliant() { return false; } /** * debug tool */ private static void debug(String s) { if (DEBUG) { AwakeLogger.log(s); } } // ///////////////////////////////////////////////////////// // JAVA 7 METHOD EMULATION // // ///////////////////////////////////////////////////////// /** * Return the parent Logger of all the Loggers used by this driver. This * should be the Logger farthest from the root Logger that is still an * ancestor of all of the Loggers used by this driver. Configuring this * Logger will affect all of the log messages generated by the driver. In * the worst case, this may be the root Logger. * * @return the parent Logger for this driver * @throws SQLFeatureNotSupportedException * if the driver does not use java.util.logging. * @since 1.7 */ // @Override do not not override for Java 6 compatibility public Logger getParentLogger() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy