Package org.hibernate.ogm.massindex.batchindexing

Source Code of org.hibernate.ogm.massindex.batchindexing.TupleIndexer

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* JBoss, Home of Professional Open Source
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*/
package org.hibernate.ogm.massindex.batchindexing;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockOptions;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.ogm.datastore.spi.Tuple;
import org.hibernate.ogm.loader.OgmLoader;
import org.hibernate.ogm.loader.OgmLoadingContext;
import org.hibernate.ogm.persister.OgmEntityPersister;
import org.hibernate.search.backend.AddLuceneWork;
import org.hibernate.search.backend.impl.batch.BatchBackend;
import org.hibernate.search.batchindexing.MassIndexerProgressMonitor;
import org.hibernate.search.bridge.spi.ConversionContext;
import org.hibernate.search.bridge.util.impl.ContextualExceptionBridgeHelper;
import org.hibernate.search.engine.impl.HibernateSessionLoadingInitializer;
import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity;
import org.hibernate.search.engine.spi.EntityIndexBinder;
import org.hibernate.search.engine.spi.SearchFactoryImplementor;
import org.hibernate.search.exception.ErrorHandler;
import org.hibernate.search.indexes.interceptor.EntityIndexingInterceptor;
import org.hibernate.search.indexes.interceptor.IndexingOverride;
import org.hibernate.search.spi.InstanceInitializer;
import org.hibernate.search.util.impl.HibernateHelper;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
* Component of batch-indexing pipeline, using chained producer-consumers.
* <p>
* This Runnable will consume {@link Tuple} objects taken one-by-one and it will create an {@link AddLuceneWork} for the
* corresponding entity.
*
* @author Sanne Grinovero
* @author Davide D'Alto <davide@hibernate.org>
*/
public class TupleIndexer implements SessionAwareRunnable {

  private static final Log log = LoggerFactory.make();

  private final SessionFactory sessionFactory;
  private final Map<Class<?>, EntityIndexBinder> entityIndexBinders;
  private final MassIndexerProgressMonitor monitor;
  private final CacheMode cacheMode;
  private final BatchBackend backend;
  private final ErrorHandler errorHandler;

  private final Class<?> indexedType;

  public TupleIndexer(Class<?> indexedType, MassIndexerProgressMonitor monitor,
      SessionFactory sessionFactory, SearchFactoryImplementor searchFactory,
      CacheMode cacheMode, BatchBackend backend, ErrorHandler errorHandler) {
    this.indexedType = indexedType;
    this.monitor = monitor;
    this.sessionFactory = sessionFactory;
    this.cacheMode = cacheMode;
    this.backend = backend;
    this.errorHandler = errorHandler;
    this.entityIndexBinders = searchFactory.getIndexBindingForEntity();
  }

  private void index(Session session, Object entity) {
    try {
      final InstanceInitializer sessionInitializer = new HibernateSessionLoadingInitializer(
          (SessionImplementor) session );
      final ConversionContext contextualBridge = new ContextualExceptionBridgeHelper();

      // trick to attach the objects to session:
      session.buildLockRequest( LockOptions.NONE ).lock( entity );
      index( entity, session, sessionInitializer, contextualBridge );
      monitor.documentsBuilt( 1 );
      session.clear();
    }
    catch ( InterruptedException e ) {
      Thread.currentThread().interrupt();
    }
  }

  private void index(Object entity, Session session, InstanceInitializer sessionInitializer,
      ConversionContext conversionContext) throws InterruptedException {
    Class<?> clazz = HibernateHelper.getClass( entity );
    EntityIndexBinder entityIndexBinding = entityIndexBinders.get( clazz );
    // it might be possible to receive not-indexes subclasses of the currently indexed type;
    // being not-indexed, we skip them.
    // FIXME for improved performance: avoid loading them in an early phase.
    if ( entityIndexBinding != null ) {
      EntityIndexingInterceptor interceptor = entityIndexBinding.getEntityIndexingInterceptor();
      if ( isNotSkippable( interceptor, entity ) ) {
        Serializable id = session.getIdentifier( entity );
        AddLuceneWork addWork = createAddLuceneWork( entity, sessionInitializer, conversionContext, id, clazz,
            entityIndexBinding );
        backend.enqueueAsyncWork( addWork );
      }
    }
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  private AddLuceneWork createAddLuceneWork(Object entity, InstanceInitializer sessionInitializer,
      ConversionContext conversionContext, Serializable id, Class<?> clazz, EntityIndexBinder entityIndexBinding) {
    DocumentBuilderIndexedEntity docBuilder = entityIndexBinding.getDocumentBuilder();
    String idInString = idInString( conversionContext, id, clazz, docBuilder );
    // depending on the complexity of the object graph going to be indexed it's possible
    // that we hit the database several times during work construction.
    return docBuilder.createAddWork( clazz, entity, id, idInString, sessionInitializer, conversionContext );
  }

  private String idInString(ConversionContext conversionContext, Serializable id, Class<?> clazz,
      DocumentBuilderIndexedEntity docBuilder) {
    conversionContext.pushProperty( docBuilder.getIdKeywordName() );
    try {
      String idInString = conversionContext.setClass( clazz ).twoWayConversionContext( docBuilder.getIdBridge() )
          .objectToString( id );
      return idInString;
    }
    finally {
      conversionContext.popProperty();
    }
  }

  private boolean isNotSkippable(EntityIndexingInterceptor interceptor, Object entity) {
    if ( interceptor == null ) {
      return true;
    }
    else {
      return !isSkippable( interceptor.onAdd( entity ) );
    }
  }

  private boolean isSkippable(IndexingOverride indexingOverride) {
    switch ( indexingOverride ) {
    case REMOVE:
    case SKIP:
      return true;
    default:
      return false;
    }
  }

  private Transaction beginTransaction(Session session) throws ClassNotFoundException, NoSuchMethodException,
      IllegalAccessException, InvocationTargetException {
    Transaction transaction = Helper.getTransactionAndMarkForJoin( session );
    transaction.begin();
    return transaction;
  }

  private Session openSession(Session upperSession) {
    Session session = upperSession;
    if ( upperSession == null ) {
      session = sessionFactory.openSession();
    }
    session.setFlushMode( FlushMode.MANUAL );
    session.setCacheMode( cacheMode );
    session.setDefaultReadOnly( true );
    return session;
  }

  private void close(Session upperSession, Session session) {
    if ( upperSession == null ) {
      session.close();
    }
  }

  @Override
  public void run(Session upperSession, Tuple tuple) {
    Session session = openSession( upperSession );
    try {
      Transaction transaction = beginTransaction( session );
      index( session, entity( session, tuple ) );
      transaction.commit();
    }
    catch ( Throwable e ) {
      errorHandler.handleException( log.massIndexerUnexpectedErrorMessage(), e );
    }
    finally {
      close( upperSession, session );
      log.debug( "finished" );
    }
  }

  private Object entity(Session session, Tuple tuple) {
    OgmEntityPersister persister = (OgmEntityPersister) ( (SessionFactoryImplementor) sessionFactory ).getEntityPersister( indexedType.getName() );
    OgmLoader loader = new OgmLoader( new OgmEntityPersister[] { persister } );
    List<Tuple> tuples = new ArrayList<Tuple>();
    tuples.add( tuple );
    OgmLoadingContext ogmLoadingContext = new OgmLoadingContext();
    ogmLoadingContext.setTuples( tuples );
    List<Object> entities = loader.loadEntities( (SessionImplementor) session, LockOptions.NONE, ogmLoadingContext );
    return entities.get( 0 );
  }

}
TOP

Related Classes of org.hibernate.ogm.massindex.batchindexing.TupleIndexer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.