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    
171                    for (String entryClassName : searchContext.getEntryClassNames()) {
172                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
173    
174                            if (indexer == null) {
175                                    continue;
176                            }
177    
178                            String searchEngineId = searchContext.getSearchEngineId();
179    
180                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
181                                    continue;
182                            }
183    
184                            if (Validator.isNotNull(keywords)) {
185                                    addSearchExpandoKeywords(
186                                            searchQuery, searchContext, keywords, entryClassName);
187                            }
188    
189                            indexer.postProcessSearchQuery(searchQuery, searchContext);
190    
191                            for (IndexerPostProcessor indexerPostProcessor :
192                                            indexer.getIndexerPostProcessors()) {
193    
194                                    indexerPostProcessor.postProcessSearchQuery(
195                                            searchQuery, searchContext);
196                            }
197                    }
198    
199                    Map<String, Facet> facets = searchContext.getFacets();
200    
201                    for (Facet facet : facets.values()) {
202                            BooleanClause facetClause = facet.getFacetClause();
203    
204                            if (facetClause != null) {
205                                    contextQuery.add(
206                                            facetClause.getQuery(),
207                                            facetClause.getBooleanClauseOccur());
208                            }
209                    }
210    
211                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
212    
213                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
214    
215                    if (searchQuery.hasClauses()) {
216                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
217                    }
218    
219                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
220    
221                    if (booleanClauses != null) {
222                            for (BooleanClause booleanClause : booleanClauses) {
223                                    fullQuery.add(
224                                            booleanClause.getQuery(),
225                                            booleanClause.getBooleanClauseOccur());
226                            }
227                    }
228    
229                    for (String entryClassName : searchContext.getEntryClassNames()) {
230                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
231    
232                            if (indexer == null) {
233                                    continue;
234                            }
235    
236                            String searchEngineId = searchContext.getSearchEngineId();
237    
238                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
239                                    continue;
240                            }
241    
242                            for (IndexerPostProcessor indexerPostProcessor :
243                                            indexer.getIndexerPostProcessors()) {
244    
245                                    indexerPostProcessor.postProcessFullQuery(
246                                            fullQuery, searchContext);
247                            }
248                    }
249    
250                    return fullQuery;
251            }
252    
253            @Override
254            protected void doDelete(Object obj) throws Exception {
255                    throw new UnsupportedOperationException();
256            }
257    
258            @Override
259            protected Document doGetDocument(Object obj) throws Exception {
260                    throw new UnsupportedOperationException();
261            }
262    
263            @Override
264            protected Summary doGetSummary(
265                            Document document, Locale locale, String snippet,
266                            PortletURL portletURL)
267                    throws Exception {
268    
269                    throw new UnsupportedOperationException();
270            }
271    
272            @Override
273            protected void doReindex(Object obj) throws Exception {
274                    throw new UnsupportedOperationException();
275            }
276    
277            @Override
278            protected void doReindex(String className, long classPK) throws Exception {
279                    throw new UnsupportedOperationException();
280            }
281    
282            @Override
283            protected void doReindex(String[] ids) throws Exception {
284                    throw new UnsupportedOperationException();
285            }
286    
287            @Override
288            protected String getPortletId(SearchContext searchContext) {
289                    return null;
290            }
291    
292            protected boolean isFilterSearch(SearchContext searchContext) {
293                    if (searchContext.getEntryClassNames() == null) {
294                            return super.isFilterSearch();
295                    }
296    
297                    for (String entryClassName : searchContext.getEntryClassNames()) {
298                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
299    
300                            if (indexer == null) {
301                                    continue;
302                            }
303    
304                            if (indexer.isFilterSearch()) {
305                                    return true;
306                            }
307                    }
308    
309                    return super.isFilterSearch();
310            }
311    
312    }