package org.fenixedu.bennu.core.domain; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; import org.fenixedu.commons.StringNormalizer; import pt.ist.fenixframework.FenixFramework; import com.google.common.collect.Sets; class NameIndex extends NameIndex_Base { private static final Map<String, NameIndex> map = new ConcurrentHashMap<>(); protected NameIndex() { super(); setBennu(Bennu.getInstance()); } protected NameIndex(String keyword) { this(); setKeyword(keyword); } static Stream<UserProfile> search(String query, int maxHits) { String[] queryParts = StringNormalizer.normalizeAndRemoveAccents(query.toLowerCase().trim()).split("\\s+"); return Stream.of(queryParts).map(NameIndex::find).reduce(Sets::intersection).orElse(Collections.emptySet()).stream() .limit(maxHits); } static void updateNameIndex(UserProfile profile) { String normalized = StringNormalizer.normalizeAndRemoveAccents(profile.getFullName().toLowerCase().trim()); profile.getNameIndexSet().clear(); for (String term : normalized.split("\\s+")) { profile.getNameIndexSet().add(create(term)); } } private static NameIndex create(String keyword) { NameIndex match = map.computeIfAbsent(keyword, query -> manualFind(keyword).orElseGet(() -> new NameIndex(keyword))); // FIXME: the second condition is there because of bug #197 in the fenix-framework if (!FenixFramework.isDomainObjectValid(match) || !match.getKeyword().equals(keyword)) { map.remove(keyword, match); return create(keyword); } return match; } private static Set<UserProfile> find(String keyword) { NameIndex match = map.computeIfAbsent(keyword, query -> manualFind(keyword).orElse(null)); if (match == null) { return Collections.emptySet(); } // FIXME: the second condition is there because of bug #197 in the fenix-framework if (!FenixFramework.isDomainObjectValid(match) || !match.getKeyword().equals(keyword)) { map.remove(keyword, match); return find(keyword); } return match.getProfileSet(); } private static Optional<NameIndex> manualFind(String keyword) { return Bennu.getInstance().getNameIndexSet().stream().filter(name -> name.getKeyword().equals(keyword)).findAny(); } static void cleanupIndex() { map.clear(); // cache must be invalidated because we are deleting indexes and cache assumes otherwise for (NameIndex index : Bennu.getInstance().getNameIndexSet()) { index.delete(); } for (UserProfile profile : Bennu.getInstance().getProfileSet()) { updateNameIndex(profile); } } private void delete() { setBennu(null); getProfileSet().clear(); deleteDomainObject(); } static void heatupCache() { Bennu.getInstance().getNameIndexSet().stream().forEach(index -> map.put(index.getKeyword(), index)); } }