1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portlet.wiki.lar;
16  
17  import com.liferay.documentlibrary.service.DLServiceUtil;
18  import com.liferay.portal.kernel.dao.orm.QueryUtil;
19  import com.liferay.portal.kernel.exception.PortalException;
20  import com.liferay.portal.kernel.exception.SystemException;
21  import com.liferay.portal.kernel.lar.BasePortletDataHandler;
22  import com.liferay.portal.kernel.lar.PortletDataContext;
23  import com.liferay.portal.kernel.lar.PortletDataException;
24  import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
25  import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
26  import com.liferay.portal.kernel.lar.PortletDataHandlerKeys;
27  import com.liferay.portal.kernel.log.Log;
28  import com.liferay.portal.kernel.log.LogFactoryUtil;
29  import com.liferay.portal.kernel.util.MapUtil;
30  import com.liferay.portal.kernel.util.PropsKeys;
31  import com.liferay.portal.kernel.util.StringBundler;
32  import com.liferay.portal.kernel.util.StringPool;
33  import com.liferay.portal.kernel.workflow.WorkflowConstants;
34  import com.liferay.portal.kernel.xml.Document;
35  import com.liferay.portal.kernel.xml.Element;
36  import com.liferay.portal.kernel.xml.SAXReaderUtil;
37  import com.liferay.portal.model.CompanyConstants;
38  import com.liferay.portal.service.ServiceContext;
39  import com.liferay.portal.util.PortletKeys;
40  import com.liferay.portal.util.PropsUtil;
41  import com.liferay.portlet.wiki.NoSuchNodeException;
42  import com.liferay.portlet.wiki.NoSuchPageException;
43  import com.liferay.portlet.wiki.model.WikiNode;
44  import com.liferay.portlet.wiki.model.WikiPage;
45  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
46  import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
47  import com.liferay.portlet.wiki.service.persistence.WikiNodeUtil;
48  import com.liferay.portlet.wiki.service.persistence.WikiPageUtil;
49  import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
50  import com.liferay.portlet.wiki.util.WikiCacheUtil;
51  import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
52  
53  import java.io.InputStream;
54  
55  import java.util.List;
56  import java.util.Map;
57  
58  import javax.portlet.PortletPreferences;
59  
60  /**
61   * <a href="WikiPortletDataHandlerImpl.java.html"><b><i>View Source</i></b></a>
62   *
63   * @author Bruno Farache
64   * @author Jorge Ferrer
65   * @author Marcellus Tavares
66   * @author Juan Fernández
67   */
68  public class WikiPortletDataHandlerImpl extends BasePortletDataHandler {
69  
70      public static void exportNode(
71              PortletDataContext context, Element nodesEl, Element pagesEl,
72              WikiNode node)
73          throws PortalException, SystemException {
74  
75          if (context.isWithinDateRange(node.getModifiedDate())) {
76              String path = getNodePath(context, node);
77  
78              if (context.isPathNotProcessed(path)) {
79                  Element nodeEl = nodesEl.addElement("node");
80  
81                  nodeEl.addAttribute("path", path);
82  
83                  node.setUserUuid(node.getUserUuid());
84  
85                  context.addPermissions(WikiNode.class, node.getNodeId());
86  
87                  context.addZipEntry(path, node);
88              }
89          }
90  
91          List<WikiPage> nodePages = WikiPageUtil.findByN_S(
92              node.getNodeId(), WorkflowConstants.STATUS_APPROVED,
93              QueryUtil.ALL_POS, QueryUtil.ALL_POS,
94              new PageVersionComparator(true));
95  
96          for (WikiPage page : nodePages) {
97              exportPage(context, nodesEl, pagesEl, page);
98          }
99      }
100 
101     public static void importNode(
102             PortletDataContext context, Map<Long, Long> nodePKs, WikiNode node)
103         throws Exception {
104 
105         long userId = context.getUserId(node.getUserUuid());
106 
107         ServiceContext serviceContext = new ServiceContext();
108 
109         serviceContext.setAddCommunityPermissions(true);
110         serviceContext.setAddGuestPermissions(true);
111         serviceContext.setCreateDate(node.getCreateDate());
112         serviceContext.setModifiedDate(node.getModifiedDate());
113         serviceContext.setScopeGroupId(context.getGroupId());
114 
115         WikiNode importedNode = null;
116 
117         if (context.getDataStrategy().equals(
118                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
119 
120             WikiNode existingNode = WikiNodeUtil.fetchByUUID_G(
121                 node.getUuid(), context.getGroupId());
122 
123             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
124 
125             if ((existingNode == null) && node.getName().equals(nodeName)) {
126                 try {
127                     WikiNodeUtil.removeByG_N(
128                         context.getGroupId(), node.getName());
129                 }
130                 catch (NoSuchNodeException nsne) {
131                 }
132             }
133 
134             if (existingNode == null) {
135                 importedNode = WikiNodeLocalServiceUtil.addNode(
136                     node.getUuid(), userId, node.getName(),
137                     node.getDescription(), serviceContext);
138             }
139             else {
140                 importedNode = WikiNodeLocalServiceUtil.updateNode(
141                     existingNode.getNodeId(), node.getName(),
142                     node.getDescription(), serviceContext);
143             }
144         }
145         else {
146             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
147 
148             if (node.getName().equals(nodeName)) {
149                 try {
150                     WikiNodeUtil.removeByG_N(
151                         context.getGroupId(), node.getName());
152                 }
153                 catch (NoSuchNodeException nsne) {
154                 }
155             }
156 
157             importedNode = WikiNodeLocalServiceUtil.addNode(
158                 userId, node.getName(), node.getDescription(), serviceContext);
159         }
160 
161         nodePKs.put(node.getNodeId(), importedNode.getNodeId());
162 
163         context.importPermissions(
164             WikiNode.class, node.getNodeId(), importedNode.getNodeId());
165     }
166 
167     public static void importPage(
168             PortletDataContext context, Map<Long, Long> nodePKs, Element pageEl,
169             WikiPage page)
170         throws Exception {
171 
172         long userId = context.getUserId(page.getUserUuid());
173         long nodeId = MapUtil.getLong(
174             nodePKs, page.getNodeId(), page.getNodeId());
175 
176         long[] assetCategoryIds = null;
177         String[] assetTagNames = null;
178 
179         if (context.getBooleanParameter(_NAMESPACE, "categories") &&
180             page.isHead()) {
181 
182             assetCategoryIds = context.getAssetCategoryIds(
183                 WikiPage.class, page.getResourcePrimKey());
184         }
185 
186         if (context.getBooleanParameter(_NAMESPACE, "tags") &&
187             page.isHead()) {
188 
189             assetTagNames = context.getAssetTagNames(
190                 WikiPage.class, page.getResourcePrimKey());
191         }
192 
193         ServiceContext serviceContext = new ServiceContext();
194 
195         serviceContext.setAddCommunityPermissions(true);
196         serviceContext.setAddGuestPermissions(true);
197         serviceContext.setAssetCategoryIds(assetCategoryIds);
198         serviceContext.setAssetTagNames(assetTagNames);
199         serviceContext.setCreateDate(page.getCreateDate());
200         serviceContext.setModifiedDate(page.getModifiedDate());
201 
202         if (page.getStatus() != WorkflowConstants.STATUS_APPROVED) {
203             serviceContext.setWorkflowAction(
204                 WorkflowConstants.ACTION_SAVE_DRAFT);
205         }
206 
207         WikiPage importedPage = null;
208 
209         try {
210             WikiNodeUtil.findByPrimaryKey(nodeId);
211 
212             if (context.getDataStrategy().equals(
213                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
214 
215                 WikiPage existingPage = WikiPageUtil.fetchByUUID_G(
216                     page.getUuid(), context.getGroupId());
217 
218                 if (existingPage == null) {
219                     try {
220                         existingPage = WikiPageLocalServiceUtil.getPage(
221                             nodeId, page.getTitle());
222                     }
223                     catch (NoSuchPageException nspe) {
224                     }
225                 }
226 
227                 if (existingPage == null) {
228                     importedPage = WikiPageLocalServiceUtil.addPage(
229                         page.getUuid(), userId, nodeId, page.getTitle(),
230                         page.getVersion(), page.getContent(), page.getSummary(),
231                         true, page.getFormat(), page.getHead(),
232                         page.getParentTitle(), page.getRedirectTitle(),
233                         serviceContext);
234                 }
235                 else {
236                     importedPage = WikiPageLocalServiceUtil.updatePage(
237                         userId, nodeId, existingPage.getTitle(), 0,
238                         page.getContent(), page.getSummary(), true,
239                         page.getFormat(), page.getParentTitle(),
240                         page.getRedirectTitle(), serviceContext);
241                 }
242             }
243             else {
244                 importedPage = WikiPageLocalServiceUtil.addPage(
245                     null, userId, nodeId, page.getTitle(), page.getVersion(),
246                     page.getContent(), page.getSummary(), true,
247                     page.getFormat(), page.getHead(), page.getParentTitle(),
248                     page.getRedirectTitle(), serviceContext);
249             }
250 
251             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
252                 page.isHead()) {
253 
254                 List<Element> attachmentEls = pageEl.elements("attachment");
255 
256                 for (Element attachmentEl : attachmentEls) {
257                     String name = attachmentEl.attributeValue("name");
258                     String binPath = attachmentEl.attributeValue("bin-path");
259 
260                     InputStream inputStream = context.getZipEntryAsInputStream(
261                         binPath);
262 
263                     WikiPageLocalServiceUtil.addPageAttachment(
264                         importedPage.getCompanyId(),
265                         importedPage.getAttachmentsDir(),
266                         importedPage.getModifiedDate(), name, inputStream);
267                 }
268             }
269 
270             if (page.isHead()) {
271                 context.importPermissions(
272                     WikiPage.class, page.getResourcePrimKey(),
273                     importedPage.getResourcePrimKey());
274             }
275 
276             if (context.getBooleanParameter(_NAMESPACE, "comments") &&
277                 page.isHead()) {
278 
279                 context.importComments(
280                     WikiPage.class, page.getResourcePrimKey(),
281                     importedPage.getResourcePrimKey(), context.getGroupId());
282             }
283 
284             if (context.getBooleanParameter(_NAMESPACE, "ratings") &&
285                 page.isHead()) {
286 
287                 context.importRatingsEntries(
288                     WikiPage.class, page.getResourcePrimKey(),
289                     importedPage.getResourcePrimKey());
290             }
291         }
292         catch (NoSuchNodeException nsne) {
293             _log.error("Could not find the node for page " + page.getPageId());
294         }
295     }
296 
297     public PortletPreferences deleteData(
298             PortletDataContext context, String portletId,
299             PortletPreferences preferences)
300         throws PortletDataException {
301 
302         try {
303             if (!context.addPrimaryKey(
304                     WikiPortletDataHandlerImpl.class, "deleteData")) {
305 
306                 WikiNodeLocalServiceUtil.deleteNodes(context.getGroupId());
307             }
308 
309             return null;
310         }
311         catch (Exception e) {
312             throw new PortletDataException(e);
313         }
314     }
315 
316     public String exportData(
317             PortletDataContext context, String portletId,
318             PortletPreferences preferences)
319         throws PortletDataException {
320 
321         try {
322             context.addPermissions(
323                 "com.liferay.portlet.wiki", context.getGroupId());
324 
325             Document doc = SAXReaderUtil.createDocument();
326 
327             Element root = doc.addElement("wiki-data");
328 
329             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
330 
331             Element nodesEl = root.addElement("nodes");
332             Element pagesEl = root.addElement("pages");
333 
334             List<WikiNode> nodes = WikiNodeUtil.findByGroupId(
335                 context.getGroupId());
336 
337             for (WikiNode node : nodes) {
338                 exportNode(context, nodesEl, pagesEl, node);
339             }
340 
341             return doc.formattedString();
342         }
343         catch (Exception e) {
344             throw new PortletDataException(e);
345         }
346     }
347 
348     public PortletDataHandlerControl[] getExportControls() {
349         return new PortletDataHandlerControl[] {
350             _nodesAndPages, _attachments, _categories, _comments, _ratings,
351             _tags
352         };
353     }
354 
355     public PortletDataHandlerControl[] getImportControls() {
356         return new PortletDataHandlerControl[] {
357             _nodesAndPages, _attachments, _categories, _comments, _ratings,
358             _tags
359         };
360     }
361 
362     public PortletPreferences importData(
363             PortletDataContext context, String portletId,
364             PortletPreferences preferences, String data)
365         throws PortletDataException {
366 
367         WikiCacheThreadLocal.setClearCache(false);
368 
369         try {
370             context.importPermissions(
371                 "com.liferay.portlet.wiki", context.getSourceGroupId(),
372                 context.getGroupId());
373 
374             Document doc = SAXReaderUtil.read(data);
375 
376             Element root = doc.getRootElement();
377 
378             List<Element> nodeEls = root.element("nodes").elements("node");
379 
380             Map<Long, Long> nodePKs =
381                 (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
382 
383             for (Element nodeEl : nodeEls) {
384                 String path = nodeEl.attributeValue("path");
385 
386                 if (!context.isPathNotProcessed(path)) {
387                     continue;
388                 }
389 
390                 WikiNode node = (WikiNode)context.getZipEntryAsObject(path);
391 
392                 importNode(context, nodePKs, node);
393             }
394 
395             List<Element> pageEls = root.element("pages").elements("page");
396 
397             for (Element pageEl : pageEls) {
398                 String path = pageEl.attributeValue("path");
399 
400                 if (!context.isPathNotProcessed(path)) {
401                     continue;
402                 }
403 
404                 WikiPage page = (WikiPage)context.getZipEntryAsObject(path);
405 
406                 importPage(context, nodePKs, pageEl, page);
407             }
408 
409             for (long nodeId : nodePKs.values()) {
410                 WikiCacheUtil.clearCache(nodeId);
411             }
412 
413             return null;
414         }
415         catch (Exception e) {
416             throw new PortletDataException(e);
417         }
418         finally {
419             WikiCacheThreadLocal.setClearCache(true);
420         }
421     }
422 
423     protected static void exportNode(
424             PortletDataContext context, Element nodesEl, long nodeId)
425         throws PortalException, SystemException {
426 
427         if (!context.hasDateRange()) {
428             return;
429         }
430 
431         WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
432 
433         String path = getNodePath(context, node);
434 
435         if (!context.isPathNotProcessed(path)) {
436             return;
437         }
438 
439         Element nodeEl = nodesEl.addElement("node");
440 
441         nodeEl.addAttribute("path", path);
442 
443         node.setUserUuid(node.getUserUuid());
444 
445         context.addPermissions(WikiNode.class, node.getNodeId());
446 
447         context.addZipEntry(path, node);
448     }
449 
450     protected static void exportPage(
451             PortletDataContext context, Element nodesEl, Element pagesEl,
452             WikiPage page)
453         throws PortalException, SystemException {
454 
455         if (!context.isWithinDateRange(page.getModifiedDate())) {
456             return;
457         }
458 
459         String path = getPagePath(context, page);
460 
461         if (context.isPathNotProcessed(path)) {
462             Element pageEl = pagesEl.addElement("page");
463 
464             pageEl.addAttribute("path", path);
465 
466             page.setUserUuid(page.getUserUuid());
467 
468             context.addPermissions(WikiPage.class, page.getResourcePrimKey());
469 
470             if (context.getBooleanParameter(_NAMESPACE, "categories") &&
471                 page.isHead()) {
472 
473                 context.addAssetCategories(
474                     WikiPage.class, page.getResourcePrimKey());
475             }
476 
477             if (context.getBooleanParameter(_NAMESPACE, "comments") &&
478                 page.isHead()) {
479 
480                 context.addComments(WikiPage.class, page.getResourcePrimKey());
481             }
482 
483             if (context.getBooleanParameter(_NAMESPACE, "ratings") &&
484                 page.isHead()) {
485 
486                 context.addRatingsEntries(
487                     WikiPage.class, page.getResourcePrimKey());
488             }
489 
490             if (context.getBooleanParameter(_NAMESPACE, "tags") &&
491                 page.isHead()) {
492 
493                 context.addAssetTags(WikiPage.class, page.getResourcePrimKey());
494             }
495 
496             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
497                 page.isHead()) {
498 
499                 for (String attachment : page.getAttachmentsFiles()) {
500                     int pos = attachment.lastIndexOf(StringPool.SLASH);
501 
502                     String name = attachment.substring(pos + 1);
503                     String binPath = getPageAttachementBinPath(
504                         context, page, name);
505 
506                     Element attachmentEl = pageEl.addElement("attachment");
507 
508                     attachmentEl.addAttribute("name", name);
509                     attachmentEl.addAttribute("bin-path", binPath);
510 
511                     byte[] bytes = DLServiceUtil.getFile(
512                         context.getCompanyId(), CompanyConstants.SYSTEM,
513                         attachment);
514 
515                     context.addZipEntry(binPath, bytes);
516                 }
517 
518                 page.setAttachmentsDir(page.getAttachmentsDir());
519             }
520 
521             context.addZipEntry(path, page);
522         }
523 
524         exportNode(context, nodesEl, page.getNodeId());
525     }
526 
527     protected static String getNodePath(
528         PortletDataContext context, WikiNode node) {
529 
530         StringBundler sb = new StringBundler(4);
531 
532         sb.append(context.getPortletPath(PortletKeys.WIKI));
533         sb.append("/nodes/");
534         sb.append(node.getNodeId());
535         sb.append(".xml");
536 
537         return sb.toString();
538     }
539 
540     protected static String getPageAttachementBinPath(
541         PortletDataContext context, WikiPage page, String attachment) {
542 
543         StringBundler sb = new StringBundler(5);
544 
545         sb.append(context.getPortletPath(PortletKeys.WIKI));
546         sb.append("/bin/");
547         sb.append(page.getPageId());
548         sb.append(StringPool.SLASH);
549         sb.append(attachment);
550 
551         return sb.toString();
552     }
553 
554     protected static String getPagePath(
555         PortletDataContext context, WikiPage page) {
556 
557         StringBundler sb = new StringBundler(4);
558 
559         sb.append(context.getPortletPath(PortletKeys.WIKI));
560         sb.append("/pages/");
561         sb.append(page.getPageId());
562         sb.append(".xml");
563 
564         return sb.toString();
565     }
566 
567     private static final String _NAMESPACE = "wiki";
568 
569     private static Log _log = LogFactoryUtil.getLog(
570         WikiPortletDataHandlerImpl.class);
571 
572     private static PortletDataHandlerBoolean _attachments =
573         new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
574 
575     private static PortletDataHandlerBoolean _categories =
576         new PortletDataHandlerBoolean(_NAMESPACE, "categories");
577 
578     private static PortletDataHandlerBoolean _comments =
579         new PortletDataHandlerBoolean(_NAMESPACE, "comments");
580 
581     private static PortletDataHandlerBoolean _nodesAndPages =
582         new PortletDataHandlerBoolean(
583             _NAMESPACE, "wikis-and-pages", true, true);
584 
585     private static PortletDataHandlerBoolean _ratings =
586         new PortletDataHandlerBoolean(_NAMESPACE, "ratings");
587 
588     private static PortletDataHandlerBoolean _tags =
589         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
590 
591 }