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.blogs.lar;
016    
017    import com.liferay.portal.kernel.lar.BasePortletDataHandler;
018    import com.liferay.portal.kernel.lar.PortletDataContext;
019    import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
020    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
021    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
022    import com.liferay.portal.kernel.util.StreamUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.kernel.workflow.WorkflowConstants;
028    import com.liferay.portal.kernel.xml.Document;
029    import com.liferay.portal.kernel.xml.Element;
030    import com.liferay.portal.kernel.xml.SAXReaderUtil;
031    import com.liferay.portal.model.Image;
032    import com.liferay.portal.service.ServiceContext;
033    import com.liferay.portal.service.persistence.ImageUtil;
034    import com.liferay.portal.util.PortletKeys;
035    import com.liferay.portal.util.PropsValues;
036    import com.liferay.portlet.blogs.model.BlogsEntry;
037    import com.liferay.portlet.blogs.service.BlogsEntryLocalServiceUtil;
038    import com.liferay.portlet.blogs.service.BlogsStatsUserLocalServiceUtil;
039    import com.liferay.portlet.blogs.service.persistence.BlogsEntryUtil;
040    import com.liferay.portlet.journal.lar.JournalPortletDataHandlerImpl;
041    
042    import java.io.InputStream;
043    
044    import java.util.Calendar;
045    import java.util.List;
046    
047    import javax.portlet.PortletPreferences;
048    
049    /**
050     * @author Bruno Farache
051     * @author Raymond Augé
052     * @author Juan Fernández
053     */
054    public class BlogsPortletDataHandlerImpl extends BasePortletDataHandler {
055    
056            @Override
057            public PortletDataHandlerControl[] getExportControls() {
058                    return new PortletDataHandlerControl[] {
059                            _entries
060                    };
061            }
062    
063            @Override
064            public PortletDataHandlerControl[] getExportMetadataControls() {
065                    return new PortletDataHandlerControl[] {
066                            new PortletDataHandlerBoolean(
067                                    _NAMESPACE, "blog-entries", true, _metadataControls)
068                    };
069            }
070    
071            @Override
072            public PortletDataHandlerControl[] getImportControls() {
073                    return new PortletDataHandlerControl[] {
074                            _entries, _wordpress
075                    };
076            }
077    
078            @Override
079            public PortletDataHandlerControl[] getImportMetadataControls() {
080                    return new PortletDataHandlerControl[] {
081                            new PortletDataHandlerBoolean(
082                                    _NAMESPACE, "blog-entries", true, _metadataControls)
083                    };
084            }
085    
086            @Override
087            public boolean isAlwaysExportable() {
088                    return _ALWAYS_EXPORTABLE;
089            }
090    
091            @Override
092            public boolean isPublishToLiveByDefault() {
093                    return PropsValues.BLOGS_PUBLISH_TO_LIVE_BY_DEFAULT;
094            }
095    
096            @Override
097            protected PortletPreferences doDeleteData(
098                            PortletDataContext portletDataContext, String portletId,
099                            PortletPreferences portletPreferences)
100                    throws Exception {
101    
102                    if (!portletDataContext.addPrimaryKey(
103                                    BlogsPortletDataHandlerImpl.class, "deleteData")) {
104    
105                            BlogsEntryLocalServiceUtil.deleteEntries(
106                                    portletDataContext.getScopeGroupId());
107    
108                            BlogsStatsUserLocalServiceUtil.deleteStatsUserByGroupId(
109                                    portletDataContext.getScopeGroupId());
110                    }
111    
112                    return null;
113            }
114    
115            @Override
116            protected String doExportData(
117                            PortletDataContext portletDataContext, String portletId,
118                            PortletPreferences portletPreferences)
119                    throws Exception {
120    
121                    portletDataContext.addPermissions(
122                            "com.liferay.portlet.blogs", portletDataContext.getScopeGroupId());
123    
124                    Document document = SAXReaderUtil.createDocument();
125    
126                    Element rootElement = document.addElement("blogs-data");
127    
128                    rootElement.addAttribute(
129                            "group-id", String.valueOf(portletDataContext.getScopeGroupId()));
130    
131                    Element entriesElement = rootElement.addElement("entries");
132    
133                    Element dlFileEntryTypesElement = entriesElement.addElement(
134                            "dl-file-entry-types");
135                    Element dlFoldersElement = entriesElement.addElement("dl-folders");
136                    Element dlFileEntriesElement = entriesElement.addElement(
137                            "dl-file-entries");
138                    Element dlFileRanksElement = entriesElement.addElement("dl-file-ranks");
139                    Element dlRepositoriesElement = entriesElement.addElement(
140                            "dl-repositories");
141                    Element dlRepositoryEntriesElement = entriesElement.addElement(
142                            "dl-repository-entries");
143    
144                    List<BlogsEntry> entries = BlogsEntryUtil.findByGroupId(
145                            portletDataContext.getScopeGroupId());
146    
147                    for (BlogsEntry entry : entries) {
148                            exportEntry(
149                                    portletDataContext, entriesElement, dlFileEntryTypesElement,
150                                    dlFoldersElement, dlFileEntriesElement, dlFileRanksElement,
151                                    dlRepositoriesElement, dlRepositoryEntriesElement, entry);
152                    }
153    
154                    return document.formattedString();
155            }
156    
157            @Override
158            protected PortletPreferences doImportData(
159                            PortletDataContext portletDataContext, String portletId,
160                            PortletPreferences portletPreferences, String data)
161                    throws Exception {
162    
163                    portletDataContext.importPermissions(
164                            "com.liferay.portlet.blogs", portletDataContext.getSourceGroupId(),
165                            portletDataContext.getScopeGroupId());
166    
167                    Document document = SAXReaderUtil.read(data);
168    
169                    Element rootElement = document.getRootElement();
170    
171                    Element entriesElement = rootElement.element("entries");
172    
173                    if (entriesElement != null) {
174                            JournalPortletDataHandlerImpl.importReferencedData(
175                                    portletDataContext, entriesElement);
176                    }
177                    else {
178                            entriesElement = rootElement;
179                    }
180    
181                    for (Element entryElement : entriesElement.elements("entry")) {
182                            String path = entryElement.attributeValue("path");
183    
184                            if (!portletDataContext.isPathNotProcessed(path)) {
185                                    continue;
186                            }
187    
188                            BlogsEntry entry =
189                                    (BlogsEntry)portletDataContext.getZipEntryAsObject(path);
190    
191                            importEntry(portletDataContext, entryElement, entry);
192                    }
193    
194                    if (portletDataContext.getBooleanParameter(_NAMESPACE, "wordpress")) {
195                            WordPressImporter.importData(portletDataContext);
196                    }
197    
198                    return null;
199            }
200    
201            protected void exportEntry(
202                            PortletDataContext portletDataContext, Element entriesElement,
203                            Element dlFileEntryTypesElement, Element dlFoldersElement,
204                            Element dlFileEntriesElement, Element dlFileRanksElement,
205                            Element dlRepositoriesElement, Element dlRepositoryEntriesElement,
206                            BlogsEntry entry)
207                    throws Exception {
208    
209                    if (!portletDataContext.isWithinDateRange(entry.getModifiedDate())) {
210                            return;
211                    }
212    
213                    if (!entry.isApproved() && !entry.isInTrash()) {
214                            return;
215                    }
216    
217                    String path = getEntryPath(portletDataContext, entry);
218    
219                    if (!portletDataContext.isPathNotProcessed(path)) {
220                            return;
221                    }
222    
223                    // Clone this entry to make sure changes to its content are never
224                    // persisted
225    
226                    entry = (BlogsEntry)entry.clone();
227    
228                    Element entryElement = (Element)entriesElement.selectSingleNode(
229                            "//page[@path='".concat(path).concat("']"));
230    
231                    if (entryElement == null) {
232                            entryElement = entriesElement.addElement("entry");
233                    }
234    
235                    String content = JournalPortletDataHandlerImpl.exportReferencedContent(
236                            portletDataContext, dlFileEntryTypesElement, dlFoldersElement,
237                            dlFileEntriesElement, dlFileRanksElement, dlRepositoriesElement,
238                            dlRepositoryEntriesElement, entryElement, entry.getContent());
239    
240                    entry.setContent(content);
241    
242                    String imagePath = getEntryImagePath(portletDataContext, entry);
243    
244                    entryElement.addAttribute("image-path", imagePath);
245    
246                    Image smallImage = ImageUtil.fetchByPrimaryKey(entry.getSmallImageId());
247    
248                    if (entry.isSmallImage() && (smallImage != null)) {
249                            String smallImagePath = getEntrySmallImagePath(
250                                    portletDataContext, entry);
251    
252                            entryElement.addAttribute("small-image-path", smallImagePath);
253    
254                            entry.setSmallImageType(smallImage.getType());
255    
256                            portletDataContext.addZipEntry(
257                                    smallImagePath, smallImage.getTextObj());
258                    }
259    
260                    portletDataContext.addClassedModel(
261                            entryElement, path, entry, _NAMESPACE);
262            }
263    
264            protected String getEntryImagePath(
265                            PortletDataContext portletDataContext, BlogsEntry entry)
266                    throws Exception {
267    
268                    StringBundler sb = new StringBundler(4);
269    
270                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
271                    sb.append("/entry/");
272                    sb.append(entry.getUuid());
273                    sb.append(StringPool.SLASH);
274    
275                    return sb.toString();
276            }
277    
278            protected String getEntryPath(
279                    PortletDataContext portletDataContext, BlogsEntry entry) {
280    
281                    StringBundler sb = new StringBundler(4);
282    
283                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
284                    sb.append("/entries/");
285                    sb.append(entry.getEntryId());
286                    sb.append(".xml");
287    
288                    return sb.toString();
289            }
290    
291            protected String getEntrySmallImagePath(
292                            PortletDataContext portletDataContext, BlogsEntry entry)
293                    throws Exception {
294    
295                    StringBundler sb = new StringBundler(6);
296    
297                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
298                    sb.append("/entries/");
299                    sb.append(entry.getUuid());
300                    sb.append("/thumbnail");
301                    sb.append(StringPool.PERIOD);
302                    sb.append(entry.getSmallImageType());
303    
304                    return sb.toString();
305            }
306    
307            protected void importEntry(
308                            PortletDataContext portletDataContext, Element entryElement,
309                            BlogsEntry entry)
310                    throws Exception {
311    
312                    long userId = portletDataContext.getUserId(entry.getUserUuid());
313    
314                    String content = JournalPortletDataHandlerImpl.importReferencedContent(
315                            portletDataContext, entryElement, entry.getContent());
316    
317                    entry.setContent(content);
318    
319                    Calendar displayDateCal = CalendarFactoryUtil.getCalendar();
320    
321                    displayDateCal.setTime(entry.getDisplayDate());
322    
323                    int displayDateMonth = displayDateCal.get(Calendar.MONTH);
324                    int displayDateDay = displayDateCal.get(Calendar.DATE);
325                    int displayDateYear = displayDateCal.get(Calendar.YEAR);
326                    int displayDateHour = displayDateCal.get(Calendar.HOUR);
327                    int displayDateMinute = displayDateCal.get(Calendar.MINUTE);
328    
329                    if (displayDateCal.get(Calendar.AM_PM) == Calendar.PM) {
330                            displayDateHour += 12;
331                    }
332    
333                    boolean allowPingbacks = entry.isAllowPingbacks();
334                    boolean allowTrackbacks = entry.isAllowTrackbacks();
335                    String[] trackbacks = StringUtil.split(entry.getTrackbacks());
336                    int status = entry.getStatus();
337    
338                    String smallImageFileName = null;
339                    InputStream smallImageInputStream = null;
340    
341                    try {
342                            String smallImagePath = entryElement.attributeValue(
343                                    "small-image-path");
344    
345                            if (entry.isSmallImage() && Validator.isNotNull(smallImagePath)) {
346                                    smallImageFileName = String.valueOf(
347                                            entry.getSmallImageId()).concat(
348                                                    StringPool.PERIOD).concat(entry.getSmallImageType());
349                                    smallImageInputStream =
350                                            portletDataContext.getZipEntryAsInputStream(smallImagePath);
351                            }
352    
353                            ServiceContext serviceContext =
354                                    portletDataContext.createServiceContext(
355                                            entryElement, entry, _NAMESPACE);
356    
357                            if ((status != WorkflowConstants.STATUS_APPROVED) &&
358                                    (status != WorkflowConstants.STATUS_IN_TRASH)) {
359    
360                                    serviceContext.setWorkflowAction(
361                                            WorkflowConstants.ACTION_SAVE_DRAFT);
362                            }
363    
364                            BlogsEntry importedEntry = null;
365    
366                            if (portletDataContext.isDataStrategyMirror()) {
367                                    serviceContext.setAttribute("urlTitle", entry.getUrlTitle());
368    
369                                    BlogsEntry existingEntry = BlogsEntryUtil.fetchByUUID_G(
370                                            entry.getUuid(), portletDataContext.getScopeGroupId());
371    
372                                    if (existingEntry == null) {
373                                            serviceContext.setUuid(entry.getUuid());
374    
375                                            importedEntry = BlogsEntryLocalServiceUtil.addEntry(
376                                                    userId, entry.getTitle(), entry.getDescription(),
377                                                    entry.getContent(), displayDateMonth, displayDateDay,
378                                                    displayDateYear, displayDateHour, displayDateMinute,
379                                                    allowPingbacks, allowTrackbacks, trackbacks,
380                                                    entry.isSmallImage(), entry.getSmallImageURL(),
381                                                    smallImageFileName, smallImageInputStream,
382                                                    serviceContext);
383    
384                                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
385                                                    importedEntry =
386                                                            BlogsEntryLocalServiceUtil.moveEntryToTrash(
387                                                                    userId, importedEntry);
388                                            }
389                                    }
390                                    else {
391                                            importedEntry = BlogsEntryLocalServiceUtil.updateEntry(
392                                                    userId, existingEntry.getEntryId(), entry.getTitle(),
393                                                    entry.getDescription(), entry.getContent(),
394                                                    displayDateMonth, displayDateDay, displayDateYear,
395                                                    displayDateHour, displayDateMinute, allowPingbacks,
396                                                    allowTrackbacks, trackbacks, entry.getSmallImage(),
397                                                    entry.getSmallImageURL(), smallImageFileName,
398                                                    smallImageInputStream, serviceContext);
399                                    }
400                            }
401                            else {
402                                    importedEntry = BlogsEntryLocalServiceUtil.addEntry(
403                                            userId, entry.getTitle(), entry.getDescription(),
404                                            entry.getContent(), displayDateMonth, displayDateDay,
405                                            displayDateYear, displayDateHour, displayDateMinute,
406                                            allowPingbacks, allowTrackbacks, trackbacks,
407                                            entry.getSmallImage(), entry.getSmallImageURL(),
408                                            smallImageFileName, smallImageInputStream, serviceContext);
409                            }
410    
411                            portletDataContext.importClassedModel(
412                                    entry, importedEntry, _NAMESPACE);
413                    }
414                    finally {
415                            StreamUtil.cleanUp(smallImageInputStream);
416                    }
417    
418            }
419    
420            private static final boolean _ALWAYS_EXPORTABLE = true;
421    
422            private static final String _NAMESPACE = "blogs";
423    
424            private static PortletDataHandlerBoolean _entries =
425                    new PortletDataHandlerBoolean(_NAMESPACE, "entries", true, true);
426    
427            private static PortletDataHandlerControl[] _metadataControls =
428                    new PortletDataHandlerControl[] {
429                            new PortletDataHandlerBoolean(_NAMESPACE, "categories"),
430                            new PortletDataHandlerBoolean(_NAMESPACE, "comments"),
431                            new PortletDataHandlerBoolean(_NAMESPACE, "ratings"),
432                            new PortletDataHandlerBoolean(_NAMESPACE, "tags")
433                    };
434    
435            private static PortletDataHandlerBoolean _wordpress =
436                    new PortletDataHandlerBoolean(_NAMESPACE, "wordpress");
437    
438    }