blob: 0480865537a65e8574ca6572f2be3e3806045508 [file] [log] [blame]
/*
* Copyright (c) 1998, 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,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// 05/28/2008-1.0M8 Andrei Ilitchev
// - New file introduced for bug 224964: Provide support for Proxy Authentication through JPA.
package org.eclipse.persistence.testing.framework.oracle;
import java.sql.SQLException;
import java.util.Map;
import java.util.Properties;
import oracle.jdbc.pool.OracleDataSource;
import org.eclipse.persistence.sessions.JNDIConnector;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
import org.eclipse.persistence.sessions.server.ServerSession;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.testing.framework.TestProblemException;
// Intended usage:
// 1.1 Obtains a session from the TestExecutor, logs it out, and keeps;
// 1.2 Using the original session's login and the passed parameters
// creates session that uses externalConnectionPools;
// 1.3 Logs the new session into TestExecutor so that it could be used by tests.
// 2.1 After done with the new session - kill it, shutdown all the data sources created for it;
// 2.2 Login the original session and set it back into TestExecutor.
//// Example: to create a new DatabaseSession that use externalConnectionPooling:
// SessionExchange exchange = new SessionExchange();
// testExecutor.setSession(exchange.createDatabaseSession((DatabaseSession)testExecutor.getSession()), true);
//// after the testing with the new session is completed:
// testExecutor.setSession(exchange.returnOriginalSession());
public class SessionExchanger {
// indicates whether the original session should be disconnected
public boolean shouldLogoutOriginalSession = true;
// indicates whether the new session should be connected
public boolean shouldLoginNewSession = true;
DatabaseSession originalSession;
DatabaseSession newSession;
boolean hasLoggedOutOriginalSession;
OracleDataSource dataSource;
// pass the original session and params for the new one:
// useDatabaseSession - "true" means new session is DatabaseSession; "false" - ServerSession;
// useExternalConnectionPooling - indicates whether the new session use external connection pooling or not.
// returns the new session
public DatabaseSession createNewSession(DatabaseSession originalSession, boolean useDatabaseSession, boolean useExternalConnectionPooling) {
return createNewSession(originalSession, useDatabaseSession, useExternalConnectionPooling, null, null);
}
// additional property parameters:
// loginProperties - if not null set into the new session's login;
// propertyProperties - if not null set into the new session;
// returns the new session
public DatabaseSession createNewSession(DatabaseSession originalSession, boolean useDatabaseSession, boolean useExternalConnectionPooling, Properties loginProperties, Map sessionProperties) {
if(useExternalConnectionPooling) {
return createNewSession(originalSession, useDatabaseSession, useExternalConnectionPooling, loginProperties, sessionProperties, -1, -1, -1, -1);
} else {
return createNewSession(originalSession, useDatabaseSession, useExternalConnectionPooling, loginProperties, sessionProperties, 2, 2, 2, 2);
}
}
// additional min / max parameters used only in case of ServerSession:
// in external pooling case only minWriteConnection and maxWriteConnection used - they determine the min / max number of connections in the created data source,
// pass -1 value for minWriteConnection and/or maxWriteConnection if no min and/or max number of connections should be set in the data source.
// in internal pooling case the min / max values used for write and read connection pools.
// returns the new session
public DatabaseSession createNewSession(DatabaseSession originalSession, boolean useDatabaseSession, boolean useExternalConnectionPooling, Properties loginProperties, Map sessionProperties,
int minWriteConnections, int maxWriteConnections, int minReadConnections, int maxReadConnections)
{
setup(originalSession);
DatabaseLogin login = cloneAndSetDataSource(originalSession.getLogin(), useExternalConnectionPooling, minWriteConnections, maxWriteConnections);
if(useDatabaseSession) {
newSession = new DatabaseSessionImpl(login);
} else {
if(useExternalConnectionPooling) {
newSession = new ServerSession(login);
} else {
newSession = new ServerSession(login, minWriteConnections, minWriteConnections);
}
if(!useExternalConnectionPooling) {
ServerSession ss = (ServerSession)newSession;
if(ss.getReadConnectionPool().getMaxNumberOfConnections() != maxReadConnections) {
ss.getReadConnectionPool().setMaxNumberOfConnections(maxReadConnections);
}
if(ss.getReadConnectionPool().getMinNumberOfConnections() != minReadConnections) {
ss.getReadConnectionPool().setMinNumberOfConnections(minReadConnections);
}
}
}
setProperties(loginProperties, sessionProperties);
newSession.setSessionLog(originalSession.getSessionLog());
newSession.setLogLevel(originalSession.getLogLevel());
if(shouldLoginNewSession) {
newSession.login();
}
return newSession;
}
// disconnects the temporary session, closes its datasource (if any);
// in case the original session was disconnected in setup - reconnects it;
// returns the original session
public DatabaseSession returnOriginalSession() {
try {
clearNewSession();
return originalSession;
} finally {
try {
if(originalSession != null && hasLoggedOutOriginalSession) {
hasLoggedOutOriginalSession = false;
originalSession.login();
}
} finally {
originalSession = null;
}
}
}
public boolean isBusy() {
return newSession != null;
}
void setup(DatabaseSession originalSession) {
if(isBusy()) {
throw new TestProblemException("SessionExchanger: new session has been already created");
}
this.originalSession = originalSession;
if(shouldLogoutOriginalSession) {
if(originalSession.isConnected()) {
originalSession.logout();
hasLoggedOutOriginalSession = true;
}
}
}
void clearNewSession() {
try {
if(newSession != null) {
if(newSession.isConnected()) {
newSession.logout();
}
}
} finally {
newSession = null;
if(dataSource != null) {
try {
dataSource.close();
} catch (SQLException ex) {
throw new TestProblemException("Exception thrown while closing OracleDataSource:\n", ex);
} finally {
dataSource = null;
}
}
}
}
DatabaseLogin cloneAndSetDataSource(DatabaseLogin login, boolean useExternalConnectionPooling, int minConnections, int maxConnections) {
DatabaseLogin cloneLogin = (DatabaseLogin)login.clone();
if(useExternalConnectionPooling) {
createDataSource(login.getConnectionString(), minConnections, maxConnections);
cloneLogin.setConnector(new JNDIConnector(dataSource));
cloneLogin.setUsesExternalConnectionPooling(true);
}
return cloneLogin;
}
void setProperties(Properties loginProperties, Map sessionProperties) {
if(loginProperties != null) {
newSession.getLogin().setProperties(loginProperties);
}
if(sessionProperties != null) {
((AbstractSession)newSession).setProperties(sessionProperties);
}
}
// create a data source using the supplied connection string
void createDataSource(String connectionString, int minConnections, int maxConnections) {
try {
dataSource = new OracleDataSource();
Properties props = new Properties();
if(minConnections >= 0) {
props.setProperty("MinLimit", Integer.toString(minConnections));
props.setProperty("InitialLimit", Integer.toString(minConnections));
}
if(maxConnections >= 0) {
props.setProperty("MaxLimit", Integer.toString(maxConnections));
}
if(!props.isEmpty()) {
dataSource.setConnectionCacheProperties(props);
}
} catch (SQLException ex) {
throw new TestProblemException("Failed to create OracleDataSource with " + connectionString + ".\n", ex);
}
dataSource.setURL(connectionString);
}
}