001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.asset.util;
016    
017    import com.liferay.portal.kernel.search.BaseSearcher;
018    import com.liferay.portal.kernel.search.BooleanClauseOccur;
019    import com.liferay.portal.kernel.search.BooleanQuery;
020    import com.liferay.portal.kernel.search.DocumentImpl;
021    import com.liferay.portal.kernel.search.Field;
022    import com.liferay.portal.kernel.search.Indexer;
023    import com.liferay.portal.kernel.search.Query;
024    import com.liferay.portal.kernel.search.SearchContext;
025    import com.liferay.portal.kernel.search.filter.BooleanFilter;
026    import com.liferay.portal.kernel.search.filter.TermsFilter;
027    import com.liferay.portal.kernel.util.ArrayUtil;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.security.permission.PermissionChecker;
030    import com.liferay.portal.security.permission.PermissionThreadLocal;
031    import com.liferay.portal.util.PortalUtil;
032    import com.liferay.portal.util.PropsValues;
033    import com.liferay.portlet.asset.model.AssetCategory;
034    import com.liferay.portlet.asset.service.AssetCategoryLocalServiceUtil;
035    import com.liferay.portlet.asset.service.persistence.AssetEntryQuery;
036    
037    import java.util.ArrayList;
038    import java.util.Collections;
039    import java.util.List;
040    import java.util.Map;
041    
042    /**
043     * @author Eudaldo Alonso
044     */
045    public class AssetSearcher extends BaseSearcher {
046    
047            public static Indexer<?> getInstance() {
048                    return new AssetSearcher();
049            }
050    
051            public AssetSearcher() {
052                    setDefaultSelectedFieldNames(
053                            Field.ENTRY_CLASS_NAME, Field.ENTRY_CLASS_PK, Field.UID);
054                    setFilterSearch(true);
055                    setPermissionAware(true);
056            }
057    
058            @Override
059            public String[] getSearchClassNames() {
060                    long[] classNameIds = _assetEntryQuery.getClassNameIds();
061    
062                    String[] classNames = new String[classNameIds.length];
063    
064                    for (int i = 0; i < classNames.length; i++) {
065                            long classNameId = classNameIds[i];
066    
067                            classNames[i] = PortalUtil.getClassName(classNameId);
068                    }
069    
070                    return classNames;
071            }
072    
073            public void setAssetEntryQuery(AssetEntryQuery assetEntryQuery) {
074                    _assetEntryQuery = assetEntryQuery;
075            }
076    
077            protected void addImpossibleTerm(
078                            BooleanFilter queryBooleanFilter, String field)
079                    throws Exception {
080    
081                    queryBooleanFilter.addTerm(field, "-1", BooleanClauseOccur.MUST);
082            }
083    
084            protected void addSearchAllCategories(BooleanFilter queryBooleanFilter)
085                    throws Exception {
086    
087                    PermissionChecker permissionChecker =
088                            PermissionThreadLocal.getPermissionChecker();
089    
090                    long[] allCategoryIds = _assetEntryQuery.getAllCategoryIds();
091    
092                    if (allCategoryIds.length == 0) {
093                            return;
094                    }
095    
096                    long[] filteredAllCategoryIds = AssetUtil.filterCategoryIds(
097                            permissionChecker, allCategoryIds);
098    
099                    if (allCategoryIds.length != filteredAllCategoryIds.length) {
100                            addImpossibleTerm(queryBooleanFilter, Field.ASSET_CATEGORY_IDS);
101    
102                            return;
103                    }
104    
105                    BooleanFilter categoryIdsBooleanFilter = new BooleanFilter();
106    
107                    for (long allCategoryId : filteredAllCategoryIds) {
108                            AssetCategory assetCategory =
109                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(allCategoryId);
110    
111                            if (assetCategory == null) {
112                                    continue;
113                            }
114    
115                            List<Long> categoryIds = new ArrayList<>();
116    
117                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
118                                    categoryIds.addAll(
119                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
120                                                    allCategoryId));
121                            }
122    
123                            if (categoryIds.isEmpty()) {
124                                    categoryIds.add(allCategoryId);
125                            }
126    
127                            TermsFilter categoryIdTermsFilter = new TermsFilter(
128                                    Field.ASSET_CATEGORY_IDS);
129    
130                            categoryIdTermsFilter.addValues(
131                                    ArrayUtil.toStringArray(
132                                            categoryIds.toArray(new Long[categoryIds.size()])));
133    
134                            categoryIdsBooleanFilter.add(
135                                    categoryIdTermsFilter, BooleanClauseOccur.MUST);
136                    }
137    
138                    queryBooleanFilter.add(
139                            categoryIdsBooleanFilter, BooleanClauseOccur.MUST);
140            }
141    
142            protected void addSearchAllTags(BooleanFilter queryBooleanFilter)
143                    throws Exception {
144    
145                    long[][] allTagIdsArray = _assetEntryQuery.getAllTagIdsArray();
146    
147                    if (allTagIdsArray.length == 0) {
148                            return;
149                    }
150    
151                    BooleanFilter tagIdsArrayBooleanFilter = new BooleanFilter();
152    
153                    for (long[] allTagIds : allTagIdsArray) {
154                            if (allTagIds.length == 0) {
155                                    continue;
156                            }
157    
158                            TermsFilter tagIdsTermsFilter = new TermsFilter(
159                                    Field.ASSET_TAG_IDS);
160    
161                            tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(allTagIds));
162    
163                            tagIdsArrayBooleanFilter.add(
164                                    tagIdsTermsFilter, BooleanClauseOccur.MUST);
165                    }
166    
167                    queryBooleanFilter.add(
168                            tagIdsArrayBooleanFilter, BooleanClauseOccur.MUST);
169            }
170    
171            protected void addSearchAnyCategories(BooleanFilter queryBooleanFilter)
172                    throws Exception {
173    
174                    PermissionChecker permissionChecker =
175                            PermissionThreadLocal.getPermissionChecker();
176    
177                    long[] anyCategoryIds = _assetEntryQuery.getAnyCategoryIds();
178    
179                    if (anyCategoryIds.length == 0) {
180                            return;
181                    }
182    
183                    long[] filteredAnyCategoryIds = AssetUtil.filterCategoryIds(
184                            permissionChecker, anyCategoryIds);
185    
186                    if (filteredAnyCategoryIds.length == 0) {
187                            addImpossibleTerm(queryBooleanFilter, Field.ASSET_CATEGORY_IDS);
188    
189                            return;
190                    }
191    
192                    TermsFilter categoryIdsTermsFilter = new TermsFilter(
193                            Field.ASSET_CATEGORY_IDS);
194    
195                    for (long anyCategoryId : filteredAnyCategoryIds) {
196                            AssetCategory assetCategory =
197                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(anyCategoryId);
198    
199                            if (assetCategory == null) {
200                                    continue;
201                            }
202    
203                            List<Long> categoryIds = new ArrayList<>();
204    
205                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
206                                    categoryIds.addAll(
207                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
208                                                    anyCategoryId));
209                            }
210    
211                            if (categoryIds.isEmpty()) {
212                                    categoryIds.add(anyCategoryId);
213                            }
214    
215                            categoryIdsTermsFilter.addValues(
216                                    ArrayUtil.toStringArray(
217                                            categoryIds.toArray(new Long[categoryIds.size()])));
218                    }
219    
220                    queryBooleanFilter.add(categoryIdsTermsFilter, BooleanClauseOccur.MUST);
221            }
222    
223            protected void addSearchAnyTags(BooleanFilter queryBooleanFilter)
224                    throws Exception {
225    
226                    long[] anyTagIds = _assetEntryQuery.getAnyTagIds();
227    
228                    if (anyTagIds.length == 0) {
229                            return;
230                    }
231    
232                    TermsFilter tagIdsTermsFilter = new TermsFilter(Field.ASSET_TAG_IDS);
233    
234                    tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(anyTagIds));
235    
236                    queryBooleanFilter.add(tagIdsTermsFilter, BooleanClauseOccur.MUST);
237            }
238    
239            @Override
240            protected void addSearchAssetCategoryIds(
241                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
242                    throws Exception {
243    
244                    addSearchAllCategories(queryBooleanFilter);
245                    addSearchAnyCategories(queryBooleanFilter);
246                    addSearchNotAnyCategories(queryBooleanFilter);
247                    addSearchNotAllCategories(queryBooleanFilter);
248            }
249    
250            @Override
251            protected void addSearchAssetTagNames(
252                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
253                    throws Exception {
254    
255                    addSearchAllTags(queryBooleanFilter);
256                    addSearchAnyTags(queryBooleanFilter);
257                    addSearchNotAllTags(queryBooleanFilter);
258                    addSearchNotAnyTags(queryBooleanFilter);
259            }
260    
261            @Override
262            protected Map<String, Query> addSearchKeywords(
263                            BooleanQuery searchQuery, SearchContext searchContext)
264                    throws Exception {
265    
266                    String keywords = searchContext.getKeywords();
267    
268                    if (Validator.isNull(keywords)) {
269                            return Collections.emptyMap();
270                    }
271    
272                    Map<String, Query> queries = super.addSearchKeywords(
273                            searchQuery, searchContext);
274    
275                    String field = DocumentImpl.getLocalizedName(
276                            searchContext.getLocale(), "localized_title");
277    
278                    Query query = searchQuery.addTerm(field, keywords, true);
279    
280                    queries.put(field, query);
281    
282                    return queries;
283            }
284    
285            @Override
286            protected void addSearchLayout(
287                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
288                    throws Exception {
289    
290                    String layoutUuid = (String)searchContext.getAttribute(
291                            Field.LAYOUT_UUID);
292    
293                    if (Validator.isNotNull(layoutUuid)) {
294                            queryBooleanFilter.addRequiredTerm(Field.LAYOUT_UUID, layoutUuid);
295                    }
296            }
297    
298            protected void addSearchNotAllCategories(BooleanFilter queryBooleanFilter)
299                    throws Exception {
300    
301                    long[] notAllCategoryIds = _assetEntryQuery.getNotAllCategoryIds();
302    
303                    if (notAllCategoryIds.length == 0) {
304                            return;
305                    }
306    
307                    BooleanFilter categoryIdsBooleanFilter = new BooleanFilter();
308    
309                    for (long notAllCategoryId : notAllCategoryIds) {
310                            AssetCategory assetCategory =
311                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(
312                                            notAllCategoryId);
313    
314                            if (assetCategory == null) {
315                                    continue;
316                            }
317    
318                            List<Long> categoryIds = new ArrayList<>();
319    
320                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
321                                    categoryIds.addAll(
322                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
323                                                    notAllCategoryId));
324                            }
325    
326                            if (categoryIds.isEmpty()) {
327                                    categoryIds.add(notAllCategoryId);
328                            }
329    
330                            TermsFilter categoryIdTermsFilter = new TermsFilter(
331                                    Field.ASSET_CATEGORY_IDS);
332    
333                            categoryIdTermsFilter.addValues(
334                                    ArrayUtil.toStringArray(
335                                            categoryIds.toArray(new Long[categoryIds.size()])));
336    
337                            categoryIdsBooleanFilter.add(
338                                    categoryIdTermsFilter, BooleanClauseOccur.MUST);
339                    }
340    
341                    queryBooleanFilter.add(
342                            categoryIdsBooleanFilter, BooleanClauseOccur.MUST_NOT);
343            }
344    
345            protected void addSearchNotAllTags(BooleanFilter queryBooleanFilter)
346                    throws Exception {
347    
348                    long[][] notAllTagIdsArray = _assetEntryQuery.getNotAllTagIdsArray();
349    
350                    if (notAllTagIdsArray.length == 0) {
351                            return;
352                    }
353    
354                    BooleanFilter tagIdsArrayBooleanFilter = new BooleanFilter();
355    
356                    for (long[] notAllTagIds : notAllTagIdsArray) {
357                            if (notAllTagIds.length == 0) {
358                                    continue;
359                            }
360    
361                            TermsFilter tagIdsTermsFilter = new TermsFilter(
362                                    Field.ASSET_TAG_IDS);
363    
364                            tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(notAllTagIds));
365    
366                            tagIdsArrayBooleanFilter.add(
367                                    tagIdsTermsFilter, BooleanClauseOccur.MUST);
368                    }
369    
370                    queryBooleanFilter.add(
371                            tagIdsArrayBooleanFilter, BooleanClauseOccur.MUST_NOT);
372            }
373    
374            protected void addSearchNotAnyCategories(BooleanFilter queryBooleanFilter)
375                    throws Exception {
376    
377                    long[] notAnyCategoryIds = _assetEntryQuery.getNotAnyCategoryIds();
378    
379                    if (notAnyCategoryIds.length == 0) {
380                            return;
381                    }
382    
383                    TermsFilter categoryIdsTermsFilter = new TermsFilter(
384                            Field.ASSET_CATEGORY_IDS);
385    
386                    for (long notAnyCategoryId : notAnyCategoryIds) {
387                            AssetCategory assetCategory =
388                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(
389                                            notAnyCategoryId);
390    
391                            if (assetCategory == null) {
392                                    continue;
393                            }
394    
395                            List<Long> categoryIds = new ArrayList<>();
396    
397                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
398                                    categoryIds.addAll(
399                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
400                                                    notAnyCategoryId));
401                            }
402    
403                            if (categoryIds.isEmpty()) {
404                                    categoryIds.add(notAnyCategoryId);
405                            }
406    
407                            categoryIdsTermsFilter.addValues(
408                                    ArrayUtil.toStringArray(
409                                            categoryIds.toArray(new Long[categoryIds.size()])));
410                    }
411    
412                    queryBooleanFilter.add(
413                            categoryIdsTermsFilter, BooleanClauseOccur.MUST_NOT);
414            }
415    
416            protected void addSearchNotAnyTags(BooleanFilter queryBooleanFilter)
417                    throws Exception {
418    
419                    long[] notAnyTagIds = _assetEntryQuery.getNotAnyTagIds();
420    
421                    if (notAnyTagIds.length == 0) {
422                            return;
423                    }
424    
425                    TermsFilter tagIgsTermsFilter = new TermsFilter(Field.ASSET_TAG_IDS);
426    
427                    tagIgsTermsFilter.addValues(ArrayUtil.toStringArray(notAnyTagIds));
428    
429                    queryBooleanFilter.add(tagIgsTermsFilter, BooleanClauseOccur.MUST_NOT);
430            }
431    
432            @Override
433            protected void postProcessFullQuery(
434                            BooleanQuery fullQuery, SearchContext searchContext)
435                    throws Exception {
436    
437                    BooleanFilter booleanFilter = fullQuery.getPreBooleanFilter();
438    
439                    if (booleanFilter == null) {
440                            booleanFilter = new BooleanFilter();
441                    }
442    
443                    booleanFilter.addRequiredTerm("visible", true);
444    
445                    if (booleanFilter.hasClauses()) {
446                            fullQuery.setPreBooleanFilter(booleanFilter);
447                    }
448            }
449    
450            private AssetEntryQuery _assetEntryQuery;
451    
452    }