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 start = searchContext.getStart();
084                            int end = searchContext.getEnd();
085    
086                            if (isFilterSearch(searchContext) && (permissionChecker != null)) {
087                                    searchContext.setStart(0);
088                                    searchContext.setEnd(end + INDEX_FILTER_SEARCH_LIMIT);
089                            }
090    
091                            Hits hits = SearchEngineUtil.search(searchContext, fullQuery);
092    
093                            searchContext.setStart(start);
094                            searchContext.setEnd(end);
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                            searchQuery.addExactTerm(Field.ASSET_CATEGORY_NAMES, keywords);
161                            searchQuery.addExactTerm(Field.ASSET_TAG_NAMES, keywords);
162                            searchQuery.addTerms(Field.KEYWORDS, keywords);
163                    }
164    
165                    for (String entryClassName : searchContext.getEntryClassNames()) {
166                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
167    
168                            if (indexer == null) {
169                                    continue;
170                            }
171    
172                            if (Validator.isNotNull(keywords)) {
173                                    addSearchExpandoKeywords(
174                                            searchQuery, searchContext, keywords, entryClassName);
175                            }
176    
177                            indexer.postProcessSearchQuery(searchQuery, searchContext);
178    
179                            for (IndexerPostProcessor indexerPostProcessor :
180                                            indexer.getIndexerPostProcessors()) {
181    
182                                    indexerPostProcessor.postProcessSearchQuery(
183                                            searchQuery, searchContext);
184                            }
185                    }
186    
187                    Map<String, Facet> facets = searchContext.getFacets();
188    
189                    for (Facet facet : facets.values()) {
190                            BooleanClause facetClause = facet.getFacetClause();
191    
192                            if (facetClause != null) {
193                                    contextQuery.add(
194                                            facetClause.getQuery(),
195                                            facetClause.getBooleanClauseOccur());
196                            }
197                    }
198    
199                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
200    
201                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
202    
203                    if (searchQuery.hasClauses()) {
204                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
205                    }
206    
207                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
208    
209                    if (booleanClauses != null) {
210                            for (BooleanClause booleanClause : booleanClauses) {
211                                    fullQuery.add(
212                                            booleanClause.getQuery(),
213                                            booleanClause.getBooleanClauseOccur());
214                            }
215                    }
216    
217                    for (String entryClassName : searchContext.getEntryClassNames()) {
218                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
219    
220                            if (indexer == null) {
221                                    continue;
222                            }
223    
224                            for (IndexerPostProcessor indexerPostProcessor :
225                                            indexer.getIndexerPostProcessors()) {
226    
227                                    indexerPostProcessor.postProcessFullQuery(
228                                            fullQuery, searchContext);
229                            }
230                    }
231    
232                    return fullQuery;
233            }
234    
235            @Override
236            protected void doDelete(Object obj) throws Exception {
237                    throw new UnsupportedOperationException();
238            }
239    
240            @Override
241            protected Document doGetDocument(Object obj) throws Exception {
242                    throw new UnsupportedOperationException();
243            }
244    
245            @Override
246            protected Summary doGetSummary(
247                            Document document, Locale locale, String snippet,
248                            PortletURL portletURL)
249                    throws Exception {
250    
251                    throw new UnsupportedOperationException();
252            }
253    
254            @Override
255            protected void doReindex(Object obj) throws Exception {
256                    throw new UnsupportedOperationException();
257            }
258    
259            @Override
260            protected void doReindex(String className, long classPK) throws Exception {
261                    throw new UnsupportedOperationException();
262            }
263    
264            @Override
265            protected void doReindex(String[] ids) throws Exception {
266                    throw new UnsupportedOperationException();
267            }
268    
269            @Override
270            protected String getPortletId(SearchContext searchContext) {
271                    return null;
272            }
273    
274            protected boolean isFilterSearch(SearchContext searchContext) {
275                    if (searchContext.getEntryClassNames() == null) {
276                            return super.isFilterSearch();
277                    }
278    
279                    for (String entryClassName : searchContext.getEntryClassNames()) {
280                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
281    
282                            if (indexer == null) {
283                                    continue;
284                            }
285    
286                            if (indexer.isFilterSearch()) {
287                                    return true;
288                            }
289                    }
290    
291                    return super.isFilterSearch();
292            }
293    
294    }