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.wiki.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.dao.orm.QueryUtil;
025    import com.liferay.portal.kernel.search.BaseIndexer;
026    import com.liferay.portal.kernel.search.BooleanClauseOccur;
027    import com.liferay.portal.kernel.search.BooleanQuery;
028    import com.liferay.portal.kernel.search.BooleanQueryFactoryUtil;
029    import com.liferay.portal.kernel.search.Document;
030    import com.liferay.portal.kernel.search.DocumentImpl;
031    import com.liferay.portal.kernel.search.Field;
032    import com.liferay.portal.kernel.search.Hits;
033    import com.liferay.portal.kernel.search.SearchContext;
034    import com.liferay.portal.kernel.search.SearchEngineUtil;
035    import com.liferay.portal.kernel.search.Summary;
036    import com.liferay.portal.kernel.util.GetterUtil;
037    import com.liferay.portal.kernel.util.HtmlUtil;
038    import com.liferay.portal.kernel.util.Validator;
039    import com.liferay.portal.kernel.workflow.WorkflowConstants;
040    import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
041    import com.liferay.portal.util.PortletKeys;
042    import com.liferay.portlet.wiki.model.WikiNode;
043    import com.liferay.portlet.wiki.model.WikiPage;
044    import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
045    import com.liferay.portlet.wiki.service.WikiNodeServiceUtil;
046    import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
047    
048    import java.util.ArrayList;
049    import java.util.Collection;
050    import java.util.List;
051    import java.util.Locale;
052    
053    import javax.portlet.PortletURL;
054    
055    /**
056     * @author Brian Wing Shun Chan
057     * @author Harry Mark
058     * @author Bruno Farache
059     * @author Raymond Augé
060     */
061    public class WikiPageIndexer extends BaseIndexer {
062    
063            public static final String[] CLASS_NAMES = {WikiPage.class.getName()};
064    
065            public static final String PORTLET_ID = PortletKeys.WIKI;
066    
067            public WikiPageIndexer() {
068                    setPermissionAware(true);
069            }
070    
071            public String[] getClassNames() {
072                    return CLASS_NAMES;
073            }
074    
075            public String getPortletId() {
076                    return PORTLET_ID;
077            }
078    
079            @Override
080            public void postProcessContextQuery(
081                            BooleanQuery contextQuery, SearchContext searchContext)
082                    throws Exception {
083    
084                    int status = GetterUtil.getInteger(
085                            searchContext.getAttribute(Field.STATUS),
086                            WorkflowConstants.STATUS_APPROVED);
087    
088                    if (status != WorkflowConstants.STATUS_ANY) {
089                            contextQuery.addRequiredTerm(Field.STATUS, status);
090                    }
091    
092                    long[] nodeIds = searchContext.getNodeIds();
093    
094                    if ((nodeIds != null) && (nodeIds.length > 0)) {
095                            BooleanQuery nodeIdsQuery = BooleanQueryFactoryUtil.create(
096                                    searchContext);
097    
098                            for (long nodeId : nodeIds) {
099                                    try {
100                                            WikiNodeServiceUtil.getNode(nodeId);
101                                    }
102                                    catch (Exception e) {
103                                            continue;
104                                    }
105    
106                                    nodeIdsQuery.addTerm(Field.NODE_ID, nodeId);
107                            }
108    
109                            contextQuery.add(nodeIdsQuery, BooleanClauseOccur.MUST);
110                    }
111            }
112    
113            protected void addReindexCriteria(
114                    DynamicQuery dynamicQuery, long companyId) {
115    
116                    Property property = PropertyFactoryUtil.forName("companyId");
117    
118                    dynamicQuery.add(property.eq(companyId));
119            }
120    
121            protected void addReindexCriteria(
122                    DynamicQuery dynamicQuery, long groupId, long nodeId) {
123    
124                    Property groupIdProperty = PropertyFactoryUtil.forName("groupId");
125    
126                    dynamicQuery.add(groupIdProperty.eq(groupId));
127    
128                    Property nodeIdProperty = PropertyFactoryUtil.forName("nodeId");
129    
130                    dynamicQuery.add(nodeIdProperty.eq(nodeId));
131    
132                    Property headProperty = PropertyFactoryUtil.forName("head");
133    
134                    dynamicQuery.add(headProperty.eq(true));
135            }
136    
137            @Override
138            protected void doDelete(Object obj) throws Exception {
139                    SearchContext searchContext = new SearchContext();
140    
141                    searchContext.setSearchEngineId(getSearchEngineId());
142    
143                    if (obj instanceof Object[]) {
144                            Object[] array = (Object[])obj;
145    
146                            long companyId = (Long)array[0];
147                            long nodeId = (Long)array[1];
148                            String title = (String)array[2];
149    
150                            Document document = new DocumentImpl();
151    
152                            document.addUID(PORTLET_ID, nodeId, title);
153    
154                            SearchEngineUtil.deleteDocument(
155                                    getSearchEngineId(), companyId, document.get(Field.UID));
156    
157                    }
158                    else if (obj instanceof WikiNode) {
159                            WikiNode node = (WikiNode)obj;
160    
161                            BooleanQuery booleanQuery = BooleanQueryFactoryUtil.create(
162                                    searchContext);
163    
164                            booleanQuery.addRequiredTerm(Field.PORTLET_ID, PORTLET_ID);
165    
166                            booleanQuery.addRequiredTerm("nodeId", node.getNodeId());
167    
168                            Hits hits = SearchEngineUtil.search(
169                                    getSearchEngineId(), node.getCompanyId(), booleanQuery,
170                                    QueryUtil.ALL_POS, QueryUtil.ALL_POS);
171    
172                            for (int i = 0; i < hits.getLength(); i++) {
173                                    Document document = hits.doc(i);
174    
175                                    SearchEngineUtil.deleteDocument(
176                                            getSearchEngineId(), node.getCompanyId(),
177                                            document.get(Field.UID));
178                            }
179                    }
180                    else if (obj instanceof WikiPage) {
181                            WikiPage page = (WikiPage)obj;
182    
183                            Document document = new DocumentImpl();
184    
185                            document.addUID(PORTLET_ID, page.getNodeId(), page.getTitle());
186    
187                            SearchEngineUtil.deleteDocument(
188                                    getSearchEngineId(), page.getCompanyId(),
189                                    document.get(Field.UID));
190                    }
191            }
192    
193            @Override
194            protected Document doGetDocument(Object obj) throws Exception {
195                    WikiPage page = (WikiPage)obj;
196    
197                    Document document = getBaseModelDocument(PORTLET_ID, page);
198    
199                    document.addUID(PORTLET_ID, page.getNodeId(), page.getTitle());
200    
201                    String content = HtmlUtil.extractText(
202                            WikiUtil.convert(page, null, null, null));
203    
204                    document.addText(Field.CONTENT, content);
205    
206                    document.addKeyword(Field.NODE_ID, page.getNodeId());
207                    document.addText(Field.TITLE, page.getTitle());
208    
209                    return document;
210            }
211    
212            @Override
213            protected Summary doGetSummary(
214                    Document document, Locale locale, String snippet,
215                    PortletURL portletURL) {
216    
217                    Summary summary = createSummary(document, Field.TITLE, Field.CONTENT);
218    
219                    summary.setMaxContentLength(200);
220    
221                    String nodeId = document.get("nodeId");
222    
223                    portletURL.setParameter("struts_action", "/wiki/view");
224                    portletURL.setParameter("nodeId", nodeId);
225                    portletURL.setParameter("title", summary.getTitle());
226    
227                    summary.setPortletURL(portletURL);
228    
229                    return summary;
230            }
231    
232            @Override
233            protected void doReindex(Object obj) throws Exception {
234                    WikiPage page = (WikiPage)obj;
235    
236                    if (Validator.isNotNull(page.getRedirectTitle())) {
237                            return;
238                    }
239    
240                    Document document = getDocument(page);
241    
242                    SearchEngineUtil.updateDocument(
243                            getSearchEngineId(), page.getCompanyId(), document);
244            }
245    
246            @Override
247            protected void doReindex(String className, long classPK) throws Exception {
248                    WikiPage page = WikiPageLocalServiceUtil.getPage(classPK);
249    
250                    doReindex(page);
251            }
252    
253            @Override
254            protected void doReindex(String[] ids) throws Exception {
255                    long companyId = GetterUtil.getLong(ids[0]);
256    
257                    reindexNodes(companyId);
258            }
259    
260            @Override
261            protected String getPortletId(SearchContext searchContext) {
262                    return PORTLET_ID;
263            }
264    
265            protected void reindexNodes(long companyId) throws Exception {
266                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
267                            WikiNode.class, PACLClassLoaderUtil.getPortalClassLoader());
268    
269                    Projection minNodeIdProjection = ProjectionFactoryUtil.min("nodeId");
270                    Projection maxNodeIdProjection = ProjectionFactoryUtil.max("nodeId");
271    
272                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
273    
274                    projectionList.add(minNodeIdProjection);
275                    projectionList.add(maxNodeIdProjection);
276    
277                    dynamicQuery.setProjection(projectionList);
278    
279                    addReindexCriteria(dynamicQuery, companyId);
280    
281                    List<Object[]> results = WikiNodeLocalServiceUtil.dynamicQuery(
282                            dynamicQuery);
283    
284                    Object[] minAndMaxNodeIds = results.get(0);
285    
286                    if ((minAndMaxNodeIds[0] == null) || (minAndMaxNodeIds[1] == null)) {
287                            return;
288                    }
289    
290                    long minNodeId = (Long)minAndMaxNodeIds[0];
291                    long maxNodeId = (Long)minAndMaxNodeIds[1];
292    
293                    long startNodeId = minNodeId;
294                    long endNodeId = startNodeId + DEFAULT_INTERVAL;
295    
296                    while (startNodeId <= maxNodeId) {
297                            reindexNodes(companyId, startNodeId, endNodeId);
298    
299                            startNodeId = endNodeId;
300                            endNodeId += DEFAULT_INTERVAL;
301                    }
302            }
303    
304            protected void reindexNodes(
305                            long companyId, long startNodeId, long endNodeId)
306                    throws Exception {
307    
308                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
309                            WikiNode.class, PACLClassLoaderUtil.getPortalClassLoader());
310    
311                    Property property = PropertyFactoryUtil.forName("nodeId");
312    
313                    dynamicQuery.add(property.ge(startNodeId));
314                    dynamicQuery.add(property.lt(endNodeId));
315    
316                    addReindexCriteria(dynamicQuery, companyId);
317    
318                    List<WikiNode> nodes = WikiNodeLocalServiceUtil.dynamicQuery(
319                            dynamicQuery);
320    
321                    for (WikiNode node : nodes) {
322                            long groupId = node.getGroupId();
323                            long nodeId = node.getNodeId();
324    
325                            reindexPages(companyId, groupId, nodeId);
326                    }
327            }
328    
329            protected void reindexPages(long companyId, long groupId, long nodeId)
330                    throws Exception {
331    
332                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
333                            WikiPage.class, PACLClassLoaderUtil.getPortalClassLoader());
334    
335                    Projection minPageIdProjection = ProjectionFactoryUtil.min("pageId");
336                    Projection maxPageIdProjection = ProjectionFactoryUtil.max("pageId");
337    
338                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
339    
340                    projectionList.add(minPageIdProjection);
341                    projectionList.add(maxPageIdProjection);
342    
343                    dynamicQuery.setProjection(projectionList);
344    
345                    addReindexCriteria(dynamicQuery, groupId, nodeId);
346    
347                    List<Object[]> results = WikiPageLocalServiceUtil.dynamicQuery(
348                            dynamicQuery);
349    
350                    Object[] minAndMaxPageIds = results.get(0);
351    
352                    if ((minAndMaxPageIds[0] == null) || (minAndMaxPageIds[1] == null)) {
353                            return;
354                    }
355    
356                    long minPageId = (Long)minAndMaxPageIds[0];
357                    long maxPageId = (Long)minAndMaxPageIds[1];
358    
359                    long startPageId = minPageId;
360                    long endPageId = startPageId + DEFAULT_INTERVAL;
361    
362                    while (startPageId <= maxPageId) {
363                            reindexPages(companyId, groupId, nodeId, startPageId, endPageId);
364    
365                            startPageId = endPageId;
366                            endPageId += DEFAULT_INTERVAL;
367                    }
368            }
369    
370            protected void reindexPages(
371                            long companyId, long groupId, long nodeId, long startPageId,
372                            long endPageId)
373                    throws Exception {
374    
375                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
376                            WikiPage.class, PACLClassLoaderUtil.getPortalClassLoader());
377    
378                    Property property = PropertyFactoryUtil.forName("pageId");
379    
380                    dynamicQuery.add(property.ge(startPageId));
381                    dynamicQuery.add(property.lt(endPageId));
382    
383                    addReindexCriteria(dynamicQuery, groupId, nodeId);
384    
385                    List<WikiPage> pages = WikiPageLocalServiceUtil.dynamicQuery(
386                            dynamicQuery);
387    
388                    if (pages.isEmpty()) {
389                            return;
390                    }
391    
392                    Collection<Document> documents = new ArrayList<Document>(pages.size());
393    
394                    for (WikiPage page : pages) {
395                            Document document = getDocument(page);
396    
397                            documents.add(document);
398                    }
399    
400                    SearchEngineUtil.updateDocuments(
401                            getSearchEngineId(), companyId, documents);
402            }
403    
404    }