/*
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
* Free Software Foundation.
*
* This program is also distributed with certain software (including but not
* limited to OpenSSL) that is licensed under separate terms, as designated in a
* particular file or component or in included license documentation. The
* authors of MySQL hereby grant you an additional permission to link the
* program and your derivative works with the separately licensed software that
* they have included with MySQL.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* This program 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 General Public License, version 2.0,
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.mysql.cj.jdbc;
import java.io.
PrintWriter;
import java.io.
Serializable;
import java.sql.
SQLException;
import java.sql.
SQLFeatureNotSupportedException;
import java.util.
Properties;
import java.util.logging.
Logger;
import javax.naming.
NamingException;
import javax.naming.
Reference;
import javax.naming.
Referenceable;
import javax.naming.
StringRefAddr;
import javax.sql.
DataSource;
import com.mysql.cj.
Messages;
import com.mysql.cj.conf.
AbstractRuntimeProperty;
import com.mysql.cj.conf.
ConnectionUrl;
import com.mysql.cj.conf.
PropertyDefinitions;
import com.mysql.cj.conf.
PropertyKey;
import com.mysql.cj.conf.
RuntimeProperty;
/**
* A JNDI DataSource for a Mysql JDBC connection
*/
public class
MysqlDataSource extends
JdbcPropertySetImpl implements
DataSource,
Referenceable,
Serializable,
JdbcPropertySet {
static final long
serialVersionUID = -5515846944416881264L;
/** The driver to create connections with */
protected final static
NonRegisteringDriver mysqlDriver;
static {
try {
mysqlDriver = new
NonRegisteringDriver();
} catch (
Exception E) {
throw new
RuntimeException(
Messages.
getString("MysqlDataSource.0"));
}
}
/** Log stream */
protected transient
PrintWriter logWriter = null;
/** Database Name */
protected
String databaseName = null;
/** Character Encoding */
protected
String encoding = null;
/** Hostname */
protected
String hostName = null;
/** Password */
protected
String password = null;
/** The profileSQL property */
protected
String profileSQLString = "false";
/** The JDBC URL */
protected
String url = null;
/** User name */
protected
String user = null;
/** Should we construct the URL, or has it been set explicitly */
protected boolean
explicitUrl = false;
/** Port number */
protected int
port = 3306;
protected
String description = "MySQL Connector/J Data Source";
/**
* Default no-arg constructor for Serialization
*/
public
MysqlDataSource() {
}
@
Override
public java.sql.
Connection getConnection() throws
SQLException {
return
getConnection(this.
user, this.
password);
}
@
Override
public java.sql.
Connection getConnection(
String userID,
String pass) throws
SQLException {
Properties props =
exposeAsProperties();
if (
userID != null) {
props.
setProperty(
PropertyKey.
USER.
getKeyName(),
userID);
}
if (
pass != null) {
props.
setProperty(
PropertyKey.
PASSWORD.
getKeyName(),
pass);
}
return
getConnection(
props);
}
public
String getDescription() {
return this.
description;
}
public void
setDescription(
String value) {
this.
description =
value;
}
/**
* Sets the database name.
*
* @param dbName
* the name of the database
*/
public void
setDatabaseName(
String dbName) {
this.
databaseName =
dbName;
}
/**
* Gets the name of the database
*
* @return the name of the database for this data source
*/
public
String getDatabaseName() {
return (this.
databaseName != null) ? this.
databaseName : "";
}
@
Override
public void
setLogWriter(
PrintWriter output) throws
SQLException {
this.
logWriter =
output;
}
@
Override
public java.io.
PrintWriter getLogWriter() {
return this.
logWriter;
}
@
Override
public void
setLoginTimeout(int
seconds) throws
SQLException {
// TODO
}
@
Override
public int
getLoginTimeout() {
return 0;
}
/**
* Sets the password
*
* @param pass
* the password
*/
public void
setPassword(
String pass) {
this.
password =
pass;
}
/**
* Get the password.
*
* @return password
*/
public
String getPassword() {
return this.
password;
}
/**
* Sets the database port.
*
* @param p
* the port
*/
public void
setPort(int
p) {
this.
port =
p;
}
/**
* Returns the port number
*
* @return the port number
*/
public int
getPort() {
return this.
port;
}
/**
* Sets the port number
*
* @param p
* the port
*/
public void
setPortNumber(int
p) {
setPort(
p);
}
/**
* Returns the port number
*
* @return the port number
*/
public int
getPortNumber() {
return
getPort();
}
/**
* Initializes driver properties that come from a JNDI reference (in the
* case of a javax.sql.DataSource bound into some name service that doesn't
* handle Java objects directly).
*
* @param ref
* The JNDI Reference that holds RefAddrs for all properties
* @throws SQLException
* if error occurs
*/
public void
setPropertiesViaRef(
Reference ref) throws
SQLException {
for (
PropertyKey propKey :
PropertyDefinitions.
PROPERTY_KEY_TO_PROPERTY_DEFINITION.
keySet()) {
RuntimeProperty<?>
propToSet =
getProperty(
propKey);
if (
ref != null) {
propToSet.
initializeFrom(
ref, null);
}
}
postInitialization();
}
/**
* Required method to support this class as a <CODE>Referenceable</CODE>.
*
* @return a Reference to this data source
*
* @throws NamingException
* if a JNDI error occurs
*/
@
Override
public
Reference getReference() throws
NamingException {
String factoryName =
MysqlDataSourceFactory.class.
getName();
Reference ref = new
Reference(
getClass().
getName(),
factoryName, null);
ref.
add(new
StringRefAddr(
PropertyKey.
USER.
getKeyName(),
getUser()));
ref.
add(new
StringRefAddr(
PropertyKey.
PASSWORD.
getKeyName(), this.
password));
ref.
add(new
StringRefAddr("serverName",
getServerName()));
ref.
add(new
StringRefAddr("port", "" +
getPort()));
ref.
add(new
StringRefAddr("databaseName",
getDatabaseName()));
ref.
add(new
StringRefAddr("url",
getUrl()));
ref.
add(new
StringRefAddr("explicitUrl",
String.
valueOf(this.
explicitUrl)));
//
// Now store all of the 'non-standard' properties...
//
for (
PropertyKey propKey :
PropertyDefinitions.
PROPERTY_KEY_TO_PROPERTY_DEFINITION.
keySet()) {
RuntimeProperty<?>
propToStore =
getProperty(
propKey);
String val =
propToStore.
getStringValue();
if (
val != null) {
ref.
add(new
StringRefAddr(
propToStore.
getPropertyDefinition().
getName(),
val));
}
}
return
ref;
}
/**
* Sets the server name.
*
* @param serverName
* the server name
*/
public void
setServerName(
String serverName) {
this.
hostName =
serverName;
}
/**
* Returns the name of the database server
*
* @return the name of the database server
*/
public
String getServerName() {
return (this.
hostName != null) ? this.
hostName : "";
}
//
// I've seen application servers use both formats, URL or url (doh)
//
/**
* Sets the URL for this connection
*
* @param url
* the URL for this connection
*/
public void
setURL(
String url) {
setUrl(
url);
}
/**
* Returns the URL for this connection
*
* @return the URL for this connection
*/
public
String getURL() {
return
getUrl();
}
/**
* This method is used by the app server to set the url string specified
* within the datasource deployment descriptor. It is discovered using
* introspection and matches if property name in descriptor is "url".
*
* @param url
* url to be used within driver.connect
*/
public void
setUrl(
String url) {
this.
url =
url;
this.
explicitUrl = true;
}
/**
* Returns the JDBC URL that will be used to create the database connection.
*
* @return the URL for this connection
*/
public
String getUrl() {
if (!this.
explicitUrl) {
StringBuilder sbUrl = new
StringBuilder(
ConnectionUrl.
Type.
SINGLE_CONNECTION.
getScheme());
sbUrl.
append("//").
append(
getServerName()).
append(":").
append(
getPort()).
append("/").
append(
getDatabaseName());
return
sbUrl.
toString();
}
return this.
url;
}
/**
* Sets the user ID.
*
* @param userID
* the User ID
*/
public void
setUser(
String userID) {
this.
user =
userID;
}
/**
* Returns the configured user for this connection
*
* @return the user for this connection
*/
public
String getUser() {
return this.
user;
}
/**
* Creates a connection using the specified properties.
*
* @param props
* the properties to connect with
*
* @return a connection to the database
*
* @throws SQLException
* if an error occurs
*/
protected java.sql.
Connection getConnection(
Properties props) throws
SQLException {
String jdbcUrlToUse = this.
explicitUrl ? this.
url :
getUrl();
//
// URL should take precedence over properties
//
ConnectionUrl connUrl =
ConnectionUrl.
getConnectionUrlInstance(
jdbcUrlToUse, null);
Properties urlProps =
connUrl.
getConnectionArgumentsAsProperties();
urlProps.
remove(
PropertyKey.
HOST.
getKeyName());
urlProps.
remove(
PropertyKey.
PORT.
getKeyName());
urlProps.
remove(
PropertyKey.
DBNAME.
getKeyName());
urlProps.
stringPropertyNames().
stream().
forEach(
k ->
props.
setProperty(
k,
urlProps.
getProperty(
k)));
return
mysqlDriver.
connect(
jdbcUrlToUse,
props);
}
@
Override
public
Logger getParentLogger() throws
SQLFeatureNotSupportedException {
return null;
}
@
Override
public <T> T
unwrap(
Class<T>
iface) throws
SQLException {
return null;
}
@
Override
public boolean
isWrapperFor(
Class<?>
iface) throws
SQLException {
return false;
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected
String getStringRuntimeProperty(
String name) throws
SQLException {
return
getStringProperty(
name).
getValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setStringRuntimeProperty(
String name,
String value) throws
SQLException {
((
AbstractRuntimeProperty<
String>)
getStringProperty(
name)).
setValueInternal(
value, null, null);
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected boolean
getBooleanRuntimeProperty(
String name) throws
SQLException {
return
getBooleanProperty(
name).
getValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setBooleanRuntimeProperty(
String name, boolean
value) throws
SQLException {
((
AbstractRuntimeProperty<
Boolean>)
getBooleanProperty(
name)).
setValueInternal(
value, null, null);
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected int
getIntegerRuntimeProperty(
String name) throws
SQLException {
return
getIntegerProperty(
name).
getValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setIntegerRuntimeProperty(
String name, int
value) throws
SQLException {
((
AbstractRuntimeProperty<
Integer>)
getIntegerProperty(
name)).
setValueInternal(
value, null, null);
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected long
getLongRuntimeProperty(
String name) throws
SQLException {
return
getLongProperty(
name).
getValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setLongRuntimeProperty(
String name, long
value) throws
SQLException {
((
AbstractRuntimeProperty<
Long>)
getLongProperty(
name)).
setValueInternal(
value, null, null);
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected int
getMemorySizeRuntimeProperty(
String name) throws
SQLException {
return
getMemorySizeProperty(
name).
getValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setMemorySizeRuntimeProperty(
String name, int
value) throws
SQLException {
((
AbstractRuntimeProperty<
Integer>)
getMemorySizeProperty(
name)).
setValueInternal(
value, null, null);
}
/**
* Used in properties getters added by instrumentation.
*
* @param name
* property name
* @return property value
* @throws SQLException
* if error occurs
*/
protected
String getEnumRuntimeProperty(
String name) throws
SQLException {
return
getEnumProperty(
name).
getStringValue();
}
/**
* Used in properties setters added by instrumentation.
*
* @param name
* property name
* @param value
* value
* @throws SQLException
* if error occurs
*/
protected void
setEnumRuntimeProperty(
String name,
String value) throws
SQLException {
((
AbstractRuntimeProperty<?>)
getEnumProperty(
name)).
setValueInternal(
value, null);
}
@
Override
public
Properties exposeAsProperties() {
Properties props = new
Properties();
for (
PropertyKey propKey :
PropertyDefinitions.
PROPERTY_KEY_TO_PROPERTY_DEFINITION.
keySet()) {
RuntimeProperty<?>
propToGet =
getProperty(
propKey);
String propValue =
propToGet.
getStringValue();
if (
propValue != null &&
propToGet.
isExplicitlySet()) {
props.
setProperty(
propToGet.
getPropertyDefinition().
getName(),
propValue);
}
}
return
props;
}
}