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