blob: feadb2c032bcf2e111f99ec120b53f23c3d21326 [file] [log] [blame]
/*
* Copyright (c) 2022 Contributors to the Eclipse Foundation.
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.gjc.spi;
import static com.sun.gjc.common.DataSourceSpec.CLASSNAME;
import static com.sun.gjc.common.DataSourceSpec.LOGINTIMEOUT;
import static com.sun.gjc.common.DataSourceSpec.PASSWORD;
import static com.sun.gjc.common.DataSourceSpec.URL;
import static com.sun.gjc.common.DataSourceSpec.USERNAME;
import static com.sun.gjc.util.SecurityUtils.getPasswordCredential;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.FINEST;
import static java.util.logging.Level.SEVERE;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import javax.security.auth.Subject;
import javax.sql.DataSource;
import com.sun.gjc.common.DataSourceObjectBuilder;
import com.sun.gjc.spi.base.AbstractDataSource;
import com.sun.gjc.spi.base.ConnectionHolder;
import com.sun.logging.LogDomains;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.ConfigProperty;
import jakarta.resource.spi.ConnectionDefinition;
import jakarta.resource.spi.ConnectionRequestInfo;
import jakarta.resource.spi.ManagedConnection;
import jakarta.resource.spi.ResourceAllocationException;
import jakarta.resource.spi.security.PasswordCredential;
/**
* Driver Manager <code>ManagedConnectionFactory</code> implementation for
* Generic JDBC Connector.
*
* @author Evani Sai Surya Kiran
* @version 1.0, 02/07/31
*/
@ConnectionDefinition(
connectionFactory = DataSource.class,
connectionFactoryImpl = AbstractDataSource.class,
connection = Connection.class,
connectionImpl = ConnectionHolder.class)
public class DMManagedConnectionFactory extends ManagedConnectionFactoryImpl {
private static Logger _logger = LogDomains.getLogger(DMManagedConnectionFactory.class, LogDomains.RSR_LOGGER);
private boolean debug = _logger.isLoggable(FINE);
Properties props;
/**
* Creates a new physical connection to the underlying EIS resource manager.
*
* @param subject <code>Subject</code> instance passed by the application server
* @param cxRequestInfo <code>ConnectionRequestInfo</code> which may be created
* as a result of the invocation <code>getConnection(user, password)</code> on
* the <code>DataSource</code> object
*
* @return <code>ManagedConnection</code> object created
*
* @throws ResourceException if there is an error in instantiating the
* <code>DataSource</code> object used for the creation of the
* <code>ManagedConnection</code> object
* @throws SecurityException if there ino <code>PasswordCredential</code> object
* satisfying this request
*/
@Override
public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException {
logFine("In createManagedConnection");
if (dataSourceObjectBuilder == null) {
dataSourceObjectBuilder = new DataSourceObjectBuilder(spec);
}
PasswordCredential passwordCredential = getPasswordCredential(this, subject, cxRequestInfo);
try {
Class.forName(spec.getDetail(CLASSNAME));
} catch (ClassNotFoundException cnfe) {
_logger.log(SEVERE, "jdbc.exc_cnfe", cnfe);
throw new ResourceException("The driver could not be loaded: " + spec.getDetail(CLASSNAME));
}
Connection connection = null;
ManagedConnectionImpl managedConnectionImpl = null;
Properties driverProps = new Properties();
// Will return a set of properties that would have setURL and <url> as objects
// Get a set of normal case properties
Map<String, List<String>> properties = dataSourceObjectBuilder.parseDriverProperties(spec, false);
for (Map.Entry<String, List<String>> entry : properties.entrySet()) {
String value = "";
List<String> values = entry.getValue();
if (!values.isEmpty() && values.size() == 1) {
value = values.get(0);
} else if (values.size() > 1) {
logFine("More than one value for key : " + entry.getKey());
}
String parsedKey = getParsedKey(entry.getKey());
driverProps.put(parsedKey, value);
if (parsedKey.equalsIgnoreCase("URL")) {
if (spec.getDetail(URL) == null) {
setConnectionURL(value);
}
}
}
try {
if (cxRequestInfo != null) {
driverProps.setProperty("user", passwordCredential.getUserName());
driverProps.setProperty("password", new String(passwordCredential.getPassword()));
} else {
String user = spec.getDetail(USERNAME);
String password = spec.getDetail(PASSWORD);
if (user != null) {
driverProps.setProperty("user", user);
}
if (password != null) {
driverProps.setProperty("password", password);
}
}
connection = DriverManager.getConnection(spec.getDetail(URL), driverProps);
} catch (SQLException sqle) {
_logger.log(SEVERE, "jdbc.exc_create_mc", sqle);
throw new ResourceAllocationException("The connection could not be allocated: " + sqle.getMessage());
}
try {
managedConnectionImpl = constructManagedConnection(null, connection, passwordCredential, this);
validateAndSetIsolation(managedConnectionImpl);
} finally {
if (managedConnectionImpl == null) {
try {
connection.close();
} catch (SQLException e) {
_logger.log(FINEST, "Exception while closing connection : createManagedConnection" + connection, e);
}
}
}
return managedConnectionImpl;
}
/**
* Parses the key and removes the "set" string at the beginning of the property.
*
* @param key
* @return
*/
private String getParsedKey(String key) throws ResourceException {
String parsedKey = null;
int indexOfSet = -1;
try {
indexOfSet = key.indexOf("set");
} catch (NullPointerException npe) {
if (debug) {
_logger.log(FINE, "jdbc.exc_caught_ign", npe.getMessage());
}
}
if (indexOfSet == 0) {
// Find the key String
try {
parsedKey = key.substring(indexOfSet + 3, key.length()).trim();
} catch (IndexOutOfBoundsException iobe) {
if (debug) {
_logger.log(FINE, "jdbc.exc_caught_ign", iobe.getMessage());
}
}
if (parsedKey != null && parsedKey.equals("")) {
throw new ResourceException("Invalid driver properties string - " + "Key cannot be an empty string");
}
}
return parsedKey;
}
/**
* Sets the login timeout.
*
* @param loginTimeOut <code>String</code>
* @see <code>getLoginTimeOut</code>
*/
@Override
public void setLoginTimeOut(String loginTimeOut) {
try {
DriverManager.setLoginTimeout(Integer.parseInt(loginTimeOut));
spec.setDetail(LOGINTIMEOUT, loginTimeOut);
} catch (Exception e) {
if (debug) {
_logger.log(FINE, "jdbc.exc_caught_ign", e.getMessage());
}
}
}
/**
* Sets the class name of the driver
*
* @param className <code>String</code>
*/
@ConfigProperty(type = String.class, defaultValue = "org.apache.derby.jdbc.ClientDriver")
@Override
public void setClassName(String className) {
spec.setDetail(CLASSNAME, className);
}
public void setURL(String url) {
spec.setDetail(URL, url);
}
public String getURL() {
return spec.getDetail(URL);
}
/**
* Sets the connection url.
*
* @param url <code>String</code>
* @see <code>getConnectionURL</code>
*/
public void setConnectionURL(String url) {
spec.setDetail(URL, url);
}
/**
* Gets the connection url.
*
* @return url
* @see <code>setConnectionURL</code>
*/
public String getConnectionURL() {
return spec.getDetail(URL);
}
@Override
public Object getDataSource() throws ResourceException {
return null;
}
/**
* Check if this <code>ManagedConnectionFactory</code> is equal to another
* <code>ManagedConnectionFactory</code>.
*
* @param other <code>ManagedConnectionFactory</code> object for checking
* equality with
* @return true if the property sets of both the
* <code>ManagedConnectionFactory</code> objects are the same false otherwise
*/
@Override
public boolean equals(Object other) {
logFine("In equals");
/**
* The check below means that two ManagedConnectionFactory objects are equal if
* and only if their properties are the same.
*/
if (other instanceof DMManagedConnectionFactory) {
DMManagedConnectionFactory otherMCF = (DMManagedConnectionFactory) other;
return this.spec.equals(otherMCF.spec);
}
return false;
}
@Override
public int hashCode() {
return 31 * 7 + (spec.hashCode());
}
}