/* * 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.infinispanremote.utils; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.ogm.datastore.document.options.AssociationStorageType; import org.hibernate.ogm.datastore.infinispanremote.InfinispanRemoteDataStoreConfiguration; import org.hibernate.ogm.datastore.infinispanremote.InfinispanRemoteDialect; import org.hibernate.ogm.datastore.infinispanremote.impl.InfinispanRemoteDatastoreProvider; import org.hibernate.ogm.datastore.infinispanremote.impl.ProtoStreamMappingAdapter; import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.ProtostreamId; import org.hibernate.ogm.datastore.infinispanremote.impl.protostream.ProtostreamPayload; import org.hibernate.ogm.datastore.spi.DatastoreConfiguration; import org.hibernate.ogm.datastore.spi.DatastoreProvider; import org.hibernate.ogm.dialect.spi.GridDialect; import org.hibernate.ogm.model.key.spi.EntityKey; import org.hibernate.ogm.model.key.spi.RowKey; import org.hibernate.ogm.persister.impl.OgmCollectionPersister; import org.hibernate.ogm.persister.impl.OgmEntityPersister; import org.hibernate.ogm.persister.impl.SingleTableOgmEntityPersister; import org.hibernate.ogm.utils.GridDialectTestHelper; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; import org.infinispan.client.hotrod.Search; import org.infinispan.commons.util.CloseableIterator; import org.infinispan.query.dsl.Query; /** * @author Sanne Grinovero (C) 2015 Red Hat Inc. */ public class InfinispanRemoteTestHelper implements GridDialectTestHelper { @Override public long getNumberOfAssociations(Session session) { return getNumberOfAssociations( session.getSessionFactory() ); } @Override public long getNumberOfAssociations(SessionFactory sessionFactory) { final InfinispanRemoteDatastoreProvider datastoreProvider = getProvider( sessionFactory ); final SessionFactoryImplementor sessionFactoryImplementor = getSessionFactoryImplementor( sessionFactory ); Collection<CollectionPersister> persisters = sessionFactoryImplementor.getCollectionPersisters().values(); long totalCount = 0; for ( CollectionPersister ep : persisters ) { OgmCollectionPersister persister = (OgmCollectionPersister) ep; String tableName = persister.getTableName(); SingleTableOgmEntityPersister owningPersister = (SingleTableOgmEntityPersister) persister.getOwnerEntityPersister().getEntityPersister(); String ownerTableName = owningPersister.getTableName(); totalCount += countAssociations( tableName, ownerTableName, datastoreProvider ); } return totalCount; } @Override public boolean backendSupportsTransactions() { return false; } @Override public void dropSchemaAndDatabase(SessionFactory sessionFactory) { final InfinispanRemoteDatastoreProvider datastoreProvider = getProvider( sessionFactory ); final Set<String> mappedCacheNames = datastoreProvider.getMappedCacheNames(); mappedCacheNames.forEach( cacheName -> datastoreProvider.getCache( cacheName ).clear() ); } @Override public Map<String, String> getAdditionalConfigurationProperties() { return Collections.emptyMap(); } @Override public long getNumberOfAssociations(SessionFactory sessionFactory, AssociationStorageType type) { if ( type == AssociationStorageType.IN_ENTITY ) { throw new IllegalArgumentException( "IN_ENTITY association storage type not supported" ); } else { return getNumberOfAssociations( sessionFactory ); } } @Override public GridDialect getGridDialect(DatastoreProvider datastoreProvider) { return new InfinispanRemoteDialect( (InfinispanRemoteDatastoreProvider) datastoreProvider ); } @Override public Class<? extends DatastoreConfiguration<?>> getDatastoreConfigurationType() { return InfinispanRemoteDataStoreConfiguration.class; } @Override public Map<String, Object> extractEntityTuple(Session session, EntityKey key) { final InfinispanRemoteDatastoreProvider datastoreProvider = getProvider( session ); ProtoStreamMappingAdapter mapper = datastoreProvider.getDataMapperForCache( key.getTable() ); ProtostreamId idBuffer = mapper.createIdPayload( key.getColumnNames(), key.getColumnValues() ); ProtostreamPayload payload = mapper.withinCacheEncodingContext( c -> c.get( idBuffer ) ); return payload.toMap(); } private long countAssociations(String tableName, String ownerTableName, InfinispanRemoteDatastoreProvider datastoreProvider) { final String[] ownerIdentifyingColumnNames = datastoreProvider.getDataMapperForCache( ownerTableName ).listIdColumnNames(); final ProtoStreamMappingAdapter mapper = datastoreProvider.getDataMapperForCache( tableName ); return mapper.withinCacheEncodingContext( c -> { Query queryAll = Search.getQueryFactory( c ).from( ProtostreamPayload.class ).build(); Set<RowKey> resultsCollector = new HashSet<>(); try ( CloseableIterator<Entry<Object,Object>> iterator = c.retrieveEntriesByQuery( queryAll, null, 100 ) ) { while ( iterator.hasNext() ) { Entry<Object,Object> e = iterator.next(); ProtostreamPayload value = ( (ProtostreamPayload) e.getValue() ); Map<String, Object> entryObject = value.toMap(); Object[] columnValues = new Object[ownerIdentifyingColumnNames.length]; for ( int i = 0; i < columnValues.length; i++ ) { columnValues[i] = entryObject.get( ownerIdentifyingColumnNames[i] ); } RowKey entryKey = new RowKey( ownerIdentifyingColumnNames, columnValues ); resultsCollector.add( entryKey ); } } return (long) resultsCollector.size(); } ); } @Override public long getNumberOfEntities(SessionFactory sessionFactory) { final InfinispanRemoteDatastoreProvider datastoreProvider = getProvider( sessionFactory ); final SessionFactoryImplementor sessionFactoryImplementor = getSessionFactoryImplementor( sessionFactory ); Collection<EntityPersister> persisters = sessionFactoryImplementor.getEntityPersisters().values(); final AtomicLong counter = new AtomicLong(); for ( EntityPersister ep : persisters ) { OgmEntityPersister persister = (OgmEntityPersister) ep; String tableName = persister.getTableName(); int increment = datastoreProvider.getCache( tableName ).size(); counter.addAndGet( increment ); } return counter.get(); } @Override public long getNumberOfEntities(Session session) { return getNumberOfEntities( session.getSessionFactory() ); } // Various static helpers below: private static SessionFactoryImplementor getSessionFactoryImplementor(SessionFactory sessionFactory) { return ( (SessionFactoryImplementor) sessionFactory ); } public static InfinispanRemoteDatastoreProvider getProvider(Session session) { return getProvider( session.getSessionFactory() ); } public static InfinispanRemoteDatastoreProvider getProvider(SessionFactory sessionFactory) { DatastoreProvider provider = ( (SessionFactoryImplementor) sessionFactory ).getServiceRegistry().getService( DatastoreProvider.class ); if ( !( InfinispanRemoteDatastoreProvider.class.isInstance( provider ) ) ) { throw new RuntimeException( "Not testing with Infinispan Remote, cannot extract underlying cache" ); } return InfinispanRemoteDatastoreProvider.class.cast( provider ); } }