/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.infinispan.persistencestrategy.table.impl;
import static org.hibernate.ogm.util.impl.CollectionHelper.newConcurrentHashMap;
import static org.hibernate.ogm.util.impl.CollectionHelper.newHashMap;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.ogm.datastore.infinispan.persistencestrategy.impl.LocalCacheManager;
import org.hibernate.ogm.datastore.infinispan.persistencestrategy.table.externalizer.impl.PersistentAssociationKey;
import org.hibernate.ogm.datastore.infinispan.persistencestrategy.table.externalizer.impl.PersistentEntityKey;
import org.hibernate.ogm.datastore.infinispan.persistencestrategy.table.externalizer.impl.PersistentIdSourceKey;
import org.hibernate.ogm.model.key.spi.AssociationKeyMetadata;
import org.hibernate.ogm.model.key.spi.EntityKeyMetadata;
import org.hibernate.ogm.model.key.spi.IdSourceKeyMetadata;
import org.hibernate.ogm.model.key.spi.RowKey;
import org.infinispan.Cache;
import org.infinispan.manager.EmbeddedCacheManager;
/**
* A {@link LocalCacheManager} which uses a dedicated {@link Cache} per entity/association/id source table.
*
* @author Gunnar Morling
*/
public class PerTableCacheManager extends LocalCacheManager<PersistentEntityKey, PersistentAssociationKey, PersistentIdSourceKey> {
private static final String ASSOCIATIONS_CACHE_PREFIX = "associations_";
private final ConcurrentMap<String, Cache<PersistentEntityKey, Map<String, Object>>> entityCaches;
private final ConcurrentMap<String, Cache<PersistentAssociationKey, Map<RowKey, Map<String, Object>>>> associationCaches;
private final ConcurrentMap<String, Cache<PersistentIdSourceKey, Object>> idSourceCaches;
public PerTableCacheManager(EmbeddedCacheManager cacheManager, Set<EntityKeyMetadata> entityTypes, Set<AssociationKeyMetadata> associationTypes, Set<IdSourceKeyMetadata> idSourceTypes) {
super( cacheManager );
entityCaches = initializeEntityCaches( getCacheManager(), entityTypes );
associationCaches = initializeAssociationCaches( getCacheManager(), associationTypes );
idSourceCaches = initializeIdSourceCaches( getCacheManager(), idSourceTypes );
}
public PerTableCacheManager(URL configUrl, JtaPlatform platform, Set<EntityKeyMetadata> entityTypes, Set<AssociationKeyMetadata> associationTypes, Set<IdSourceKeyMetadata> idSourceTypes) {
super( configUrl, platform, getCacheNames( entityTypes, associationTypes, idSourceTypes ), new PerTableKeyProvider() );
entityCaches = initializeEntityCaches( getCacheManager(), entityTypes );
associationCaches = initializeAssociationCaches( getCacheManager(), associationTypes );
idSourceCaches = initializeIdSourceCaches( getCacheManager(), idSourceTypes );
}
private static Set<String> getCacheNames(Set<EntityKeyMetadata> entityTypes, Set<AssociationKeyMetadata> associationTypes, Set<IdSourceKeyMetadata> idSourceTypes) {
Set<String> cacheNames = new HashSet<String>();
for ( EntityKeyMetadata entityKeyMetadata : entityTypes ) {
cacheNames.add( entityKeyMetadata.getTable() );
}
for ( AssociationKeyMetadata associationKeyMetadata : associationTypes ) {
cacheNames.add( getCacheName( associationKeyMetadata ) );
}
for ( IdSourceKeyMetadata idSourceKeyMetadata : idSourceTypes ) {
cacheNames.add( idSourceKeyMetadata.getName() );
}
return cacheNames;
}
private static ConcurrentMap<String, Cache<PersistentEntityKey, Map<String,Object>>> initializeEntityCaches(EmbeddedCacheManager embeddedCacheManager, Set<EntityKeyMetadata> entityTypes) {
ConcurrentHashMap<String, Cache<PersistentEntityKey, Map<String, Object>>> entityCaches = newConcurrentHashMap( entityTypes.size() );
for ( EntityKeyMetadata entityKeyMetadata : entityTypes ) {
Cache<PersistentEntityKey, Map<String, Object>> entityCache = embeddedCacheManager.getCache( entityKeyMetadata.getTable() );
entityCaches.put( entityKeyMetadata.getTable(), entityCache );
}
return entityCaches;
}
private static ConcurrentMap<String, Cache<PersistentAssociationKey, Map<RowKey, Map<String, Object>>>> initializeAssociationCaches(EmbeddedCacheManager embeddedCacheManager, Set<AssociationKeyMetadata> associationTypes) {
ConcurrentHashMap<String, Cache<PersistentAssociationKey, Map<RowKey, Map<String, Object>>>> associationCaches = newConcurrentHashMap( associationTypes.size() );
for ( AssociationKeyMetadata associationKeyMetadata : associationTypes ) {
String cacheName = getCacheName( associationKeyMetadata );
associationCaches.put(
cacheName,
embeddedCacheManager.<PersistentAssociationKey, Map<RowKey, Map<String, Object>>>getCache( cacheName )
);
}
return associationCaches;
}
private static ConcurrentMap<String, Cache<PersistentIdSourceKey, Object>> initializeIdSourceCaches(EmbeddedCacheManager embeddedCacheManager, Set<IdSourceKeyMetadata> idSourceTypes) {
ConcurrentMap<String, Cache<PersistentIdSourceKey, Object>> idSourceCaches = newConcurrentHashMap( idSourceTypes.size() );
for ( IdSourceKeyMetadata idSourceKeyMetadata : idSourceTypes ) {
if ( !idSourceCaches.containsKey( idSourceKeyMetadata.getName() ) ) {
Cache<PersistentIdSourceKey, Object> idSourceCache = embeddedCacheManager.getCache( idSourceKeyMetadata.getName() );
idSourceCaches.put( idSourceKeyMetadata.getName(), idSourceCache );
}
}
return idSourceCaches;
}
@Override
public Cache<PersistentEntityKey, Map<String, Object>> getEntityCache(EntityKeyMetadata keyMetadata) {
return entityCaches.get( keyMetadata.getTable() );
}
@Override
public Cache<PersistentAssociationKey, Map<RowKey, Map<String, Object>>> getAssociationCache(AssociationKeyMetadata keyMetadata) {
return associationCaches.get( getCacheName( keyMetadata ) );
}
@Override
public Cache<PersistentIdSourceKey, Object> getIdSourceCache(IdSourceKeyMetadata keyMetadata) {
return idSourceCaches.get( keyMetadata.getName() );
}
@Override
public Set<Bucket<PersistentEntityKey>> getWorkBucketsFor(EntityKeyMetadata... entityKeyMetadatas) {
Map<String, List<EntityKeyMetadata>> metadataByTable = groupByTable( entityKeyMetadatas );
Set<Bucket<PersistentEntityKey>> result = new HashSet<Bucket<PersistentEntityKey>>();
for ( Entry<String, List<EntityKeyMetadata>> entry : metadataByTable.entrySet() ) {
result.add( new Bucket<PersistentEntityKey>( entityCaches.get( entry.getKey() ), entry.getValue() ) );
}
return result;
}
private Map<String, List<EntityKeyMetadata>> groupByTable(EntityKeyMetadata... entityKeyMetadatas) {
Map<String, List<EntityKeyMetadata>> metadataByTable = newHashMap();
for ( EntityKeyMetadata entityKeyMetadata : entityKeyMetadatas ) {
List<EntityKeyMetadata> metadataOfTable = metadataByTable.get( entityKeyMetadata.getTable() );
if ( metadataOfTable == null ) {
metadataOfTable = new ArrayList<EntityKeyMetadata>();
metadataByTable.put( entityKeyMetadata.getTable(), metadataOfTable );
}
metadataOfTable.add( entityKeyMetadata );
}
return metadataByTable;
}
private static String getCacheName(AssociationKeyMetadata keyMetadata) {
return ASSOCIATIONS_CACHE_PREFIX + keyMetadata.getTable();
}
}