1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.search;
16  
17  import com.liferay.portal.NoSuchModelException;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.search.BooleanClause;
21  import com.liferay.portal.kernel.search.BooleanClauseOccur;
22  import com.liferay.portal.kernel.search.BooleanQuery;
23  import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
24  import com.liferay.portal.kernel.search.Document;
25  import com.liferay.portal.kernel.search.Field;
26  import com.liferay.portal.kernel.search.Hits;
27  import com.liferay.portal.kernel.search.Indexer;
28  import com.liferay.portal.kernel.search.SearchContext;
29  import com.liferay.portal.kernel.search.SearchEngineUtil;
30  import com.liferay.portal.kernel.search.SearchException;
31  import com.liferay.portal.kernel.search.TermQuery;
32  import com.liferay.portal.kernel.search.TermQueryFactoryUtil;
33  import com.liferay.portal.kernel.util.Validator;
34  import com.liferay.portal.model.Group;
35  import com.liferay.portal.service.GroupLocalServiceUtil;
36  
37  /**
38   * <a href="BaseIndexer.java.html"><b><i>View Source</i></b></a>
39   *
40   * @author Brian Wing Shun Chan
41   */
42  public abstract class BaseIndexer implements Indexer {
43  
44      public void delete(Object obj) throws SearchException {
45          try {
46              doDelete(obj);
47          }
48          catch (SearchException se) {
49              throw se;
50          }
51          catch (Exception e) {
52              throw new SearchException(e);
53          }
54      }
55  
56      public Document getDocument(Object obj) throws SearchException {
57          try {
58              return doGetDocument(obj);
59          }
60          catch (SearchException se) {
61              throw se;
62          }
63          catch (Exception e) {
64              throw new SearchException(e);
65          }
66      }
67  
68      public void reindex(Object obj) throws SearchException {
69          try {
70              if (SearchEngineUtil.isIndexReadOnly()) {
71                  return;
72              }
73  
74              doReindex(obj);
75          }
76          catch (SearchException se) {
77              throw se;
78          }
79          catch (Exception e) {
80              throw new SearchException(e);
81          }
82      }
83  
84      public void reindex(String className, long classPK) throws SearchException {
85          try {
86              if (SearchEngineUtil.isIndexReadOnly()) {
87                  return;
88              }
89  
90              doReindex(className, classPK);
91          }
92          catch (NoSuchModelException nsme) {
93              if (_log.isWarnEnabled()) {
94                  _log.warn("Unable to index " + className + " " + classPK);
95              }
96          }
97          catch (SearchException se) {
98              throw se;
99          }
100         catch (Exception e) {
101             throw new SearchException(e);
102         }
103     }
104 
105     public void reindex(String[] ids) throws SearchException {
106         try {
107             if (SearchEngineUtil.isIndexReadOnly()) {
108                 return;
109             }
110 
111             doReindex(ids);
112         }
113         catch (SearchException se) {
114             throw se;
115         }
116         catch (Exception e) {
117             throw new SearchException(e);
118         }
119     }
120 
121     public Hits search(SearchContext searchContext) throws SearchException {
122         try {
123             String className = getClassName(searchContext);
124 
125             BooleanQuery contextQuery = BooleanQueryFactoryUtil.create();
126 
127             contextQuery.addRequiredTerm(
128                 Field.PORTLET_ID, getPortletId(searchContext));
129 
130             addSearchGroupId(contextQuery, searchContext);
131             addSearchOwnerUserId(contextQuery, searchContext);
132             addSearchCategoryIds(contextQuery, searchContext);
133             addSearchNodeIds(contextQuery, searchContext);
134             addSearchFolderIds(contextQuery, searchContext);
135 
136             BooleanQuery fullQuery = createFullQuery(
137                 contextQuery, searchContext);
138 
139             return SearchEngineUtil.search(
140                 searchContext.getCompanyId(), searchContext.getGroupId(),
141                 searchContext.getUserId(), className, fullQuery,
142                 searchContext.getSorts(), searchContext.getStart(),
143                 searchContext.getEnd());
144         }
145         catch (SearchException se) {
146             throw se;
147         }
148         catch (Exception e) {
149             throw new SearchException(e);
150         }
151     }
152 
153     protected void addSearchCategoryIds(
154             BooleanQuery contextQuery, SearchContext searchContext)
155         throws Exception {
156 
157         long[] categoryIds = searchContext.getCategoryIds();
158 
159         if ((categoryIds == null) || (categoryIds.length == 0)) {
160             return;
161         }
162 
163         BooleanQuery categoryIdsQuery = BooleanQueryFactoryUtil.create();
164 
165         for (long categoryId : categoryIds) {
166             if (searchContext.getUserId() > 0) {
167                 try {
168                     checkSearchCategoryId(categoryId, searchContext);
169                 }
170                 catch (Exception e) {
171                     continue;
172                 }
173             }
174 
175             TermQuery termQuery = TermQueryFactoryUtil.create(
176                 Field.CATEGORY_ID, categoryId);
177 
178             categoryIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
179         }
180 
181         if (!categoryIdsQuery.clauses().isEmpty()) {
182             contextQuery.add(categoryIdsQuery, BooleanClauseOccur.MUST);
183         }
184     }
185 
186     protected void addSearchFolderIds(
187             BooleanQuery contextQuery, SearchContext searchContext)
188         throws Exception {
189 
190         long[] folderIds = searchContext.getFolderIds();
191 
192         if ((folderIds == null) || (folderIds.length == 0)) {
193             return;
194         }
195 
196         BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create();
197 
198         for (long folderId : folderIds) {
199             if (searchContext.getUserId() > 0) {
200                 try {
201                     checkSearchFolderId(folderId, searchContext);
202                 }
203                 catch (Exception e) {
204                     continue;
205                 }
206             }
207 
208             TermQuery termQuery = TermQueryFactoryUtil.create(
209                 Field.FOLDER_ID, folderId);
210 
211             folderIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
212         }
213 
214         if (!folderIdsQuery.clauses().isEmpty()) {
215             contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
216         }
217     }
218 
219     protected void addSearchGroupId(
220             BooleanQuery contextQuery, SearchContext searchContext)
221         throws Exception {
222 
223         long groupId = searchContext.getGroupId();
224 
225         if (groupId <= 0) {
226             return;
227         }
228 
229         Group group = GroupLocalServiceUtil.getGroup(groupId);
230 
231         long parentGroupId = groupId;
232 
233         if (group.isLayout() || searchContext.isScopeStrict()) {
234             contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
235         }
236 
237         if (group.isLayout()) {
238             parentGroupId = group.getParentGroupId();
239         }
240 
241         contextQuery.addRequiredTerm(Field.GROUP_ID, parentGroupId);
242 
243         searchContext.setGroupId(parentGroupId);
244     }
245 
246     protected void addSearchKeywords(
247             BooleanQuery searchQuery, SearchContext searchContext)
248         throws Exception {
249 
250         String keywords = searchContext.getKeywords();
251 
252         if (Validator.isNull(keywords)) {
253             return;
254         }
255 
256         searchQuery.addTerm(Field.USER_NAME, keywords);
257         searchQuery.addTerm(Field.TITLE, keywords);
258         searchQuery.addTerm(Field.CONTENT, keywords);
259         searchQuery.addTerm(Field.DESCRIPTION, keywords);
260         searchQuery.addTerm(Field.PROPERTIES, keywords);
261         searchQuery.addTerm(Field.ASSET_TAG_NAMES, keywords, true);
262         searchQuery.addTerm(Field.URL, keywords);
263         searchQuery.addTerm(Field.COMMENTS, keywords);
264     }
265 
266     protected void addSearchNodeIds(
267             BooleanQuery contextQuery, SearchContext searchContext)
268         throws Exception {
269 
270         long[] nodeIds = searchContext.getNodeIds();
271 
272         if ((nodeIds == null) || (nodeIds.length == 0)) {
273             return;
274         }
275 
276         BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
277 
278         for (long nodeId : nodeIds) {
279             if (searchContext.getUserId() > 0) {
280                 try {
281                     checkSearchNodeId(nodeId, searchContext);
282                 }
283                 catch (Exception e) {
284                     continue;
285                 }
286             }
287 
288             TermQuery termQuery = TermQueryFactoryUtil.create(
289                 Field.NODE_ID, nodeId);
290 
291             nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
292         }
293 
294         if (!nodeIdsQuery.clauses().isEmpty()) {
295             contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
296         }
297     }
298 
299     protected void addSearchOwnerUserId(
300         BooleanQuery contextQuery, SearchContext searchContext) {
301 
302         long ownerUserId = searchContext.getOwnerUserId();
303 
304         if (ownerUserId > 0) {
305             contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
306         }
307     }
308 
309     protected void checkSearchCategoryId(
310             long categoryId, SearchContext searchContext)
311         throws Exception {
312     }
313 
314     protected void checkSearchFolderId(
315             long folderId, SearchContext searchContext)
316         throws Exception {
317     }
318 
319     protected void checkSearchNodeId(
320             long nodeId, SearchContext searchContext)
321         throws Exception {
322     }
323 
324     protected BooleanQuery createFullQuery(
325             BooleanQuery contextQuery, SearchContext searchContext)
326         throws Exception {
327 
328         postProcessContextQuery(contextQuery, searchContext);
329 
330         BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
331 
332         addSearchKeywords(searchQuery, searchContext);
333         postProcessSearchQuery(searchQuery, searchContext);
334 
335         BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
336 
337         fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
338 
339         if (!searchQuery.clauses().isEmpty()) {
340             fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
341         }
342 
343         BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
344 
345         if (booleanClauses != null) {
346             for (BooleanClause booleanClause : booleanClauses) {
347                 fullQuery.add(
348                     booleanClause.getQuery(),
349                     booleanClause.getBooleanClauseOccur());
350             }
351         }
352 
353         postProcessFullQuery(fullQuery, searchContext);
354 
355         return fullQuery;
356     }
357 
358     protected abstract void doDelete(Object obj) throws Exception;
359 
360     protected abstract Document doGetDocument(Object obj) throws Exception;
361 
362     protected abstract void doReindex(Object obj) throws Exception;
363 
364     protected abstract void doReindex(String className, long classPK)
365         throws Exception;
366 
367     protected abstract void doReindex(String[] ids) throws Exception;
368 
369     protected String getClassName(SearchContext searchContext) {
370         String[] classNames = getClassNames();
371 
372         if (classNames.length != 1) {
373             throw new UnsupportedOperationException(
374                 "Search method needs to be manually implemented for " +
375                     "indexers with more than one class name");
376         }
377 
378         return classNames[0];
379     }
380 
381     protected long getParentGroupId(long groupId) {
382         long parentGroupId = groupId;
383 
384         try {
385             Group group = GroupLocalServiceUtil.getGroup(groupId);
386 
387             if (group.isLayout()) {
388                 parentGroupId = group.getParentGroupId();
389             }
390         }
391         catch (Exception e) {
392         }
393 
394         return parentGroupId;
395     }
396 
397     protected abstract String getPortletId(SearchContext searchContext);
398 
399     protected void postProcessContextQuery(
400             BooleanQuery contextQuery, SearchContext searchContext)
401         throws Exception {
402     }
403 
404     protected void postProcessFullQuery(
405             BooleanQuery fullQuery, SearchContext searchContext)
406         throws Exception {
407     }
408 
409     protected void postProcessSearchQuery(
410             BooleanQuery searchQuery, SearchContext searchContext)
411         throws Exception {
412     }
413 
414     private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
415 
416 }