1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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  public class WikiPortletDataHandlerImpl implements PortletDataHandler {
73  
74      public PortletPreferences deleteData(
75              PortletDataContext context, String portletId,
76              PortletPreferences prefs)
77          throws PortletDataException {
78  
79          try {
80              if (!context.addPrimaryKey(
81                      WikiPortletDataHandlerImpl.class, "deleteData")) {
82  
83                  WikiNodeLocalServiceUtil.deleteNodes(context.getGroupId());
84              }
85              return null;
86          }
87          catch (Exception e) {
88              throw new PortletDataException(e);
89          }
90      }
91  
92      public String exportData(
93              PortletDataContext context, String portletId,
94              PortletPreferences prefs)
95          throws PortletDataException {
96  
97          try {
98              Document doc = SAXReaderUtil.createDocument();
99  
100             Element root = doc.addElement("wiki-data");
101 
102             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
103 
104             Element nodesEl = root.addElement("nodes");
105             Element pagesEl = root.addElement("pages");
106 
107             List<WikiNode> nodes = WikiNodeUtil.findByGroupId(
108                 context.getGroupId());
109 
110             for (WikiNode node : nodes) {
111                 exportNode(context, nodesEl, pagesEl, node);
112             }
113 
114             return doc.formattedString();
115         }
116         catch (Exception e) {
117             throw new PortletDataException(e);
118         }
119     }
120 
121     public PortletDataHandlerControl[] getExportControls() {
122         return new PortletDataHandlerControl[] {
123             _nodesAndPages, _attachments, _comments, _tags
124         };
125     }
126 
127     public PortletDataHandlerControl[] getImportControls() {
128         return new PortletDataHandlerControl[] {
129             _nodesAndPages, _attachments, _comments, _tags
130         };
131     }
132 
133     public PortletPreferences importData(
134             PortletDataContext context, String portletId,
135             PortletPreferences prefs, String data)
136         throws PortletDataException {
137 
138         try {
139             Document doc = SAXReaderUtil.read(data);
140 
141             Element root = doc.getRootElement();
142 
143             List<Element> nodeEls = root.element("nodes").elements("node");
144 
145             Map<Long, Long> nodePKs =
146                 (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
147 
148             for (Element nodeEl : nodeEls) {
149                 String path = nodeEl.attributeValue("path");
150 
151                 if (!context.isPathNotProcessed(path)) {
152                     continue;
153                 }
154 
155                 WikiNode node = (WikiNode)context.getZipEntryAsObject(path);
156 
157                 importNode(context, nodePKs, node);
158             }
159 
160             List<Element> pageEls = root.element("pages").elements("page");
161 
162             for (Element pageEl : pageEls) {
163                 String path = pageEl.attributeValue("path");
164 
165                 if (!context.isPathNotProcessed(path)) {
166                     continue;
167                 }
168 
169                 WikiPage page = (WikiPage)context.getZipEntryAsObject(path);
170 
171                 importPage(context, nodePKs, pageEl, page);
172             }
173 
174             return null;
175         }
176         catch (Exception e) {
177             throw new PortletDataException(e);
178         }
179     }
180 
181     public boolean isPublishToLiveByDefault() {
182         return false;
183     }
184 
185     protected void exportNode(
186             PortletDataContext context, Element nodesEl, Element pagesEl,
187             WikiNode node)
188         throws PortalException, SystemException {
189 
190         if (context.isWithinDateRange(node.getModifiedDate())) {
191             String path = getNodePath(context, node);
192 
193             if (context.isPathNotProcessed(path)) {
194                 Element nodeEl = nodesEl.addElement("node");
195 
196                 nodeEl.addAttribute("path", path);
197 
198                 node.setUserUuid(node.getUserUuid());
199 
200                 context.addZipEntry(path, node);
201             }
202         }
203 
204         List<WikiPage> nodePages = WikiPageUtil.findByNodeId(
205             node.getNodeId(), QueryUtil.ALL_POS, QueryUtil.ALL_POS,
206             new PageCreateDateComparator(true));
207 
208         for (WikiPage page : nodePages) {
209             exportPage(context, nodesEl, pagesEl, page);
210         }
211     }
212 
213     protected void exportNode(
214             PortletDataContext context, Element nodesEl, long nodeId)
215         throws PortalException, SystemException {
216 
217         if (!context.hasDateRange()) {
218             return;
219         }
220 
221         WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
222 
223         String path = getNodePath(context, node);
224 
225         if (!context.isPathNotProcessed(path)) {
226             return;
227         }
228 
229         Element nodeEl = nodesEl.addElement("node");
230 
231         nodeEl.addAttribute("path", path);
232 
233         node.setUserUuid(node.getUserUuid());
234 
235         context.addZipEntry(path, node);
236     }
237 
238     protected void exportPage(
239             PortletDataContext context, Element nodesEl, Element pagesEl,
240             WikiPage page)
241         throws PortalException, SystemException {
242 
243         if (!context.isWithinDateRange(page.getModifiedDate())) {
244             return;
245         }
246 
247         String path = getPagePath(context, page);
248 
249         if (context.isPathNotProcessed(path)) {
250             Element pageEl = pagesEl.addElement("page");
251 
252             pageEl.addAttribute("path", path);
253 
254             page.setUserUuid(page.getUserUuid());
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                     try {
281                         byte[] bytes = DLServiceUtil.getFile(
282                             context.getCompanyId(), CompanyConstants.SYSTEM,
283                             attachment);
284 
285                         context.addZipEntry(binPath, bytes);
286                     }
287                     catch (RemoteException re) {
288                     }
289                 }
290 
291                 page.setAttachmentsDir(page.getAttachmentsDir());
292             }
293 
294             context.addZipEntry(path, page);
295         }
296 
297         exportNode(context, nodesEl, page.getNodeId());
298     }
299 
300     protected void importNode(
301             PortletDataContext context, Map<Long, Long> nodePKs, WikiNode node)
302         throws Exception {
303 
304         long userId = context.getUserId(node.getUserUuid());
305         long plid = context.getPlid();
306 
307         boolean addCommunityPermissions = true;
308         boolean addGuestPermissions = true;
309 
310         WikiNode existingNode = null;
311 
312         if (context.getDataStrategy().equals(
313                 PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
314 
315             existingNode = WikiNodeUtil.fetchByUUID_G(
316                 node.getUuid(), context.getGroupId());
317 
318             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
319 
320             if (existingNode == null && node.getName().equals(nodeName)) {
321                 try {
322                     WikiNodeUtil.removeByG_N(
323                         context.getGroupId(), node.getName());
324                 }
325                 catch (NoSuchNodeException nsne) {
326                 }
327             }
328 
329             if (existingNode == null) {
330                 existingNode = WikiNodeLocalServiceUtil.addNode(
331                     node.getUuid(), userId, plid, node.getName(),
332                     node.getDescription(), addCommunityPermissions,
333                     addGuestPermissions);
334             }
335             else {
336                 existingNode = WikiNodeLocalServiceUtil.updateNode(
337                     existingNode.getNodeId(), node.getName(),
338                     node.getDescription());
339             }
340         }
341         else {
342             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
343 
344             if (node.getName().equals(nodeName)) {
345                 try {
346                     WikiNodeUtil.removeByG_N(
347                         context.getGroupId(), node.getName());
348                 }
349                 catch (NoSuchNodeException nsne) {
350                 }
351             }
352 
353             existingNode = WikiNodeLocalServiceUtil.addNode(
354                 userId, plid, node.getName(), node.getDescription(),
355                 addCommunityPermissions, addGuestPermissions);
356         }
357 
358         nodePKs.put(node.getNodeId(), existingNode.getNodeId());
359     }
360 
361     protected void importPage(
362             PortletDataContext context, Map<Long, Long> nodePKs, Element pageEl,
363             WikiPage page)
364         throws Exception {
365 
366         long userId = context.getUserId(page.getUserUuid());
367         long nodeId = MapUtil.getLong(
368             nodePKs, page.getNodeId(), page.getNodeId());
369 
370         String[] tagsEntries = null;
371 
372         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
373             tagsEntries = context.getTagsEntries(
374                 WikiPage.class, page.getResourcePrimKey());
375         }
376 
377         PortletPreferences prefs = null;
378 
379         ThemeDisplay themeDisplay = null;
380 
381         WikiPage existingPage = null;
382 
383         try {
384             WikiNodeUtil.findByPrimaryKey(nodeId);
385 
386             if (context.getDataStrategy().equals(
387                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
388 
389                 try {
390                     existingPage = WikiPageUtil.findByUUID_G(
391                         page.getUuid(), context.getGroupId());
392                 }
393                 catch (NoSuchPageException nspe) {
394                 }
395 
396                 if (existingPage == null) {
397                     try {
398                         existingPage = WikiPageLocalServiceUtil.getPage(
399                             nodeId, page.getTitle());
400                     }
401                     catch (NoSuchPageException nspe) {
402                     }
403                 }
404 
405                 if (existingPage != null) {
406                     existingPage = WikiPageLocalServiceUtil.updatePage(
407                         userId, nodeId, existingPage.getTitle(), 0,
408                         page.getContent(), page.getSummary(), true,
409                         page.getFormat(), page.getParentTitle(),
410                         page.getRedirectTitle(), tagsEntries, prefs,
411                         themeDisplay);
412                 }
413                 else {
414                     existingPage = WikiPageLocalServiceUtil.addPage(
415                         page.getUuid(), userId, nodeId, page.getTitle(),
416                         page.getVersion(), page.getContent(), page.getSummary(),
417                         true, page.getFormat(), page.getHead(),
418                         page.getParentTitle(), page.getRedirectTitle(),
419                         tagsEntries, prefs, themeDisplay);
420                 }
421             }
422             else {
423                 existingPage = WikiPageLocalServiceUtil.addPage(
424                     null, userId, nodeId, page.getTitle(), page.getVersion(),
425                     page.getContent(), page.getSummary(), true,
426                     page.getFormat(), page.getHead(), page.getParentTitle(),
427                     page.getRedirectTitle(), tagsEntries, prefs, themeDisplay);
428             }
429 
430             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
431                 page.isHead()) {
432 
433                 List<Element> attachmentEls = pageEl.elements("attachment");
434 
435                 List<ObjectValuePair<String, byte[]>> files =
436                     new ArrayList<ObjectValuePair<String, byte[]>>();
437 
438                 for (Element attachmentEl : attachmentEls) {
439                     String name = attachmentEl.attributeValue("name");
440                     String binPath = attachmentEl.attributeValue("bin-path");
441 
442                     byte[] bytes = context.getZipEntryAsByteArray(binPath);
443 
444                     files.add(new ObjectValuePair<String, byte[]>(name, bytes));
445                 }
446 
447                 if (files.size() > 0) {
448                     WikiPageLocalServiceUtil.addPageAttachments(
449                         nodeId, page.getTitle(), files);
450                 }
451             }
452 
453             if (context.getBooleanParameter(_NAMESPACE, "comments") &&
454                 page.isHead()) {
455 
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 _comments =
518         new PortletDataHandlerBoolean(_NAMESPACE, "comments");
519 
520     private static final PortletDataHandlerBoolean _tags =
521         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
522 
523     private static Log _log =
524         LogFactoryUtil.getLog(WikiPortletDataHandlerImpl.class);
525 
526 }