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