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.portlet.bookmarks.util;
016    
017    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
018    import com.liferay.portal.kernel.dao.orm.DynamicQueryFactoryUtil;
019    import com.liferay.portal.kernel.dao.orm.Projection;
020    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
021    import com.liferay.portal.kernel.dao.orm.ProjectionList;
022    import com.liferay.portal.kernel.dao.orm.Property;
023    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
024    import com.liferay.portal.kernel.search.BaseIndexer;
025    import com.liferay.portal.kernel.search.BooleanClauseOccur;
026    import com.liferay.portal.kernel.search.BooleanQuery;
027    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
028    import com.liferay.portal.kernel.search.Document;
029    import com.liferay.portal.kernel.search.Field;
030    import com.liferay.portal.kernel.search.SearchContext;
031    import com.liferay.portal.kernel.search.SearchEngineUtil;
032    import com.liferay.portal.kernel.search.Summary;
033    import com.liferay.portal.kernel.util.GetterUtil;
034    import com.liferay.portal.model.Group;
035    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
036    import com.liferay.portal.service.GroupLocalServiceUtil;
037    import com.liferay.portal.util.PortletKeys;
038    import com.liferay.portlet.bookmarks.model.BookmarksEntry;
039    import com.liferay.portlet.bookmarks.model.BookmarksFolder;
040    import com.liferay.portlet.bookmarks.model.BookmarksFolderConstants;
041    import com.liferay.portlet.bookmarks.service.BookmarksEntryLocalServiceUtil;
042    import com.liferay.portlet.bookmarks.service.BookmarksFolderLocalServiceUtil;
043    import com.liferay.portlet.bookmarks.service.BookmarksFolderServiceUtil;
044    
045    import java.util.ArrayList;
046    import java.util.Collection;
047    import java.util.List;
048    import java.util.Locale;
049    
050    import javax.portlet.PortletURL;
051    
052    /**
053     * @author Brian Wing Shun Chan
054     * @author Bruno Farache
055     * @author Raymond Augé
056     */
057    public class BookmarksIndexer extends BaseIndexer {
058    
059            public static final String[] CLASS_NAMES = {BookmarksEntry.class.getName()};
060    
061            public static final String PORTLET_ID = PortletKeys.BOOKMARKS;
062    
063            public BookmarksIndexer() {
064                    setPermissionAware(true);
065            }
066    
067            public String[] getClassNames() {
068                    return CLASS_NAMES;
069            }
070    
071            public String getPortletId() {
072                    return PORTLET_ID;
073            }
074    
075            @Override
076            public void postProcessContextQuery(
077                            BooleanQuery contextQuery, SearchContext searchContext)
078                    throws Exception {
079    
080                    long[] folderIds = searchContext.getFolderIds();
081    
082                    if ((folderIds != null) && (folderIds.length > 0)) {
083                            if (folderIds[0] ==
084                                            BookmarksFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
085    
086                                    return;
087                            }
088    
089                            BooleanQuery folderIdsQuery = BooleanQueryFactoryUtil.create(
090                                    searchContext);
091    
092                            for (long folderId : folderIds) {
093                                    try {
094                                            BookmarksFolderServiceUtil.getFolder(folderId);
095                                    }
096                                    catch (Exception e) {
097                                            continue;
098                                    }
099    
100                                    folderIdsQuery.addTerm(Field.FOLDER_ID, folderId);
101                            }
102    
103                            contextQuery.add(folderIdsQuery, BooleanClauseOccur.MUST);
104                    }
105            }
106    
107            protected void addReindexCriteria(
108                    DynamicQuery dynamicQuery, long companyId) {
109    
110                    Property property = PropertyFactoryUtil.forName("companyId");
111    
112                    dynamicQuery.add(property.eq(companyId));
113            }
114    
115            protected void addReindexCriteria(
116                    DynamicQuery dynamicQuery, long groupId, long folderId) {
117    
118                    Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
119    
120                    dynamicQuery.add(groupIdProperty.eq(groupId));
121    
122                    Property folderIdProperty = PropertyFactoryUtil.forName("folderId");
123    
124                    dynamicQuery.add(folderIdProperty.eq(folderId));
125            }
126    
127            @Override
128            protected void doDelete(Object obj) throws Exception {
129                    BookmarksEntry entry = (BookmarksEntry)obj;
130    
131                    deleteDocument(entry.getCompanyId(), entry.getEntryId());
132            }
133    
134            @Override
135            protected Document doGetDocument(Object obj) throws Exception {
136                    BookmarksEntry entry = (BookmarksEntry)obj;
137    
138                    Document document = getBaseModelDocument(PORTLET_ID, entry);
139    
140                    document.addText(Field.DESCRIPTION, entry.getDescription());
141                    document.addKeyword(Field.FOLDER_ID, entry.getFolderId());
142                    document.addText(Field.TITLE, entry.getName());
143                    document.addText(Field.URL, entry.getUrl());
144    
145                    return document;
146            }
147    
148            @Override
149            protected Summary doGetSummary(
150                    Document document, Locale locale, String snippet,
151                    PortletURL portletURL) {
152    
153                    String entryId = document.get(Field.ENTRY_CLASS_PK);
154    
155                    portletURL.setParameter("struts_action", "/bookmarks/view_entry");
156                    portletURL.setParameter("entryId", entryId);
157    
158                    Summary summary = createSummary(document, Field.TITLE, Field.URL);
159    
160                    summary.setPortletURL(portletURL);
161    
162                    return summary;
163            }
164    
165            @Override
166            protected void doReindex(Object obj) throws Exception {
167                    BookmarksEntry entry = (BookmarksEntry)obj;
168    
169                    Document document = getDocument(entry);
170    
171                    SearchEngineUtil.updateDocument(
172                            getSearchEngineId(), entry.getCompanyId(), document);
173            }
174    
175            @Override
176            protected void doReindex(String className, long classPK) throws Exception {
177                    BookmarksEntry entry = BookmarksEntryLocalServiceUtil.getEntry(classPK);
178    
179                    doReindex(entry);
180            }
181    
182            @Override
183            protected void doReindex(String[] ids) throws Exception {
184                    long companyId = GetterUtil.getLong(ids[0]);
185    
186                    reindexFolders(companyId);
187                    reindexRoot(companyId);
188            }
189    
190            @Override
191            protected String getPortletId(SearchContext searchContext) {
192                    return PORTLET_ID;
193            }
194    
195            protected void reindexEntries(long companyId, long groupId, long folderId)
196                    throws Exception {
197    
198                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
199                            BookmarksEntry.class, PACLClassLoaderUtil.getPortalClassLoader());
200    
201                    Projection minEntryIdProjection = ProjectionFactoryUtil.min("entryId");
202                    Projection maxEntryIdProjection = ProjectionFactoryUtil.max("entryId");
203    
204                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
205    
206                    projectionList.add(minEntryIdProjection);
207                    projectionList.add(maxEntryIdProjection);
208    
209                    dynamicQuery.setProjection(projectionList);
210    
211                    addReindexCriteria(dynamicQuery, groupId, folderId);
212    
213                    List<Object[]> results = BookmarksEntryLocalServiceUtil.dynamicQuery(
214                            dynamicQuery);
215    
216                    Object[] minAndMaxEntryIds = results.get(0);
217    
218                    if ((minAndMaxEntryIds[0] == null) || (minAndMaxEntryIds[1] == null)) {
219                            return;
220                    }
221    
222                    long minEntryId = (Long)minAndMaxEntryIds[0];
223                    long maxEntryId = (Long)minAndMaxEntryIds[1];
224    
225                    long startEntryId = minEntryId;
226                    long endEntryId = startEntryId + DEFAULT_INTERVAL;
227    
228                    while (startEntryId <= maxEntryId) {
229                            reindexEntries(
230                                    companyId, groupId, folderId, startEntryId, endEntryId);
231    
232                            startEntryId = endEntryId;
233                            endEntryId += DEFAULT_INTERVAL;
234                    }
235            }
236    
237            protected void reindexEntries(
238                            long companyId, long groupId, long folderId, long startEntryId,
239                            long endEntryId)
240                    throws Exception {
241    
242                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
243                            BookmarksEntry.class, PACLClassLoaderUtil.getPortalClassLoader());
244    
245                    Property property = PropertyFactoryUtil.forName("entryId");
246    
247                    dynamicQuery.add(property.ge(startEntryId));
248                    dynamicQuery.add(property.lt(endEntryId));
249    
250                    addReindexCriteria(dynamicQuery, groupId, folderId);
251    
252                    List<BookmarksEntry> entries =
253                            BookmarksEntryLocalServiceUtil.dynamicQuery(dynamicQuery);
254    
255                    if (entries.isEmpty()) {
256                            return;
257                    }
258    
259                    Collection<Document> documents = new ArrayList<Document>(
260                            entries.size());
261    
262                    for (BookmarksEntry entry : entries) {
263                            Document document = getDocument(entry);
264    
265                            documents.add(document);
266                    }
267    
268                    SearchEngineUtil.updateDocuments(
269                            getSearchEngineId(), companyId, documents);
270            }
271    
272            protected void reindexFolders(long companyId) throws Exception {
273                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
274                            BookmarksFolder.class, PACLClassLoaderUtil.getPortalClassLoader());
275    
276                    Projection minFolderIdProjection = ProjectionFactoryUtil.min(
277                            "folderId");
278                    Projection maxFolderIdProjection = ProjectionFactoryUtil.max(
279                            "folderId");
280    
281                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
282    
283                    projectionList.add(minFolderIdProjection);
284                    projectionList.add(maxFolderIdProjection);
285    
286                    dynamicQuery.setProjection(projectionList);
287    
288                    addReindexCriteria(dynamicQuery, companyId);
289    
290                    List<Object[]> results = BookmarksFolderLocalServiceUtil.dynamicQuery(
291                            dynamicQuery);
292    
293                    Object[] minAndMaxFolderIds = results.get(0);
294    
295                    if ((minAndMaxFolderIds[0] == null) ||
296                            (minAndMaxFolderIds[1] == null)) {
297    
298                            return;
299                    }
300    
301                    long minFolderId = (Long)minAndMaxFolderIds[0];
302                    long maxFolderId = (Long)minAndMaxFolderIds[1];
303    
304                    long startFolderId = minFolderId;
305                    long endFolderId = startFolderId + DEFAULT_INTERVAL;
306    
307                    while (startFolderId <= maxFolderId) {
308                            reindexFolders(companyId, startFolderId, endFolderId);
309    
310                            startFolderId = endFolderId;
311                            endFolderId += DEFAULT_INTERVAL;
312                    }
313            }
314    
315            protected void reindexFolders(
316                            long companyId, long startFolderId, long endFolderId)
317                    throws Exception {
318    
319                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
320                            BookmarksFolder.class, PACLClassLoaderUtil.getPortalClassLoader());
321    
322                    Property property = PropertyFactoryUtil.forName("folderId");
323    
324                    dynamicQuery.add(property.ge(startFolderId));
325                    dynamicQuery.add(property.lt(endFolderId));
326    
327                    addReindexCriteria(dynamicQuery, companyId);
328    
329                    List<BookmarksFolder> folders =
330                            BookmarksFolderLocalServiceUtil.dynamicQuery(dynamicQuery);
331    
332                    for (BookmarksFolder folder : folders) {
333                            long groupId = folder.getGroupId();
334                            long folderId = folder.getFolderId();
335    
336                            reindexEntries(companyId, groupId, folderId);
337                    }
338            }
339    
340            protected void reindexRoot(long companyId) throws Exception {
341                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
342                            Group.class, PACLClassLoaderUtil.getPortalClassLoader());
343    
344                    Projection minGroupIdProjection = ProjectionFactoryUtil.min("groupId");
345                    Projection maxGroupIdProjection = ProjectionFactoryUtil.max("groupId");
346    
347                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
348    
349                    projectionList.add(minGroupIdProjection);
350                    projectionList.add(maxGroupIdProjection);
351    
352                    dynamicQuery.setProjection(projectionList);
353    
354                    addReindexCriteria(dynamicQuery, companyId);
355    
356                    List<Object[]> results = GroupLocalServiceUtil.dynamicQuery(
357                            dynamicQuery);
358    
359                    Object[] minAndMaxGroupIds = results.get(0);
360    
361                    if ((minAndMaxGroupIds[0] == null) || (minAndMaxGroupIds[1] == null)) {
362                            return;
363                    }
364    
365                    long minGroupId = (Long)minAndMaxGroupIds[0];
366                    long maxGroupId = (Long)minAndMaxGroupIds[1];
367    
368                    long startGroupId = minGroupId;
369                    long endGroupId = startGroupId + DEFAULT_INTERVAL;
370    
371                    while (startGroupId <= maxGroupId) {
372                            reindexRoot(companyId, startGroupId, endGroupId);
373    
374                            startGroupId = endGroupId;
375                            endGroupId += DEFAULT_INTERVAL;
376                    }
377            }
378    
379            protected void reindexRoot(
380                            long companyId, long startGroupId, long endGroupId)
381                    throws Exception {
382    
383                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
384                            Group.class, PACLClassLoaderUtil.getPortalClassLoader());
385    
386                    Property property = PropertyFactoryUtil.forName("groupId");
387    
388                    dynamicQuery.add(property.ge(startGroupId));
389                    dynamicQuery.add(property.lt(endGroupId));
390    
391                    addReindexCriteria(dynamicQuery, companyId);
392    
393                    List<Group> groups = GroupLocalServiceUtil.dynamicQuery(dynamicQuery);
394    
395                    for (Group group : groups) {
396                            long groupId = group.getGroupId();
397                            long folderId = BookmarksFolderConstants.DEFAULT_PARENT_FOLDER_ID;
398    
399                            reindexEntries(companyId, groupId, folderId);
400                    }
401            }
402    
403    }