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.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.util.MapUtil;
24  import com.liferay.portal.kernel.util.ObjectValuePair;
25  import com.liferay.portal.kernel.util.PropsKeys;
26  import com.liferay.portal.kernel.util.StringBundler;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.kernel.xml.Document;
29  import com.liferay.portal.kernel.xml.Element;
30  import com.liferay.portal.kernel.xml.SAXReaderUtil;
31  import com.liferay.portal.lar.BasePortletDataHandler;
32  import com.liferay.portal.lar.PortletDataContext;
33  import com.liferay.portal.lar.PortletDataException;
34  import com.liferay.portal.lar.PortletDataHandlerBoolean;
35  import com.liferay.portal.lar.PortletDataHandlerControl;
36  import com.liferay.portal.lar.PortletDataHandlerKeys;
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.comparator.PageCreateDateComparator;
50  
51  import java.util.ArrayList;
52  import java.util.List;
53  import java.util.Map;
54  
55  import javax.portlet.PortletPreferences;
56  
57  /**
58   * <a href="WikiPortletDataHandlerImpl.java.html"><b><i>View Source</i></b></a>
59   *
60   * @author Bruno Farache
61   * @author Jorge Ferrer
62   * @author Marcellus Tavares
63   */
64  public class WikiPortletDataHandlerImpl extends BasePortletDataHandler {
65  
66      public static void exportNode(
67              PortletDataContext context, Element nodesEl, Element pagesEl,
68              WikiNode node)
69          throws PortalException, SystemException {
70  
71          if (context.isWithinDateRange(node.getModifiedDate())) {
72              String path = getNodePath(context, node);
73  
74              if (context.isPathNotProcessed(path)) {
75                  Element nodeEl = nodesEl.addElement("node");
76  
77                  nodeEl.addAttribute("path", path);
78  
79                  node.setUserUuid(node.getUserUuid());
80  
81                  context.addZipEntry(path, node);
82              }
83          }
84  
85          List<WikiPage> nodePages = WikiPageUtil.findByNodeId(
86              node.getNodeId(), QueryUtil.ALL_POS, QueryUtil.ALL_POS,
87              new PageCreateDateComparator(true));
88  
89          for (WikiPage page : nodePages) {
90              exportPage(context, nodesEl, pagesEl, page);
91          }
92      }
93  
94      public static void importNode(
95              PortletDataContext context, Map<Long, Long> nodePKs, WikiNode node)
96          throws Exception {
97  
98          long userId = context.getUserId(node.getUserUuid());
99  
100         ServiceContext serviceContext = new ServiceContext();
101 
102         serviceContext.setAddCommunityPermissions(true);
103         serviceContext.setAddGuestPermissions(true);
104         serviceContext.setScopeGroupId(context.getGroupId());
105 
106         WikiNode existingNode = null;
107 
108         if (context.getDataStrategy().equals(
109                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
110 
111             existingNode = WikiNodeUtil.fetchByUUID_G(
112                 node.getUuid(), context.getGroupId());
113 
114             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
115 
116             if (existingNode == null && node.getName().equals(nodeName)) {
117                 try {
118                     WikiNodeUtil.removeByG_N(
119                         context.getGroupId(), node.getName());
120                 }
121                 catch (NoSuchNodeException nsne) {
122                 }
123             }
124 
125             if (existingNode == null) {
126                 existingNode = WikiNodeLocalServiceUtil.addNode(
127                     node.getUuid(), userId, node.getName(),
128                     node.getDescription(), serviceContext);
129             }
130             else {
131                 existingNode = WikiNodeLocalServiceUtil.updateNode(
132                     existingNode.getNodeId(), node.getName(),
133                     node.getDescription());
134             }
135         }
136         else {
137             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
138 
139             if (node.getName().equals(nodeName)) {
140                 try {
141                     WikiNodeUtil.removeByG_N(
142                         context.getGroupId(), node.getName());
143                 }
144                 catch (NoSuchNodeException nsne) {
145                 }
146             }
147 
148             existingNode = WikiNodeLocalServiceUtil.addNode(
149                 userId, node.getName(), node.getDescription(), serviceContext);
150         }
151 
152         nodePKs.put(node.getNodeId(), existingNode.getNodeId());
153     }
154 
155     public static void importPage(
156             PortletDataContext context, Map<Long, Long> nodePKs, Element pageEl,
157             WikiPage page)
158         throws Exception {
159 
160         long userId = context.getUserId(page.getUserUuid());
161         long nodeId = MapUtil.getLong(
162             nodePKs, page.getNodeId(), page.getNodeId());
163 
164         long[] assetCategoryIds = null;
165         String[] assetTagNames = null;
166 
167         if (context.getBooleanParameter(_NAMESPACE, "categories")) {
168             assetCategoryIds = context.getAssetCategoryIds(
169                 WikiPage.class, page.getResourcePrimKey());
170         }
171 
172         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
173             assetTagNames = context.getAssetTagNames(
174                 WikiPage.class, page.getResourcePrimKey());
175         }
176 
177         ServiceContext serviceContext = new ServiceContext();
178 
179         serviceContext.setAddCommunityPermissions(true);
180         serviceContext.setAddGuestPermissions(true);
181         serviceContext.setAssetCategoryIds(assetCategoryIds);
182         serviceContext.setAssetTagNames(assetTagNames);
183 
184         WikiPage existingPage = null;
185 
186         try {
187             WikiNodeUtil.findByPrimaryKey(nodeId);
188 
189             if (context.getDataStrategy().equals(
190                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
191 
192                 try {
193                     existingPage = WikiPageUtil.findByUUID_G(
194                         page.getUuid(), context.getGroupId());
195                 }
196                 catch (NoSuchPageException nspe) {
197                 }
198 
199                 if (existingPage == null) {
200                     try {
201                         existingPage = WikiPageLocalServiceUtil.getPage(
202                             nodeId, page.getTitle());
203                     }
204                     catch (NoSuchPageException nspe) {
205                     }
206                 }
207 
208                 if (existingPage != null) {
209                     existingPage = WikiPageLocalServiceUtil.updatePage(
210                         userId, nodeId, existingPage.getTitle(), 0,
211                         page.getContent(), page.getSummary(), true,
212                         page.getFormat(), page.getParentTitle(),
213                         page.getRedirectTitle(), serviceContext);
214                 }
215                 else {
216                     existingPage = WikiPageLocalServiceUtil.addPage(
217                         page.getUuid(), userId, nodeId, page.getTitle(),
218                         page.getVersion(), page.getContent(), page.getSummary(),
219                         true, page.getFormat(), page.getHead(),
220                         page.getParentTitle(), page.getRedirectTitle(),
221                         serviceContext);
222                 }
223             }
224             else {
225                 existingPage = WikiPageLocalServiceUtil.addPage(
226                     null, userId, nodeId, page.getTitle(), page.getVersion(),
227                     page.getContent(), page.getSummary(), true,
228                     page.getFormat(), page.getHead(), page.getParentTitle(),
229                     page.getRedirectTitle(), serviceContext);
230             }
231 
232             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
233                 page.isHead()) {
234 
235                 List<Element> attachmentEls = pageEl.elements("attachment");
236 
237                 List<ObjectValuePair<String, byte[]>> files =
238                     new ArrayList<ObjectValuePair<String, byte[]>>();
239 
240                 for (Element attachmentEl : attachmentEls) {
241                     String name = attachmentEl.attributeValue("name");
242                     String binPath = attachmentEl.attributeValue("bin-path");
243 
244                     byte[] bytes = context.getZipEntryAsByteArray(binPath);
245 
246                     files.add(new ObjectValuePair<String, byte[]>(name, bytes));
247                 }
248 
249                 if (files.size() > 0) {
250                     WikiPageLocalServiceUtil.addPageAttachments(
251                         nodeId, page.getTitle(), files);
252                 }
253             }
254 
255             if (context.getBooleanParameter(_NAMESPACE, "comments") &&
256                 page.isHead()) {
257 
258                 context.importComments(
259                     WikiPage.class, page.getResourcePrimKey(),
260                     existingPage.getResourcePrimKey(), context.getGroupId());
261             }
262 
263             if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
264                 context.importRatingsEntries(
265                     WikiPage.class, page.getResourcePrimKey(),
266                     existingPage.getResourcePrimKey());
267             }
268         }
269         catch (NoSuchNodeException nsne) {
270             _log.error("Could not find the node for page " + page.getPageId());
271         }
272     }
273 
274     public PortletPreferences deleteData(
275             PortletDataContext context, String portletId,
276             PortletPreferences preferences)
277         throws PortletDataException {
278 
279         try {
280             if (!context.addPrimaryKey(
281                     WikiPortletDataHandlerImpl.class, "deleteData")) {
282 
283                 WikiNodeLocalServiceUtil.deleteNodes(context.getGroupId());
284             }
285 
286             return null;
287         }
288         catch (Exception e) {
289             throw new PortletDataException(e);
290         }
291     }
292 
293     public String exportData(
294             PortletDataContext context, String portletId,
295             PortletPreferences preferences)
296         throws PortletDataException {
297 
298         try {
299             Document doc = SAXReaderUtil.createDocument();
300 
301             Element root = doc.addElement("wiki-data");
302 
303             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
304 
305             Element nodesEl = root.addElement("nodes");
306             Element pagesEl = root.addElement("pages");
307 
308             List<WikiNode> nodes = WikiNodeUtil.findByGroupId(
309                 context.getGroupId());
310 
311             for (WikiNode node : nodes) {
312                 exportNode(context, nodesEl, pagesEl, node);
313             }
314 
315             return doc.formattedString();
316         }
317         catch (Exception e) {
318             throw new PortletDataException(e);
319         }
320     }
321 
322     public PortletDataHandlerControl[] getExportControls() {
323         return new PortletDataHandlerControl[] {
324             _nodesAndPages, _attachments, _categories, _comments, _tags
325         };
326     }
327 
328     public PortletDataHandlerControl[] getImportControls() {
329         return new PortletDataHandlerControl[] {
330             _nodesAndPages, _attachments, _categories, _comments, _tags
331         };
332     }
333 
334     public PortletPreferences importData(
335             PortletDataContext context, String portletId,
336             PortletPreferences preferences, String data)
337         throws PortletDataException {
338 
339         try {
340             Document doc = SAXReaderUtil.read(data);
341 
342             Element root = doc.getRootElement();
343 
344             List<Element> nodeEls = root.element("nodes").elements("node");
345 
346             Map<Long, Long> nodePKs =
347                 (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
348 
349             for (Element nodeEl : nodeEls) {
350                 String path = nodeEl.attributeValue("path");
351 
352                 if (!context.isPathNotProcessed(path)) {
353                     continue;
354                 }
355 
356                 WikiNode node = (WikiNode)context.getZipEntryAsObject(path);
357 
358                 importNode(context, nodePKs, node);
359             }
360 
361             List<Element> pageEls = root.element("pages").elements("page");
362 
363             for (Element pageEl : pageEls) {
364                 String path = pageEl.attributeValue("path");
365 
366                 if (!context.isPathNotProcessed(path)) {
367                     continue;
368                 }
369 
370                 WikiPage page = (WikiPage)context.getZipEntryAsObject(path);
371 
372                 importPage(context, nodePKs, pageEl, page);
373             }
374 
375             return null;
376         }
377         catch (Exception e) {
378             throw new PortletDataException(e);
379         }
380     }
381 
382     protected static void exportNode(
383             PortletDataContext context, Element nodesEl, long nodeId)
384         throws PortalException, SystemException {
385 
386         if (!context.hasDateRange()) {
387             return;
388         }
389 
390         WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
391 
392         String path = getNodePath(context, node);
393 
394         if (!context.isPathNotProcessed(path)) {
395             return;
396         }
397 
398         Element nodeEl = nodesEl.addElement("node");
399 
400         nodeEl.addAttribute("path", path);
401 
402         node.setUserUuid(node.getUserUuid());
403 
404         context.addZipEntry(path, node);
405     }
406 
407     protected static void exportPage(
408             PortletDataContext context, Element nodesEl, Element pagesEl,
409             WikiPage page)
410         throws PortalException, SystemException {
411 
412         if (!context.isWithinDateRange(page.getModifiedDate())) {
413             return;
414         }
415 
416         String path = getPagePath(context, page);
417 
418         if (context.isPathNotProcessed(path)) {
419             Element pageEl = pagesEl.addElement("page");
420 
421             pageEl.addAttribute("path", path);
422 
423             page.setUserUuid(page.getUserUuid());
424 
425             if (context.getBooleanParameter(_NAMESPACE, "categories")) {
426                 context.addAssetCategories(
427                     WikiPage.class, page.getResourcePrimKey());
428             }
429 
430             if (context.getBooleanParameter(_NAMESPACE, "comments")) {
431                 context.addComments(WikiPage.class, page.getResourcePrimKey());
432             }
433 
434             if (context.getBooleanParameter(_NAMESPACE, "tags")) {
435                 context.addAssetTags(WikiPage.class, page.getResourcePrimKey());
436             }
437 
438             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
439                 page.isHead()) {
440 
441                 for (String attachment : page.getAttachmentsFiles()) {
442                     int pos = attachment.lastIndexOf(StringPool.SLASH);
443 
444                     String name = attachment.substring(pos + 1);
445                     String binPath = getPageAttachementBinPath(
446                         context, page, name);
447 
448                     Element attachmentEl = pageEl.addElement("attachment");
449 
450                     attachmentEl.addAttribute("name", name);
451                     attachmentEl.addAttribute("bin-path", binPath);
452 
453                     byte[] bytes = DLServiceUtil.getFile(
454                         context.getCompanyId(), CompanyConstants.SYSTEM,
455                         attachment);
456 
457                     context.addZipEntry(binPath, bytes);
458                 }
459 
460                 page.setAttachmentsDir(page.getAttachmentsDir());
461             }
462 
463             context.addZipEntry(path, page);
464         }
465 
466         exportNode(context, nodesEl, page.getNodeId());
467     }
468 
469     protected static String getNodePath(
470         PortletDataContext context, WikiNode node) {
471 
472         StringBundler sb = new StringBundler(4);
473 
474         sb.append(context.getPortletPath(PortletKeys.WIKI));
475         sb.append("/nodes/");
476         sb.append(node.getNodeId());
477         sb.append(".xml");
478 
479         return sb.toString();
480     }
481 
482     protected static String getPageAttachementBinPath(
483         PortletDataContext context, WikiPage page, String attachment) {
484 
485         StringBundler sb = new StringBundler(5);
486 
487         sb.append(context.getPortletPath(PortletKeys.WIKI));
488         sb.append("/bin/");
489         sb.append(page.getPageId());
490         sb.append(StringPool.SLASH);
491         sb.append(attachment);
492 
493         return sb.toString();
494     }
495 
496     protected static String getPagePath(
497         PortletDataContext context, WikiPage page) {
498 
499         StringBundler sb = new StringBundler(4);
500 
501         sb.append(context.getPortletPath(PortletKeys.WIKI));
502         sb.append("/pages/");
503         sb.append(page.getPageId());
504         sb.append(".xml");
505 
506         return sb.toString();
507     }
508 
509     private static final String _NAMESPACE = "wiki";
510 
511     private static final PortletDataHandlerBoolean _nodesAndPages =
512         new PortletDataHandlerBoolean(
513             _NAMESPACE, "wikis-and-pages", true, true);
514 
515     private static final PortletDataHandlerBoolean _attachments =
516         new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
517 
518     private static final PortletDataHandlerBoolean _categories =
519         new PortletDataHandlerBoolean(_NAMESPACE, "categories");
520 
521     private static final PortletDataHandlerBoolean _comments =
522         new PortletDataHandlerBoolean(_NAMESPACE, "comments");
523 
524     private static final PortletDataHandlerBoolean _tags =
525         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
526 
527     private static Log _log = LogFactoryUtil.getLog(
528         WikiPortletDataHandlerImpl.class);
529 
530 }