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                            return hits;
103                    }
104                    catch (SearchException se) {
105                            throw se;
106                    }
107                    catch (Exception e) {
108                            throw new SearchException(e);
109                    }
110            }
111    
112            @Override
113            public void unregisterIndexerPostProcessor(
114                    IndexerPostProcessor indexerPostProcessor) {
115    
116                    throw new UnsupportedOperationException();
117            }
118    
119            protected void addSearchExpandoKeywords(
120                            BooleanQuery searchQuery, SearchContext searchContext,
121                            String keywords, String className)
122                    throws Exception {
123    
124                    ExpandoBridge expandoBridge = ExpandoBridgeFactoryUtil.getExpandoBridge(
125                            searchContext.getCompanyId(), className);
126    
127                    Set<String> attributeNames = SetUtil.fromEnumeration(
128                            expandoBridge.getAttributeNames());
129    
130                    for (String attributeName : attributeNames) {
131                            UnicodeProperties properties = expandoBridge.getAttributeProperties(
132                                    attributeName);
133    
134                            int indexType = GetterUtil.getInteger(
135                                    properties.getProperty(ExpandoColumnConstants.INDEX_TYPE));
136    
137                            if (indexType != ExpandoColumnConstants.INDEX_TYPE_NONE) {
138                                    String fieldName = ExpandoBridgeIndexerUtil.encodeFieldName(
139                                            attributeName);
140    
141                                    if (searchContext.isAndSearch()) {
142                                            searchQuery.addRequiredTerm(fieldName, keywords);
143                                    }
144                                    else {
145                                            searchQuery.addTerm(fieldName, keywords);
146                                    }
147                            }
148                    }
149            }
150    
151            @Override
152            protected BooleanQuery createFullQuery(
153                            BooleanQuery contextQuery, SearchContext searchContext)
154                    throws Exception {
155    
156                    BooleanQuery searchQuery = BooleanQueryFactoryUtil.create(
157                            searchContext);
158    
159                    String keywords = searchContext.getKeywords();
160    
161                    if (Validator.isNotNull(keywords)) {
162                            addSearchLocalizedTerm(
163                                    searchQuery, searchContext, Field.ASSET_CATEGORY_TITLES, false);
164    
165                            searchQuery.addExactTerm(Field.ASSET_TAG_NAMES, keywords);
166                            searchQuery.addTerms(Field.KEYWORDS, keywords);
167                    }
168    
169                    for (String entryClassName : searchContext.getEntryClassNames()) {
170                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
171    
172                            if (indexer == null) {
173                                    continue;
174                            }
175    
176                            String searchEngineId = searchContext.getSearchEngineId();
177    
178                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
179                                    continue;
180                            }
181    
182                            if (Validator.isNotNull(keywords)) {
183                                    addSearchExpandoKeywords(
184                                            searchQuery, searchContext, keywords, entryClassName);
185                            }
186    
187                            indexer.postProcessSearchQuery(searchQuery, searchContext);
188    
189                            for (IndexerPostProcessor indexerPostProcessor :
190                                            indexer.getIndexerPostProcessors()) {
191    
192                                    indexerPostProcessor.postProcessSearchQuery(
193                                            searchQuery, searchContext);
194                            }
195                    }
196    
197                    Map<String, Facet> facets = searchContext.getFacets();
198    
199                    for (Facet facet : facets.values()) {
200                            BooleanClause facetClause = facet.getFacetClause();
201    
202                            if (facetClause != null) {
203                                    contextQuery.add(
204                                            facetClause.getQuery(),
205                                            facetClause.getBooleanClauseOccur());
206                            }
207                    }
208    
209                    BooleanQuery fullQuery = BooleanQueryFactoryUtil.create(searchContext);
210    
211                    fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
212    
213                    if (searchQuery.hasClauses()) {
214                            fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
215                    }
216    
217                    BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
218    
219                    if (booleanClauses != null) {
220                            for (BooleanClause booleanClause : booleanClauses) {
221                                    fullQuery.add(
222                                            booleanClause.getQuery(),
223                                            booleanClause.getBooleanClauseOccur());
224                            }
225                    }
226    
227                    for (String entryClassName : searchContext.getEntryClassNames()) {
228                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
229    
230                            if (indexer == null) {
231                                    continue;
232                            }
233    
234                            String searchEngineId = searchContext.getSearchEngineId();
235    
236                            if (!searchEngineId.equals(indexer.getSearchEngineId())) {
237                                    continue;
238                            }
239    
240                            for (IndexerPostProcessor indexerPostProcessor :
241                                            indexer.getIndexerPostProcessors()) {
242    
243                                    indexerPostProcessor.postProcessFullQuery(
244                                            fullQuery, searchContext);
245                            }
246                    }
247    
248                    return fullQuery;
249            }
250    
251            @Override
252            protected void doDelete(Object obj) throws Exception {
253                    throw new UnsupportedOperationException();
254            }
255    
256            @Override
257            protected Document doGetDocument(Object obj) throws Exception {
258                    throw new UnsupportedOperationException();
259            }
260    
261            @Override
262            protected Summary doGetSummary(
263                            Document document, Locale locale, String snippet,
264                            PortletURL portletURL)
265                    throws Exception {
266    
267                    throw new UnsupportedOperationException();
268            }
269    
270            @Override
271            protected void doReindex(Object obj) throws Exception {
272                    throw new UnsupportedOperationException();
273            }
274    
275            @Override
276            protected void doReindex(String className, long classPK) throws Exception {
277                    throw new UnsupportedOperationException();
278            }
279    
280            @Override
281            protected void doReindex(String[] ids) throws Exception {
282                    throw new UnsupportedOperationException();
283            }
284    
285            @Override
286            protected String getPortletId(SearchContext searchContext) {
287                    return null;
288            }
289    
290            protected boolean isFilterSearch(SearchContext searchContext) {
291                    if (searchContext.getEntryClassNames() == null) {
292                            return super.isFilterSearch();
293                    }
294    
295                    for (String entryClassName : searchContext.getEntryClassNames()) {
296                            Indexer indexer = IndexerRegistryUtil.getIndexer(entryClassName);
297    
298                            if (indexer == null) {
299                                    continue;
300                            }
301    
302                            if (indexer.isFilterSearch()) {
303                                    return true;
304                            }
305                    }
306    
307                    return super.isFilterSearch();
308            }
309    
310    }