001    /**
002     * Copyright (c) 2000-2013 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.portal.kernel.search;
016    
017    import com.liferay.portal.kernel.search.facet.Facet;
018    import com.liferay.portal.kernel.util.GetterUtil;
019    import com.liferay.portal.kernel.util.SetUtil;
020    import com.liferay.portal.kernel.util.UnicodeProperties;
021    import com.liferay.portal.kernel.util.Validator;
022    import com.liferay.portal.security.permission.PermissionChecker;
023    import com.liferay.portal.security.permission.PermissionThreadLocal;
024    import com.liferay.portlet.expando.model.ExpandoBridge;
025    import com.liferay.portlet.expando.model.ExpandoColumnConstants;
026    import com.liferay.portlet.expando.util.ExpandoBridgeFactoryUtil;
027    import com.liferay.portlet.expando.util.ExpandoBridgeIndexerUtil;
028    
029    import java.util.Locale;
030    import java.util.Map;
031    import java.util.Set;
032    
033    import javax.portlet.PortletURL;
034    
035    /**
036     * @author Raymond Aug??
037     */
038    public class FacetedSearcher extends BaseIndexer {
039    
040            public static Indexer getInstance() {
041                    return new FacetedSearcher();
042            }
043    
044            @Override
045            public String[] getClassNames() {
046                    return null;
047            }
048    
049            @Override
050            public IndexerPostProcessor[] getIndexerPostProcessors() {
051                    throw new UnsupportedOperationException();
052            }
053    
054            @Override
055            public String getPortletId() {
056                    return null;
057            }
058    
059            @Override
060            public void registerIndexerPostProcessor(
061                    IndexerPostProcessor indexerPostProcessor) {
062    
063                    throw new UnsupportedOperationException();
064            }
065    
066            @Override
067            public Hits search(SearchContext searchContext) throws SearchException {
068                    try {
069                            searchContext.setSearchEngineId(getSearchEngineId());
070    
071                            BooleanQuery contextQuery = BooleanQueryFactoryUtil.create(
072                                    searchContext);
073    
074                            contextQuery.addRequiredTerm(
075                                    Field.COMPANY_ID, searchContext.getCompanyId());
076    
077                            BooleanQuery fullQuery = createFullQuery(
078                                    contextQuery, searchContext);
079    
080                            fullQuery.setQueryConfig(searchContext.getQueryConfig());
081    
082                            PermissionChecker permissionChecker =
083                                    PermissionThreadLocal.getPermissionChecker();
084    
085                            int end = searchContext.getEnd();
086                            int start = searchContext.getStart();
087    
088                            if (isFilterSearch(searchContext) && (permissionChecker != null)) {
089                                    searchContext.setEnd(end + INDEX_FILTER_SEARCH_LIMIT);
090                                    searchContext.setStart(0);
091                            }
092    
093                            Hits hits = SearchEngineUtil.search(searchContext, fullQuery);
094    
095                            searchContext.setEnd(end);
096                            searchContext.setStart(start);
097    
098                            if (isFilterSearch(searchContext) && (permissionChecker != null)) {
099                                    hits = filterSearch(hits, permissionChecker, searchContext);
100                            }
101    
102                            processHits(searchContext, hits);
103    
104                            return hits;
105                    }
106                    catch (SearchException se) {
107                            throw se;
108                    }
109                    catch (Exception e) {
110                            throw new SearchException(e);
111                    }
112            }
113    
114            @Override
115            public void unregisterIndexerPostProcessor(
116                    IndexerPostProcessor indexerPostProcessor) {
117    
118                    throw new UnsupportedOperationException();
119            }
120    
121            protected void addSearchExpandoKeywords(
122                            BooleanQuery searchQuery, SearchContext searchContext,
123                            String keywords, String className)
124                    throws Exception {
125    
126                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
127                            searchContext.getCompanyId(), className);
128    
129                    Set<String> attributeNames = SetUtil.fromEnumeration(
130                            expandoBridge.getAttributeNames());
131    
132                    for (String attributeName : attributeNames) {
133                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
134                                    attributeName);
135    
136                            int indexType = GetterUtil.getInteger(
137                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
138    
139                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
140                                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
141                                            attributeName);
142    
143                                    if (searchContext.isAndSearch()) {
144                                            searchQuery.addRequiredTerm(fieldName, keywords);
145                                    }
146                                    else {
147                                            searchQuery.addTerm(fieldName, keywords);
148                                    }
149                            }
150                    }
151            }
152    
153            @Override
154            protected BooleanQuery createFullQuery(
155                            BooleanQuery contextQuery, SearchContext searchContext)
156                    throws Exception {
157    
158                    BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
159                            searchContext);
160    
161                    String keywords = searchContext.getKeywords();
162    
163                    if (Validator.isNotNull(keywords)) {
164                            addSearchLocalizedTerm(
165                                    searchQuery, searchContext, Field.ASSET_CATEGORY_TITLES, false);
166    
167                            searchQuery.addExactTerm(Field.ASSET_TAG_NAMES, keywords);
168                            searchQuery.addTerms(Field.KEYWORDS, keywords);
169    
170                            int groupId = GetterUtil.getInteger(
171                                    searchContext.getAttribute(Field.GROUP_ID));
172    
173                            if (groupId == 0) {
174                                    searchQuery.addTerm(
175                                            Field.STAGING_GROUP, "true", false,
176                                            BooleanClauseOccur.MUST_NOT);
177                            }
178                    }
179    
180                    for (String entryClassName : searchContext.getEntryClassNames()) {
181                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
182    
183                            if (indexer == null) {
184                                    continue;
185                            }
186    
187                            String searchEngineId = searchContext.getSearchEngineId();
188    
189                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
190                                    continue;
191                            }
192    
193                            if (Validator.isNotNull(keywords)) {
194                                    addSearchExpandoKeywords(
195                                            searchQuery, searchContext, keywords, entryClassName);
196                            }
197    
198                            indexer.postProcessSearchQuery(searchQuery, searchContext);
199    
200                            for (IndexerPostProcessor indexerPostProcessor :
201                                            indexer.getIndexerPostProcessors()) {
202    
203                                    indexerPostProcessor.postProcessSearchQuery(
204                                            searchQuery, searchContext);
205                            }
206                    }
207    
208                    Map<String, Facet> facets = searchContext.getFacets();
209    
210                    for (Facet facet : facets.values()) {
211                            BooleanClause facetClause = facet.getFacetClause();
212    
213                            if (facetClause != null) {
214                                    contextQuery.add(
215                                            facetClause.getQuery(),
216                                            facetClause.getBooleanClauseOccur());
217                            }
218                    }
219    
220                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
221    
222                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
223    
224                    if (searchQuery.hasClauses()) {
225                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
226                    }
227    
228                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
229    
230                    if (booleanClauses != null) {
231                            for (BooleanClause booleanClause : booleanClauses) {
232                                    fullQuery.add(
233                                            booleanClause.getQuery(),
234                                            booleanClause.getBooleanClauseOccur());
235                            }
236                    }
237    
238                    for (String entryClassName : searchContext.getEntryClassNames()) {
239                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
240    
241                            if (indexer == null) {
242                                    continue;
243                            }
244    
245                            String searchEngineId = searchContext.getSearchEngineId();
246    
247                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
248                                    continue;
249                            }
250    
251                            for (IndexerPostProcessor indexerPostProcessor :
252                                            indexer.getIndexerPostProcessors()) {
253    
254                                    indexerPostProcessor.postProcessFullQuery(
255                                            fullQuery, searchContext);
256                            }
257                    }
258    
259                    return fullQuery;
260            }
261    
262            @Override
263            protected void doDelete(Object obj) throws Exception {
264                    throw new UnsupportedOperationException();
265            }
266    
267            @Override
268            protected Document doGetDocument(Object obj) throws Exception {
269                    throw new UnsupportedOperationException();
270            }
271    
272            @Override
273            protected Summary doGetSummary(
274                            Document document, Locale locale, String snippet,
275                            PortletURL portletURL)
276                    throws Exception {
277    
278                    throw new UnsupportedOperationException();
279            }
280    
281            @Override
282            protected void doReindex(Object obj) throws Exception {
283                    throw new UnsupportedOperationException();
284            }
285    
286            @Override
287            protected void doReindex(String className, long classPK) throws Exception {
288                    throw new UnsupportedOperationException();
289            }
290    
291            @Override
292            protected void doReindex(String[] ids) throws Exception {
293                    throw new UnsupportedOperationException();
294            }
295    
296            @Override
297            protected String getPortletId(SearchContext searchContext) {
298                    return null;
299            }
300    
301            protected boolean isFilterSearch(SearchContext searchContext) {
302                    if (searchContext.getEntryClassNames() == null) {
303                            return super.isFilterSearch();
304                    }
305    
306                    for (String entryClassName : searchContext.getEntryClassNames()) {
307                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
308    
309                            if (indexer == null) {
310                                    continue;
311                            }
312    
313                            if (indexer.isFilterSearch()) {
314                                    return true;
315                            }
316                    }
317    
318                    return super.isFilterSearch();
319            }
320    
321    }