001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.wiki.lar;
016    
017    import com.liferay.documentlibrary.service.DLServiceUtil;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.lar.BasePortletDataHandler;
020    import com.liferay.portal.kernel.lar.PortletDataContext;
021    import com.liferay.portal.kernel.lar.PortletDataException;
022    import com.liferay.portal.kernel.lar.PortletDataHandlerBoolean;
023    import com.liferay.portal.kernel.lar.PortletDataHandlerControl;
024    import com.liferay.portal.kernel.util.MapUtil;
025    import com.liferay.portal.kernel.util.PropsKeys;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.kernel.xml.Document;
030    import com.liferay.portal.kernel.xml.Element;
031    import com.liferay.portal.kernel.xml.SAXReaderUtil;
032    import com.liferay.portal.model.CompanyConstants;
033    import com.liferay.portal.service.ServiceContext;
034    import com.liferay.portal.util.PortletKeys;
035    import com.liferay.portal.util.PropsUtil;
036    import com.liferay.portlet.wiki.NoSuchNodeException;
037    import com.liferay.portlet.wiki.NoSuchPageException;
038    import com.liferay.portlet.wiki.model.WikiNode;
039    import com.liferay.portlet.wiki.model.WikiPage;
040    import com.liferay.portlet.wiki.service.WikiNodeLocalServiceUtil;
041    import com.liferay.portlet.wiki.service.WikiPageLocalServiceUtil;
042    import com.liferay.portlet.wiki.service.persistence.WikiNodeUtil;
043    import com.liferay.portlet.wiki.service.persistence.WikiPageUtil;
044    import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
045    import com.liferay.portlet.wiki.util.WikiCacheUtil;
046    import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
047    
048    import java.io.InputStream;
049    
050    import java.util.List;
051    import java.util.Map;
052    
053    import javax.portlet.PortletPreferences;
054    
055    /**
056     * @author Bruno Farache
057     * @author Jorge Ferrer
058     * @author Marcellus Tavares
059     * @author Juan Fernández
060     */
061    public class WikiPortletDataHandlerImpl extends BasePortletDataHandler {
062    
063            public static void exportNode(
064                            PortletDataContext context, Element nodesElement,
065                            Element pagesElement, WikiNode node)
066                    throws Exception {
067    
068                    if (context.isWithinDateRange(node.getModifiedDate())) {
069                            String path = getNodePath(context, node);
070    
071                            if (context.isPathNotProcessed(path)) {
072                                    Element nodeElement = nodesElement.addElement("node");
073    
074                                    nodeElement.addAttribute("path", path);
075    
076                                    node.setUserUuid(node.getUserUuid());
077    
078                                    context.addPermissions(WikiNode.class, node.getNodeId());
079    
080                                    context.addZipEntry(path, node);
081                            }
082                    }
083    
084                    List<WikiPage> pages = WikiPageUtil.findByN_S(
085                            node.getNodeId(), WorkflowConstants.STATUS_APPROVED,
086                            QueryUtil.ALL_POS, QueryUtil.ALL_POS,
087                            new PageVersionComparator(true));
088    
089                    for (WikiPage page : pages) {
090                            exportPage(context, nodesElement, pagesElement, page);
091                    }
092            }
093    
094            public static void importNode(PortletDataContext context, WikiNode node)
095                    throws Exception {
096    
097                    long userId = context.getUserId(node.getUserUuid());
098    
099                    ServiceContext serviceContext = new ServiceContext();
100    
101                    serviceContext.setAddCommunityPermissions(true);
102                    serviceContext.setAddGuestPermissions(true);
103                    serviceContext.setCreateDate(node.getCreateDate());
104                    serviceContext.setModifiedDate(node.getModifiedDate());
105                    serviceContext.setScopeGroupId(context.getScopeGroupId());
106    
107                    WikiNode importedNode = null;
108    
109                    if (context.isDataStrategyMirror()) {
110                            WikiNode existingNode = WikiNodeUtil.fetchByUUID_G(
111                                    node.getUuid(), context.getScopeGroupId());
112    
113                            String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
114    
115                            if ((existingNode == null) && node.getName().equals(nodeName)) {
116                                    try {
117                                            WikiNodeUtil.removeByG_N(
118                                                    context.getScopeGroupId(), node.getName());
119                                    }
120                                    catch (NoSuchNodeException nsne) {
121                                    }
122                            }
123    
124                            if (existingNode == null) {
125                                    serviceContext.setUuid(node.getUuid());
126    
127                                    importedNode = WikiNodeLocalServiceUtil.addNode(
128                                            userId, node.getName(), node.getDescription(),
129                                            serviceContext);
130                            }
131                            else {
132                                    importedNode = WikiNodeLocalServiceUtil.updateNode(
133                                            existingNode.getNodeId(), node.getName(),
134                                            node.getDescription(), serviceContext);
135                            }
136                    }
137                    else {
138                            String nodeName = PropsUtil.get(PropsKeys.WIKI_INITIAL_NODE_NAME);
139    
140                            if (node.getName().equals(nodeName)) {
141                                    try {
142                                            WikiNodeUtil.removeByG_N(
143                                                    context.getScopeGroupId(), node.getName());
144                                    }
145                                    catch (NoSuchNodeException nsne) {
146                                    }
147                            }
148    
149                            importedNode = WikiNodeLocalServiceUtil.addNode(
150                                    userId, node.getName(), node.getDescription(), serviceContext);
151                    }
152    
153                    Map<Long, Long> nodePKs =
154                            (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
155    
156                    nodePKs.put(node.getNodeId(), importedNode.getNodeId());
157    
158                    context.importPermissions(
159                            WikiNode.class, node.getNodeId(), importedNode.getNodeId());
160            }
161    
162            public static void importPage(
163                            PortletDataContext context, Element pageElement, WikiPage page)
164                    throws Exception {
165    
166                    long userId = context.getUserId(page.getUserUuid());
167    
168                    Map<Long, Long> nodePKs =
169                            (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
170    
171                    long nodeId = MapUtil.getLong(
172                            nodePKs, page.getNodeId(), page.getNodeId());
173    
174                    long[] assetCategoryIds = null;
175                    String[] assetTagNames = null;
176    
177                    if (context.getBooleanParameter(_NAMESPACE, "categories") &&
178                            page.isHead()) {
179    
180                            assetCategoryIds = context.getAssetCategoryIds(
181                                    WikiPage.class, page.getResourcePrimKey());
182                    }
183    
184                    if (context.getBooleanParameter(_NAMESPACE, "tags") &&
185                            page.isHead()) {
186    
187                            assetTagNames = context.getAssetTagNames(
188                                    WikiPage.class, page.getResourcePrimKey());
189                    }
190    
191                    ServiceContext serviceContext = new ServiceContext();
192    
193                    serviceContext.setAddCommunityPermissions(true);
194                    serviceContext.setAddGuestPermissions(true);
195                    serviceContext.setAssetCategoryIds(assetCategoryIds);
196                    serviceContext.setAssetTagNames(assetTagNames);
197                    serviceContext.setCreateDate(page.getCreateDate());
198                    serviceContext.setModifiedDate(page.getModifiedDate());
199    
200                    if (page.getStatus() != WorkflowConstants.STATUS_APPROVED) {
201                            serviceContext.setWorkflowAction(
202                                    WorkflowConstants.ACTION_SAVE_DRAFT);
203                    }
204    
205                    WikiPage importedPage = null;
206    
207                    if (context.isDataStrategyMirror()) {
208                            WikiPage existingPage = WikiPageUtil.fetchByUUID_G(
209                                    page.getUuid(), context.getScopeGroupId());
210    
211                            if (existingPage == null) {
212                                    try {
213                                            existingPage = WikiPageLocalServiceUtil.getPage(
214                                                    nodeId, page.getTitle());
215                                    }
216                                    catch (NoSuchPageException nspe) {
217                                    }
218                            }
219    
220                            if (existingPage == null) {
221                                    serviceContext.setUuid(page.getUuid());
222    
223                                    importedPage = WikiPageLocalServiceUtil.addPage(
224                                            userId, nodeId, page.getTitle(), page.getVersion(),
225                                            page.getContent(), page.getSummary(), true,
226                                            page.getFormat(), page.getHead(), page.getParentTitle(),
227                                            page.getRedirectTitle(), serviceContext);
228                            }
229                            else {
230                                    importedPage = WikiPageLocalServiceUtil.updatePage(
231                                            userId, nodeId, existingPage.getTitle(), 0,
232                                            page.getContent(), page.getSummary(), true,
233                                            page.getFormat(), page.getParentTitle(),
234                                            page.getRedirectTitle(), serviceContext);
235                            }
236                    }
237                    else {
238                            importedPage = WikiPageLocalServiceUtil.addPage(
239                                    userId, nodeId, page.getTitle(), page.getVersion(),
240                                    page.getContent(), page.getSummary(), true, page.getFormat(),
241                                    page.getHead(), page.getParentTitle(), page.getRedirectTitle(),
242                                    serviceContext);
243                    }
244    
245                    if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
246                            page.isHead()) {
247    
248                            for (Element attachmentElement :
249                                            pageElement.elements("attachment")) {
250    
251                                    String name = attachmentElement.attributeValue("name");
252                                    String binPath = attachmentElement.attributeValue("bin-path");
253    
254                                    InputStream inputStream = context.getZipEntryAsInputStream(
255                                            binPath);
256    
257                                    WikiPageLocalServiceUtil.addPageAttachment(
258                                            importedPage.getCompanyId(),
259                                            importedPage.getAttachmentsDir(),
260                                            importedPage.getModifiedDate(), name, inputStream);
261                            }
262                    }
263    
264                    if (page.isHead()) {
265                            context.importPermissions(
266                                    WikiPage.class, page.getResourcePrimKey(),
267                                    importedPage.getResourcePrimKey());
268                    }
269    
270                    if (context.getBooleanParameter(_NAMESPACE, "comments") &&
271                            page.isHead()) {
272    
273                            context.importComments(
274                                    WikiPage.class, page.getResourcePrimKey(),
275                                    importedPage.getResourcePrimKey(), context.getScopeGroupId());
276                    }
277    
278                    if (context.getBooleanParameter(_NAMESPACE, "ratings") &&
279                            page.isHead()) {
280    
281                            context.importRatingsEntries(
282                                    WikiPage.class, page.getResourcePrimKey(),
283                                    importedPage.getResourcePrimKey());
284                    }
285            }
286    
287            public PortletDataHandlerControl[] getExportControls() {
288                    return new PortletDataHandlerControl[] {
289                            _nodesAndPages, _attachments, _categories, _comments, _ratings,
290                            _tags
291                    };
292            }
293    
294            public PortletDataHandlerControl[] getImportControls() {
295                    return new PortletDataHandlerControl[] {
296                            _nodesAndPages, _attachments, _categories, _comments, _ratings,
297                            _tags
298                    };
299            }
300    
301            public PortletPreferences importData(
302                            PortletDataContext context, String portletId,
303                            PortletPreferences preferences, String data)
304                    throws PortletDataException {
305    
306                    WikiCacheThreadLocal.setClearCache(false);
307    
308                    try {
309                            return super.importData(context, portletId, preferences, data);
310                    }
311                    finally {
312                            WikiCacheThreadLocal.setClearCache(true);
313                    }
314            }
315    
316            protected static void exportNode(
317                            PortletDataContext context, Element nodesElement, long nodeId)
318                    throws Exception {
319    
320                    if (!context.hasDateRange()) {
321                            return;
322                    }
323    
324                    WikiNode node = WikiNodeUtil.findByPrimaryKey(nodeId);
325    
326                    String path = getNodePath(context, node);
327    
328                    if (!context.isPathNotProcessed(path)) {
329                            return;
330                    }
331    
332                    Element nodeElement = nodesElement.addElement("node");
333    
334                    nodeElement.addAttribute("path", path);
335    
336                    node.setUserUuid(node.getUserUuid());
337    
338                    context.addPermissions(WikiNode.class, node.getNodeId());
339    
340                    context.addZipEntry(path, node);
341            }
342    
343            protected static void exportPage(
344                            PortletDataContext context, Element nodesElement,
345                            Element pagesElement, WikiPage page)
346                    throws Exception {
347    
348                    if (!context.isWithinDateRange(page.getModifiedDate())) {
349                            return;
350                    }
351    
352                    String path = getPagePath(context, page);
353    
354                    if (context.isPathNotProcessed(path)) {
355                            Element pageElement = pagesElement.addElement("page");
356    
357                            pageElement.addAttribute("path", path);
358    
359                            page.setUserUuid(page.getUserUuid());
360    
361                            context.addPermissions(WikiPage.class, page.getResourcePrimKey());
362    
363                            if (context.getBooleanParameter(_NAMESPACE, "categories") &&
364                                    page.isHead()) {
365    
366                                    context.addAssetCategories(
367                                            WikiPage.class, page.getResourcePrimKey());
368                            }
369    
370                            if (context.getBooleanParameter(_NAMESPACE, "comments") &&
371                                    page.isHead()) {
372    
373                                    context.addComments(WikiPage.class, page.getResourcePrimKey());
374                            }
375    
376                            if (context.getBooleanParameter(_NAMESPACE, "ratings") &&
377                                    page.isHead()) {
378    
379                                    context.addRatingsEntries(
380                                            WikiPage.class, page.getResourcePrimKey());
381                            }
382    
383                            if (context.getBooleanParameter(_NAMESPACE, "tags") &&
384                                    page.isHead()) {
385    
386                                    context.addAssetTags(WikiPage.class, page.getResourcePrimKey());
387                            }
388    
389                            if (context.getBooleanParameter(_NAMESPACE, "attachments") &&
390                                    page.isHead()) {
391    
392                                    for (String attachment : page.getAttachmentsFiles()) {
393                                            int pos = attachment.lastIndexOf(StringPool.SLASH);
394    
395                                            String name = attachment.substring(pos + 1);
396                                            String binPath = getPageAttachementBinPath(
397                                                    context, page, name);
398    
399                                            Element attachmentEl = pageElement.addElement("attachment");
400    
401                                            attachmentEl.addAttribute("name", name);
402                                            attachmentEl.addAttribute("bin-path", binPath);
403    
404                                            byte[] bytes = DLServiceUtil.getFile(
405                                                    context.getCompanyId(), CompanyConstants.SYSTEM,
406                                                    attachment);
407    
408                                            context.addZipEntry(binPath, bytes);
409                                    }
410    
411                                    page.setAttachmentsDir(page.getAttachmentsDir());
412                            }
413    
414                            context.addZipEntry(path, page);
415                    }
416    
417                    exportNode(context, nodesElement, page.getNodeId());
418            }
419    
420            protected static String getNodePath(
421                    PortletDataContext context, WikiNode node) {
422    
423                    StringBundler sb = new StringBundler(4);
424    
425                    sb.append(context.getPortletPath(PortletKeys.WIKI));
426                    sb.append("/nodes/");
427                    sb.append(node.getNodeId());
428                    sb.append(".xml");
429    
430                    return sb.toString();
431            }
432    
433            protected static String getPageAttachementBinPath(
434                    PortletDataContext context, WikiPage page, String attachment) {
435    
436                    StringBundler sb = new StringBundler(5);
437    
438                    sb.append(context.getPortletPath(PortletKeys.WIKI));
439                    sb.append("/bin/");
440                    sb.append(page.getPageId());
441                    sb.append(StringPool.SLASH);
442                    sb.append(attachment);
443    
444                    return sb.toString();
445            }
446    
447            protected static String getPagePath(
448                    PortletDataContext context, WikiPage page) {
449    
450                    StringBundler sb = new StringBundler(4);
451    
452                    sb.append(context.getPortletPath(PortletKeys.WIKI));
453                    sb.append("/pages/");
454                    sb.append(page.getPageId());
455                    sb.append(".xml");
456    
457                    return sb.toString();
458            }
459    
460            protected PortletPreferences doDeleteData(
461                            PortletDataContext context, String portletId,
462                            PortletPreferences preferences)
463                    throws Exception {
464    
465                    if (!context.addPrimaryKey(
466                                    WikiPortletDataHandlerImpl.class, "deleteData")) {
467    
468                            WikiNodeLocalServiceUtil.deleteNodes(context.getScopeGroupId());
469                    }
470    
471                    return null;
472            }
473    
474            protected String doExportData(
475                            PortletDataContext context, String portletId,
476                            PortletPreferences preferences)
477                    throws Exception {
478    
479                    context.addPermissions(
480                            "com.liferay.portlet.wiki", context.getScopeGroupId());
481    
482                    Document document = SAXReaderUtil.createDocument();
483    
484                    Element rootElement = document.addElement("wiki-data");
485    
486                    rootElement.addAttribute(
487                            "group-id", String.valueOf(context.getScopeGroupId()));
488    
489                    Element nodesElement = rootElement.addElement("nodes");
490                    Element pagesElement = rootElement.addElement("pages");
491    
492                    List<WikiNode> nodes = WikiNodeUtil.findByGroupId(
493                            context.getScopeGroupId());
494    
495                    for (WikiNode node : nodes) {
496                            exportNode(context, nodesElement, pagesElement, node);
497                    }
498    
499                    return document.formattedString();
500            }
501    
502            protected PortletPreferences doImportData(
503                            PortletDataContext context, String portletId,
504                            PortletPreferences preferences, String data)
505                    throws Exception {
506    
507                    context.importPermissions(
508                            "com.liferay.portlet.wiki", context.getSourceGroupId(),
509                            context.getScopeGroupId());
510    
511                    Document document = SAXReaderUtil.read(data);
512    
513                    Element rootElement = document.getRootElement();
514    
515                    Element nodesElement = rootElement.element("nodes");
516    
517                    for (Element nodeElement : nodesElement.elements("node")) {
518                            String path = nodeElement.attributeValue("path");
519    
520                            if (!context.isPathNotProcessed(path)) {
521                                    continue;
522                            }
523    
524                            WikiNode node = (WikiNode)context.getZipEntryAsObject(path);
525    
526                            importNode(context, node);
527                    }
528    
529                    Element pagesElement = rootElement.element("pages");
530    
531                    for (Element pageElement : pagesElement.elements("page")) {
532                            String path = pageElement.attributeValue("path");
533    
534                            if (!context.isPathNotProcessed(path)) {
535                                    continue;
536                            }
537    
538                            WikiPage page = (WikiPage)context.getZipEntryAsObject(path);
539    
540                            importPage(context, pageElement, page);
541                    }
542    
543                    Map<Long, Long> nodePKs =
544                            (Map<Long, Long>)context.getNewPrimaryKeysMap(WikiNode.class);
545    
546                    for (long nodeId : nodePKs.values()) {
547                            WikiCacheUtil.clearCache(nodeId);
548                    }
549    
550                    return null;
551            }
552    
553            private static final String _NAMESPACE = "wiki";
554    
555            private static PortletDataHandlerBoolean _attachments =
556                    new PortletDataHandlerBoolean(_NAMESPACE, "attachments");
557    
558            private static PortletDataHandlerBoolean _categories =
559                    new PortletDataHandlerBoolean(_NAMESPACE, "categories");
560    
561            private static PortletDataHandlerBoolean _comments =
562                    new PortletDataHandlerBoolean(_NAMESPACE, "comments");
563    
564            private static PortletDataHandlerBoolean _nodesAndPages =
565                    new PortletDataHandlerBoolean(
566                            _NAMESPACE, "wikis-and-pages", true, true);
567    
568            private static PortletDataHandlerBoolean _ratings =
569                    new PortletDataHandlerBoolean(_NAMESPACE, "ratings");
570    
571            private static PortletDataHandlerBoolean _tags =
572                    new PortletDataHandlerBoolean(_NAMESPACE, "tags");
573    
574    }