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                    PermissionChecker permissionChecker =
146                            PermissionThreadLocal.getPermissionChecker();
147    
148                    long[][] allTagIdsArray = _assetEntryQuery.getAllTagIdsArray();
149    
150                    if (allTagIdsArray.length == 0) {
151                            return;
152                    }
153    
154                    BooleanFilter tagIdsArrayBooleanFilter = new BooleanFilter();
155    
156                    for (long[] allTagIds : allTagIdsArray) {
157                            if (allTagIds.length == 0) {
158                                    continue;
159                            }
160    
161                            long[] filteredAllTagIds = AssetUtil.filterTagIds(
162                                    permissionChecker, allTagIds);
163    
164                            if (allTagIds.length != filteredAllTagIds.length) {
165                                    addImpossibleTerm(queryBooleanFilter, Field.ASSET_TAG_IDS);
166    
167                                    return;
168                            }
169    
170                            TermsFilter tagIdsTermsFilter = new TermsFilter(
171                                    Field.ASSET_TAG_IDS);
172    
173                            tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(allTagIds));
174    
175                            tagIdsArrayBooleanFilter.add(
176                                    tagIdsTermsFilter, BooleanClauseOccur.MUST);
177                    }
178    
179                    queryBooleanFilter.add(
180                            tagIdsArrayBooleanFilter, BooleanClauseOccur.MUST);
181            }
182    
183            protected void addSearchAnyCategories(BooleanFilter queryBooleanFilter)
184                    throws Exception {
185    
186                    PermissionChecker permissionChecker =
187                            PermissionThreadLocal.getPermissionChecker();
188    
189                    long[] anyCategoryIds = _assetEntryQuery.getAnyCategoryIds();
190    
191                    if (anyCategoryIds.length == 0) {
192                            return;
193                    }
194    
195                    long[] filteredAnyCategoryIds = AssetUtil.filterCategoryIds(
196                            permissionChecker, anyCategoryIds);
197    
198                    if (filteredAnyCategoryIds.length == 0) {
199                            addImpossibleTerm(queryBooleanFilter, Field.ASSET_CATEGORY_IDS);
200    
201                            return;
202                    }
203    
204                    TermsFilter categoryIdsTermsFilter = new TermsFilter(
205                            Field.ASSET_CATEGORY_IDS);
206    
207                    for (long anyCategoryId : filteredAnyCategoryIds) {
208                            AssetCategory assetCategory =
209                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(anyCategoryId);
210    
211                            if (assetCategory == null) {
212                                    continue;
213                            }
214    
215                            List<Long> categoryIds = new ArrayList<>();
216    
217                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
218                                    categoryIds.addAll(
219                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
220                                                    anyCategoryId));
221                            }
222    
223                            if (categoryIds.isEmpty()) {
224                                    categoryIds.add(anyCategoryId);
225                            }
226    
227                            categoryIdsTermsFilter.addValues(
228                                    ArrayUtil.toStringArray(
229                                            categoryIds.toArray(new Long[categoryIds.size()])));
230                    }
231    
232                    queryBooleanFilter.add(categoryIdsTermsFilter, BooleanClauseOccur.MUST);
233            }
234    
235            protected void addSearchAnyTags(BooleanFilter queryBooleanFilter)
236                    throws Exception {
237    
238                    PermissionChecker permissionChecker =
239                            PermissionThreadLocal.getPermissionChecker();
240    
241                    long[] anyTagIds = _assetEntryQuery.getAnyTagIds();
242    
243                    if (anyTagIds.length == 0) {
244                            return;
245                    }
246    
247                    long[] filteredAnyTagIds = AssetUtil.filterTagIds(
248                            permissionChecker, anyTagIds);
249    
250                    if (filteredAnyTagIds.length == 0) {
251                            addImpossibleTerm(queryBooleanFilter, Field.ASSET_TAG_IDS);
252    
253                            return;
254                    }
255    
256                    TermsFilter tagIdsTermsFilter = new TermsFilter(Field.ASSET_TAG_IDS);
257    
258                    tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(anyTagIds));
259    
260                    queryBooleanFilter.add(tagIdsTermsFilter, BooleanClauseOccur.MUST);
261            }
262    
263            @Override
264            protected void addSearchAssetCategoryIds(
265                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
266                    throws Exception {
267    
268                    addSearchAllCategories(queryBooleanFilter);
269                    addSearchAnyCategories(queryBooleanFilter);
270                    addSearchNotAnyCategories(queryBooleanFilter);
271                    addSearchNotAllCategories(queryBooleanFilter);
272            }
273    
274            @Override
275            protected void addSearchAssetTagNames(
276                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
277                    throws Exception {
278    
279                    addSearchAllTags(queryBooleanFilter);
280                    addSearchAnyTags(queryBooleanFilter);
281                    addSearchNotAllTags(queryBooleanFilter);
282                    addSearchNotAnyTags(queryBooleanFilter);
283            }
284    
285            @Override
286            protected Map<String, Query> addSearchKeywords(
287                            BooleanQuery searchQuery, SearchContext searchContext)
288                    throws Exception {
289    
290                    String keywords = searchContext.getKeywords();
291    
292                    if (Validator.isNull(keywords)) {
293                            return Collections.emptyMap();
294                    }
295    
296                    Map<String, Query> queries = super.addSearchKeywords(
297                            searchQuery, searchContext);
298    
299                    String field = DocumentImpl.getLocalizedName(
300                            searchContext.getLocale(), "localized_title");
301    
302                    Query query = searchQuery.addTerm(field, keywords, true);
303    
304                    queries.put(field, query);
305    
306                    return queries;
307            }
308    
309            @Override
310            protected void addSearchLayout(
311                            BooleanFilter queryBooleanFilter, SearchContext searchContext)
312                    throws Exception {
313    
314                    String layoutUuid = (String)searchContext.getAttribute(
315                            Field.LAYOUT_UUID);
316    
317                    if (Validator.isNotNull(layoutUuid)) {
318                            queryBooleanFilter.addRequiredTerm(Field.LAYOUT_UUID, layoutUuid);
319                    }
320            }
321    
322            protected void addSearchNotAllCategories(BooleanFilter queryBooleanFilter)
323                    throws Exception {
324    
325                    long[] notAllCategoryIds = _assetEntryQuery.getNotAllCategoryIds();
326    
327                    if (notAllCategoryIds.length == 0) {
328                            return;
329                    }
330    
331                    BooleanFilter categoryIdsBooleanFilter = new BooleanFilter();
332    
333                    for (long notAllCategoryId : notAllCategoryIds) {
334                            AssetCategory assetCategory =
335                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(
336                                            notAllCategoryId);
337    
338                            if (assetCategory == null) {
339                                    continue;
340                            }
341    
342                            List<Long> categoryIds = new ArrayList<>();
343    
344                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
345                                    categoryIds.addAll(
346                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
347                                                    notAllCategoryId));
348                            }
349    
350                            if (categoryIds.isEmpty()) {
351                                    categoryIds.add(notAllCategoryId);
352                            }
353    
354                            TermsFilter categoryIdTermsFilter = new TermsFilter(
355                                    Field.ASSET_CATEGORY_IDS);
356    
357                            categoryIdTermsFilter.addValues(
358                                    ArrayUtil.toStringArray(
359                                            categoryIds.toArray(new Long[categoryIds.size()])));
360    
361                            categoryIdsBooleanFilter.add(
362                                    categoryIdTermsFilter, BooleanClauseOccur.MUST);
363                    }
364    
365                    queryBooleanFilter.add(
366                            categoryIdsBooleanFilter, BooleanClauseOccur.MUST_NOT);
367            }
368    
369            protected void addSearchNotAllTags(BooleanFilter queryBooleanFilter)
370                    throws Exception {
371    
372                    long[][] notAllTagIdsArray = _assetEntryQuery.getNotAllTagIdsArray();
373    
374                    if (notAllTagIdsArray.length == 0) {
375                            return;
376                    }
377    
378                    BooleanFilter tagIdsArrayBooleanFilter = new BooleanFilter();
379    
380                    for (long[] notAllTagIds : notAllTagIdsArray) {
381                            if (notAllTagIds.length == 0) {
382                                    continue;
383                            }
384    
385                            TermsFilter tagIdsTermsFilter = new TermsFilter(
386                                    Field.ASSET_TAG_IDS);
387    
388                            tagIdsTermsFilter.addValues(ArrayUtil.toStringArray(notAllTagIds));
389    
390                            tagIdsArrayBooleanFilter.add(
391                                    tagIdsTermsFilter, BooleanClauseOccur.MUST);
392                    }
393    
394                    queryBooleanFilter.add(
395                            tagIdsArrayBooleanFilter, BooleanClauseOccur.MUST_NOT);
396            }
397    
398            protected void addSearchNotAnyCategories(BooleanFilter queryBooleanFilter)
399                    throws Exception {
400    
401                    long[] notAnyCategoryIds = _assetEntryQuery.getNotAnyCategoryIds();
402    
403                    if (notAnyCategoryIds.length == 0) {
404                            return;
405                    }
406    
407                    TermsFilter categoryIdsTermsFilter = new TermsFilter(
408                            Field.ASSET_CATEGORY_IDS);
409    
410                    for (long notAnyCategoryId : notAnyCategoryIds) {
411                            AssetCategory assetCategory =
412                                    AssetCategoryLocalServiceUtil.fetchAssetCategory(
413                                            notAnyCategoryId);
414    
415                            if (assetCategory == null) {
416                                    continue;
417                            }
418    
419                            List<Long> categoryIds = new ArrayList<>();
420    
421                            if (PropsValues.ASSET_CATEGORIES_SEARCH_HIERARCHICAL) {
422                                    categoryIds.addAll(
423                                            AssetCategoryLocalServiceUtil.getSubcategoryIds(
424                                                    notAnyCategoryId));
425                            }
426    
427                            if (categoryIds.isEmpty()) {
428                                    categoryIds.add(notAnyCategoryId);
429                            }
430    
431                            categoryIdsTermsFilter.addValues(
432                                    ArrayUtil.toStringArray(
433                                            categoryIds.toArray(new Long[categoryIds.size()])));
434                    }
435    
436                    queryBooleanFilter.add(
437                            categoryIdsTermsFilter, BooleanClauseOccur.MUST_NOT);
438            }
439    
440            protected void addSearchNotAnyTags(BooleanFilter queryBooleanFilter)
441                    throws Exception {
442    
443                    long[] notAnyTagIds = _assetEntryQuery.getNotAnyTagIds();
444    
445                    if (notAnyTagIds.length == 0) {
446                            return;
447                    }
448    
449                    TermsFilter tagIgsTermsFilter = new TermsFilter(Field.ASSET_TAG_IDS);
450    
451                    tagIgsTermsFilter.addValues(ArrayUtil.toStringArray(notAnyTagIds));
452    
453                    queryBooleanFilter.add(tagIgsTermsFilter, BooleanClauseOccur.MUST_NOT);
454            }
455    
456            @Override
457            protected void postProcessFullQuery(
458                            BooleanQuery fullQuery, SearchContext searchContext)
459                    throws Exception {
460    
461                    BooleanFilter booleanFilter = fullQuery.getPreBooleanFilter();
462    
463                    if (booleanFilter == null) {
464                            booleanFilter = new BooleanFilter();
465                    }
466    
467                    booleanFilter.addRequiredTerm("visible", true);
468    
469                    if (booleanFilter.hasClauses()) {
470                            fullQuery.setPreBooleanFilter(booleanFilter);
471                    }
472            }
473    
474            private AssetEntryQuery _assetEntryQuery;
475    
476    }