/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed 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 org.pentaho.di.core.database.util; import java.sql.Connection; import java.sql.Statement; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import org.pentaho.di.core.util.Utils; import org.pentaho.di.core.database.DataSourceNamingException; import org.pentaho.di.core.database.DataSourceProviderInterface; import org.pentaho.di.core.database.Database; import org.pentaho.di.i18n.BaseMessages; import javax.naming.Context; /** * Provides default implementation for looking data sources up in JNDI. * * @author mbatchel */ public class DatabaseUtil implements DataSourceProviderInterface { private static Class<?> PKG = Database.class; // for i18n purposes, needed by Translator2!! private static Map<String, DataSource> FoundDS = Collections.synchronizedMap( new HashMap<String, DataSource>() ); /** * Clears cache of DataSources (For Unit test) */ protected static void clearDSCache() { FoundDS.clear(); } /** * Since JNDI is supported different ways in different app servers, it's nearly impossible to have a ubiquitous way to * look up a datasource. This method is intended to hide all the lookups that may be required to find a jndi name. * * @param dsName The Datasource name * @return DataSource if there is one bound in JNDI * @throws NamingException */ protected static DataSource getDataSourceFromJndi( String dsName, Context ctx ) throws NamingException { if ( Utils.isEmpty( dsName ) ) { throw new NamingException( BaseMessages.getString( PKG, "DatabaseUtil.DSNotFound", String.valueOf( dsName ) ) ); } Object foundDs = FoundDS.get( dsName ); if ( foundDs != null ) { return (DataSource) foundDs; } Object lkup = null; DataSource rtn = null; NamingException firstNe = null; // First, try what they ask for... try { lkup = ctx.lookup( dsName ); if ( lkup instanceof DataSource ) { rtn = (DataSource) lkup; FoundDS.put( dsName, rtn ); return rtn; } } catch ( NamingException ignored ) { firstNe = ignored; } try { // Needed this for Jboss lkup = ctx.lookup( "java:" + dsName ); if ( lkup instanceof DataSource ) { rtn = (DataSource) lkup; FoundDS.put( dsName, rtn ); return rtn; } } catch ( NamingException ignored ) { // ignore } try { // Tomcat lkup = ctx.lookup( "java:comp/env/jdbc/" + dsName ); if ( lkup instanceof DataSource ) { rtn = (DataSource) lkup; FoundDS.put( dsName, rtn ); return rtn; } } catch ( NamingException ignored ) { // ignore } try { // Others? lkup = ctx.lookup( "jdbc/" + dsName ); if ( lkup instanceof DataSource ) { rtn = (DataSource) lkup; FoundDS.put( dsName, rtn ); return rtn; } } catch ( NamingException ignored ) { // ignore } if ( firstNe != null ) { throw firstNe; } throw new NamingException( BaseMessages.getString( PKG, "DatabaseUtil.DSNotFound", dsName ) ); } public static void closeSilently( Connection[] connections ) { if ( connections == null || connections.length == 0 ) { return; } for ( Connection conn : connections ) { closeSilently( conn ); } } public static void closeSilently( Connection conn ) { if ( conn == null ) { return; } try { conn.close(); } catch ( Throwable e ) { // omit } } public static void closeSilently( Statement[] statements ) { if ( statements == null || statements.length == 0 ) { return; } for ( Statement st : statements ) { closeSilently( st ); } } public static void closeSilently( Statement st ) { if ( st == null ) { return; } try { st.close(); } catch ( Throwable e ) { // omit } } /** * Implementation of DatasourceProviderInterface. */ @Override public DataSource getNamedDataSource( String datasourceName ) throws DataSourceNamingException { ClassLoader original = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( getClass().getClassLoader() ); return DatabaseUtil.getDataSourceFromJndi( datasourceName, new InitialContext() ); } catch ( NamingException ex ) { throw new DataSourceNamingException( ex ); } finally { Thread.currentThread().setContextClassLoader( original ); } } @Override public DataSource getNamedDataSource( String datasourceName, DatasourceType type ) throws DataSourceNamingException { if ( type != null ) { switch ( type ) { case JNDI: return getNamedDataSource( datasourceName ); case POOLED: throw new UnsupportedOperationException( getClass().getName() + " does not support providing pooled data sources" ); } } throw new IllegalArgumentException( "Unsupported data source type: " + type ); } }