001    /**
002     * Copyright (c) 2000-present 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.lar.backgroundtask;
016    
017    import com.liferay.portal.kernel.backgroundtask.BackgroundTaskResult;
018    import com.liferay.portal.kernel.backgroundtask.BaseBackgroundTaskExecutor;
019    import com.liferay.portal.kernel.dao.orm.ActionableDynamicQuery;
020    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
021    import com.liferay.portal.kernel.dao.orm.Property;
022    import com.liferay.portal.kernel.dao.orm.PropertyFactoryUtil;
023    import com.liferay.portal.kernel.exception.PortalException;
024    import com.liferay.portal.kernel.exception.SystemException;
025    import com.liferay.portal.kernel.lar.PortletDataContext;
026    import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
027    import com.liferay.portal.kernel.log.Log;
028    import com.liferay.portal.kernel.log.LogFactoryUtil;
029    import com.liferay.portal.kernel.search.Indexer;
030    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
031    import com.liferay.portal.kernel.util.ArrayUtil;
032    import com.liferay.portal.kernel.util.GetterUtil;
033    import com.liferay.portal.kernel.util.MapUtil;
034    import com.liferay.portal.kernel.util.ReflectionUtil;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.model.BackgroundTask;
038    import com.liferay.portal.model.User;
039    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
040    import com.liferay.portlet.documentlibrary.service.DLFileEntryLocalServiceUtil;
041    import com.liferay.portlet.dynamicdatamapping.model.DDMStructure;
042    import com.liferay.portlet.dynamicdatamapping.service.DDMStructureLocalServiceUtil;
043    import com.liferay.portlet.journal.model.JournalArticle;
044    import com.liferay.portlet.journal.service.persistence.JournalArticleActionableDynamicQuery;
045    import com.liferay.portlet.journal.util.JournalArticleIndexer;
046    
047    import java.io.Serializable;
048    
049    import java.lang.reflect.Method;
050    
051    import java.util.ArrayList;
052    import java.util.HashSet;
053    import java.util.List;
054    import java.util.Map;
055    import java.util.Set;
056    
057    /**
058     * @author Mate Thurzo
059     */
060    public class StagingIndexingBackgroundTaskExecutor
061            extends BaseBackgroundTaskExecutor {
062    
063            public StagingIndexingBackgroundTaskExecutor() {
064                    setSerial(true);
065            }
066    
067            @Override
068            public BackgroundTaskResult execute(BackgroundTask backgroundTask)
069                    throws Exception {
070    
071                    Map<String, Serializable> taskContextMap =
072                            backgroundTask.getTaskContextMap();
073    
074                    PortletDataContext portletDataContext =
075                            (PortletDataContext)taskContextMap.get("portletDataContext");
076    
077                    boolean importPermissions = MapUtil.getBoolean(
078                            portletDataContext.getParameterMap(),
079                            PortletDataHandlerKeys.PERMISSIONS);
080    
081                    if (importPermissions) {
082                            long userId = MapUtil.getLong(taskContextMap, "userId");
083    
084                            if (userId > 0) {
085                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
086                                            User.class);
087    
088                                    indexer.reindex(userId);
089                            }
090                    }
091    
092                    Map<String, Map<?, ?>> newPrimaryKeysMaps =
093                            portletDataContext.getNewPrimaryKeysMaps();
094    
095                    for (Map.Entry<String, Map<?, ?>> newPrimaryKeysMapsEntry :
096                                    newPrimaryKeysMaps.entrySet()) {
097    
098                            String className = newPrimaryKeysMapsEntry.getKey();
099    
100                            Indexer indexer = IndexerRegistryUtil.getIndexer(className);
101    
102                            if ((indexer == null) &&
103                                    !className.equals(DDMStructure.class.getName())) {
104    
105                                    continue;
106                            }
107    
108                            Map<?, ?> newPrimaryKeysMap = newPrimaryKeysMapsEntry.getValue();
109    
110                            List<Long> newPrimaryKeys = new ArrayList<Long>();
111    
112                            for (Object object : newPrimaryKeysMap.values()) {
113                                    long classPK = GetterUtil.getLong(object);
114    
115                                    if (classPK > 0) {
116                                            newPrimaryKeys.add(classPK);
117                                    }
118                            }
119    
120                            if (className.equals(DDMStructure.class.getName())) {
121                                    reindexDDMStructures(
122                                            newPrimaryKeys, newPrimaryKeysMaps,
123                                            portletDataContext.getGroupId());
124                            }
125                            else {
126                                    for (Long classPK : newPrimaryKeys) {
127                                            indexer.reindex(className, classPK);
128                                    }
129                            }
130                    }
131    
132                    return BackgroundTaskResult.SUCCESS;
133            }
134    
135            protected ActionableDynamicQuery getJournalArticleActionableDynamicQuery(
136                            long groupId, final Map<?, ?> journalArticleIds,
137                            final String[] ddmStructureKeys)
138                    throws Exception {
139    
140                    ActionableDynamicQuery journalArticleActionableDynamicQuery =
141                            new JournalArticleActionableDynamicQuery() {
142    
143                            @Override
144                            protected void addCriteria(DynamicQuery dynamicQuery) {
145                                    Property structureIdProperty = PropertyFactoryUtil.forName(
146                                            "structureId");
147    
148                                    dynamicQuery.add(structureIdProperty.in(ddmStructureKeys));
149                            }
150    
151                            @Override
152                            protected void performAction(Object object) throws PortalException {
153                                    JournalArticle article = (JournalArticle)object;
154    
155                                    if (containsValue(
156                                                    journalArticleIds, article.getResourcePrimKey())) {
157    
158                                            return;
159                                    }
160    
161                                    try {
162                                            _journalArticleIndexer.doReindex(article, false);
163                                    }
164                                    catch (Exception e) {
165                                            throw new PortalException(e);
166                                    }
167                            }
168    
169                            private final JournalArticleIndexer _journalArticleIndexer =
170                                    (JournalArticleIndexer)IndexerRegistryUtil.getIndexer(
171                                            JournalArticle.class);
172    
173                    };
174    
175                    journalArticleActionableDynamicQuery.setGroupId(groupId);
176    
177                    return journalArticleActionableDynamicQuery;
178            }
179    
180            protected void reindexDDMStructures(
181                            List<Long> ddmStructureIds,
182                            final Map<String, Map<?, ?>> newPrimaryKeysMaps, long groupId)
183                    throws Exception {
184    
185                    if ((ddmStructureIds == null) || ddmStructureIds.isEmpty()) {
186                            return;
187                    }
188    
189                    Set<Long> descendantDDMStructureIds = new HashSet<Long>();
190    
191                    for (long structureId : ddmStructureIds) {
192                            DDMStructure ddmStructure =
193                                    DDMStructureLocalServiceUtil.getDDMStructure(structureId);
194    
195                            descendantDDMStructureIds.addAll(
196                                    getDescendantDDMStructureIds(
197                                            ddmStructure.getGroupId(), ddmStructure.getStructureId()));
198                    }
199    
200                    int i = 0;
201    
202                    String[] ddmStructureKeys =
203                            new String[descendantDDMStructureIds.size()];
204    
205                    for (long ddmStructureId : descendantDDMStructureIds) {
206                            DDMStructure ddmStructure =
207                                    DDMStructureLocalServiceUtil.getDDMStructure(ddmStructureId);
208    
209                            ddmStructureKeys[i++] = ddmStructure.getStructureKey();
210                    }
211    
212                    // Journal
213    
214                    Map<?, ?> articleIds = (Map<?, ?>)newPrimaryKeysMaps.get(
215                            JournalArticle.class.getName());
216    
217                    ActionableDynamicQuery journalArticleActionableDynamicQuery =
218                            getJournalArticleActionableDynamicQuery(
219                                    groupId, articleIds, ddmStructureKeys);
220    
221                    journalArticleActionableDynamicQuery.performActions();
222    
223                    // Document library
224    
225                    List<DLFileEntry> dlFileEntries = new ArrayList<DLFileEntry>();
226    
227                    try {
228                            Method method = ReflectionUtil.getDeclaredMethod(
229                                    DLFileEntryLocalServiceUtil.class, "getDDMStructureFileEntries",
230                                    long.class, long[].class);
231    
232                            Object object = method.invoke(
233                                    DLFileEntryLocalServiceUtil.class, groupId,
234                                    ArrayUtil.toLongArray(descendantDDMStructureIds));
235    
236                            if (object != null) {
237                                    dlFileEntries = (List<DLFileEntry>)object;
238                            }
239                    }
240                    catch (Exception e) {
241                            List<DLFileEntry> allDlFileEntries =
242                                    DLFileEntryLocalServiceUtil.getDDMStructureFileEntries(
243                                            ArrayUtil.toLongArray(descendantDDMStructureIds));
244    
245                            for (DLFileEntry dlFileEntry : allDlFileEntries) {
246                                    if (groupId == dlFileEntry.getGroupId()) {
247                                            dlFileEntries.add(dlFileEntry);
248                                    }
249                            }
250                    }
251    
252                    Map<?, ?> dlFileEntryPrimaryKeysMap = newPrimaryKeysMaps.get(
253                            DLFileEntry.class.getName());
254    
255                    Indexer dlFileEntryIndexer = IndexerRegistryUtil.getIndexer(
256                            DLFileEntry.class);
257    
258                    for (DLFileEntry dlFileEntry : dlFileEntries) {
259                            if (containsValue(
260                                            dlFileEntryPrimaryKeysMap, dlFileEntry.getFileEntryId())) {
261    
262                                    continue;
263                            }
264    
265                            dlFileEntryIndexer.reindex(dlFileEntry);
266                    }
267            }
268    
269            protected boolean containsValue(Map<?, ?> map, long value) {
270                    if ((map == null) || map.isEmpty() || (value <= 0)) {
271                            return false;
272                    }
273    
274                    for (Object object : map.values()) {
275                            if (GetterUtil.getLong(object) == value) {
276                                    return true;
277                            }
278                    }
279    
280                    return false;
281            }
282    
283            protected void getDescendantDDMStructureIds(
284                            List<Long> ddmStructureIds, long groupId, long parentDDMStructureId)
285                    throws PortalException, SystemException {
286    
287                    DynamicQuery query = DDMStructureLocalServiceUtil.dynamicQuery();
288    
289                    Property groupProperty = PropertyFactoryUtil.forName("groupId");
290    
291                    query.add(groupProperty.eq(groupId));
292    
293                    Property parentStructureIdProperty = PropertyFactoryUtil.forName(
294                            "parentStructureId");
295    
296                    query.add(parentStructureIdProperty.eq(parentDDMStructureId));
297    
298                    List<DDMStructure> ddmStructures =
299                                    DDMStructureLocalServiceUtil.dynamicQuery(query);
300    
301                    for (DDMStructure ddmStructure : ddmStructures) {
302                            ddmStructureIds.add(ddmStructure.getStructureId());
303    
304                            getDescendantDDMStructureIds(
305                                    ddmStructureIds, ddmStructure.getGroupId(),
306                                    ddmStructure.getStructureId());
307                    }
308            }
309    
310            protected List<Long> getDescendantDDMStructureIds(
311                            long groupId, long ddmStructureId)
312                    throws PortalException, SystemException {
313    
314                    List<Long> ddmStructureIds = new ArrayList<Long>();
315    
316                    getDescendantDDMStructureIds(ddmStructureIds, groupId, ddmStructureId);
317    
318                    ddmStructureIds.add(0, ddmStructureId);
319    
320                    return ddmStructureIds;
321            }
322    
323            @Override
324            public String handleException(BackgroundTask backgroundTask, Exception e) {
325                    StringBundler sb = new StringBundler(4);
326    
327                    sb.append("Indexing failed after importing with the following error: ");
328                    sb.append(e.getMessage());
329                    sb.append(StringPool.PERIOD);
330                    sb.append(StringPool.SPACE);
331                    sb.append("Please reindex site manually.");
332    
333                    String message = sb.toString();
334    
335                    if (_log.isInfoEnabled()) {
336                            _log.info(message);
337                    }
338    
339                    return message;
340            }
341    
342            private static Log _log = LogFactoryUtil.getLog(
343                    StagingIndexingBackgroundTaskExecutor.class);
344    
345    }