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