/** * If we have a work instance we have to check whether the instance to be indexed is contained in * any other indexed entities for a tenant. * * @param instance the instance to be indexed * @param workPlan the current work plan * @param currentRecursionContext the current {@link * org.hibernate.search.engine.spi.ContainedInRecursionContext} object used to check the graph * traversal * @param tenantIdentifier the identifier of the tenant or null, if there isn't one * @see #appendContainedInWorkForInstance(Object, WorkPlan, ContainedInRecursionContext) */ public void appendContainedInWorkForInstance( Object instance, WorkPlan workPlan, ContainedInRecursionContext currentRecursionContext, String tenantIdentifier) { for (ContainedInMetadata containedInMetadata : typeMetadata.getContainedInMetadata()) { XMember member = containedInMetadata.getContainedInMember(); Object unproxiedInstance = instanceInitializer.unproxy(instance); ContainedInRecursionContext recursionContext = updateContainedInRecursionContext( unproxiedInstance, containedInMetadata, currentRecursionContext); if (recursionContext.isTerminal()) { continue; } Object value = ReflectionHelper.getMemberValue(unproxiedInstance, member); if (value == null) { continue; } if (member.isArray()) { Object[] array = (Object[]) value; for (Object arrayValue : array) { processSingleContainedInInstance( workPlan, arrayValue, recursionContext, tenantIdentifier); } } else if (member.isCollection()) { Collection<?> collection = null; try { collection = getActualCollection(member, value); collection.size(); // load it } catch (Exception e) { if (e.getClass().getName().contains("org.hibernate.LazyInitializationException")) { /* A deleted entity not having its collection initialized * leads to a LIE because the collection is no longer attached to the session * * But that's ok as the collection update event has been processed before * or the fk would have been cleared and thus triggering the cleaning */ collection = null; } } if (collection != null) { for (Object collectionValue : collection) { processSingleContainedInInstance( workPlan, collectionValue, recursionContext, tenantIdentifier); } } } else { processSingleContainedInInstance(workPlan, value, recursionContext, tenantIdentifier); } } }
private ContainedInRecursionContext updateContainedInRecursionContext( Object containedInstance, ContainedInMetadata containedInMetadata, ContainedInRecursionContext containedContext) { int maxDepth; int depth; // Handle @IndexedEmbedded.depth-induced limits Integer metadataMaxDepth = containedInMetadata.getMaxDepth(); if (containedInstance != null && metadataMaxDepth != null) { maxDepth = metadataMaxDepth; } else { maxDepth = containedContext != null ? containedContext.getMaxDepth() : Integer.MAX_VALUE; } depth = containedContext != null ? containedContext.getDepth() : 0; if (depth < Integer.MAX_VALUE) { // Avoid integer overflow ++depth; } /* * Handle @IndexedEmbedded.includePaths-induced limits If the context for the contained element has a * comprehensive set of included paths, and if the @IndexedEmbedded matching the @ContainedIn we're currently * processing also has a comprehensive set of embedded paths, *then* we can compute the resulting set of * embedded fields (which is the intersection of those two sets). If this resulting set is empty, we can safely * stop the @ContainedIn processing: any changed field wouldn't be included in the Lucene document for * "containerInstance" anyway. */ Set<String> comprehensivePaths; Set<String> metadataIncludePaths = containedInMetadata.getIncludePaths(); /* * See @IndexedEmbedded.depth: it should be considered as zero if it has its default value and if includePaths * contains elements */ if (metadataIncludePaths != null && !metadataIncludePaths.isEmpty() && metadataMaxDepth != null && metadataMaxDepth.equals(Integer.MAX_VALUE)) { String metadataPrefix = containedInMetadata.getPrefix(); /* * If the contained context Filter by contained context's included paths if they are comprehensive This * allows to detect when a @ContainedIn is irrelevant because the matching @IndexedEmbedded would not * capture any property. */ Set<String> containedComprehensivePaths = containedContext != null ? containedContext.getComprehensivePaths() : null; comprehensivePaths = new HashSet<>(); for (String includedPath : metadataIncludePaths) { /* * If the contained context has a comprehensive list of included paths, use it to filter out our own * list */ if (containedComprehensivePaths == null || containedComprehensivePaths.contains(includedPath)) { comprehensivePaths.add(metadataPrefix + includedPath); } } } else { comprehensivePaths = null; } return new ContainedInRecursionContext(maxDepth, depth, comprehensivePaths); }