001    /**
002     * Copyright (c) 2000-2013 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.getStatus() != WorkflowConstants.STATUS_APPROVED) {
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                    if (entry.isSmallImage()) {
247                            Image smallImage = ImageUtil.fetchByPrimaryKey(
248                                    entry.getSmallImageId());
249    
250                            if (Validator.isNotNull(entry.getSmallImageURL())) {
251                                    String smallImageURL =
252                                            JournalPortletDataHandlerImpl.exportReferencedContent(
253                                                    portletDataContext, dlFileEntryTypesElement,
254                                                    dlFoldersElement, dlFileEntriesElement,
255                                                    dlFileRanksElement, dlRepositoriesElement,
256                                                    dlRepositoryEntriesElement, entryElement,
257                                                    entry.getSmallImageURL().concat(StringPool.SPACE));
258    
259                                    entry.setSmallImageURL(smallImageURL);
260                            }
261                            else if (smallImage != null) {
262                                    String smallImagePath = getEntrySmallImagePath(
263                                            portletDataContext, entry);
264    
265                                    entryElement.addAttribute("small-image-path", smallImagePath);
266    
267                                    entry.setSmallImageType(smallImage.getType());
268    
269                                    portletDataContext.addZipEntry(
270                                            smallImagePath, smallImage.getTextObj());
271                            }
272                    }
273    
274                    portletDataContext.addClassedModel(
275                            entryElement, path, entry, _NAMESPACE);
276            }
277    
278            protected String getEntryImagePath(
279                            PortletDataContext portletDataContext, BlogsEntry entry)
280                    throws Exception {
281    
282                    StringBundler sb = new StringBundler(4);
283    
284                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
285                    sb.append("/entry/");
286                    sb.append(entry.getUuid());
287                    sb.append(StringPool.SLASH);
288    
289                    return sb.toString();
290            }
291    
292            protected String getEntryPath(
293                    PortletDataContext portletDataContext, BlogsEntry entry) {
294    
295                    StringBundler sb = new StringBundler(4);
296    
297                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
298                    sb.append("/entries/");
299                    sb.append(entry.getEntryId());
300                    sb.append(".xml");
301    
302                    return sb.toString();
303            }
304    
305            protected String getEntrySmallImagePath(
306                            PortletDataContext portletDataContext, BlogsEntry entry)
307                    throws Exception {
308    
309                    StringBundler sb = new StringBundler(6);
310    
311                    sb.append(portletDataContext.getPortletPath(PortletKeys.BLOGS));
312                    sb.append("/entries/");
313                    sb.append(entry.getUuid());
314                    sb.append("/thumbnail");
315                    sb.append(StringPool.PERIOD);
316                    sb.append(entry.getSmallImageType());
317    
318                    return sb.toString();
319            }
320    
321            protected void importEntry(
322                            PortletDataContext portletDataContext, Element entryElement,
323                            BlogsEntry entry)
324                    throws Exception {
325    
326                    long userId = portletDataContext.getUserId(entry.getUserUuid());
327    
328                    String content = JournalPortletDataHandlerImpl.importReferencedContent(
329                            portletDataContext, entryElement, entry.getContent());
330    
331                    entry.setContent(content);
332    
333                    Calendar displayDateCal = CalendarFactoryUtil.getCalendar();
334    
335                    displayDateCal.setTime(entry.getDisplayDate());
336    
337                    int displayDateMonth = displayDateCal.get(Calendar.MONTH);
338                    int displayDateDay = displayDateCal.get(Calendar.DATE);
339                    int displayDateYear = displayDateCal.get(Calendar.YEAR);
340                    int displayDateHour = displayDateCal.get(Calendar.HOUR);
341                    int displayDateMinute = displayDateCal.get(Calendar.MINUTE);
342    
343                    if (displayDateCal.get(Calendar.AM_PM) == Calendar.PM) {
344                            displayDateHour += 12;
345                    }
346    
347                    boolean allowPingbacks = entry.isAllowPingbacks();
348                    boolean allowTrackbacks = entry.isAllowTrackbacks();
349                    String[] trackbacks = StringUtil.split(entry.getTrackbacks());
350                    int status = entry.getStatus();
351    
352                    ServiceContext serviceContext = portletDataContext.createServiceContext(
353                            entryElement, entry, _NAMESPACE);
354    
355                    if (status != WorkflowConstants.STATUS_APPROVED) {
356                            serviceContext.setWorkflowAction(
357                                    WorkflowConstants.ACTION_SAVE_DRAFT);
358                    }
359    
360                    String smallImageFileName = null;
361                    InputStream smallImageInputStream = null;
362    
363                    try {
364                            if (entry.isSmallImage()) {
365                                    String smallImagePath = entryElement.attributeValue(
366                                            "small-image-path");
367    
368                                    if (Validator.isNotNull(entry.getSmallImageURL())) {
369                                            String smallImageURL =
370                                                    JournalPortletDataHandlerImpl.importReferencedContent(
371                                                            portletDataContext, entryElement,
372                                                            entry.getSmallImageURL());
373    
374                                            entry.setSmallImageURL(smallImageURL);
375                                    }
376                                    else if (Validator.isNotNull(smallImagePath)) {
377                                            smallImageFileName = String.valueOf(
378                                                    entry.getSmallImageId()).concat(
379                                                            StringPool.PERIOD).concat(
380                                                                    entry.getSmallImageType());
381                                            smallImageInputStream =
382                                                    portletDataContext.getZipEntryAsInputStream(
383                                                            smallImagePath);
384                                    }
385                            }
386    
387                            BlogsEntry importedEntry = null;
388    
389                            if (portletDataContext.isDataStrategyMirror()) {
390                                    serviceContext.setAttribute("urlTitle", entry.getUrlTitle());
391    
392                                    BlogsEntry existingEntry = BlogsEntryUtil.fetchByUUID_G(
393                                            entry.getUuid(), portletDataContext.getScopeGroupId());
394    
395                                    if (existingEntry == null) {
396                                            serviceContext.setUuid(entry.getUuid());
397    
398                                            importedEntry = BlogsEntryLocalServiceUtil.addEntry(
399                                                    userId, entry.getTitle(), entry.getDescription(),
400                                                    entry.getContent(), displayDateMonth, displayDateDay,
401                                                    displayDateYear, displayDateHour, displayDateMinute,
402                                                    allowPingbacks, allowTrackbacks, trackbacks,
403                                                    entry.isSmallImage(), entry.getSmallImageURL(),
404                                                    smallImageFileName, smallImageInputStream,
405                                                    serviceContext);
406                                    }
407                                    else {
408                                            importedEntry = BlogsEntryLocalServiceUtil.updateEntry(
409                                                    userId, existingEntry.getEntryId(), entry.getTitle(),
410                                                    entry.getDescription(), entry.getContent(),
411                                                    displayDateMonth, displayDateDay, displayDateYear,
412                                                    displayDateHour, displayDateMinute, allowPingbacks,
413                                                    allowTrackbacks, trackbacks, entry.getSmallImage(),
414                                                    entry.getSmallImageURL(), smallImageFileName,
415                                                    smallImageInputStream, serviceContext);
416                                    }
417                            }
418                            else {
419                                    importedEntry = BlogsEntryLocalServiceUtil.addEntry(
420                                            userId, entry.getTitle(), entry.getDescription(),
421                                            entry.getContent(), displayDateMonth, displayDateDay,
422                                            displayDateYear, displayDateHour, displayDateMinute,
423                                            allowPingbacks, allowTrackbacks, trackbacks,
424                                            entry.getSmallImage(), entry.getSmallImageURL(),
425                                            smallImageFileName, smallImageInputStream, serviceContext);
426                            }
427    
428                            portletDataContext.importClassedModel(
429                                    entry, importedEntry, _NAMESPACE);
430                    }
431                    finally {
432                            StreamUtil.cleanUp(smallImageInputStream);
433                    }
434    
435            }
436    
437            private static final boolean _ALWAYS_EXPORTABLE = true;
438    
439            private static final String _NAMESPACE = "blogs";
440    
441            private static PortletDataHandlerBoolean _entries =
442                    new PortletDataHandlerBoolean(_NAMESPACE, "entries", true, true);
443            private static PortletDataHandlerControl[] _metadataControls =
444                    new PortletDataHandlerControl[] {
445                            new PortletDataHandlerBoolean(_NAMESPACE, "categories"),
446                            new PortletDataHandlerBoolean(_NAMESPACE, "comments"),
447                            new PortletDataHandlerBoolean(_NAMESPACE, "ratings"),
448                            new PortletDataHandlerBoolean(_NAMESPACE, "tags")
449                    };
450            private static PortletDataHandlerBoolean _wordpress =
451                    new PortletDataHandlerBoolean(_NAMESPACE, "wordpress");
452    
453    }