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.portlet.messageboards.lar;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryUtil;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.lar.BaseStagedModelDataHandler;
020    import com.liferay.portal.kernel.lar.ExportImportPathUtil;
021    import com.liferay.portal.kernel.lar.PortletDataContext;
022    import com.liferay.portal.kernel.lar.StagedModelDataHandlerUtil;
023    import com.liferay.portal.kernel.lar.StagedModelModifiedDateComparator;
024    import com.liferay.portal.kernel.log.Log;
025    import com.liferay.portal.kernel.log.LogFactoryUtil;
026    import com.liferay.portal.kernel.repository.model.FileEntry;
027    import com.liferay.portal.kernel.trash.TrashHandler;
028    import com.liferay.portal.kernel.util.GetterUtil;
029    import com.liferay.portal.kernel.util.ListUtil;
030    import com.liferay.portal.kernel.util.MapUtil;
031    import com.liferay.portal.kernel.util.ObjectValuePair;
032    import com.liferay.portal.kernel.util.StreamUtil;
033    import com.liferay.portal.kernel.util.Validator;
034    import com.liferay.portal.kernel.xml.Element;
035    import com.liferay.portal.service.ServiceContext;
036    import com.liferay.portlet.documentlibrary.lar.FileEntryUtil;
037    import com.liferay.portlet.documentlibrary.model.DLFileEntry;
038    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
039    import com.liferay.portlet.messageboards.model.MBCategory;
040    import com.liferay.portlet.messageboards.model.MBCategoryConstants;
041    import com.liferay.portlet.messageboards.model.MBDiscussion;
042    import com.liferay.portlet.messageboards.model.MBMessage;
043    import com.liferay.portlet.messageboards.model.MBThread;
044    import com.liferay.portlet.messageboards.service.MBDiscussionLocalServiceUtil;
045    import com.liferay.portlet.messageboards.service.MBMessageLocalServiceUtil;
046    import com.liferay.portlet.messageboards.service.MBThreadLocalServiceUtil;
047    import com.liferay.portlet.ratings.model.RatingsEntry;
048    import com.liferay.portlet.ratings.service.RatingsEntryLocalServiceUtil;
049    
050    import java.io.InputStream;
051    
052    import java.util.ArrayList;
053    import java.util.Collections;
054    import java.util.List;
055    import java.util.Map;
056    
057    /**
058     * @author Daniel Kocsis
059     */
060    public class MBMessageStagedModelDataHandler
061            extends BaseStagedModelDataHandler<MBMessage> {
062    
063            public static final String[] CLASS_NAMES = {MBMessage.class.getName()};
064    
065            @Override
066            public void deleteStagedModel(
067                            String uuid, long groupId, String className, String extraData)
068                    throws PortalException {
069    
070                    MBMessage message = fetchStagedModelByUuidAndGroupId(uuid, groupId);
071    
072                    if (message != null) {
073                            MBMessageLocalServiceUtil.deleteMessage(message);
074                    }
075            }
076    
077            @Override
078            public MBMessage fetchStagedModelByUuidAndCompanyId(
079                    String uuid, long companyId) {
080    
081                    List<MBMessage> messages =
082                            MBMessageLocalServiceUtil.getMBMessagesByUuidAndCompanyId(
083                                    uuid, companyId, QueryUtil.ALL_POS, QueryUtil.ALL_POS,
084                                    new StagedModelModifiedDateComparator<MBMessage>());
085    
086                    if (ListUtil.isEmpty(messages)) {
087                            return null;
088                    }
089    
090                    return messages.get(0);
091            }
092    
093            @Override
094            public MBMessage fetchStagedModelByUuidAndGroupId(
095                    String uuid, long groupId) {
096    
097                    return MBMessageLocalServiceUtil.fetchMBMessageByUuidAndGroupId(
098                            uuid, groupId);
099            }
100    
101            @Override
102            public String[] getClassNames() {
103                    return CLASS_NAMES;
104            }
105    
106            @Override
107            public String getDisplayName(MBMessage message) {
108                    return message.getSubject();
109            }
110    
111            protected MBMessage addDiscussionMessage(
112                            PortletDataContext portletDataContext, long userId, long threadId,
113                            long parentMessageId, MBMessage message,
114                            ServiceContext serviceContext)
115                    throws PortalException {
116    
117                    MBDiscussion discussion =
118                            MBDiscussionLocalServiceUtil.getThreadDiscussion(threadId);
119    
120                    MBMessage importedMessage = null;
121    
122                    if (!message.isRoot()) {
123                            importedMessage = MBMessageLocalServiceUtil.addDiscussionMessage(
124                                    userId, message.getUserName(),
125                                    portletDataContext.getScopeGroupId(), discussion.getClassName(),
126                                    discussion.getClassPK(), threadId, parentMessageId,
127                                    message.getSubject(), message.getBody(), serviceContext);
128                    }
129                    else {
130                            MBThread thread = MBThreadLocalServiceUtil.getThread(threadId);
131    
132                            importedMessage = MBMessageLocalServiceUtil.getMBMessage(
133                                    thread.getRootMessageId());
134                    }
135    
136                    return importedMessage;
137            }
138    
139            @Override
140            protected void doExportStagedModel(
141                            PortletDataContext portletDataContext, MBMessage message)
142                    throws Exception {
143    
144                    if (message.isDiscussion()) {
145                            MBDiscussion discussion =
146                                    MBDiscussionLocalServiceUtil.getDiscussion(
147                                            message.getClassName(), message.getClassPK());
148    
149                            StagedModelDataHandlerUtil.exportReferenceStagedModel(
150                                    portletDataContext, message, discussion,
151                                    PortletDataContext.REFERENCE_TYPE_PARENT);
152    
153                            // Ratings that belong to discussion messages cannot be exported
154                            // automatically because of the special class name and class PK pair
155    
156                            List<RatingsEntry> ratingsEntries =
157                                    RatingsEntryLocalServiceUtil.getEntries(
158                                            MBDiscussion.class.getName(), message.getMessageId());
159    
160                            for (RatingsEntry ratingsEntry : ratingsEntries) {
161                                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
162                                            portletDataContext, message, ratingsEntry,
163                                            PortletDataContext.REFERENCE_TYPE_WEAK);
164                            }
165                    }
166                    else if (message.getCategoryId() !=
167                                            MBCategoryConstants.DEFAULT_PARENT_CATEGORY_ID) {
168    
169                            StagedModelDataHandlerUtil.exportReferenceStagedModel(
170                                    portletDataContext, message, message.getCategory(),
171                                    PortletDataContext.REFERENCE_TYPE_PARENT);
172                    }
173    
174                    if (!message.isRoot()) {
175                            MBMessage parentMessage = MBMessageLocalServiceUtil.getMessage(
176                                    message.getParentMessageId());
177    
178                            StagedModelDataHandlerUtil.exportReferenceStagedModel(
179                                    portletDataContext, message, parentMessage,
180                                    PortletDataContext.REFERENCE_TYPE_PARENT);
181                    }
182    
183                    message.setPriority(message.getPriority());
184    
185                    MBThread thread = message.getThread();
186    
187                    Element messageElement = portletDataContext.getExportDataElement(
188                            message);
189    
190                    messageElement.addAttribute(
191                            "question", String.valueOf(thread.isQuestion()));
192    
193                    boolean hasAttachmentsFileEntries =
194                            message.getAttachmentsFileEntriesCount() > 0;
195    
196                    messageElement.addAttribute(
197                            "hasAttachmentsFileEntries",
198                            String.valueOf(hasAttachmentsFileEntries));
199    
200                    if (hasAttachmentsFileEntries) {
201                            for (FileEntry fileEntry : message.getAttachmentsFileEntries()) {
202                                    StagedModelDataHandlerUtil.exportReferenceStagedModel(
203                                            portletDataContext, message, fileEntry,
204                                            PortletDataContext.REFERENCE_TYPE_WEAK);
205                            }
206    
207                            long folderId = message.getAttachmentsFolderId();
208    
209                            if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
210                                    message.setAttachmentsFolderId(folderId);
211                            }
212                    }
213    
214                    portletDataContext.addClassedModel(
215                            messageElement, ExportImportPathUtil.getModelPath(message),
216                            message);
217            }
218    
219            @Override
220            protected void doImportStagedModel(
221                            PortletDataContext portletDataContext, MBMessage message)
222                    throws Exception {
223    
224                    long userId = portletDataContext.getUserId(message.getUserUuid());
225    
226                    Map<Long, Long> categoryIds =
227                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
228                                    MBCategory.class);
229    
230                    long parentCategoryId = MapUtil.getLong(
231                            categoryIds, message.getCategoryId(), message.getCategoryId());
232    
233                    Map<Long, Long> threadIds =
234                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
235                                    MBThread.class);
236    
237                    long threadId = MapUtil.getLong(threadIds, message.getThreadId(), 0);
238    
239                    Map<Long, Long> messageIds =
240                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
241                                    MBMessage.class);
242    
243                    long parentMessageId = MapUtil.getLong(
244                            messageIds, message.getParentMessageId(),
245                            message.getParentMessageId());
246    
247                    Element element = portletDataContext.getImportDataStagedModelElement(
248                            message);
249    
250                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
251                            getAttachments(portletDataContext, element, message);
252    
253                    try {
254                            ServiceContext serviceContext =
255                                    portletDataContext.createServiceContext(message);
256    
257                            MBMessage importedMessage = null;
258    
259                            if (portletDataContext.isDataStrategyMirror()) {
260                                    MBMessage existingMessage = fetchStagedModelByUuidAndGroupId(
261                                            message.getUuid(), portletDataContext.getScopeGroupId());
262    
263                                    if (existingMessage == null) {
264                                            serviceContext.setUuid(message.getUuid());
265    
266                                            if (message.isDiscussion()) {
267                                                    importedMessage = addDiscussionMessage(
268                                                            portletDataContext, userId, threadId,
269                                                            parentMessageId, message, serviceContext);
270                                            }
271                                            else {
272                                                    importedMessage = MBMessageLocalServiceUtil.addMessage(
273                                                            userId, message.getUserName(),
274                                                            portletDataContext.getScopeGroupId(),
275                                                            parentCategoryId, threadId, parentMessageId,
276                                                            message.getSubject(), message.getBody(),
277                                                            message.getFormat(), inputStreamOVPs,
278                                                            message.getAnonymous(), message.getPriority(),
279                                                            message.getAllowPingbacks(), serviceContext);
280                                            }
281                                    }
282                                    else {
283                                            if (!message.isRoot() && message.isDiscussion()) {
284                                                    MBDiscussion discussion =
285                                                            MBDiscussionLocalServiceUtil.getThreadDiscussion(
286                                                                    threadId);
287    
288                                                    importedMessage =
289                                                            MBMessageLocalServiceUtil.updateDiscussionMessage(
290                                                                    userId, existingMessage.getMessageId(),
291                                                                    discussion.getClassName(),
292                                                                    discussion.getClassPK(), message.getSubject(),
293                                                                    message.getBody(), serviceContext);
294                                            }
295                                            else {
296                                                    importedMessage =
297                                                            MBMessageLocalServiceUtil.updateMessage(
298                                                                    userId, existingMessage.getMessageId(),
299                                                                    message.getSubject(), message.getBody(),
300                                                                    inputStreamOVPs, new ArrayList<String>(),
301                                                                    message.getPriority(),
302                                                                    message.getAllowPingbacks(), serviceContext);
303                                            }
304                                    }
305                            }
306                            else {
307                                    if (message.isDiscussion()) {
308                                            importedMessage = addDiscussionMessage(
309                                                    portletDataContext, userId, threadId, parentMessageId,
310                                                    message, serviceContext);
311                                    }
312                                    else {
313                                            importedMessage = MBMessageLocalServiceUtil.addMessage(
314                                                    userId, message.getUserName(),
315                                                    portletDataContext.getScopeGroupId(), parentCategoryId,
316                                                    threadId, parentMessageId, message.getSubject(),
317                                                    message.getBody(), message.getFormat(), inputStreamOVPs,
318                                                    message.getAnonymous(), message.getPriority(),
319                                                    message.getAllowPingbacks(), serviceContext);
320                                    }
321                            }
322    
323                            MBMessageLocalServiceUtil.updateAnswer(
324                                    importedMessage, message.isAnswer(), false);
325    
326                            if (importedMessage.isRoot() && !importedMessage.isDiscussion()) {
327                                    MBThreadLocalServiceUtil.updateQuestion(
328                                            importedMessage.getThreadId(),
329                                            GetterUtil.getBoolean(element.attributeValue("question")));
330                            }
331    
332                            if (message.isDiscussion()) {
333                                    Map<Long, Long> discussionIds =
334                                            (Map<Long, Long>)portletDataContext.getNewPrimaryKeysMap(
335                                                    MBDiscussion.class);
336    
337                                    discussionIds.put(
338                                            message.getMessageId(), importedMessage.getMessageId());
339                            }
340    
341                            threadIds.put(message.getThreadId(), importedMessage.getThreadId());
342    
343                            portletDataContext.importClassedModel(message, importedMessage);
344                    }
345                    finally {
346                            for (ObjectValuePair<String, InputStream> inputStreamOVP :
347                                            inputStreamOVPs) {
348    
349                                    InputStream inputStream = inputStreamOVP.getValue();
350    
351                                    StreamUtil.cleanUp(inputStream);
352                            }
353                    }
354            }
355    
356            @Override
357            protected void doRestoreStagedModel(
358                            PortletDataContext portletDataContext, MBMessage message)
359                    throws Exception {
360    
361                    long userId = portletDataContext.getUserId(message.getUserUuid());
362    
363                    MBMessage existingMessage = fetchStagedModelByUuidAndGroupId(
364                            message.getUuid(), portletDataContext.getScopeGroupId());
365    
366                    if (existingMessage == null) {
367                            return;
368                    }
369    
370                    if (existingMessage.isInTrash()) {
371                            TrashHandler trashHandler = existingMessage.getTrashHandler();
372    
373                            if (trashHandler.isRestorable(existingMessage.getMessageId())) {
374                                    trashHandler.restoreTrashEntry(
375                                            userId, existingMessage.getMessageId());
376                            }
377                    }
378    
379                    if (existingMessage.isInTrashContainer()) {
380                            MBThread existingThread = existingMessage.getThread();
381    
382                            TrashHandler trashHandler = existingThread.getTrashHandler();
383    
384                            if (trashHandler.isRestorable(existingThread.getThreadId())) {
385                                    trashHandler.restoreTrashEntry(
386                                            userId, existingThread.getThreadId());
387                            }
388                    }
389            }
390    
391            protected List<ObjectValuePair<String, InputStream>> getAttachments(
392                    PortletDataContext portletDataContext, Element messageElement,
393                    MBMessage message) {
394    
395                    boolean hasAttachmentsFileEntries = GetterUtil.getBoolean(
396                            messageElement.attributeValue("hasAttachmentsFileEntries"));
397    
398                    if (!hasAttachmentsFileEntries) {
399                            return Collections.emptyList();
400                    }
401    
402                    List<ObjectValuePair<String, InputStream>> inputStreamOVPs =
403                            new ArrayList<ObjectValuePair<String, InputStream>>();
404    
405                    List<Element> attachmentElements =
406                            portletDataContext.getReferenceDataElements(
407                                    messageElement, DLFileEntry.class,
408                                    PortletDataContext.REFERENCE_TYPE_WEAK);
409    
410                    for (Element attachmentElement : attachmentElements) {
411                            String path = attachmentElement.attributeValue("path");
412    
413                            FileEntry fileEntry =
414                                    (FileEntry)portletDataContext.getZipEntryAsObject(path);
415    
416                            InputStream inputStream = null;
417    
418                            String binPath = attachmentElement.attributeValue("bin-path");
419    
420                            if (Validator.isNull(binPath) &&
421                                    portletDataContext.isPerformDirectBinaryImport()) {
422    
423                                    try {
424                                            inputStream = FileEntryUtil.getContentStream(fileEntry);
425                                    }
426                                    catch (Exception e) {
427                                    }
428                            }
429                            else {
430                                    inputStream = portletDataContext.getZipEntryAsInputStream(
431                                            binPath);
432                            }
433    
434                            if (inputStream == null) {
435                                    if (_log.isWarnEnabled()) {
436                                            _log.warn(
437                                                    "Unable to import attachment for file entry " +
438                                                            fileEntry.getFileEntryId());
439                                    }
440    
441                                    continue;
442                            }
443    
444                            ObjectValuePair<String, InputStream> inputStreamOVP =
445                                    new ObjectValuePair<String, InputStream>(
446                                            fileEntry.getTitle(), inputStream);
447    
448                            inputStreamOVPs.add(inputStreamOVP);
449                    }
450    
451                    if (inputStreamOVPs.isEmpty()) {
452                            _log.error(
453                                    "Could not find attachments for message " +
454                                            message.getMessageId());
455                    }
456    
457                    return inputStreamOVPs;
458            }
459    
460            private static final Log _log = LogFactoryUtil.getLog(
461                    MBMessageStagedModelDataHandler.class);
462    
463    }