1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portlet.journal.lar;
24  
25  import com.liferay.portal.NoSuchImageException;
26  import com.liferay.portal.PortalException;
27  import com.liferay.portal.SystemException;
28  import com.liferay.portal.kernel.lar.PortletDataContext;
29  import com.liferay.portal.kernel.lar.PortletDataException;
30  import com.liferay.portal.kernel.lar.PortletDataHandler;
31  import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
32  import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
33  import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
34  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
35  import com.liferay.portal.kernel.util.FileUtil;
36  import com.liferay.portal.kernel.util.ObjectValuePair;
37  import com.liferay.portal.kernel.util.StringPool;
38  import com.liferay.portal.kernel.util.Validator;
39  import com.liferay.portal.model.Image;
40  import com.liferay.portal.service.persistence.ImageUtil;
41  import com.liferay.portal.util.DocumentUtil;
42  import com.liferay.portal.util.PortletKeys;
43  import com.liferay.portlet.journal.model.JournalArticle;
44  import com.liferay.portlet.journal.model.JournalArticleImage;
45  import com.liferay.portlet.journal.model.JournalFeed;
46  import com.liferay.portlet.journal.model.JournalStructure;
47  import com.liferay.portlet.journal.model.JournalTemplate;
48  import com.liferay.portlet.journal.model.impl.JournalArticleImpl;
49  import com.liferay.portlet.journal.service.JournalArticleLocalServiceUtil;
50  import com.liferay.portlet.journal.service.JournalFeedLocalServiceUtil;
51  import com.liferay.portlet.journal.service.JournalStructureLocalServiceUtil;
52  import com.liferay.portlet.journal.service.JournalTemplateLocalServiceUtil;
53  import com.liferay.portlet.journal.service.persistence.JournalArticleImageUtil;
54  import com.liferay.portlet.journal.service.persistence.JournalArticleUtil;
55  import com.liferay.portlet.journal.service.persistence.JournalFeedUtil;
56  import com.liferay.portlet.journal.service.persistence.JournalStructureUtil;
57  import com.liferay.portlet.journal.service.persistence.JournalTemplateUtil;
58  import com.liferay.util.MapUtil;
59  import com.liferay.util.xml.XMLFormatter;
60  
61  import java.io.File;
62  
63  import java.util.Calendar;
64  import java.util.Date;
65  import java.util.HashMap;
66  import java.util.List;
67  import java.util.Map;
68  
69  import javax.portlet.PortletPreferences;
70  
71  import org.apache.commons.logging.Log;
72  import org.apache.commons.logging.LogFactory;
73  
74  import org.dom4j.Document;
75  import org.dom4j.DocumentHelper;
76  import org.dom4j.Element;
77  
78  /**
79   * <a href="JournalPortletDataHandlerImpl.java.html"><b><i>View Source</i></b>
80   * </a>
81   *
82   * <p>
83   * Provides the Journal portlet export and import functionality, which is to
84   * clone all articles, structures, and templates associated with the layout's
85   * group. Upon import, new instances of the corresponding articles, structures,
86   * and templates are created or updated according to the DATA_MIRROW strategy
87   * The author of the newly created objects are determined by the
88   * JournalCreationStrategy class defined in <i>portal.properties</i>. That
89   * strategy also allows the text of the journal article to be modified prior
90   * to import.
91   * </p>
92   *
93   * <p>
94   * This <code>PortletDataHandler</code> differs from
95   * <code>JournalContentPortletDataHandlerImpl</code> in that it exports all
96   * articles owned by the group whether or not they are actually displayed in a
97   * portlet in the layout set.
98   * </p>
99   *
100  * @author Raymond Augé
101  * @author Joel Kozikowski
102  * @author Brian Wing Shun Chan
103  * @author Bruno Farache
104  *
105  * @see com.liferay.portal.kernel.lar.PortletDataHandler
106  * @see com.liferay.portlet.journal.lar.JournalContentPortletDataHandlerImpl
107  * @see com.liferay.portlet.journal.lar.JournalCreationStrategy
108  *
109  */
110 public class JournalPortletDataHandlerImpl implements PortletDataHandler {
111 
112     public static void exportArticle(
113             PortletDataContext context, Element articlesEl,
114             JournalArticle article)
115         throws PortalException, SystemException {
116 
117         if (!context.isWithinDateRange(article.getModifiedDate())) {
118             return;
119         }
120 
121         String path = getArticlePath(context, article);
122 
123         Element articleEl = articlesEl.addElement("article");
124 
125         articleEl.addAttribute("path", path);
126 
127         if (!context.isPathNotProcessed(path)) {
128             return;
129         }
130 
131         if (article.isSmallImage()) {
132             Image smallImage = ImageUtil.fetchByPrimaryKey(
133                 article.getSmallImageId());
134 
135             article.setSmallImageType(smallImage.getType());
136 
137             context.addZipEntry(
138                 getArticleSmallImagePath(context, article),
139                 smallImage.getTextObj());
140         }
141 
142         if (context.getBooleanParameter(_NAMESPACE, "images")) {
143             List<JournalArticleImage> articleImages =
144                 JournalArticleImageUtil.findByG_A_V(
145                     context.getGroupId(), article.getArticleId(),
146                     article.getVersion());
147 
148             for (JournalArticleImage articleImage : articleImages) {
149                 try {
150                     Image image = ImageUtil.findByPrimaryKey(
151                         articleImage.getArticleImageId());
152 
153                     String imagePath = getArticleImagePath(
154                         context, article, articleImage, image);
155 
156                     context.addZipEntry(imagePath, image.getTextObj());
157                 }
158                 catch (NoSuchImageException nsie) {
159                 }
160             }
161         }
162 
163         if (context.getBooleanParameter(_NAMESPACE, "comments")) {
164             context.addComments(
165                 JournalArticle.class, article.getResourcePrimKey());
166         }
167 
168         if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
169             context.addRatingsEntries(
170                 JournalArticle.class, article.getResourcePrimKey());
171         }
172 
173         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
174             context.addTagsEntries(
175                 JournalArticle.class, article.getResourcePrimKey());
176         }
177 
178         article.setUserUuid(article.getUserUuid());
179         article.setApprovedByUserUuid(article.getApprovedByUserUuid());
180 
181         context.addZipEntry(path, article);
182     }
183 
184     protected void exportFeed(
185             PortletDataContext context, Element feedsEl, JournalFeed feed)
186         throws SystemException {
187 
188         if (!context.isWithinDateRange(feed.getModifiedDate())) {
189             return;
190         }
191 
192         String path = getFeedPath(context, feed);
193 
194         Element feedEl = feedsEl.addElement("feed");
195 
196         feedEl.addAttribute("path", path);
197 
198         if (context.isPathNotProcessed(path)) {
199             feed.setUserUuid(feed.getUserUuid());
200 
201             context.addZipEntry(path, feed);
202         }
203     }
204 
205     public static void exportStructure(
206             PortletDataContext context, Element structuresEl,
207             JournalStructure structure)
208         throws SystemException {
209 
210         if (!context.isWithinDateRange(structure.getModifiedDate())) {
211             return;
212         }
213 
214         String path = getStructurePath(context, structure);
215 
216         Element structureEl = structuresEl.addElement("structure");
217 
218         structureEl.addAttribute("path", path);
219 
220         if (context.isPathNotProcessed(path)) {
221             structure.setUserUuid(structure.getUserUuid());
222 
223             context.addZipEntry(path, structure);
224         }
225     }
226 
227     public static void exportTemplate(
228             PortletDataContext context, Element templatesEl,
229             JournalTemplate template)
230         throws PortalException, SystemException {
231 
232         if (!context.isWithinDateRange(template.getModifiedDate())) {
233             return;
234         }
235 
236         String path = getTemplatePath(context, template);
237 
238         Element templateEl = templatesEl.addElement("template");
239 
240         templateEl.addAttribute("path", path);
241 
242         if (!context.isPathNotProcessed(path)) {
243             return;
244         }
245 
246         if (template.isSmallImage()) {
247             Image smallImage = ImageUtil.fetchByPrimaryKey(
248                 template.getSmallImageId());
249 
250             template.setSmallImageType(smallImage.getType());
251 
252             context.addZipEntry(
253                 getTemplateSmallImagePath(context, template),
254                 smallImage.getTextObj());
255         }
256 
257         template.setUserUuid(template.getUserUuid());
258 
259         context.addZipEntry(path, template);
260     }
261 
262     public static void importArticle(
263             PortletDataContext context, Map<String, String> structureIds,
264             Map<String, String> templateIds, Map<String, String> articleIds,
265             Element articleEl)
266         throws Exception {
267 
268         String path = articleEl.attributeValue("path");
269 
270         if (!context.isPathNotProcessed(path)) {
271             return;
272         }
273 
274         JournalArticle article = (JournalArticle)context.getZipEntryAsObject(
275             path);
276 
277         long userId = context.getUserId(article.getUserUuid());
278         long plid = context.getPlid();
279 
280         String articleId = article.getArticleId();
281         boolean autoArticleId = false;
282 
283         if ((Validator.isNumber(articleId)) ||
284             (JournalArticleUtil.fetchByG_A_V(
285                 context.getGroupId(), articleId,
286                     JournalArticleImpl.DEFAULT_VERSION) != null)) {
287 
288             autoArticleId = true;
289         }
290 
291         String newArticleId = articleIds.get(articleId);
292 
293         if (Validator.isNotNull(newArticleId)) {
294 
295             // A sibling of a different version was already assigned a new
296             // article id
297 
298             articleId = newArticleId;
299             autoArticleId = false;
300         }
301 
302         boolean incrementVersion = false;
303 
304         String parentStructureId = MapUtil.getString(
305             structureIds, article.getStructureId(), article.getStructureId());
306         String parentTemplateId = MapUtil.getString(
307             templateIds, article.getTemplateId(), article.getTemplateId());
308 
309         Date displayDate = article.getDisplayDate();
310 
311         int displayDateMonth = 0;
312         int displayDateDay = 0;
313         int displayDateYear = 0;
314         int displayDateHour = 0;
315         int displayDateMinute = 0;
316 
317         if (displayDate != null) {
318             Calendar displayCal = CalendarFactoryUtil.getCalendar();
319 
320             displayCal.setTime(displayDate);
321 
322             displayDateMonth = displayCal.get(Calendar.MONTH);
323             displayDateDay = displayCal.get(Calendar.DATE);
324             displayDateYear = displayCal.get(Calendar.YEAR);
325             displayDateHour = displayCal.get(Calendar.HOUR);
326             displayDateMinute = displayCal.get(Calendar.MINUTE);
327 
328             if (displayCal.get(Calendar.AM_PM) == Calendar.PM) {
329                 displayDateHour += 12;
330             }
331         }
332 
333         Date expirationDate = article.getExpirationDate();
334 
335         int expirationDateMonth = 0;
336         int expirationDateDay = 0;
337         int expirationDateYear = 0;
338         int expirationDateHour = 0;
339         int expirationDateMinute = 0;
340         boolean neverExpire = true;
341 
342         if (expirationDate != null) {
343             Calendar expirationCal = CalendarFactoryUtil.getCalendar();
344 
345             expirationCal.setTime(expirationDate);
346 
347             expirationDateMonth = expirationCal.get(Calendar.MONTH);
348             expirationDateDay = expirationCal.get(Calendar.DATE);
349             expirationDateYear = expirationCal.get(Calendar.YEAR);
350             expirationDateHour = expirationCal.get(Calendar.HOUR);
351             expirationDateMinute = expirationCal.get(Calendar.MINUTE);
352             neverExpire = false;
353 
354             if (expirationCal.get(Calendar.AM_PM) == Calendar.PM) {
355                 expirationDateHour += 12;
356             }
357         }
358 
359         Date reviewDate = article.getReviewDate();
360 
361         int reviewDateMonth = 0;
362         int reviewDateDay = 0;
363         int reviewDateYear = 0;
364         int reviewDateHour = 0;
365         int reviewDateMinute = 0;
366         boolean neverReview = true;
367 
368         if (reviewDate != null) {
369             Calendar reviewCal = CalendarFactoryUtil.getCalendar();
370 
371             reviewCal.setTime(reviewDate);
372 
373             reviewDateMonth = reviewCal.get(Calendar.MONTH);
374             reviewDateDay = reviewCal.get(Calendar.DATE);
375             reviewDateYear = reviewCal.get(Calendar.YEAR);
376             reviewDateHour = reviewCal.get(Calendar.HOUR);
377             reviewDateMinute = reviewCal.get(Calendar.MINUTE);
378             neverReview = false;
379 
380             if (reviewCal.get(Calendar.AM_PM) == Calendar.PM) {
381                 reviewDateHour += 12;
382             }
383         }
384 
385         File smallFile = null;
386 
387         if (article.isSmallImage()) {
388             byte[] bytes = context.getZipEntryAsByteArray(
389                 getArticleSmallImagePath(context, article));
390 
391             smallFile = File.createTempFile(
392                 String.valueOf(article.getSmallImageId()),
393                 StringPool.PERIOD + article.getSmallImageType());
394 
395             FileUtil.write(smallFile, bytes);
396         }
397 
398         Map<String, byte[]> images = new HashMap<String, byte[]>();
399 
400         if (context.getBooleanParameter(_NAMESPACE, "images")) {
401             List<ObjectValuePair<String, byte[]>> imageFiles =
402                 context.getZipFolderEntries(
403                     getArticleImagePath(context, article));
404 
405             if (imageFiles != null) {
406                 for (ObjectValuePair<String, byte[]> imageFile : imageFiles) {
407                     String fileName = imageFile.getKey();
408 
409                     if (!fileName.endsWith(".xml")) {
410                         int pos = fileName.lastIndexOf(StringPool.PERIOD);
411 
412                         if (pos != -1) {
413                             fileName = fileName.substring(0, pos);
414                         }
415 
416                         images.put(fileName, imageFile.getValue());
417                     }
418                 }
419             }
420         }
421 
422         String articleURL = null;
423 
424         PortletPreferences prefs = null;
425 
426         String[] tagsEntries = null;
427 
428         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
429             tagsEntries = context.getTagsEntries(
430                 JournalArticle.class, article.getResourcePrimKey());
431         }
432 
433         JournalCreationStrategy creationStrategy =
434             JournalCreationStrategyFactory.getInstance();
435 
436         long authorId = creationStrategy.getAuthorUserId(context, article);
437 
438         if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
439             userId = authorId;
440         }
441 
442         String newContent = creationStrategy.getTransformedContent(
443             context, article);
444 
445         if (newContent != JournalCreationStrategy.ARTICLE_CONTENT_UNCHANGED) {
446             article.setContent(newContent);
447         }
448 
449         boolean addCommunityPermissions =
450             creationStrategy.addCommunityPermissions(context, article);
451         boolean addGuestPermissions = creationStrategy.addGuestPermissions(
452             context, article);
453 
454         JournalArticle existingArticle = null;
455 
456         if (context.getDataStrategy().equals(
457                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
458 
459             existingArticle = JournalArticleUtil.fetchByUUID_G(
460                 article.getUuid(), context.getGroupId());
461 
462             if (existingArticle == null) {
463                 existingArticle = JournalArticleLocalServiceUtil.addArticle(
464                     article.getUuid(), userId, articleId, autoArticleId,
465                     plid, article.getVersion(), article.getTitle(),
466                     article.getDescription(), article.getContent(),
467                     article.getType(), parentStructureId, parentTemplateId,
468                     displayDateMonth, displayDateDay, displayDateYear,
469                     displayDateHour, displayDateMinute, expirationDateMonth,
470                     expirationDateDay, expirationDateYear, expirationDateHour,
471                     expirationDateMinute, neverExpire, reviewDateMonth,
472                     reviewDateDay, reviewDateYear, reviewDateHour,
473                     reviewDateMinute, neverReview, article.getIndexable(),
474                     article.getSmallImage(), article.getSmallImageURL(),
475                     smallFile, images, articleURL, prefs, tagsEntries,
476                     addCommunityPermissions, addGuestPermissions);
477             }
478             else {
479                 existingArticle = JournalArticleLocalServiceUtil.updateArticle(
480                     userId, existingArticle.getGroupId(),
481                     existingArticle.getArticleId(),
482                     existingArticle.getVersion(), incrementVersion,
483                     article.getTitle(), article.getDescription(),
484                     article.getContent(), article.getType(),
485                     existingArticle.getStructureId(),
486                     existingArticle.getTemplateId(), displayDateMonth,
487                     displayDateDay, displayDateYear, displayDateHour,
488                     displayDateMinute, expirationDateMonth, expirationDateDay,
489                     expirationDateYear, expirationDateHour,
490                     expirationDateMinute, neverExpire, reviewDateMonth,
491                     reviewDateDay, reviewDateYear, reviewDateHour,
492                     reviewDateMinute, neverReview, article.getIndexable(),
493                     article.getSmallImage(), article.getSmallImageURL(),
494                     smallFile, images, articleURL, prefs, tagsEntries);
495             }
496         }
497         else {
498             existingArticle = JournalArticleLocalServiceUtil.addArticle(
499                 userId, articleId, autoArticleId, plid, article.getVersion(),
500                 article.getTitle(), article.getDescription(),
501                 article.getContent(), article.getType(), parentStructureId,
502                 parentTemplateId, displayDateMonth, displayDateDay,
503                 displayDateYear, displayDateHour, displayDateMinute,
504                 expirationDateMonth, expirationDateDay, expirationDateYear,
505                 expirationDateHour, expirationDateMinute, neverExpire,
506                 reviewDateMonth, reviewDateDay, reviewDateYear, reviewDateHour,
507                 reviewDateMinute, neverReview, article.getIndexable(),
508                 article.getSmallImage(), article.getSmallImageURL(), smallFile,
509                 images, articleURL, prefs, tagsEntries, addCommunityPermissions,
510                 addGuestPermissions);
511         }
512 
513         long strategyApprovalUserId = creationStrategy.getApprovalUserId(
514             context, article);
515 
516         if ((strategyApprovalUserId !=
517                 JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) ||
518             (article.isApproved() && !existingArticle.isApproved())) {
519 
520             long approvedByUserId = strategyApprovalUserId;
521 
522             if (approvedByUserId == 0) {
523                 approvedByUserId = context.getUserId(
524                     article.getApprovedByUserUuid());
525             }
526 
527             JournalArticleLocalServiceUtil.approveArticle(
528                 approvedByUserId, context.getGroupId(),
529                 existingArticle.getArticleId(), existingArticle.getVersion(),
530                 articleURL, prefs);
531         }
532 
533         if (context.getBooleanParameter(_NAMESPACE, "comments")) {
534             context.importComments(
535                 JournalArticle.class, article.getResourcePrimKey(),
536                 existingArticle.getResourcePrimKey(), context.getGroupId());
537         }
538 
539         if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
540             context.importRatingsEntries(
541                 JournalArticle.class, article.getResourcePrimKey(),
542                 existingArticle.getResourcePrimKey());
543         }
544 
545         articleIds.put(articleId, existingArticle.getArticleId());
546 
547         if (!articleId.equals(existingArticle.getArticleId())) {
548             if (_log.isWarnEnabled()) {
549                 _log.warn(
550                     "An article with the ID " + articleId + " already " +
551                         "exists. The new generated ID is " +
552                             existingArticle.getArticleId());
553             }
554         }
555     }
556 
557     public static void importFeed(
558             PortletDataContext context, Map<String, String> structureIds,
559             Map<String, String> templateIds, Map<String, String> feedIds,
560             Element feedEl)
561         throws Exception {
562 
563         String path = feedEl.attributeValue("path");
564 
565         if (!context.isPathNotProcessed(path)) {
566             return;
567         }
568 
569         JournalFeed feed = (JournalFeed)context.getZipEntryAsObject(path);
570 
571         long userId = context.getUserId(feed.getUserUuid());
572         long plid = context.getPlid();
573 
574         String feedId = feed.getFeedId();
575         boolean autoFeedId = false;
576 
577         if ((Validator.isNumber(feedId)) ||
578             (JournalFeedUtil.fetchByG_F(
579                 context.getGroupId(), feedId) != null)) {
580 
581             autoFeedId = true;
582         }
583 
584         String parentStructureId = MapUtil.getString(
585             structureIds, feed.getStructureId(), feed.getStructureId());
586         String parentTemplateId = MapUtil.getString(
587             templateIds, feed.getTemplateId(), feed.getTemplateId());
588         String parentRenderTemplateId = MapUtil.getString(
589             templateIds, feed.getRendererTemplateId(),
590             feed.getRendererTemplateId());
591 
592         JournalCreationStrategy creationStrategy =
593             JournalCreationStrategyFactory.getInstance();
594 
595         long authorId = creationStrategy.getAuthorUserId(context, feed);
596 
597         if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
598             userId = authorId;
599         }
600 
601         boolean addCommunityPermissions =
602             creationStrategy.addCommunityPermissions(context, feed);
603         boolean addGuestPermissions = creationStrategy.addGuestPermissions(
604             context, feed);
605 
606         JournalFeed existingFeed = null;
607 
608         if (context.getDataStrategy().equals(
609                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
610 
611             existingFeed = JournalFeedUtil.fetchByUUID_G(
612                 feed.getUuid(), context.getGroupId());
613 
614             if (existingFeed == null) {
615                 existingFeed = JournalFeedLocalServiceUtil.addFeed(
616                     feed.getUuid(), userId, plid, feedId, autoFeedId,
617                     feed.getName(), feed.getDescription(), feed.getType(),
618                     parentStructureId, parentTemplateId, parentRenderTemplateId,
619                     feed.getDelta(), feed.getOrderByCol(),
620                     feed.getOrderByType(), feed.getTargetLayoutFriendlyUrl(),
621                     feed.getTargetPortletId(), feed.getContentField(),
622                     feed.getFeedType(), feed.getFeedVersion(),
623                     addCommunityPermissions, addGuestPermissions);
624             }
625             else {
626                 existingFeed = JournalFeedLocalServiceUtil.updateFeed(
627                     existingFeed.getGroupId(), existingFeed.getFeedId(),
628                     feed.getName(), feed.getDescription(), feed.getType(),
629                     parentStructureId, parentTemplateId, parentRenderTemplateId,
630                     feed.getDelta(), feed.getOrderByCol(),
631                     feed.getOrderByType(), feed.getTargetLayoutFriendlyUrl(),
632                     feed.getTargetPortletId(), feed.getContentField(),
633                     feed.getFeedType(), feed.getFeedVersion());
634             }
635         }
636         else {
637             existingFeed = JournalFeedLocalServiceUtil.addFeed(
638                 userId, plid, feedId, autoFeedId, feed.getName(),
639                 feed.getDescription(), feed.getType(), parentStructureId,
640                 parentTemplateId, parentRenderTemplateId, feed.getDelta(),
641                 feed.getOrderByCol(), feed.getOrderByType(),
642                 feed.getTargetLayoutFriendlyUrl(), feed.getTargetPortletId(),
643                 feed.getContentField(), feed.getFeedType(),
644                 feed.getFeedVersion(), addCommunityPermissions,
645                 addGuestPermissions);
646         }
647 
648         feedIds.put(feedId, existingFeed.getFeedId());
649 
650         if (!feedId.equals(existingFeed.getStructureId())) {
651             if (_log.isWarnEnabled()) {
652                 _log.warn(
653                     "A feed with the ID " + feedId + " already " +
654                         "exists. The new generated ID is " +
655                             existingFeed.getFeedId());
656             }
657         }
658     }
659 
660     public static void importStructure(
661             PortletDataContext context, Map<String, String> structureIds,
662             Element structureEl)
663         throws Exception {
664 
665         String path = structureEl.attributeValue("path");
666 
667         if (!context.isPathNotProcessed(path)) {
668             return;
669         }
670 
671         JournalStructure structure =
672             (JournalStructure)context.getZipEntryAsObject(path);
673 
674         long userId = context.getUserId(structure.getUserUuid());
675         long plid = context.getPlid();
676 
677         String structureId = structure.getStructureId();
678         boolean autoStructureId = false;
679 
680         if ((Validator.isNumber(structureId)) ||
681             (JournalStructureUtil.fetchByG_S(
682                 context.getGroupId(), structureId) != null)) {
683 
684             autoStructureId = true;
685         }
686 
687         JournalCreationStrategy creationStrategy =
688             JournalCreationStrategyFactory.getInstance();
689 
690         long authorId = creationStrategy.getAuthorUserId(context, structure);
691 
692         if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
693             userId = authorId;
694         }
695 
696         boolean addCommunityPermissions =
697             creationStrategy.addCommunityPermissions(context, structure);
698         boolean addGuestPermissions = creationStrategy.addGuestPermissions(
699             context, structure);
700 
701         JournalStructure existingStructure = null;
702 
703         if (context.getDataStrategy().equals(
704                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
705 
706             existingStructure = JournalStructureUtil.fetchByUUID_G(
707                 structure.getUuid(), context.getGroupId());
708 
709             if (existingStructure == null) {
710                 existingStructure =
711                     JournalStructureLocalServiceUtil.addStructure(
712                         structure.getUuid(), userId, structureId,
713                         autoStructureId, plid, structure.getName(),
714                         structure.getDescription(), structure.getXsd(),
715                         addCommunityPermissions, addGuestPermissions);
716             }
717             else {
718                 existingStructure =
719                     JournalStructureLocalServiceUtil.updateStructure(
720                         existingStructure.getGroupId(),
721                         existingStructure.getStructureId(), structure.getName(),
722                         structure.getDescription(), structure.getXsd());
723             }
724         }
725         else {
726             existingStructure = JournalStructureLocalServiceUtil.addStructure(
727                 userId, structureId, autoStructureId, plid, structure.getName(),
728                 structure.getDescription(), structure.getXsd(),
729                 addCommunityPermissions, addGuestPermissions);
730         }
731 
732         structureIds.put(structureId, existingStructure.getStructureId());
733 
734         if (!structureId.equals(existingStructure.getStructureId())) {
735             if (_log.isWarnEnabled()) {
736                 _log.warn(
737                     "A structure with the ID " + structureId + " already " +
738                         "exists. The new generated ID is " +
739                             existingStructure.getStructureId());
740             }
741         }
742     }
743 
744     public static void importTemplate(
745             PortletDataContext context, Map<String, String> structureIds,
746             Map<String, String> templateIds, Element templateEl)
747         throws Exception {
748 
749         String path = templateEl.attributeValue("path");
750 
751         if (!context.isPathNotProcessed(path)) {
752             return;
753         }
754 
755         JournalTemplate template = (JournalTemplate)context.getZipEntryAsObject(
756             path);
757 
758         long userId = context.getUserId(template.getUserUuid());
759         long plid = context.getPlid();
760 
761         String templateId = template.getTemplateId();
762         boolean autoTemplateId = false;
763 
764         if ((Validator.isNumber(templateId)) ||
765             (JournalTemplateUtil.fetchByG_T(
766                 context.getGroupId(), templateId) != null)) {
767 
768             autoTemplateId = true;
769         }
770 
771         String parentStructureId = MapUtil.getString(
772             structureIds, template.getStructureId(), template.getStructureId());
773 
774         boolean formatXsl = false;
775 
776         JournalCreationStrategy creationStrategy =
777             JournalCreationStrategyFactory.getInstance();
778 
779         long authorId = creationStrategy.getAuthorUserId(context, template);
780 
781         if (authorId != JournalCreationStrategy.USE_DEFAULT_USER_ID_STRATEGY) {
782             userId = authorId;
783         }
784 
785         boolean addCommunityPermissions =
786             creationStrategy.addCommunityPermissions(context, template);
787         boolean addGuestPermissions = creationStrategy.addGuestPermissions(
788             context, template);
789 
790         File smallFile = null;
791 
792         if (template.isSmallImage()) {
793             byte[] bytes = context.getZipEntryAsByteArray(
794                 getTemplateSmallImagePath(context, template));
795 
796             smallFile = File.createTempFile(
797                 String.valueOf(template.getSmallImageId()),
798                 StringPool.PERIOD + template.getSmallImageType());
799 
800             FileUtil.write(smallFile, bytes);
801         }
802 
803         JournalTemplate existingTemplate = null;
804 
805         if (context.getDataStrategy().equals(
806                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
807 
808             existingTemplate = JournalTemplateUtil.fetchByUUID_G(
809                 template.getUuid(), context.getGroupId());
810 
811             if (existingTemplate == null) {
812                 existingTemplate = JournalTemplateLocalServiceUtil.addTemplate(
813                     template.getUuid(), userId, templateId, autoTemplateId,
814                     plid, parentStructureId, template.getName(),
815                     template.getDescription(), template.getXsl(), formatXsl,
816                     template.getLangType(), template.getCacheable(),
817                     template.isSmallImage(), template.getSmallImageURL(),
818                     smallFile, addCommunityPermissions, addGuestPermissions);
819             }
820             else {
821                 existingTemplate =
822                     JournalTemplateLocalServiceUtil.updateTemplate(
823                         existingTemplate.getGroupId(),
824                         existingTemplate.getTemplateId(),
825                         existingTemplate.getStructureId(), template.getName(),
826                         template.getDescription(), template.getXsl(), formatXsl,
827                         template.getLangType(), template.getCacheable(),
828                         template.isSmallImage(), template.getSmallImageURL(),
829                         smallFile);
830             }
831         }
832         else {
833             existingTemplate = JournalTemplateLocalServiceUtil.addTemplate(
834                 userId, templateId, autoTemplateId, plid, parentStructureId,
835                 template.getName(), template.getDescription(),
836                 template.getXsl(), formatXsl, template.getLangType(),
837                 template.getCacheable(), template.isSmallImage(),
838                 template.getSmallImageURL(), smallFile, addCommunityPermissions,
839                 addGuestPermissions);
840         }
841 
842         templateIds.put(templateId, existingTemplate.getTemplateId());
843 
844         if (!templateId.equals(existingTemplate.getTemplateId())) {
845             if (_log.isWarnEnabled()) {
846                 _log.warn(
847                     "A template with the ID " + templateId + " already " +
848                         "exists. The new generated ID is " +
849                             existingTemplate.getTemplateId());
850             }
851         }
852     }
853 
854     public PortletPreferences deleteData(
855             PortletDataContext context, String portletId,
856             PortletPreferences prefs)
857         throws PortletDataException {
858 
859         try {
860             if (!context.addPrimaryKey(
861                     JournalPortletDataHandlerImpl.class, "deleteData")) {
862 
863                 JournalArticleLocalServiceUtil.deleteArticles(
864                     context.getGroupId());
865 
866                 JournalTemplateLocalServiceUtil.deleteTemplates(
867                     context.getGroupId());
868 
869                 JournalStructureLocalServiceUtil.deleteStructures(
870                     context.getGroupId());
871             }
872 
873             return prefs;
874         }
875         catch (Exception e) {
876             throw new PortletDataException(e);
877         }
878     }
879 
880     public String exportData(
881             PortletDataContext context, String portletId,
882             PortletPreferences prefs)
883         throws PortletDataException {
884 
885         try {
886             Document doc = DocumentHelper.createDocument();
887 
888             Element root = doc.addElement("journal-data");
889 
890             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
891 
892             Element structuresEl = root.addElement("structures");
893 
894             List<JournalStructure> structures =
895                 JournalStructureUtil.findByGroupId(context.getGroupId());
896 
897             for (JournalStructure structure : structures) {
898                 exportStructure(context, structuresEl, structure);
899             }
900 
901             Element templatesEl = root.addElement("templates");
902 
903             List<JournalTemplate> templates = JournalTemplateUtil.findByGroupId(
904                 context.getGroupId());
905 
906             for (JournalTemplate template : templates) {
907                 exportTemplate(context, templatesEl, template);
908             }
909 
910             Element feedsEl = root.addElement("feeds");
911 
912             List<JournalFeed> feeds = JournalFeedUtil.findByGroupId(
913                 context.getGroupId());
914 
915             for (JournalFeed feed : feeds) {
916                 if (context.isWithinDateRange(feed.getModifiedDate())) {
917                     exportFeed(context, feedsEl, feed);
918                 }
919             }
920 
921             Element articlesEl = root.addElement("articles");
922 
923             if (context.getBooleanParameter(_NAMESPACE, "articles")) {
924                 List<JournalArticle> articles =
925                     JournalArticleUtil.findByGroupId(context.getGroupId());
926 
927                 for (JournalArticle article : articles) {
928                     if (context.isWithinDateRange(article.getModifiedDate())) {
929                         exportArticle(context, articlesEl, article);
930                     }
931                 }
932             }
933 
934             return XMLFormatter.toString(doc);
935         }
936         catch (Exception e) {
937             throw new PortletDataException(e);
938         }
939     }
940 
941     public PortletDataHandlerControl[] getExportControls() {
942         return new PortletDataHandlerControl[] {
943             _articles, _structuresTemplatesAndFeeds
944         };
945     }
946 
947     public PortletDataHandlerControl[] getImportControls() {
948         return new PortletDataHandlerControl[] {
949             _articles, _structuresTemplatesAndFeeds
950         };
951     }
952 
953     public PortletPreferences importData(
954             PortletDataContext context, String portletId,
955             PortletPreferences prefs, String data)
956         throws PortletDataException {
957 
958         try {
959             Document doc = DocumentUtil.readDocumentFromXML(data);
960 
961             Element root = doc.getRootElement();
962 
963             List<Element> structureEls = root.element("structures").elements(
964                 "structure");
965 
966             Map<String, String> structureIds = context.getNewPrimaryKeysMap(
967                 JournalStructure.class);
968 
969             for (Element structureEl : structureEls) {
970                 importStructure(context, structureIds, structureEl);
971             }
972 
973             List<Element> templateEls = root.element("templates").elements(
974                 "template");
975 
976             Map<String, String> templateIds = context.getNewPrimaryKeysMap(
977                 JournalTemplate.class);
978 
979             for (Element templateEl : templateEls) {
980                 importTemplate(context, structureIds, templateIds, templateEl);
981             }
982 
983             List<Element> feedEls = root.element("feeds").elements("feed");
984 
985             Map<String, String> feedIds = context.getNewPrimaryKeysMap(
986                 JournalFeed.class);
987 
988             for (Element feedEl : feedEls) {
989                 importFeed(context, structureIds, templateIds, feedIds, feedEl);
990             }
991 
992             if (context.getBooleanParameter(_NAMESPACE, "articles")) {
993                 List<Element> articleEls = root.element("articles").elements(
994                     "article");
995 
996                 Map<String, String> articleIds = context.getNewPrimaryKeysMap(
997                     JournalArticle.class);
998 
999                 for (Element articleEl : articleEls) {
1000                    importArticle(
1001                        context, structureIds, templateIds, articleIds,
1002                        articleEl);
1003                }
1004            }
1005
1006            return prefs;
1007        }
1008        catch (Exception e) {
1009            throw new PortletDataException(e);
1010        }
1011    }
1012
1013    public boolean isPublishToLiveByDefault() {
1014        return true;
1015    }
1016
1017    protected static String getArticlePath(
1018        PortletDataContext context, JournalArticle article) {
1019
1020        StringBuilder sb = new StringBuilder();
1021
1022        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1023        sb.append("/articles/");
1024        sb.append(article.getArticleId());
1025        sb.append(StringPool.SLASH);
1026        sb.append(article.getVersion());
1027        sb.append(StringPool.SLASH);
1028        sb.append(article.getArticleId());
1029        sb.append(".xml");
1030
1031        return sb.toString();
1032    }
1033
1034    protected static String getArticleImagePath(
1035        PortletDataContext context, JournalArticle article) {
1036
1037        StringBuilder sb = new StringBuilder();
1038
1039        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1040        sb.append("/articles/");
1041        sb.append(article.getArticleId());
1042        sb.append(StringPool.SLASH);
1043        sb.append(article.getVersion());
1044        sb.append(StringPool.SLASH);
1045
1046        return sb.toString();
1047    }
1048
1049    protected static String getArticleImagePath(
1050        PortletDataContext context, JournalArticle article,
1051        JournalArticleImage articleImage, Image image) {
1052
1053        StringBuilder sb = new StringBuilder();
1054
1055        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1056        sb.append("/articles/");
1057        sb.append(article.getArticleId());
1058        sb.append(StringPool.SLASH);
1059        sb.append(article.getVersion());
1060        sb.append(StringPool.SLASH);
1061        sb.append(articleImage.getElName());
1062        sb.append(articleImage.getLanguageId());
1063        sb.append(StringPool.PERIOD);
1064        sb.append(image.getType());
1065
1066        return sb.toString();
1067    }
1068
1069    protected static String getArticleSmallImagePath(
1070            PortletDataContext context, JournalArticle article)
1071        throws PortalException, SystemException {
1072
1073        StringBuilder sb = new StringBuilder();
1074
1075        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1076        sb.append("/articles/thumbnail.");
1077        sb.append(article.getSmallImageType());
1078
1079        return sb.toString();
1080    }
1081
1082    protected static String getFeedPath(
1083        PortletDataContext context, JournalFeed feed) {
1084
1085        StringBuilder sb = new StringBuilder();
1086
1087        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1088        sb.append("/feeds/");
1089        sb.append(feed.getFeedId());
1090        sb.append(".xml");
1091
1092        return sb.toString();
1093    }
1094
1095    protected static String getTemplatePath(
1096        PortletDataContext context, JournalTemplate template) {
1097
1098        StringBuilder sb = new StringBuilder();
1099
1100        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1101        sb.append("/templates/");
1102        sb.append(template.getTemplateId());
1103        sb.append(".xml");
1104
1105        return sb.toString();
1106    }
1107
1108    protected static String getTemplateSmallImagePath(
1109            PortletDataContext context, JournalTemplate template)
1110        throws PortalException, SystemException {
1111
1112        StringBuilder sb = new StringBuilder();
1113
1114        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1115        sb.append("/templates/thumbnail-");
1116        sb.append(template.getTemplateId());
1117        sb.append(template.getSmallImageType());
1118
1119        return sb.toString();
1120    }
1121
1122    protected static String getStructurePath(
1123        PortletDataContext context, JournalStructure structure) {
1124
1125        StringBuilder sb = new StringBuilder();
1126
1127        sb.append(context.getPortletPath(PortletKeys.JOURNAL));
1128        sb.append("/structures/");
1129        sb.append(structure.getStructureId());
1130
1131        return sb.toString();
1132    }
1133
1134    private static final String _NAMESPACE = "journal";
1135
1136    private static final PortletDataHandlerBoolean _images =
1137        new PortletDataHandlerBoolean(_NAMESPACE, "images");
1138
1139    private static final PortletDataHandlerBoolean _comments =
1140        new PortletDataHandlerBoolean(_NAMESPACE, "comments");
1141
1142    private static final PortletDataHandlerBoolean _ratings =
1143        new PortletDataHandlerBoolean(_NAMESPACE, "ratings");
1144
1145    private static final PortletDataHandlerBoolean _tags =
1146        new PortletDataHandlerBoolean(_NAMESPACE, "tags");
1147
1148    private static final PortletDataHandlerBoolean _articles =
1149        new PortletDataHandlerBoolean(_NAMESPACE, "articles", true, false,
1150        new PortletDataHandlerControl[] {_images, _comments, _ratings, _tags});
1151
1152    private static final PortletDataHandlerBoolean
1153        _structuresTemplatesAndFeeds = new PortletDataHandlerBoolean(
1154            _NAMESPACE, "structures-templates-and-feeds", true, true);
1155
1156    private static Log _log =
1157        LogFactory.getLog(JournalPortletDataHandlerImpl.class);
1158
1159}