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         contextQuery.add(categoryIdsQuery, BooleanClauseOccur.MUST);
182     }
183 
184     protected void addSearchFolderIds(
185             BooleanQuery contextQuery, SearchContext searchContext)
186         throws Exception {
187 
188         long[] folderIds = searchContext.getFolderIds();
189 
190         if ((folderIds == null) || (folderIds.length == 0)) {
191             return;
192         }
193 
194         BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create();
195 
196         for (long folderId : folderIds) {
197             if (searchContext.getUserId() > 0) {
198                 try {
199                     checkSearchFolderId(folderId, searchContext);
200                 }
201                 catch (Exception e) {
202                     continue;
203                 }
204             }
205 
206             TermQuery termQuery = TermQueryFactoryUtil.create(
207                 Field.FOLDER_ID, folderId);
208 
209             folderIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
210         }
211 
212         contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
213     }
214 
215     protected void addSearchGroupId(
216             BooleanQuery contextQuery, SearchContext searchContext)
217         throws Exception {
218 
219         long groupId = searchContext.getGroupId();
220 
221         if (groupId <= 0) {
222             return;
223         }
224 
225         Group group = GroupLocalServiceUtil.getGroup(groupId);
226 
227         long parentGroupId = groupId;
228 
229         if (group.isLayout() || searchContext.isScopeStrict()) {
230             contextQuery.addRequiredTerm(Field.SCOPE_GROUP_ID, groupId);
231         }
232 
233         if (group.isLayout()) {
234             parentGroupId = group.getParentGroupId();
235         }
236 
237         contextQuery.addRequiredTerm(Field.GROUP_ID, parentGroupId);
238 
239         searchContext.setGroupId(parentGroupId);
240     }
241 
242     protected void addSearchKeywords(
243             BooleanQuery searchQuery, SearchContext searchContext)
244         throws Exception {
245 
246         String keywords = searchContext.getKeywords();
247 
248         if (Validator.isNull(keywords)) {
249             return;
250         }
251 
252         searchQuery.addTerm(Field.USER_NAME, keywords);
253         searchQuery.addTerm(Field.TITLE, keywords);
254         searchQuery.addTerm(Field.CONTENT, keywords);
255         searchQuery.addTerm(Field.DESCRIPTION, keywords);
256         searchQuery.addTerm(Field.PROPERTIES, keywords);
257         searchQuery.addTerm(Field.ASSET_TAG_NAMES, keywords, true);
258         searchQuery.addTerm(Field.URL, keywords);
259         searchQuery.addTerm(Field.COMMENTS, keywords);
260     }
261 
262     protected void addSearchNodeIds(
263             BooleanQuery contextQuery, SearchContext searchContext)
264         throws Exception {
265 
266         long[] nodeIds = searchContext.getNodeIds();
267 
268         if ((nodeIds == null) || (nodeIds.length == 0)) {
269             return;
270         }
271 
272         BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create();
273 
274         for (long nodeId : nodeIds) {
275             if (searchContext.getUserId() > 0) {
276                 try {
277                     checkSearchNodeId(nodeId, searchContext);
278                 }
279                 catch (Exception e) {
280                     continue;
281                 }
282             }
283 
284             TermQuery termQuery = TermQueryFactoryUtil.create(
285                 Field.NODE_ID, nodeId);
286 
287             nodeIdsQuery.add(termQuery, BooleanClauseOccur.SHOULD);
288         }
289 
290         contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
291     }
292 
293     protected void addSearchOwnerUserId(
294         BooleanQuery contextQuery, SearchContext searchContext) {
295 
296         long ownerUserId = searchContext.getOwnerUserId();
297 
298         if (ownerUserId > 0) {
299             contextQuery.addRequiredTerm(Field.USER_ID, ownerUserId);
300         }
301     }
302 
303     protected void checkSearchCategoryId(
304             long categoryId, SearchContext searchContext)
305         throws Exception {
306     }
307 
308     protected void checkSearchFolderId(
309             long folderId, SearchContext searchContext)
310         throws Exception {
311     }
312 
313     protected void checkSearchNodeId(
314             long nodeId, SearchContext searchContext)
315         throws Exception {
316     }
317 
318     protected BooleanQuery createFullQuery(
319             BooleanQuery contextQuery, SearchContext searchContext)
320         throws Exception {
321 
322         postProcessContextQuery(contextQuery, searchContext);
323 
324         BooleanQuery searchQuery = BooleanQueryFactoryUtil.create();
325 
326         addSearchKeywords(searchQuery, searchContext);
327         postProcessSearchQuery(searchQuery, searchContext);
328 
329         BooleanQuery fullQuery = BooleanQueryFactoryUtil.create();
330 
331         fullQuery.add(contextQuery, BooleanClauseOccur.MUST);
332 
333         if (searchQuery.clauses().size() > 0) {
334             fullQuery.add(searchQuery, BooleanClauseOccur.MUST);
335         }
336 
337         BooleanClause[] booleanClauses = searchContext.getBooleanClauses();
338 
339         if (booleanClauses != null) {
340             for (BooleanClause booleanClause : booleanClauses) {
341                 fullQuery.add(
342                     booleanClause.getQuery(),
343                     booleanClause.getBooleanClauseOccur());
344             }
345         }
346 
347         postProcessFullQuery(fullQuery, searchContext);
348 
349         return fullQuery;
350     }
351 
352     protected abstract void doDelete(Object obj) throws Exception;
353 
354     protected abstract Document doGetDocument(Object obj) throws Exception;
355 
356     protected abstract void doReindex(Object obj) throws Exception;
357 
358     protected abstract void doReindex(String className, long classPK)
359         throws Exception;
360 
361     protected abstract void doReindex(String[] ids) throws Exception;
362 
363     protected String getClassName(SearchContext searchContext) {
364         String[] classNames = getClassNames();
365 
366         if (classNames.length != 1) {
367             throw new UnsupportedOperationException(
368                 "Search method needs to be manually implemented for " +
369                     "indexers with more than one class name");
370         }
371 
372         return classNames[0];
373     }
374 
375     protected long getParentGroupId(long groupId) {
376         long parentGroupId = groupId;
377 
378         try {
379             Group group = GroupLocalServiceUtil.getGroup(groupId);
380 
381             if (group.isLayout()) {
382                 parentGroupId = group.getParentGroupId();
383             }
384         }
385         catch (Exception e) {
386         }
387 
388         return parentGroupId;
389     }
390 
391     protected abstract String getPortletId(SearchContext searchContext);
392 
393     protected void postProcessContextQuery(
394             BooleanQuery contextQuery, SearchContext searchContext)
395         throws Exception {
396     }
397 
398     protected void postProcessFullQuery(
399             BooleanQuery fullQuery, SearchContext searchContext)
400         throws Exception {
401     }
402 
403     protected void postProcessSearchQuery(
404             BooleanQuery searchQuery, SearchContext searchContext)
405         throws Exception {
406     }
407 
408     private static Log _log = LogFactoryUtil.getLog(BaseIndexer.class);
409 
410 }