/* Copyright (C) 2016 maik.jablonski@jease.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package jease.site; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.Supplier; import org.apache.commons.lang3.ArrayUtils; import org.zkoss.zsoup.Zsoup; import jease.cms.domain.Content; import jease.cms.domain.Folder; import jease.cms.domain.Reference; import jease.cms.domain.Trash; import jfix.db4o.Database; import jfix.search.FullTextIndex; /** * Service for searching through fulltext of content. */ public class Fulltexts { private static Supplier<FullTextIndex<Content>> fullTextIndex = () -> { FullTextIndex<Content> index = new FullTextIndex<>(); for (Content content : getContents()) { index.add(content, Zsoup.parseBodyFragment(content.getFulltext().toString()).text()); } index.commit(); return index; }; private static Collection<Content> getContents() { return Database.query(Content.class, $content -> isDefault($content) || isPublic($content)); } /** * Checks if given content is default content of Folder or Reference. */ private static boolean isDefault(Content content) { if (content.getParent() != null) { Content parent = (Content) content.getParent(); if (isPublic(parent) && (((parent instanceof Folder) && ((Folder) parent).getContent() == content) || (((parent instanceof Reference) && ((Reference) parent).getContent() == content)))) { return true; } } return false; } /** * Checks if given content is available for public access. */ private static boolean isPublic(Content content) { return content.isVisible() && ArrayUtils.isEmpty(content.getParents(Trash.class)); } /** * Returns all visible content which descends from given context and matches * the given query. */ public static List<Content> query(Content context, String query) { try { List<Content> result = new ArrayList<>(); for (Content content : Database.query(fullTextIndex).search(query)) { // When content is child of a "paged container" (e.g. // Composite), traverse upwards to the top-level container. Content target = content; while (target.getParent() != null && ((Content) target.getParent()).isPage() && target.getParent().isContainer()) { target = (Content) target.getParent(); } if (!result.contains(target) && (context == null || target.isDescendant(context))) { result.add(target); } } return result; } catch (Exception e) { return Collections.EMPTY_LIST; } } public static List<Content> query(String query) { return query(null, query); } }