/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.esri.gpt.framework.sql;
import com.esri.gpt.framework.collection.StringSet;
import com.esri.gpt.framework.util.LogUtil;
import com.esri.gpt.framework.util.Val;
import java.util.logging.Level;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
/**
* Configuration reference for a database.
* <p>
* The reference usually represents a JNDI based connection.
* It can also represent a direct connection (driver/url/user/pwd), but this
* is usually limited to a non-production environment.
*/
public final class DatabaseReference {
// class variables =============================================================
// instance variables ==========================================================
private String _directDriver = "";
private String _directPassword = "";
private String _directUrl = "";
private String _directUsername = "";
private boolean _isJndiBased = true;
private DataSource _jndiDataSource = null;
private String _jndiName = "";
private String _refName = "";
private StringSet _tags = new StringSet();
// constructors ================================================================
/** Default constructor. */
public DatabaseReference() {}
// properties ==================================================================
/**
* Gets the driver class name for a direct database reference.
* @return the database driver class name
*/
public String getDirectDriverClassName() {
return _directDriver;
}
/**
* Sets the driver class name for a direct database reference.
* @param driver the database driver class name
*/
public void setDirectDriverClassName(String driver) {
_directDriver = Val.chkStr(driver);
}
/**
* Gets the password for a direct database reference.
* @return the password
*/
public String getDirectPassword() {
return _directPassword;
}
/**
* Sets the password for a direct database reference.
* @param password the password
*/
public void setDirectPassword(String password) {
_directPassword = password;
}
/**
* Gets the URL for a direct database reference.
* @return the database url
*/
public String getDirectUrl() {
return _directUrl;
}
/**
* Sets the URL for a direct database reference.
* @param url the database url
*/
public void setDirectUrl(String url) {
_directUrl = Val.chkStr(url);
}
/**
* Gets the username for a direct database reference.
* @return the username
*/
public String getDirectUsername() {
return _directUsername;
}
/**
* Sets the username for a direct database reference.
* @param username the username
*/
public void setDirectUsername(String username) {
_directUsername = Val.chkStr(username);
}
/**
* Gets the JNDI based reference status.
* @return <b>true</b> if this reference is JNDI based
*/
public boolean getIsJndiBased() {
return _isJndiBased;
}
/**
* Sets the JNDI based reference status.
* @param isJndiBased <b>true</b> if this reference is JNDI based
*/
public void setIsJndiBased(boolean isJndiBased) {
_isJndiBased = isJndiBased;
}
/**
* Gets the JNDI based DataSource for the reference.
* @return the data source
* @throws NamingException if a JNDI naming exception occurs
*/
protected DataSource getJndiDataSource()
throws NamingException {
if (_jndiDataSource == null) {
_jndiDataSource = openJndiDataSource(getJndiName());
}
return _jndiDataSource;
}
/**
* Gets the name for a JNDI based database reference.
* @return the JNDI name
*/
public String getJndiName() {
return _jndiName;
}
/**
* Sets the name for a JNDI based database reference.
* @param jndiName the JNDI name
*/
public void setJndiName(String jndiName) {
_jndiName = Val.chkStr(jndiName);
}
/**
* Gets the label for the database reference.
* @return the reference label
*/
protected String getReferenceLabel() {
if (getIsJndiBased()) {
return getReferenceName()+", jndiName: "+getJndiName();
} else {
return getReferenceName()+", url: "+getDirectUrl();
}
}
/**
* Gets the name for the database reference.
* @return the name
*/
public String getReferenceName() {
return _refName;
}
/**
* Sets the name for the database reference.
* @param referenceName the reference name
*/
public void setReferenceName(String referenceName) {
_refName = Val.chkStr(referenceName);
}
/**
* Gets the tags associated with the reference.
* @return the associated tags
*/
public StringSet getTags() {
return _tags;
}
// methods =====================================================================
/**
* Closes a JDBC connection.
* <br/>Executes the close() method against the JDBC connection.
* @param con the connection to close
*/
public void closeConnection(Connection con) {
if (con != null) {
try {
if (!con.isClosed()) {
LogUtil.getLogger().fine("Closing connection for "+getReferenceLabel());
con.close();
}
} catch (Exception e) {
String sMsg = "Unable to close connection for "+getReferenceLabel();
LogUtil.getLogger().log(Level.SEVERE,sMsg,e);
}
}
}
/**
* Makes a JDBC connection from based upon the configuration of the database reference.
* @return the JDBC connection
* @throws ClassNotFoundException if the database driver class was not found
* @throws NamingException if a JNDI naming exception occurs
* @throws SQLException if an SQL exception occurs while establishing the connection
*/
public Connection openConnection()
throws ClassNotFoundException, NamingException, SQLException {
Connection con = null;
String sMsg;
// obtain the connection
sMsg = "Opening connection for "+getReferenceLabel();
LogUtil.getLogger().finer(sMsg);
if (getIsJndiBased()) {
con = openJndiConnection();
} else {
con = openDirectConnection();
}
if (con != null) {
con.setAutoCommit(true);
}
// log information about the connection obtained
try {
//System.err.println(con.getMetaData().getDatabaseMajorVersion());
//System.err.println(con.getMetaData().getDatabaseMinorVersion());
//System.err.println(con.getMetaData().supportsGetGeneratedKeys());
sMsg = "Connection opened for "+getReferenceLabel();
sMsg += ", productName: "+con.getMetaData().getDatabaseProductName();
sMsg += ", driver: "+con.getMetaData().getDriverName();
sMsg += " "+con.getMetaData().getDriverVersion();
LogUtil.getLogger().fine(sMsg);
} catch (Exception e2) {
LogUtil.getLogger().log(Level.WARNING,"Unable to determine connection metaData",e2);
}
return con;
}
/**
* Opens a direct JDBC connection based upon the driver, url, username and password.
* @return the JDBC connection
* @throws ClassNotFoundException if the database driver class was not found
* @throws SQLException if an SQL exception occurs while establishing the connection
*/
protected Connection openDirectConnection()
throws ClassNotFoundException, SQLException {
Class.forName(getDirectDriverClassName());
return DriverManager.getConnection(
getDirectUrl(),getDirectUsername(),getDirectPassword());
}
/**
* Opens a JDBC connection from the JNDI DataSource associated with the JNDI name.
* @return the JDBC connection
* @throws NamingException if a JNDI naming exception occurs
* @throws SQLException if an SQL exception occurs while establishing the connection
*/
protected Connection openJndiConnection()
throws NamingException, SQLException {
DataSource dataSource = getJndiDataSource();
return dataSource.getConnection();
}
/**
* Opens the DataSource associated with the JNDI name.
* @param jndiName the associated JNDI name
* @return the associated data source
* @throws NamingException if a JNDI naming exception occurs
*/
protected DataSource openJndiDataSource(String jndiName)
throws NamingException {
DataSource dataSource = null;
InitialContext initContext = new InitialContext();
try {
dataSource = (DataSource)initContext.lookup(jndiName);
} catch (NamingException e1) {
try {
dataSource = (DataSource)initContext.lookup("java:comp/env/"+jndiName);
} catch (NamingException e2) {
Context envContext = (Context)initContext.lookup("java:comp/env");
dataSource = (DataSource)envContext.lookup(jndiName);
}
}
return dataSource;
}
/**
* Tests the connection associated with the database reference.
* <br/>A connection is opened, then immediately closed.
*/
protected void testConnection() {
LogUtil.getLogger().finer("Testing connection for "+getReferenceLabel());
Connection con = null;
try {
con = openConnection();
} catch (Throwable t) {
LogUtil.getLogger().log(Level.SEVERE,"Connection test failed.",t);
} finally {
closeConnection(con);
}
}
/**
* Returns a string representation of this object.
* @return the string
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(getClass().getName()).append(" (\n");
sb.append(" name=").append(getReferenceName()).append("\n");
if (getIsJndiBased()) {
sb.append(" jndiName=").append(getJndiName()).append("\n");
} else {
sb.append(" driver=").append(getDirectDriverClassName()).append("\n");
sb.append(" url=").append(getDirectUrl()).append("\n");
sb.append(" username=").append(getDirectUsername()).append("\n");
sb.append(" password=").append(getDirectPassword()).append("\n");
}
sb.append(" referenceTags=").append(getTags()).append("\n");
sb.append(") ===== end ").append(getClass().getName());
return sb.toString();
}
}