/*! ******************************************************************************
*
* 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.map;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.database.Database;
import org.pentaho.di.core.database.DatabaseTransactionListener;
/**
* This class contains a map between on the one hand
* <p/>
* the transformation name/thread the partition ID the connection group
* <p/>
* And on the other hand
* <p/>
* The database connection The number of times it was opened
*
* @author Matt
*/
public class DatabaseConnectionMap {
private final ConcurrentMap<String, Database> map;
private final AtomicInteger transactionId;
private final Map<String, List<DatabaseTransactionListener>> transactionListenersMap;
private static final DatabaseConnectionMap connectionMap = new DatabaseConnectionMap();
public static synchronized DatabaseConnectionMap getInstance() {
return connectionMap;
}
private DatabaseConnectionMap() {
map = new ConcurrentHashMap<String, Database>();
transactionId = new AtomicInteger( 0 );
transactionListenersMap = new HashMap<String, List<DatabaseTransactionListener>>();
}
/**
* Tries to obtain an existing <tt>Database</tt> instance for specified parameters. If none is found, then maps the
* key's value to <tt>database</tt>. Similarly to {@linkplain ConcurrentHashMap#putIfAbsent(Object, Object)} returns
* <tt>null</tt> if there was no value for the specified key and they mapped value otherwise.
*
* @param connectionGroup connection group
* @param partitionID partition's id
* @param database database
* @return <tt>null</tt> or previous value
*/
public Database getOrStoreIfAbsent( String connectionGroup, String partitionID, Database database ) {
String key = createEntryKey( connectionGroup, partitionID, database );
return map.putIfAbsent( key, database );
}
public void removeConnection( String connectionGroup, String partitionID, Database database ) {
String key = createEntryKey( connectionGroup, partitionID, database );
map.remove( key );
}
/**
* @deprecated use {@linkplain #getOrStoreIfAbsent(String, String, Database)} instead
*/
@Deprecated
public synchronized void storeDatabase( String connectionGroup, String partitionID, Database database ) {
String key = createEntryKey( connectionGroup, partitionID, database );
map.put( key, database );
}
/**
* @deprecated use {@linkplain #getOrStoreIfAbsent(String, String, Database)} instead
*/
@Deprecated
public synchronized Database getDatabase( String connectionGroup, String partitionID, Database database ) {
String key = createEntryKey( connectionGroup, partitionID, database );
return map.get( key );
}
public static String createEntryKey( String connectionGroup, String partitionID, Database database ) {
StringBuilder key = new StringBuilder( connectionGroup );
key.append( ':' ).append( database.getDatabaseMeta().getName() );
if ( !Utils.isEmpty( partitionID ) ) {
key.append( ':' ).append( partitionID );
}
return key.toString();
}
public Map<String, Database> getMap() {
return map;
}
public String getNextTransactionId() {
return Integer.toString( transactionId.incrementAndGet() );
}
public void addTransactionListener( String transactionId, DatabaseTransactionListener listener ) {
List<DatabaseTransactionListener> transactionListeners = getTransactionListeners( transactionId );
transactionListeners.add( listener );
}
public void removeTransactionListener( String transactionId, DatabaseTransactionListener listener ) {
List<DatabaseTransactionListener> transactionListeners = getTransactionListeners( transactionId );
transactionListeners.remove( listener );
}
public List<DatabaseTransactionListener> getTransactionListeners( String transactionId ) {
List<DatabaseTransactionListener> transactionListeners = transactionListenersMap.get( transactionId );
if ( transactionListeners == null ) {
transactionListeners = new ArrayList<DatabaseTransactionListener>();
transactionListenersMap.put( transactionId, transactionListeners );
}
return transactionListeners;
}
public void removeTransactionListeners( String transactionId ) {
transactionListenersMap.remove( transactionId );
}
}