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