Skip to content

Commit

Permalink
[PDI-13633] Regression: Database Connections with JNDI mix up JNDI na…
Browse files Browse the repository at this point in the history
…me with Connection name
  • Loading branch information
ivanpogodin committed Apr 28, 2015
1 parent e8b0d4f commit 9ef7532
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 16 deletions.
1 change: 1 addition & 0 deletions core/ivy.xml
Expand Up @@ -63,5 +63,6 @@

<dependency org="xml-apis" name="xml-apis-ext" rev="${dependency.xml-apis-ext.revision}" transitive="false"/>

<dependency org="org.springframework" name="spring-test" rev="2.5.6" transitive="false" conf="test->default"/>
</dependencies>
</ivy-module>
53 changes: 40 additions & 13 deletions core/src/org/pentaho/di/core/database/Database.java
Expand Up @@ -66,6 +66,7 @@
import org.pentaho.di.core.RowMetaAndData;
import org.pentaho.di.core.database.map.DatabaseConnectionMap;
import org.pentaho.di.core.database.util.DatabaseLogExceptionFactory;
import org.pentaho.di.core.database.util.DatabaseUtil;
import org.pentaho.di.core.encryption.Encr;
import org.pentaho.di.core.exception.KettleDatabaseBatchException;
import org.pentaho.di.core.exception.KettleDatabaseException;
Expand Down Expand Up @@ -396,13 +397,19 @@ public void normalConnect( String partitionId ) throws KettleDatabaseException {
} catch ( Exception e ) {
throw new KettleDatabaseException( "Error occurred while trying to connect to the database", e );
}
} else if ( databaseMeta.getAccessType() == DatabaseMeta.TYPE_ACCESS_JNDI ) {
final String jndiName = environmentSubstitute( databaseMeta.getDatabaseName() );
connectUsingJNDIDataSource( jndiName );
} else {
// TODO connectUsingNamedDataSource can be called here but the current implementation of
// org.pentaho.platform.plugin.action.kettle.PlatformKettleDataSourceProvider can cause collision of name and
// JNDI name. See also [PDI-13633], [SP-1776].
connectUsingClass( databaseMeta.getDriverClass(), partitionId );
if ( log.isDetailed() ) {
log.logDetailed( "Connected to database." );
}
}
// See if we need to execute extra SQL statemtent...
// See if we need to execute extra SQL statement...
String sql = environmentSubstitute( databaseMeta.getConnectSQL() );

// only execute if the SQL is not empty, null and is not just a bunch of
Expand All @@ -425,37 +432,57 @@ public void normalConnect( String partitionId ) throws KettleDatabaseException {
* @param dataSourceName
* @throws KettleDatabaseException
*/
private void initWithNamedDataSource( String dataSourceName ) throws KettleDatabaseException {
private void connectUsingNamedDataSource( String dataSourceName ) throws KettleDatabaseException {
connection = null;
DataSource dataSource =
DataSourceProviderFactory.getDataSourceProviderInterface().getNamedDataSource( dataSourceName );
if ( dataSource != null ) {
try {
connection = dataSource.getConnection();
} catch ( SQLException e ) {
throw new KettleDatabaseException( "Invalid JNDI connection " + dataSourceName + " : " + e.getMessage() );
throw new KettleDatabaseException( "Invalid named connection " + dataSourceName + " : " + e.getMessage() );
}
if ( connection == null ) {
throw new KettleDatabaseException( "Invalid JNDI connection " + dataSourceName );
throw new KettleDatabaseException( "Invalid named connection " + dataSourceName );
}
} else {
throw new KettleDatabaseException( "Invalid JNDI connection " + dataSourceName );
throw new KettleDatabaseException( "Invalid named connection " + dataSourceName );
}
}

/**
* Initialize by getting the connection from a javax.sql.DataSource.
*
* This method now _does_not_use the DataSourceProviderFactory to get the provider of DataSource objects.
*
* @param jndiName
* @throws KettleDatabaseException
*/
private void connectUsingJNDIDataSource( String jndiName ) throws KettleDatabaseException {
Connection connection = null;
DataSource dataSource = ( new DatabaseUtil() ).getNamedDataSource( jndiName );
if ( dataSource != null ) {
try {
connection = dataSource.getConnection();
} catch ( SQLException e ) {
throw new KettleDatabaseException( "Invalid JNDI connection " + jndiName + " : " + e.getMessage() );
}
if ( connection == null ) {
throw new KettleDatabaseException( "Invalid JNDI connection " + jndiName );
}
} else {
throw new KettleDatabaseException( "Invalid JNDI connection " + jndiName );
}
this.connection = connection;
}

/**
* Connect using the correct classname
*
* @param classname for example "org.gjt.mm.mysql.Driver"
* @return true if the connect was successful, false if something went wrong.
*/
private void connectUsingClass( String classname, String partitionId ) throws KettleDatabaseException {
// first see if this is a JNDI connection
if ( databaseMeta.getAccessType() == DatabaseMeta.TYPE_ACCESS_JNDI ) {
initWithNamedDataSource( environmentSubstitute( databaseMeta.getDatabaseName() ) );
return;
}

// Install and load the jdbc Driver
PluginInterface plugin =
PluginRegistry.getInstance().getPlugin( DatabasePluginType.class, databaseMeta.getDatabaseInterface() );
Expand Down Expand Up @@ -486,10 +513,10 @@ private void connectUsingClass( String classname, String partitionId ) throws Ke
}
} catch ( NoClassDefFoundError e ) {
throw new KettleDatabaseException( BaseMessages.getString( PKG,
"Database.Exception.UnableToFindClassMissingDriver", databaseMeta.getDriverClass(), plugin.getName() ), e );
"Database.Exception.UnableToFindClassMissingDriver", classname, plugin.getName() ), e );
} catch ( ClassNotFoundException e ) {
throw new KettleDatabaseException( BaseMessages.getString( PKG,
"Database.Exception.UnableToFindClassMissingDriver", databaseMeta.getDriverClass(), plugin.getName() ), e );
"Database.Exception.UnableToFindClassMissingDriver", classname, plugin.getName() ), e );
} catch ( Exception e ) {
throw new KettleDatabaseException( "Exception while loading class", e );
}
Expand Down
@@ -0,0 +1,71 @@
package org.pentaho.di.core.database;

import static org.mockito.Mockito.mock;

import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.spi.InitialContextFactoryBuilder;
import javax.naming.spi.NamingManager;

import junit.framework.Assert;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.logging.LoggingObjectType;
import org.pentaho.di.core.logging.SimpleLoggingObject;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;

public class DatabaseConnectUnitTest {

static LoggingObjectInterface log = new SimpleLoggingObject( "junit", LoggingObjectType.GENERAL, null );
String name = "testName";
String jndiName = "testJNDIName";
String fullJndiName = "jdbc/testJNDIName";
String displayName = "testDisplayName";

@BeforeClass
public static void beforeClass() throws NamingException {
if ( !NamingManager.hasInitialContextFactoryBuilder() ) {
// If JNDI is not initialized, use simpleJNDI
System.setProperty( Context.INITIAL_CONTEXT_FACTORY, "org.osjava.jndi.PropertiesFactory" );
InitialContextFactoryBuilder simpleBuilder = new SimpleNamingContextBuilder();
NamingManager.setInitialContextFactoryBuilder( simpleBuilder );
}
}

@After
public void after() throws NamingException {
InitialContext ctx = new InitialContext();
ctx.unbind( fullJndiName );
}

@Test
public void testConnect2() throws SQLException, NamingException, KettleDatabaseException {
InitialContext ctx = new InitialContext();

DatabaseMeta meta = Mockito.mock( DatabaseMeta.class );
Mockito.when( meta.getName() ).thenReturn( name );
Mockito.when( meta.getDatabaseName() ).thenReturn( jndiName );
Mockito.when( meta.getDisplayName() ).thenReturn( displayName );
Mockito.when( meta.getAccessType() ).thenReturn( DatabaseMeta.TYPE_ACCESS_JNDI );
Mockito.when( meta.environmentSubstitute( jndiName ) ).thenReturn( jndiName );

Connection connection = mock( Connection.class );
TestDataSource ds = new TestDataSource( connection );
ctx.bind( fullJndiName, ds );

Database db = new Database( log, meta );

db.connect();
Assert.assertEquals( connection, db.getConnection() );
}

}
Expand Up @@ -55,6 +55,7 @@
import org.pentaho.di.core.DBCacheEntry;
import org.pentaho.di.core.database.DataSourceProviderFactory;
import org.pentaho.di.core.database.DatabaseMeta;
import org.pentaho.di.core.database.util.DatabaseUtil;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
Expand Down Expand Up @@ -99,9 +100,7 @@ public void openQuery() throws KettleDatabaseException {
String realRole = space.environmentSubstitute( role );

if ( databaseMeta.getAccessType() == DatabaseMeta.TYPE_ACCESS_JNDI ) {
DataSource dataSource =
DataSourceProviderFactory.getDataSourceProviderInterface().getNamedDataSource(
databaseMeta.getDatabaseName() );
DataSource dataSource = ( new DatabaseUtil() ).getNamedDataSource( databaseMeta.getDatabaseName() );
mondrian.olap.Util.PropertyList propList = new mondrian.olap.Util.PropertyList();
propList.put( "Provider", "mondrian" );
propList.put( "Catalog", space.environmentSubstitute( catalog ) );
Expand Down

0 comments on commit 9ef7532

Please sign in to comment.