@Override
  public void initializeObjects(
      List<EntityInfo> entityInfos,
      LinkedHashMap<EntityInfoLoadKey, Object> idToObjectMap,
      ObjectInitializationContext objectInitializationContext) {
    // Do not call isTimeOut here as the caller might be the last biggie on the list.
    final int numberOfObjectsToInitialize = entityInfos.size();

    if (numberOfObjectsToInitialize == 0) {
      if (log.isTraceEnabled()) {
        log.tracef("No object to initialize");
      }
      return;
    }

    SessionImplementor sessionImplementor =
        (SessionImplementor) objectInitializationContext.getSession();
    String entityName =
        objectInitializationContext
            .getSession()
            .getSessionFactory()
            .getClassMetadata(objectInitializationContext.getEntityType())
            .getEntityName();
    EntityPersister persister = sessionImplementor.getFactory().getEntityPersister(entityName);
    PersistenceContext persistenceContext = sessionImplementor.getPersistenceContext();

    // check the persistence context
    List<EntityInfo> remainingEntityInfos = new ArrayList<>(numberOfObjectsToInitialize);
    for (EntityInfo entityInfo : entityInfos) {
      if (ObjectLoaderHelper.areDocIdAndEntityIdIdentical(
          entityInfo, objectInitializationContext.getSession())) {
        EntityKey entityKey = sessionImplementor.generateEntityKey(entityInfo.getId(), persister);
        Object o = persistenceContext.getEntity(entityKey);
        if (o == null) {
          remainingEntityInfos.add(entityInfo);
        } else {
          EntityInfoLoadKey key = new EntityInfoLoadKey(entityInfo.getClazz(), entityInfo.getId());
          idToObjectMap.put(key, o);
        }
      } else {
        // if document id !=  entity id we can't use PC lookup
        remainingEntityInfos.add(entityInfo);
      }
    }

    // update entityInfos to only contains the remaining ones
    final int remainingSize = remainingEntityInfos.size();
    if (log.isTraceEnabled()) {
      log.tracef(
          "Initialized %d objects out of %d in the persistence context",
          (Integer) (numberOfObjectsToInitialize - remainingSize),
          (Integer) numberOfObjectsToInitialize);
    }

    if (remainingSize > 0) {
      delegate.initializeObjects(remainingEntityInfos, idToObjectMap, objectInitializationContext);
    }
  }
  public void performWork(LuceneWork work, IndexWriter writer) {
    final Class<?> entityType = work.getEntityClass();
    final Serializable id = work.getId();
    log.tracef("Removing %s#%s by query.", entityType, id);
    DocumentBuilderIndexedEntity<?> builder = workspace.getDocumentBuilder(entityType);

    BooleanQuery entityDeletionQuery = new BooleanQuery();

    Query idQueryTerm;
    if (isIdNumeric(builder)) {
      idQueryTerm = NumericFieldUtils.createExactMatchQuery(builder.getIdKeywordName(), id);
    } else {
      idQueryTerm = new TermQuery(builder.getTerm(id));
    }
    entityDeletionQuery.add(idQueryTerm, BooleanClause.Occur.MUST);

    Term classNameQueryTerm = new Term(ProjectionConstants.OBJECT_CLASS, entityType.getName());
    TermQuery classNameQuery = new TermQuery(classNameQueryTerm);
    entityDeletionQuery.add(classNameQuery, BooleanClause.Occur.MUST);

    try {
      writer.deleteDocuments(entityDeletionQuery);
    } catch (Exception e) {
      String message = "Unable to remove " + entityType + "#" + id + " from index.";
      throw new SearchException(message, e);
    }
  }
 @Override
 public void performWork(LuceneWork work, IndexWriterDelegate delegate, IndexingMonitor monitor) {
   final Serializable id = work.getId();
   final String tenantId = work.getTenantId();
   final Class<?> managedType = work.getEntityClass();
   DocumentBuilderIndexedEntity builder = workspace.getDocumentBuilder(managedType);
   try {
     if (DeleteWorkExecutor.isIdNumeric(builder)) {
       log.tracef(
           "Deleting %s#%s by query using an IndexWriter#updateDocument as id is Numeric",
           managedType, id);
       Query exactMatchQuery =
           NumericFieldUtils.createExactMatchQuery(builder.getIdKeywordName(), id);
       BooleanQuery.Builder deleteDocumentsQueryBuilder = new BooleanQuery.Builder();
       deleteDocumentsQueryBuilder.add(exactMatchQuery, Occur.FILTER);
       if (tenantId != null) {
         TermQuery tenantTermQuery =
             new TermQuery(new Term(DocumentBuilderIndexedEntity.TENANT_ID_FIELDNAME, tenantId));
         deleteDocumentsQueryBuilder.add(tenantTermQuery, Occur.FILTER);
       }
       delegate.deleteDocuments(deleteDocumentsQueryBuilder.build());
       // no need to log the Add operation as we'll log in the delegate
       this.addDelegate.performWork(work, delegate, monitor);
     } else {
       log.tracef("Updating %s#%s by id using an IndexWriter#updateDocument.", managedType, id);
       Term idTerm = new Term(builder.getIdKeywordName(), work.getIdInString());
       Map<String, String> fieldToAnalyzerMap = work.getFieldToAnalyzerMap();
       ScopedAnalyzerReference analyzerReference = builder.getAnalyzerReference();
       analyzerReference =
           AddWorkExecutor.updateAnalyzerMappings(
               workspace, analyzerReference, fieldToAnalyzerMap);
       delegate.updateDocument(idTerm, work.getDocument(), analyzerReference);
     }
     workspace.notifyWorkApplied(work);
   } catch (Exception e) {
     String message = "Unable to update " + managedType + "#" + id + " in index.";
     throw new SearchException(message, e);
   }
   if (monitor != null) {
     monitor.documentsAdded(1l);
   }
 }
 /**
  * Verifies entity level preconditions to know if it's safe to skip index updates based on
  * specific field or collection updates.
  *
  * @return true if it seems safe to apply such optimizations
  */
 boolean stateInspectionOptimizationsEnabled() {
   if (!typeMetadata.areStateInspectionOptimizationsEnabled()) {
     return false;
   }
   if (typeMetadata.areClassBridgesUsed()) {
     log.tracef(
         "State inspection optimization disabled as entity %s uses class bridges",
         this.beanClass.getName());
     return false; // can't know what a class bridge is going to look at -> reindex // TODO nice
     // new feature to have?
   }
   BoostStrategy boostStrategy = typeMetadata.getDynamicBoost();
   if (boostStrategy != null && !(boostStrategy instanceof DefaultBoostStrategy)) {
     log.tracef(
         "State inspection optimization disabled as DynamicBoost is enabled on entity %s",
         this.beanClass.getName());
     return false; // as with class bridge: might be affected by any field // TODO nice new feature
     // to have?
   }
   return true;
 }
  private void loadAllFromQueue(Session session) throws Exception {
    final InstanceInitializer sessionInitializer =
        new HibernateSessionLoadingInitializer((SessionImplementor) session);

    try {
      List<Serializable> idList;
      do {
        idList = source.take();
        if (idList != null) {
          log.tracef("received list of ids %s", idList);
          loadList(idList, session, sessionInitializer);
        }
      } while (idList != null);
    } catch (InterruptedException e) {
      // just quit
      Thread.currentThread().interrupt();
    }
  }
  private void indexAllQueue(
      Session session, List<?> entities, InstanceInitializer sessionInitializer)
      throws InterruptedException {
    ConversionContext contextualBridge = new ContextualExceptionBridgeHelper();

    if (entities == null || entities.isEmpty()) {
      return;
    } else {
      log.tracef("received a list of objects to index: %s", entities);
      for (Object object : entities) {
        try {
          index(object, session, sessionInitializer, contextualBridge);
          monitor.documentsBuilt(1);
        } catch (RuntimeException e) {
          String errorMsg =
              log.massIndexerUnableToIndexInstance(object.getClass().getName(), object.toString());
          errorHandler.handleException(errorMsg, e);
        }
      }
    }
  }