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