1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portlet.wiki.lar;
21  
22  import com.liferay.documentlibrary.service.DLServiceUtil;
23  import com.liferay.portal.PortalException;
24  import com.liferay.portal.SystemException;
25  import com.liferay.portal.kernel.dao.orm.QueryUtil;
26  import com.liferay.portal.kernel.log.Log;
27  import com.liferay.portal.kernel.log.LogFactoryUtil;
28  import com.liferay.portal.kernel.util.MapUtil;
29  import com.liferay.portal.kernel.util.ObjectValuePair;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.xml.Document;
32  import com.liferay.portal.kernel.xml.Element;
33  import com.liferay.portal.kernel.xml.SAXReaderUtil;
34  import com.liferay.portal.lar.PortletDataContext;
35  import com.liferay.portal.lar.PortletDataException;
36  import com.liferay.portal.lar.PortletDataHandler;
37  import com.liferay.portal.lar.PortletDataHandlerBoolean;
38  import com.liferay.portal.lar.PortletDataHandlerControl;
39  import com.liferay.portal.lar.PortletDataHandlerKeys;
40  import com.liferay.portal.model.CompanyConstants;
41  import com.liferay.portal.theme.ThemeDisplay;
42  import com.liferay.portal.util.PortletKeys;
43  import com.liferay.portal.util.PropsKeys;
44  import com.liferay.portal.util.PropsUtil;
45  import com.liferay.portlet.wiki.NoSuchNodeException;
46  import com.liferay.portlet.wiki.NoSuchPageException;
47  import com.liferay.portlet.wiki.model.WikiNode;
48  import com.liferay.portlet.wiki.model.WikiPage;
49  import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
50  import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
51  import com.liferay.portlet.wiki.service.persistence.WikiNodeUtil;
52  import com.liferay.portlet.wiki.service.persistence.WikiPageUtil;
53  import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
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  /**
64   * <a href="WikiPortletDataHandlerImpl.java.html"><b><i>View Source</i></b></a>
65   *
66   * @author Bruno Farache
67   * @author Jorge Ferrer
68   *
69   */
70  public class WikiPortletDataHandlerImpl implements PortletDataHandler {
71  
72      public PortletPreferences deleteData(
73              PortletDataContext context, String portletId,
74              PortletPreferences prefs)
75          throws PortletDataException {
76  
77          try {
78              if (!context.addPrimaryKey(
79                      WikiPortletDataHandlerImpl.class, "deleteData")) {
80  
81                  WikiNodeLocalServiceUtil.deleteNodes(context.getGroupId());
82              }
83              return null;
84          }
85          catch (Exception e) {
86              throw new PortletDataException(e);
87          }
88      }
89  
90      public String exportData(
91              PortletDataContext context, String portletId,
92              PortletPreferences prefs)
93          throws PortletDataException {
94  
95          try {
96              Document doc = SAXReaderUtil.createDocument();
97  
98              Element root = doc.addElement("wiki-data");
99  
100             root.addAttribute("group-id", String.valueOf(context.getGroupId()));
101 
102             Element nodesEl = root.addElement("nodes");
103             Element pagesEl = root.addElement("pages");
104 
105             List<WikiNode> nodes = WikiNodeUtil.findByGroupId(
106                 context.getGroupId());
107 
108             for (WikiNode node : nodes) {
109                 exportNode(context, nodesEl, pagesEl, node);
110             }
111 
112             return doc.formattedString();
113         }
114         catch (Exception e) {
115             throw new PortletDataException(e);
116         }
117     }
118 
119     public PortletDataHandlerControl[] getExportControls() {
120         return new PortletDataHandlerControl[] {
121             _nodesAndPages, _attachments, _comments, _tags
122         };
123     }
124 
125     public PortletDataHandlerControl[] getImportControls() {
126         return new PortletDataHandlerControl[] {
127             _nodesAndPages, _attachments, _comments, _tags
128         };
129     }
130 
131     public PortletPreferences importData(
132             PortletDataContext context, String portletId,
133             PortletPreferences prefs, String data)
134         throws PortletDataException {
135 
136         try {
137             Document doc = SAXReaderUtil.read(data);
138 
139             Element root = doc.getRootElement();
140 
141             List<Element> nodeEls = root.element("nodes").elements("node");
142 
143             Map<Long, Long> nodePKs =
144                 (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
145 
146             for (Element nodeEl : nodeEls) {
147                 String path = nodeEl.attributeValue("path");
148 
149                 if (!context.isPathNotProcessed(path)) {
150                     continue;
151                 }
152 
153                 WikiNode node = (WikiNode)context.getZipEntryAsObject(path);
154 
155                 importNode(context, nodePKs, node);
156             }
157 
158             List<Element> pageEls = root.element("pages").elements("page");
159 
160             for (Element pageEl : pageEls) {
161                 String path = pageEl.attributeValue("path");
162 
163                 if (!context.isPathNotProcessed(path)) {
164                     continue;
165                 }
166 
167                 WikiPage page = (WikiPage)context.getZipEntryAsObject(path);
168 
169                 importPage(context, nodePKs, pageEl, page);
170             }
171 
172             return null;
173         }
174         catch (Exception e) {
175             throw new PortletDataException(e);
176         }
177     }
178 
179     public boolean isPublishToLiveByDefault() {
180         return false;
181     }
182 
183     protected void exportNode(
184             PortletDataContext context, Element nodesEl, Element pagesEl,
185             WikiNode node)
186         throws PortalException, SystemException {
187 
188         if (context.isWithinDateRange(node.getModifiedDate())) {
189             String path = getNodePath(context, node);
190 
191             if (context.isPathNotProcessed(path)) {
192                 Element nodeEl = nodesEl.addElement("node");
193 
194                 nodeEl.addAttribute("path", path);
195 
196                 node.setUserUuid(node.getUserUuid());
197 
198                 context.addZipEntry(path, node);
199             }
200         }
201 
202         List<WikiPage> nodePages = WikiPageUtil.findByNodeId(
203             node.getNodeId(), QueryUtil.ALL_POS, QueryUtil.ALL_POS,
204             new PageCreateDateComparator(true));
205 
206         for (WikiPage page : nodePages) {
207             exportPage(context, nodesEl, pagesEl, page);
208         }
209     }
210 
211     protected void exportNode(
212             PortletDataContext context, Element nodesEl, long nodeId)
213         throws PortalException, SystemException {
214 
215         if (!context.hasDateRange()) {
216             return;
217         }
218 
219         WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
220 
221         String path = getNodePath(context, node);
222 
223         if (!context.isPathNotProcessed(path)) {
224             return;
225         }
226 
227         Element nodeEl = nodesEl.addElement("node");
228 
229         nodeEl.addAttribute("path", path);
230 
231         node.setUserUuid(node.getUserUuid());
232 
233         context.addZipEntry(path, node);
234     }
235 
236     protected void exportPage(
237             PortletDataContext context, Element nodesEl, Element pagesEl,
238             WikiPage page)
239         throws PortalException, SystemException {
240 
241         if (!context.isWithinDateRange(page.getModifiedDate())) {
242             return;
243         }
244 
245         String path = getPagePath(context, page);
246 
247         if (context.isPathNotProcessed(path)) {
248             Element pageEl = pagesEl.addElement("page");
249 
250             pageEl.addAttribute("path", path);
251 
252             page.setUserUuid(page.getUserUuid());
253 
254             if (context.getBooleanParameter(_NAMESPACE, "comments")) {
255                 context.addComments(WikiPage.class, page.getResourcePrimKey());
256             }
257 
258             if (context.getBooleanParameter(_NAMESPACE, "tags")) {
259                 context.addTagsEntries(
260                     WikiPage.class, page.getResourcePrimKey());
261             }
262 
263             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
264                 page.isHead()) {
265 
266                 for (String attachment : page.getAttachmentsFiles()) {
267                     int pos = attachment.lastIndexOf(StringPool.SLASH);
268 
269                     String name = attachment.substring(pos + 1);
270                     String binPath = getPageAttachementBinPath(
271                         context, page, name);
272 
273                     Element attachmentEl = pageEl.addElement("attachment");
274 
275                     attachmentEl.addAttribute("name", name);
276                     attachmentEl.addAttribute("bin-path", binPath);
277 
278                     try {
279                         byte[] bytes = DLServiceUtil.getFile(
280                             context.getCompanyId(), CompanyConstants.SYSTEM,
281                             attachment);
282 
283                         context.addZipEntry(binPath, bytes);
284                     }
285                     catch (RemoteException re) {
286                     }
287                 }
288 
289                 page.setAttachmentsDir(page.getAttachmentsDir());
290             }
291 
292             context.addZipEntry(path, page);
293         }
294 
295         exportNode(context, nodesEl, page.getNodeId());
296     }
297 
298     protected void importNode(
299             PortletDataContext context, Map<Long, Long> nodePKs, WikiNode node)
300         throws Exception {
301 
302         long userId = context.getUserId(node.getUserUuid());
303         long plid = context.getPlid();
304 
305         boolean addCommunityPermissions = true;
306         boolean addGuestPermissions = true;
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, plid, node.getName(),
330                     node.getDescription(), addCommunityPermissions,
331                     addGuestPermissions);
332             }
333             else {
334                 existingNode = WikiNodeLocalServiceUtil.updateNode(
335                     existingNode.getNodeId(), node.getName(),
336                     node.getDescription());
337             }
338         }
339         else {
340             String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
341 
342             if (node.getName().equals(nodeName)) {
343                 try {
344                     WikiNodeUtil.removeByG_N(
345                         context.getGroupId(), node.getName());
346                 }
347                 catch (NoSuchNodeException nsne) {
348                 }
349             }
350 
351             existingNode = WikiNodeLocalServiceUtil.addNode(
352                 userId, plid, node.getName(), node.getDescription(),
353                 addCommunityPermissions, addGuestPermissions);
354         }
355 
356         nodePKs.put(node.getNodeId(), existingNode.getNodeId());
357     }
358 
359     protected void importPage(
360             PortletDataContext context, Map<Long, Long> nodePKs, Element pageEl,
361             WikiPage page)
362         throws Exception {
363 
364         long userId = context.getUserId(page.getUserUuid());
365         long nodeId = MapUtil.getLong(
366             nodePKs, page.getNodeId(), page.getNodeId());
367 
368         String[] tagsEntries = null;
369 
370         if (context.getBooleanParameter(_NAMESPACE, "tags")) {
371             tagsEntries = context.getTagsEntries(
372                 WikiPage.class, page.getResourcePrimKey());
373         }
374 
375         PortletPreferences prefs = null;
376 
377         ThemeDisplay themeDisplay = null;
378 
379         WikiPage existingPage = null;
380 
381         try {
382             WikiNodeUtil.findByPrimaryKey(nodeId);
383 
384             if (context.getDataStrategy().equals(
385                     PortletDataHandlerKeys.DATA_STRATEGY_MIRROR)) {
386 
387                 try {
388                     existingPage = WikiPageUtil.findByUUID_G(
389                         page.getUuid(), context.getGroupId());
390                 }
391                 catch (NoSuchPageException nspe) {
392                 }
393 
394                 if (existingPage == null) {
395                     try {
396                         existingPage = WikiPageLocalServiceUtil.getPage(
397                             nodeId, page.getTitle());
398                     }
399                     catch (NoSuchPageException nspe) {
400                     }
401                 }
402 
403                 if (existingPage != null) {
404                     existingPage = WikiPageLocalServiceUtil.updatePage(
405                         userId, nodeId, existingPage.getTitle(), 0,
406                         page.getContent(), page.getSummary(), true,
407                         page.getFormat(), page.getParentTitle(),
408                         page.getRedirectTitle(), tagsEntries, prefs,
409                         themeDisplay);
410                 }
411                 else {
412                     existingPage = WikiPageLocalServiceUtil.addPage(
413                         page.getUuid(), userId, nodeId, page.getTitle(),
414                         page.getVersion(), page.getContent(), page.getSummary(),
415                         true, page.getFormat(), page.getHead(),
416                         page.getParentTitle(), page.getRedirectTitle(),
417                         tagsEntries, prefs, themeDisplay);
418                 }
419             }
420             else {
421                 existingPage = WikiPageLocalServiceUtil.addPage(
422                     null, userId, nodeId, page.getTitle(), page.getVersion(),
423                     page.getContent(), page.getSummary(), true,
424                     page.getFormat(), page.getHead(), page.getParentTitle(),
425                     page.getRedirectTitle(), tagsEntries, prefs, themeDisplay);
426             }
427 
428             if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
429                 page.isHead()) {
430 
431                 List<Element> attachmentEls = pageEl.elements("attachment");
432 
433                 List<ObjectValuePair<String, byte[]>> files =
434                     new ArrayList<ObjectValuePair<String, byte[]>>();
435 
436                 for (Element attachmentEl : attachmentEls) {
437                     String name = attachmentEl.attributeValue("name");
438                     String binPath = attachmentEl.attributeValue("bin-path");
439 
440                     byte[] bytes = context.getZipEntryAsByteArray(binPath);
441 
442                     files.add(new ObjectValuePair<String, byte[]>(name, bytes));
443                 }
444 
445                 if (files.size() > 0) {
446                     WikiPageLocalServiceUtil.addPageAttachments(
447                         nodeId, page.getTitle(), files);
448                 }
449             }
450 
451             if (context.getBooleanParameter(_NAMESPACE, "comments")) {
452                 context.importComments(
453                     WikiPage.class, page.getResourcePrimKey(),
454                     existingPage.getResourcePrimKey(), context.getGroupId());
455             }
456 
457             if (context.getBooleanParameter(_NAMESPACE, "ratings")) {
458                 context.importRatingsEntries(
459                     WikiPage.class, page.getResourcePrimKey(),
460                     existingPage.getResourcePrimKey());
461             }
462         }
463         catch (NoSuchNodeException nsne) {
464             _log.error("Could not find the node for page " + page.getPageId());
465         }
466     }
467 
468     protected String getNodePath(PortletDataContext context, WikiNode node) {
469         StringBuilder sb = new StringBuilder();
470 
471         sb.append(context.getPortletPath(PortletKeys.WIKI));
472         sb.append("/nodes/");
473         sb.append(node.getNodeId());
474         sb.append(".xml");
475 
476         return sb.toString();
477     }
478 
479     protected String getPageAttachementBinPath(
480         PortletDataContext context, WikiPage page, String attachment) {
481 
482         StringBuilder sb = new StringBuilder();
483 
484         sb.append(context.getPortletPath(PortletKeys.WIKI));
485         sb.append("/bin/");
486         sb.append(page.getPageId());
487         sb.append(StringPool.SLASH);
488         sb.append(attachment);
489 
490         return sb.toString();
491     }
492 
493     protected String getPagePath(PortletDataContext context, WikiPage page) {
494         StringBuilder sb = new StringBuilder();
495 
496         sb.append(context.getPortletPath(PortletKeys.WIKI));
497         sb.append("/pages/");
498         sb.append(page.getPageId());
499         sb.append(".xml");
500 
501         return sb.toString();
502     }
503 
504     private static final String _NAMESPACE = "wiki";
505 
506     private static final PortletDataHandlerBoolean _nodesAndPages =
507         new PortletDataHandlerBoolean(
508             _NAMESPACE, "wikis-and-pages", true, true);
509 
510     private static final PortletDataHandlerBoolean _attachments =
511         new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
512 
513     private static final PortletDataHandlerBoolean _comments =
514         new PortletDataHandlerBoolean(_NAMESPACE, "comments");
515 
516     private static final PortletDataHandlerBoolean _tags =
517         new PortletDataHandlerBoolean(_NAMESPACE, "tags");
518 
519     private static Log _log =
520         LogFactoryUtil.getLog(WikiPortletDataHandlerImpl.class);
521 
522 }