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