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