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.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.util.ObjectValuePair;
29  import com.liferay.portal.kernel.util.StringPool;
30  import com.liferay.portal.kernel.xml.Document;
31  import com.liferay.portal.kernel.xml.Element;
32  import com.liferay.portal.kernel.xml.SAXReaderUtil;
33  import com.liferay.portal.lar.PortletDataContext;
34  import com.liferay.portal.lar.PortletDataException;
35  import com.liferay.portal.lar.PortletDataHandler;
36  import com.liferay.portal.lar.PortletDataHandlerBoolean;
37  import com.liferay.portal.lar.PortletDataHandlerControl;
38  import com.liferay.portal.lar.PortletDataHandlerKeys;
39  import com.liferay.portal.model.CompanyConstants;
40  import com.liferay.portal.theme.ThemeDisplay;
41  import com.liferay.portal.util.PortletKeys;
42  import com.liferay.portal.util.PropsKeys;
43  import com.liferay.portal.util.PropsUtil;
44  import com.liferay.portlet.wiki.NoSuchNodeException;
45  import com.liferay.portlet.wiki.NoSuchPageException;
46  import com.liferay.portlet.wiki.model.WikiNode;
47  import com.liferay.portlet.wiki.model.WikiPage;
48  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
49  import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
50  import com.liferay.portlet.wiki.service.persistence.WikiNodeUtil;
51  import com.liferay.portlet.wiki.service.persistence.WikiPageFinderUtil;
52  import com.liferay.portlet.wiki.service.persistence.WikiPageUtil;
53  import com.liferay.util.MapUtil;
54  
55  import java.rmi.RemoteException;
56  
57  import java.util.ArrayList;
58  import java.util.List;
59  import java.util.Map;
60  
61  import javax.portlet.PortletPreferences;
62  
63  import org.apache.commons.logging.Log;
64  import org.apache.commons.logging.LogFactory;
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(node.getNodeId());
206 
207         for (WikiPage page : nodePages) {
208             exportPage(context, nodesEl, pagesEl, page);
209         }
210     }
211 
212     protected void exportNode(
213             PortletDataContext context, Element nodesEl, long nodeId)
214         throws PortalException, SystemException {
215 
216         if (!context.hasDateRange()) {
217             return;
218         }
219 
220         WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
221 
222         String path = getNodePath(context, node);
223 
224         if (!context.isPathNotProcessed(path)) {
225             return;
226         }
227 
228         Element nodeEl = nodesEl.addElement("node");
229 
230         nodeEl.addAttribute("path", path);
231 
232         node.setUserUuid(node.getUserUuid());
233 
234         context.addZipEntry(path, node);
235     }
236 
237     protected void exportPage(
238             PortletDataContext context, Element nodesEl, Element pagesEl,
239             WikiPage page)
240         throws PortalException, SystemException {
241 
242         if (!context.isWithinDateRange(page.getModifiedDate())) {
243             return;
244         }
245 
246         String path = getPagePath(context, page);
247 
248         if (context.isPathNotProcessed(path)) {
249             Element pageEl = pagesEl.addElement("page");
250 
251             pageEl.addAttribute("path", path);
252 
253             page.setUserUuid(page.getUserUuid());
254 
255             if (context.getBooleanParameter(_NAMESPACE, "comments")) {
256                 context.addComments(WikiPage.class, page.getResourcePrimKey());
257             }
258 
259             if (context.getBooleanParameter(_NAMESPACE, "tags")) {
260                 context.addTagsEntries(
261                     WikiPage.class, page.getResourcePrimKey());
262             }
263 
264             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
265                 page.isHead()) {
266 
267                 for (String attachment : page.getAttachmentsFiles()) {
268                     int pos = attachment.lastIndexOf(StringPool.SLASH);
269 
270                     String name = attachment.substring(pos + 1);
271                     String binPath = getPageAttachementBinPath(
272                         context, page, name);
273 
274                     Element attachmentEl = pageEl.addElement("attachment");
275 
276                     attachmentEl.addAttribute("name", name);
277                     attachmentEl.addAttribute("bin-path", binPath);
278 
279                     try {
280                         byte[] bytes = DLServiceUtil.getFile(
281                             context.getCompanyId(), CompanyConstants.SYSTEM,
282                             attachment);
283 
284                         context.addZipEntry(binPath, bytes);
285                     }
286                     catch (RemoteException re) {
287                     }
288                 }
289 
290                 page.setAttachmentsDir(page.getAttachmentsDir());
291             }
292 
293             context.addZipEntry(path, page);
294         }
295 
296         exportNode(context, nodesEl, page.getNodeId());
297     }
298 
299     protected void importNode(
300             PortletDataContext context, Map<Long, Long> nodePKs, WikiNode node)
301         throws Exception {
302 
303         long userId = context.getUserId(node.getUserUuid());
304         long plid = context.getPlid();
305 
306         boolean addCommunityPermissions = true;
307         boolean addGuestPermissions = true;
308 
309         WikiNode existingNode = null;
310 
311         if (context.getDataStrategy().equals(
312                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
313 
314             existingNode = WikiNodeUtil.fetchByUUID_G(
315                 node.getUuid(), context.getGroupId());
316 
317             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
318 
319             if (existingNode == null && node.getName().equals(nodeName)) {
320                 try {
321                     WikiNodeUtil.removeByG_N(
322                         context.getGroupId(), node.getName());
323                 }
324                 catch (NoSuchNodeException nsne) {
325                 }
326             }
327 
328             if (existingNode == null) {
329                 existingNode = WikiNodeLocalServiceUtil.addNode(
330                     node.getUuid(), userId, plid, node.getName(),
331                     node.getDescription(), addCommunityPermissions,
332                     addGuestPermissions);
333             }
334             else {
335                 existingNode = WikiNodeLocalServiceUtil.updateNode(
336                     existingNode.getNodeId(), node.getName(),
337                     node.getDescription());
338             }
339         }
340         else {
341             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
342 
343             if (node.getName().equals(nodeName)) {
344                 try {
345                     WikiNodeUtil.removeByG_N(
346                         context.getGroupId(), node.getName());
347                 }
348                 catch (NoSuchNodeException nsne) {
349                 }
350             }
351 
352             existingNode = WikiNodeLocalServiceUtil.addNode(
353                 userId, plid, node.getName(), node.getDescription(),
354                 addCommunityPermissions, addGuestPermissions);
355         }
356 
357         nodePKs.put(node.getNodeId(), existingNode.getNodeId());
358     }
359 
360     protected void importPage(
361             PortletDataContext context, Map<Long, Long> nodePKs, Element pageEl,
362             WikiPage page)
363         throws Exception {
364 
365         long userId = context.getUserId(page.getUserUuid());
366         long nodeId = MapUtil.getLong(
367             nodePKs, page.getNodeId(), page.getNodeId());
368 
369         String[] tagsEntries = null;
370 
371         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
372             tagsEntries = context.getTagsEntries(
373                 WikiPage.class, page.getResourcePrimKey());
374         }
375 
376         PortletPreferences prefs = null;
377 
378         ThemeDisplay themeDisplay = null;
379 
380         WikiPage existingPage = null;
381 
382         try {
383             WikiNodeUtil.findByPrimaryKey(nodeId);
384 
385             if (context.getDataStrategy().equals(
386                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
387 
388                 try {
389                     existingPage = WikiPageFinderUtil.findByUuid_G(
390                         page.getUuid(), context.getGroupId());
391 
392                     existingPage = WikiPageLocalServiceUtil.updatePage(
393                         userId, nodeId, existingPage.getTitle(), 0,
394                         page.getContent(), page.getSummary(), true,
395                         page.getFormat(), page.getParentTitle(),
396                         page.getRedirectTitle(), tagsEntries, prefs,
397                         themeDisplay);
398                 }
399                 catch (NoSuchPageException nspe) {
400                     existingPage = WikiPageLocalServiceUtil.addPage(
401                         page.getUuid(), userId, nodeId, page.getTitle(),
402                         page.getVersion(), page.getContent(), page.getSummary(),
403                         true, page.getFormat(), page.getHead(),
404                         page.getParentTitle(), page.getRedirectTitle(),
405                         tagsEntries, prefs, themeDisplay);
406                 }
407             }
408             else {
409                 existingPage = WikiPageLocalServiceUtil.addPage(
410                     null, userId, nodeId, page.getTitle(), page.getVersion(),
411                     page.getContent(), page.getSummary(), true,
412                     page.getFormat(), page.getHead(), page.getParentTitle(),
413                     page.getRedirectTitle(), tagsEntries, prefs, themeDisplay);
414             }
415 
416             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
417                 page.isHead()) {
418 
419                 List<Element> attachmentEls = pageEl.elements("attachment");
420 
421                 List<ObjectValuePair<String, byte[]>> files =
422                     new ArrayList<ObjectValuePair<String, byte[]>>();
423 
424                 for (Element attachmentEl : attachmentEls) {
425                     String name = attachmentEl.attributeValue("name");
426                     String binPath = attachmentEl.attributeValue("bin-path");
427 
428                     byte[] bytes = context.getZipEntryAsByteArray(binPath);
429 
430                     files.add(new ObjectValuePair<String, byte[]>(name, bytes));
431                 }
432 
433                 if (files.size() > 0) {
434                     WikiPageLocalServiceUtil.addPageAttachments(
435                         nodeId, page.getTitle(), files);
436                 }
437             }
438 
439             if (context.getBooleanParameter(_NAMESPACE, "comments")) {
440                 context.importComments(
441                     WikiPage.class, page.getResourcePrimKey(),
442                     existingPage.getResourcePrimKey(), context.getGroupId());
443             }
444 
445             if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
446                 context.importRatingsEntries(
447                     WikiPage.class, page.getResourcePrimKey(),
448                     existingPage.getResourcePrimKey());
449             }
450         }
451         catch (NoSuchNodeException nsne) {
452             _log.error("Could not find the node for page " + page.getPageId());
453         }
454     }
455 
456     protected String getNodePath(PortletDataContext context, WikiNode node) {
457         StringBuilder sb = new StringBuilder();
458 
459         sb.append(context.getPortletPath(PortletKeys.WIKI));
460         sb.append("/nodes/");
461         sb.append(node.getNodeId());
462         sb.append(".xml");
463 
464         return sb.toString();
465     }
466 
467     protected String getPageAttachementBinPath(
468         PortletDataContext context, WikiPage page, String attachment) {
469 
470         StringBuilder sb = new StringBuilder();
471 
472         sb.append(context.getPortletPath(PortletKeys.WIKI));
473         sb.append("/bin/");
474         sb.append(page.getPageId());
475         sb.append(StringPool.SLASH);
476         sb.append(attachment);
477 
478         return sb.toString();
479     }
480 
481     protected String getPagePath(PortletDataContext context, WikiPage page) {
482         StringBuilder sb = new StringBuilder();
483 
484         sb.append(context.getPortletPath(PortletKeys.WIKI));
485         sb.append("/pages/");
486         sb.append(page.getPageId());
487         sb.append(".xml");
488 
489         return sb.toString();
490     }
491 
492     private static final String _NAMESPACE = "wiki";
493 
494     private static final PortletDataHandlerBoolean _nodesAndPages =
495         new PortletDataHandlerBoolean(
496             _NAMESPACE, "wikis-and-pages", true, true);
497 
498     private static final PortletDataHandlerBoolean _attachments =
499         new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
500 
501     private static final PortletDataHandlerBoolean _comments =
502         new PortletDataHandlerBoolean(_NAMESPACE, "comments");
503 
504     private static final PortletDataHandlerBoolean _tags =
505         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
506 
507     private static Log _log =
508         LogFactory.getLog(WikiPortletDataHandlerImpl.class);
509 
510 }