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.service.impl;
24  
25  import com.liferay.documentlibrary.DuplicateDirectoryException;
26  import com.liferay.documentlibrary.DuplicateFileException;
27  import com.liferay.documentlibrary.NoSuchDirectoryException;
28  import com.liferay.documentlibrary.NoSuchFileException;
29  import com.liferay.portal.PortalException;
30  import com.liferay.portal.SystemException;
31  import com.liferay.portal.kernel.json.JSONFactoryUtil;
32  import com.liferay.portal.kernel.json.JSONObject;
33  import com.liferay.portal.kernel.messaging.DestinationNames;
34  import com.liferay.portal.kernel.messaging.MessageBusUtil;
35  import com.liferay.portal.kernel.search.SearchException;
36  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
37  import com.liferay.portal.kernel.util.ContentTypes;
38  import com.liferay.portal.kernel.util.NotificationThreadLocal;
39  import com.liferay.portal.kernel.util.ObjectValuePair;
40  import com.liferay.portal.kernel.util.OrderByComparator;
41  import com.liferay.portal.kernel.util.StringPool;
42  import com.liferay.portal.kernel.util.StringUtil;
43  import com.liferay.portal.kernel.util.Validator;
44  import com.liferay.portal.model.Company;
45  import com.liferay.portal.model.CompanyConstants;
46  import com.liferay.portal.model.Group;
47  import com.liferay.portal.model.ResourceConstants;
48  import com.liferay.portal.model.User;
49  import com.liferay.portal.model.impl.GroupImpl;
50  import com.liferay.portal.theme.ThemeDisplay;
51  import com.liferay.portal.util.PortalUtil;
52  import com.liferay.portal.util.PortletKeys;
53  import com.liferay.portal.util.PropsValues;
54  import com.liferay.portlet.wiki.DuplicatePageException;
55  import com.liferay.portlet.wiki.NoSuchPageException;
56  import com.liferay.portlet.wiki.PageContentException;
57  import com.liferay.portlet.wiki.PageTitleException;
58  import com.liferay.portlet.wiki.PageVersionException;
59  import com.liferay.portlet.wiki.model.WikiNode;
60  import com.liferay.portlet.wiki.model.WikiPage;
61  import com.liferay.portlet.wiki.model.WikiPageDisplay;
62  import com.liferay.portlet.wiki.model.WikiPageResource;
63  import com.liferay.portlet.wiki.model.impl.WikiPageDisplayImpl;
64  import com.liferay.portlet.wiki.model.impl.WikiPageImpl;
65  import com.liferay.portlet.wiki.service.base.WikiPageLocalServiceBaseImpl;
66  import com.liferay.portlet.wiki.social.WikiActivityKeys;
67  import com.liferay.portlet.wiki.util.Indexer;
68  import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
69  import com.liferay.portlet.wiki.util.WikiCacheUtil;
70  import com.liferay.portlet.wiki.util.WikiUtil;
71  import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
72  import com.liferay.util.MathUtil;
73  import com.liferay.util.UniqueList;
74  
75  import java.rmi.RemoteException;
76  
77  import java.util.ArrayList;
78  import java.util.Calendar;
79  import java.util.Collections;
80  import java.util.Date;
81  import java.util.HashSet;
82  import java.util.Iterator;
83  import java.util.List;
84  import java.util.Map;
85  import java.util.Set;
86  import java.util.regex.Matcher;
87  import java.util.regex.Pattern;
88  
89  import javax.portlet.PortletPreferences;
90  import javax.portlet.PortletURL;
91  
92  import org.apache.commons.logging.Log;
93  import org.apache.commons.logging.LogFactory;
94  
95  /**
96   * <a href="WikiPageLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
97   *
98   * @author Brian Wing Shun Chan
99   * @author Jorge Ferrer
100  *
101  */
102 public class WikiPageLocalServiceImpl extends WikiPageLocalServiceBaseImpl {
103 
104     public WikiPage addPage(
105             long userId, long nodeId, String title, String content,
106             String summary, boolean minorEdit, PortletPreferences prefs,
107             ThemeDisplay themeDisplay)
108         throws PortalException, SystemException {
109 
110         String uuid = null;
111         double version = WikiPageImpl.DEFAULT_VERSION;
112         String format = WikiPageImpl.DEFAULT_FORMAT;
113         boolean head = true;
114         String parentTitle = null;
115         String redirectTitle = null;
116         String[] tagsEntries = null;
117 
118         return addPage(
119             uuid, userId, nodeId, title, version, content, summary, minorEdit,
120             format, head, parentTitle, redirectTitle, tagsEntries, prefs,
121             themeDisplay);
122     }
123 
124     public WikiPage addPage(
125             String uuid, long userId, long nodeId, String title, double version,
126             String content, String summary, boolean minorEdit, String format,
127             boolean head, String parentTitle, String redirectTitle,
128             String[] tagsEntries, PortletPreferences prefs,
129             ThemeDisplay themeDisplay)
130         throws PortalException, SystemException {
131 
132         // Page
133 
134         User user = userPersistence.findByPrimaryKey(userId);
135         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
136 
137         Date now = new Date();
138 
139         validate(title, nodeId, content, format);
140 
141         long pageId = counterLocalService.increment();
142 
143         long resourcePrimKey =
144             wikiPageResourceLocalService.getPageResourcePrimKey(nodeId, title);
145 
146         WikiPage page = wikiPagePersistence.create(pageId);
147 
148         page.setUuid(uuid);
149         page.setResourcePrimKey(resourcePrimKey);
150         page.setCompanyId(user.getCompanyId());
151         page.setUserId(user.getUserId());
152         page.setUserName(user.getFullName());
153         page.setCreateDate(now);
154         page.setModifiedDate(now);
155         page.setNodeId(nodeId);
156         page.setTitle(title);
157         page.setVersion(version);
158         page.setContent(content);
159         page.setSummary(summary);
160         page.setFormat(format);
161         page.setHead(head);
162         page.setParentTitle(parentTitle);
163         page.setRedirectTitle(redirectTitle);
164 
165         wikiPagePersistence.update(page, false);
166 
167         // Resources
168 
169         addPageResources(page.getNode(), page, true, true);
170 
171         // Node
172 
173         node.setLastPostDate(now);
174 
175         wikiNodePersistence.update(node, false);
176 
177         // Social
178 
179         socialActivityLocalService.addActivity(
180             userId, node.getGroupId(), WikiPage.class.getName(),
181             page.getResourcePrimKey(), WikiActivityKeys.ADD_PAGE,
182             StringPool.BLANK, 0);
183 
184         // Subscriptions
185 
186         if (!minorEdit && NotificationThreadLocal.isNotificationEnabled()) {
187             notifySubscribers(node, page, prefs, themeDisplay, false);
188         }
189 
190         // Tags
191 
192         updateTagsAsset(userId, page, tagsEntries);
193 
194         // Lucene
195 
196         try {
197             Indexer.addPage(
198                 page.getCompanyId(), node.getGroupId(), nodeId, title,
199                 content, tagsEntries);
200         }
201         catch (SearchException se) {
202             _log.error("Indexing " + pageId, se);
203         }
204 
205         // Cache
206 
207         clearReferralsCache(page);
208         clearPageCache(page);
209 
210         return page;
211     }
212 
213     public void addPageAttachments(
214             long nodeId, String title,
215             List<ObjectValuePair<String, byte[]>> files)
216         throws PortalException, SystemException {
217 
218         if (files.size() == 0) {
219             return;
220         }
221 
222         WikiPage page = getPage(nodeId, title);
223 
224         long companyId = page.getCompanyId();
225         String portletId = CompanyConstants.SYSTEM_STRING;
226         long groupId = GroupImpl.DEFAULT_PARENT_GROUP_ID;
227         long repositoryId = CompanyConstants.SYSTEM;
228         String dirName = page.getAttachmentsDir();
229 
230         try {
231             try {
232                 dlService.addDirectory(companyId, repositoryId, dirName);
233             }
234             catch (DuplicateDirectoryException dde) {
235             }
236 
237             for (int i = 0; i < files.size(); i++) {
238                 ObjectValuePair<String, byte[]> ovp = files.get(i);
239 
240                 String fileName = ovp.getKey();
241                 byte[] bytes = ovp.getValue();
242 
243                 if (Validator.isNull(fileName)) {
244                     continue;
245                 }
246 
247                 try {
248                     dlService.addFile(
249                         companyId, portletId, groupId, repositoryId,
250                         dirName + "/" + fileName, StringPool.BLANK,
251                         new String[0], bytes);
252                 }
253                 catch (DuplicateFileException dfe) {
254                 }
255             }
256         }
257         catch (RemoteException re) {
258             throw new SystemException(re);
259         }
260     }
261 
262     public void addPageResources(
263             long nodeId, String title, boolean addCommunityPermissions,
264             boolean addGuestPermissions)
265         throws PortalException, SystemException {
266 
267         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
268         WikiPage page = getPage(nodeId, title);
269 
270         addPageResources(
271             node, page, addCommunityPermissions, addGuestPermissions);
272     }
273 
274     public void addPageResources(
275             WikiNode node, WikiPage page, boolean addCommunityPermissions,
276             boolean addGuestPermissions)
277         throws PortalException, SystemException {
278 
279         resourceLocalService.addResources(
280             page.getCompanyId(), node.getGroupId(), page.getUserId(),
281             WikiPage.class.getName(), page.getResourcePrimKey(), false,
282             addCommunityPermissions, addGuestPermissions);
283     }
284 
285     public void addPageResources(
286             long nodeId, String title, String[] communityPermissions,
287             String[] guestPermissions)
288         throws PortalException, SystemException {
289 
290         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
291         WikiPage page = getPage(nodeId, title);
292 
293         addPageResources(node, page, communityPermissions, guestPermissions);
294     }
295 
296     public void addPageResources(
297             WikiNode node, WikiPage page, String[] communityPermissions,
298             String[] guestPermissions)
299         throws PortalException, SystemException {
300 
301         resourceLocalService.addModelResources(
302             page.getCompanyId(), node.getGroupId(), page.getUserId(),
303             WikiPage.class.getName(), page.getResourcePrimKey(),
304             communityPermissions, guestPermissions);
305     }
306 
307     public void changeParent(
308             long userId, long nodeId, String title, String newParentTitle,
309             PortletPreferences prefs, ThemeDisplay themeDisplay)
310         throws PortalException, SystemException {
311 
312         WikiPage page = getPage(nodeId, title);
313 
314         String originalParentTitle = page.getParentTitle();
315 
316         double version = page.getVersion();
317         String content = page.getContent();
318         String summary = themeDisplay.translate(
319             "changed-parent-from-x", originalParentTitle);
320         boolean minorEdit = false;
321         String format = page.getFormat();
322         String redirectTitle = page.getRedirectTitle();
323         String[] tagsEntries = null;
324 
325         updatePage(
326             userId, nodeId, title, version, content, summary, minorEdit,
327             format, newParentTitle, redirectTitle, tagsEntries, prefs,
328             themeDisplay);
329 
330         List<WikiPage> oldPages = wikiPagePersistence.findByN_T_H(
331             nodeId, title, false);
332 
333         for (WikiPage oldPage : oldPages) {
334             oldPage.setParentTitle(originalParentTitle);
335 
336             wikiPagePersistence.update(oldPage, false);
337         }
338     }
339 
340     public void deletePage(long nodeId, String title)
341         throws PortalException, SystemException {
342 
343         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
344             nodeId, title, true, 0, 1);
345 
346         if (pages.size() > 0) {
347             WikiPage page = pages.iterator().next();
348 
349             deletePage(page);
350         }
351     }
352 
353     public void deletePage(WikiPage page)
354         throws PortalException, SystemException {
355 
356         // Children
357 
358         List<WikiPage> children = wikiPagePersistence.findByN_P(
359             page.getNodeId(), page.getTitle());
360 
361         for (WikiPage curPage : children) {
362             deletePage(curPage);
363         }
364 
365         // Lucene
366 
367         try {
368             Indexer.deletePage(
369                 page.getCompanyId(), page.getNodeId(), page.getTitle());
370         }
371         catch (SearchException se) {
372             _log.error("Deleting index " + page.getPrimaryKey(), se);
373         }
374 
375         // Attachments
376 
377         long companyId = page.getCompanyId();
378         String portletId = CompanyConstants.SYSTEM_STRING;
379         long repositoryId = CompanyConstants.SYSTEM;
380         String dirName = page.getAttachmentsDir();
381 
382         try {
383             dlService.deleteDirectory(
384                 companyId, portletId, repositoryId, dirName);
385         }
386         catch (NoSuchDirectoryException nsde) {
387         }
388         catch (RemoteException re) {
389             throw new SystemException(re);
390         }
391 
392         // Tags
393 
394         tagsAssetLocalService.deleteAsset(
395             WikiPage.class.getName(), page.getResourcePrimKey());
396 
397         // Subscriptions
398 
399         subscriptionLocalService.deleteSubscriptions(
400             page.getCompanyId(), WikiPage.class.getName(), page.getPageId());
401 
402         // Social
403 
404         socialActivityLocalService.deleteActivities(
405             WikiPage.class.getName(), page.getResourcePrimKey());
406 
407         // Message boards
408 
409         mbMessageLocalService.deleteDiscussionMessages(
410             WikiPage.class.getName(), page.getResourcePrimKey());
411 
412         // Resources
413 
414         resourceLocalService.deleteResource(
415             page.getCompanyId(), WikiPage.class.getName(),
416             ResourceConstants.SCOPE_INDIVIDUAL, page.getResourcePrimKey());
417 
418         // Resource
419 
420         wikiPageResourceLocalService.deletePageResource(
421             page.getNodeId(), page.getTitle());
422 
423         // All versions
424 
425         wikiPagePersistence.removeByN_T(page.getNodeId(), page.getTitle());
426 
427         // All referrals
428 
429         wikiPagePersistence.removeByN_R(page.getNodeId(), page.getTitle());
430 
431         // Cache
432 
433         clearReferralsCache(page);
434     }
435 
436     public void deletePageAttachment(long nodeId, String title, String fileName)
437         throws PortalException, SystemException {
438 
439         if (Validator.isNull(fileName)) {
440             return;
441         }
442 
443         WikiPage page = getPage(nodeId, title);
444 
445         long companyId = page.getCompanyId();
446         String portletId = CompanyConstants.SYSTEM_STRING;
447         long repositoryId = CompanyConstants.SYSTEM;
448 
449         try {
450             dlService.deleteFile(companyId, portletId, repositoryId, fileName);
451         }
452         catch (NoSuchFileException nsfe) {
453         }
454         catch (RemoteException re) {
455             throw new SystemException(re);
456         }
457     }
458 
459     public void deletePages(long nodeId)
460         throws PortalException, SystemException {
461 
462         Iterator<WikiPage> itr = wikiPagePersistence.findByN_H(
463             nodeId, true).iterator();
464 
465         while (itr.hasNext()) {
466             WikiPage page = itr.next();
467 
468             deletePage(page);
469         }
470     }
471 
472     public List<WikiPage> getChildren(
473             long nodeId, boolean head, String parentTitle)
474         throws SystemException {
475 
476         return wikiPagePersistence.findByN_H_P(nodeId, head, parentTitle);
477     }
478 
479     public List<WikiPage> getIncomingLinks(long nodeId, String title)
480         throws PortalException, SystemException {
481 
482         List<WikiPage> links = new UniqueList<WikiPage>();
483 
484         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
485 
486         for (WikiPage page : pages) {
487             if (isLinkedTo(page, title)) {
488                 links.add(page);
489             }
490         }
491 
492         List<WikiPage> referrals = wikiPagePersistence.findByN_R(nodeId, title);
493 
494         for (WikiPage referral : referrals) {
495             for (WikiPage page : pages) {
496                 if (isLinkedTo(page, referral.getTitle())) {
497                     links.add(page);
498                 }
499             }
500         }
501 
502         Collections.sort(links);
503 
504         return links;
505     }
506 
507     public List<WikiPage> getNoAssetPages() throws SystemException {
508         return wikiPageFinder.findByNoAssets();
509     }
510 
511     public List<WikiPage> getOrphans(long nodeId)
512         throws PortalException, SystemException {
513 
514         List<Map<String, Boolean>> pageTitles =
515             new ArrayList<Map<String, Boolean>>();
516 
517         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
518 
519         for (WikiPage page : pages) {
520             pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
521         }
522 
523         Set<WikiPage> notOrphans = new HashSet<WikiPage>();
524 
525         for (WikiPage page : pages) {
526             for (Map<String, Boolean> pageTitle : pageTitles) {
527                 if (pageTitle.get(page.getTitle()) != null) {
528                     notOrphans.add(page);
529 
530                     break;
531                 }
532             }
533         }
534 
535         List<WikiPage> orphans = new ArrayList<WikiPage>();
536 
537         for (WikiPage page : pages) {
538             if (!notOrphans.contains(page)) {
539                 orphans.add(page);
540             }
541         }
542 
543         Collections.sort(orphans);
544 
545         return orphans;
546     }
547 
548     public List<WikiPage> getOutgoingLinks(long nodeId, String title)
549         throws PortalException, SystemException {
550 
551         WikiPage page = getPage(nodeId, title);
552 
553         List<WikiPage> pages = new UniqueList<WikiPage>();
554 
555         Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
556 
557         for (String curTitle : links.keySet()) {
558             Boolean exists = links.get(curTitle);
559 
560             if (exists) {
561                 pages.add(getPage(nodeId, curTitle));
562             }
563             else {
564                 WikiPageImpl newPage = new WikiPageImpl();
565 
566                 newPage.setNew(true);
567                 newPage.setNodeId(nodeId);
568                 newPage.setTitle(curTitle);
569 
570                 pages.add(newPage);
571             }
572         }
573 
574         return pages;
575     }
576 
577     public WikiPage getPage(long nodeId, String title)
578         throws PortalException, SystemException {
579 
580         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
581             nodeId, title, true, 0, 1);
582 
583         if (pages.size() > 0) {
584             return pages.get(0);
585         }
586         else {
587             throw new NoSuchPageException();
588         }
589     }
590 
591     public WikiPage getPage(long nodeId, String title, double version)
592         throws PortalException, SystemException {
593 
594         WikiPage page = null;
595 
596         if (version == 0) {
597             page = getPage(nodeId, title);
598         }
599         else {
600             page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
601         }
602 
603         return page;
604     }
605 
606     public WikiPageDisplay getPageDisplay(
607             long nodeId, String title, PortletURL viewPageURL,
608             PortletURL editPageURL, String attachmentURLPrefix)
609         throws PortalException, SystemException {
610 
611         WikiPage page = getPage(nodeId, title);
612 
613         String formattedContent = WikiUtil.convert(
614             page, viewPageURL, editPageURL, attachmentURLPrefix);
615 
616         return new WikiPageDisplayImpl(
617             page.getUserId(), page.getNodeId(), page.getTitle(),
618             page.getVersion(), page.getContent(), formattedContent,
619             page.getFormat(), page.getHead(), page.getAttachmentsFiles());
620     }
621 
622     public List<WikiPage> getPages(long nodeId, int start, int end)
623         throws SystemException {
624 
625         return wikiPagePersistence.findByNodeId(
626             nodeId, start, end, new PageCreateDateComparator(false));
627     }
628 
629     public List<WikiPage> getPages(String format) throws SystemException {
630         return wikiPagePersistence.findByFormat(format);
631     }
632 
633     public List<WikiPage> getPages(
634             long nodeId, String title, int start, int end)
635         throws SystemException {
636 
637         return wikiPagePersistence.findByN_T(
638             nodeId, title, start, end, new PageCreateDateComparator(false));
639     }
640 
641     public List<WikiPage> getPages(
642             long nodeId, String title, int start, int end,
643             OrderByComparator obc)
644         throws SystemException {
645 
646         return wikiPagePersistence.findByN_T(nodeId, title, start, end, obc);
647     }
648 
649     public List<WikiPage> getPages(
650             long nodeId, boolean head, int start, int end)
651         throws SystemException {
652 
653         return wikiPagePersistence.findByN_H(
654             nodeId, head, start, end, new PageCreateDateComparator(false));
655     }
656 
657     public List<WikiPage> getPages(
658             long nodeId, String title, boolean head, int start, int end)
659         throws SystemException {
660 
661         return wikiPagePersistence.findByN_T_H(
662             nodeId, title, head, start, end,
663             new PageCreateDateComparator(false));
664     }
665 
666     public int getPagesCount(long nodeId) throws SystemException {
667         return wikiPagePersistence.countByNodeId(nodeId);
668     }
669 
670     public int getPagesCount(long nodeId, String title)
671         throws SystemException {
672 
673         return wikiPagePersistence.countByN_T(nodeId, title);
674     }
675 
676     public int getPagesCount(long nodeId, boolean head)
677         throws SystemException {
678 
679         return wikiPagePersistence.countByN_H(nodeId, head);
680     }
681 
682     public int getPagesCount(long nodeId, String title, boolean head)
683         throws SystemException {
684 
685         return wikiPagePersistence.countByN_T_H(nodeId, title, head);
686     }
687 
688     public List<WikiPage> getRecentChanges(long nodeId, int start, int end)
689         throws SystemException {
690 
691         Calendar cal = CalendarFactoryUtil.getCalendar();
692 
693         cal.add(Calendar.WEEK_OF_YEAR, -1);
694 
695         return wikiPageFinder.findByCreateDate(
696             nodeId, cal.getTime(), false, start, end);
697     }
698 
699     public int getRecentChangesCount(long nodeId) throws SystemException {
700         Calendar cal = CalendarFactoryUtil.getCalendar();
701 
702         cal.add(Calendar.WEEK_OF_YEAR, -1);
703 
704         return wikiPageFinder.countByCreateDate(nodeId, cal.getTime(), false);
705     }
706 
707     public void movePage(
708             long userId, long nodeId, String title, String newTitle,
709             PortletPreferences prefs, ThemeDisplay themeDisplay)
710         throws PortalException, SystemException {
711 
712         movePage(userId, nodeId, title, newTitle, true, prefs, themeDisplay);
713     }
714 
715     public void movePage(
716             long userId, long nodeId, String title, String newTitle,
717             boolean strict, PortletPreferences prefs, ThemeDisplay themeDisplay)
718         throws PortalException, SystemException {
719 
720         validateTitle(newTitle);
721 
722         // Check if the new title already exists
723 
724         if (isUsedTitle(nodeId, newTitle)) {
725             WikiPage page = getPage(nodeId, newTitle);
726 
727             // Support moving back to a previously moved title
728 
729             if (((page.getVersion() == WikiPageImpl.DEFAULT_VERSION) &&
730                  (page.getContent().equals(WikiPageImpl.MOVED))) ||
731                 !strict) {
732 
733                 deletePage(nodeId, newTitle);
734             }
735             else {
736                 throw new DuplicatePageException(newTitle);
737             }
738         }
739 
740         // All versions
741 
742         List<WikiPage> pageVersions = wikiPagePersistence.findByN_T(
743             nodeId, title);
744 
745         if (pageVersions.size() == 0) {
746             return;
747         }
748 
749         for (WikiPage page : pageVersions) {
750             page.setTitle(newTitle);
751 
752             wikiPagePersistence.update(page, false);
753         }
754 
755         // Children
756 
757         List<WikiPage> children = wikiPagePersistence.findByN_P(nodeId, title);
758 
759         for (WikiPage page : children) {
760             page.setParentTitle(newTitle);
761 
762             wikiPagePersistence.update(page, false);
763         }
764 
765         WikiPage page = pageVersions.get(pageVersions.size() - 1);
766 
767         // Page resource
768 
769         WikiPageResource wikiPageResource =
770             wikiPageResourcePersistence.findByPrimaryKey(
771                 page.getResourcePrimKey());
772 
773         wikiPageResource.setTitle(newTitle);
774 
775         wikiPageResourcePersistence.update(wikiPageResource, false);
776 
777         // Create stub page at the old location
778 
779         String uuid = null;
780         double version = WikiPageImpl.DEFAULT_VERSION;
781         String format = page.getFormat();
782         boolean head = true;
783         String parentTitle = page.getParentTitle();
784         String redirectTitle = page.getTitle();
785         String content =
786             StringPool.DOUBLE_OPEN_BRACKET + redirectTitle +
787                 StringPool.DOUBLE_CLOSE_BRACKET;
788         String summary = WikiPageImpl.MOVED + " to " + title;
789         String[] tagsEntries = null;
790 
791         addPage(
792             uuid, userId, nodeId, title, version, content, summary, false,
793             format, head, parentTitle, redirectTitle, tagsEntries, prefs,
794             themeDisplay);
795 
796         // Move redirects to point to the page with the new title
797 
798         List<WikiPage> redirectedPages = wikiPagePersistence.findByN_R(
799             nodeId, title);
800 
801         for (WikiPage redirectedPage : redirectedPages) {
802             redirectedPage.setRedirectTitle(newTitle);
803 
804             wikiPagePersistence.update(redirectedPage, false);
805         }
806 
807         // Tags
808 
809         updateTagsAsset(userId, page, tagsEntries);
810 
811         // Lucene
812 
813         try {
814             Indexer.updatePage(
815                 page.getCompanyId(), page.getNode().getGroupId(), nodeId,
816                 newTitle, content, tagsEntries);
817         }
818         catch (SearchException se) {
819             _log.error("Indexing " + newTitle, se);
820         }
821     }
822 
823     public WikiPage revertPage(
824             long userId, long nodeId, String title, double version,
825             PortletPreferences prefs, ThemeDisplay themeDisplay)
826         throws PortalException, SystemException {
827 
828         WikiPage oldPage = getPage(nodeId, title, version);
829 
830         return updatePage(
831             userId, nodeId, title, 0, oldPage.getContent(),
832             WikiPageImpl.REVERTED + " to " + version, false,
833             oldPage.getFormat(), null, oldPage.getRedirectTitle(), null, prefs,
834             themeDisplay);
835     }
836 
837     public void subscribePage(long userId, long nodeId, String title)
838         throws PortalException, SystemException {
839 
840         WikiPage page = getPage(nodeId, title);
841 
842         subscriptionLocalService.addSubscription(
843             userId, WikiPage.class.getName(), page.getResourcePrimKey());
844     }
845 
846     public void unsubscribePage(long userId, long nodeId, String title)
847         throws PortalException, SystemException {
848 
849         WikiPage page = getPage(nodeId, title);
850 
851         subscriptionLocalService.deleteSubscription(
852             userId, WikiPage.class.getName(), page.getResourcePrimKey());
853     }
854 
855     public WikiPage updatePage(
856             long userId, long nodeId, String title, double version,
857             String content, String summary, boolean minorEdit, String format,
858             String parentTitle, String redirectTitle, String[] tagsEntries,
859             PortletPreferences prefs, ThemeDisplay themeDisplay)
860         throws PortalException, SystemException {
861 
862         // Page
863 
864         User user = userPersistence.findByPrimaryKey(userId);
865         Date now = new Date();
866 
867         validate(nodeId, content, format);
868 
869         WikiPage page = null;
870 
871         try {
872             page = getPage(nodeId, title);
873         }
874         catch (NoSuchPageException nspe) {
875             return addPage(
876                 null, userId, nodeId, title, WikiPageImpl.DEFAULT_VERSION,
877                 content, summary, minorEdit, format, true, parentTitle,
878                 redirectTitle, tagsEntries, prefs, themeDisplay);
879         }
880 
881         double oldVersion = page.getVersion();
882 
883         if ((version > 0) && (version != oldVersion)) {
884             throw new PageVersionException();
885         }
886 
887         long resourcePrimKey = page.getResourcePrimKey();
888 
889         page.setHead(false);
890         page.setModifiedDate(now);
891 
892         wikiPagePersistence.update(page, false);
893 
894         double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
895 
896         long pageId = counterLocalService.increment();
897 
898         page = wikiPagePersistence.create(pageId);
899 
900         page.setResourcePrimKey(resourcePrimKey);
901         page.setCompanyId(user.getCompanyId());
902         page.setUserId(user.getUserId());
903         page.setUserName(user.getFullName());
904         page.setCreateDate(now);
905         page.setModifiedDate(now);
906         page.setNodeId(nodeId);
907         page.setTitle(title);
908         page.setVersion(newVersion);
909         page.setContent(content);
910         page.setSummary(summary);
911         page.setFormat(format);
912         page.setHead(true);
913 
914         if (Validator.isNotNull(parentTitle)) {
915             page.setParentTitle(parentTitle);
916         }
917 
918         if (Validator.isNotNull(redirectTitle)) {
919             page.setRedirectTitle(redirectTitle);
920         }
921 
922         wikiPagePersistence.update(page, false);
923 
924         // Node
925 
926         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
927 
928         node.setLastPostDate(now);
929 
930         wikiNodePersistence.update(node, false);
931 
932         // Social
933 
934         socialActivityLocalService.addActivity(
935             userId, node.getGroupId(), WikiPage.class.getName(),
936             page.getResourcePrimKey(), WikiActivityKeys.UPDATE_PAGE,
937             StringPool.BLANK, 0);
938 
939         // Subscriptions
940 
941         if (!minorEdit && NotificationThreadLocal.isNotificationEnabled()) {
942             notifySubscribers(node, page, prefs, themeDisplay, true);
943         }
944 
945         // Tags
946 
947         updateTagsAsset(userId, page, tagsEntries);
948 
949         // Lucene
950 
951         try {
952             Indexer.updatePage(
953                 node.getCompanyId(), node.getGroupId(), nodeId, title, content,
954                 tagsEntries);
955         }
956         catch (SearchException se) {
957             _log.error("Indexing " + page.getPrimaryKey(), se);
958         }
959 
960         // Cache
961 
962         clearPageCache(page);
963 
964         return page;
965     }
966 
967     public void updateTagsAsset(
968             long userId, WikiPage page, String[] tagsEntries)
969         throws PortalException, SystemException {
970 
971         tagsAssetLocalService.updateAsset(
972             userId, page.getNode().getGroupId(), WikiPage.class.getName(),
973             page.getResourcePrimKey(), tagsEntries, null, null, null, null,
974             ContentTypes.TEXT_HTML, page.getTitle(), null, null, null, 0, 0,
975             null, false);
976     }
977 
978     public void validateTitle(String title) throws PortalException {
979         if (title.equals("all_pages") || title.equals("orphan_pages") ||
980             title.equals("recent_changes")) {
981 
982             throw new PageTitleException(title + " is reserved");
983         }
984 
985         if (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
986             Pattern pattern = Pattern.compile(
987                 PropsValues.WIKI_PAGE_TITLES_REGEXP);
988 
989             Matcher matcher = pattern.matcher(title);
990 
991             if (!matcher.matches()) {
992                 throw new PageTitleException();
993             }
994         }
995     }
996 
997     protected void clearPageCache(WikiPage page) {
998         if (!WikiCacheThreadLocal.isClearCache()) {
999             return;
1000        }
1001
1002        WikiCacheUtil.clearCache(page.getNodeId(), page.getTitle());
1003    }
1004
1005    protected void clearReferralsCache(WikiPage page)
1006        throws PortalException, SystemException {
1007
1008        if (!WikiCacheThreadLocal.isClearCache()) {
1009            return;
1010        }
1011
1012        List<WikiPage> links = getIncomingLinks(
1013            page.getNodeId(), page.getTitle());
1014
1015        for (WikiPage curPage : links) {
1016            WikiCacheUtil.clearCache(curPage.getNodeId(), curPage.getTitle());
1017        }
1018    }
1019
1020    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1021        throws PortalException {
1022
1023        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1024
1025        Boolean link = links.get(targetTitle);
1026
1027        if (link != null) {
1028            return true;
1029        }
1030        else {
1031            return false;
1032        }
1033    }
1034
1035    protected boolean isUsedTitle(long nodeId, String title)
1036        throws SystemException {
1037
1038        if (getPagesCount(nodeId, title, true) > 0) {
1039            return true;
1040        }
1041        else {
1042            return false;
1043        }
1044    }
1045
1046    protected void notifySubscribers(
1047            WikiNode node, WikiPage page, PortletPreferences prefs,
1048            ThemeDisplay themeDisplay, boolean update)
1049        throws PortalException, SystemException {
1050
1051        if (prefs == null) {
1052            long ownerId = node.getGroupId();
1053            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1054            long plid = PortletKeys.PREFS_PLID_SHARED;
1055            String portletId = PortletKeys.WIKI;
1056            String defaultPreferences = null;
1057
1058            prefs = portletPreferencesLocalService.getPreferences(
1059                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1060                defaultPreferences);
1061        }
1062
1063        if (!update && WikiUtil.getEmailPageAddedEnabled(prefs)) {
1064        }
1065        else if (update && WikiUtil.getEmailPageUpdatedEnabled(prefs)) {
1066        }
1067        else {
1068            return;
1069        }
1070
1071        Company company = companyPersistence.findByPrimaryKey(
1072            page.getCompanyId());
1073
1074        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1075
1076        User user = userPersistence.findByPrimaryKey(page.getUserId());
1077
1078        String pageURL = StringPool.BLANK;
1079
1080        if (themeDisplay != null) {
1081            String portalURL = PortalUtil.getPortalURL(themeDisplay);
1082            String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
1083
1084            pageURL =
1085                portalURL + layoutURL + "/wiki/" + node.getNodeId() + "/" +
1086                    page.getTitle();
1087        }
1088
1089        String portletName = PortalUtil.getPortletTitle(
1090            PortletKeys.WIKI, user);
1091
1092        String fromName = WikiUtil.getEmailFromName(prefs);
1093        String fromAddress = WikiUtil.getEmailFromAddress(prefs);
1094
1095        String replyToAddress = fromAddress;
1096        String mailId = WikiUtil.getMailId(
1097            company.getMx(), page.getNodeId(), page.getPageId());
1098
1099        fromName = StringUtil.replace(
1100            fromName,
1101            new String[] {
1102                "[$COMPANY_ID$]",
1103                "[$COMPANY_MX$]",
1104                "[$COMPANY_NAME$]",
1105                "[$COMMUNITY_NAME$]",
1106                "[$PAGE_USER_ADDRESS$]",
1107                "[$PAGE_USER_NAME$]",
1108                "[$PORTLET_NAME$]"
1109            },
1110            new String[] {
1111                String.valueOf(company.getCompanyId()),
1112                company.getMx(),
1113                company.getName(),
1114                group.getName(),
1115                user.getEmailAddress(),
1116                user.getFullName(),
1117                portletName
1118            });
1119
1120        fromAddress = StringUtil.replace(
1121            fromAddress,
1122            new String[] {
1123                "[$COMPANY_ID$]",
1124                "[$COMPANY_MX$]",
1125                "[$COMPANY_NAME$]",
1126                "[$COMMUNITY_NAME$]",
1127                "[$PAGE_USER_ADDRESS$]",
1128                "[$PAGE_USER_NAME$]",
1129                "[$PORTLET_NAME$]"
1130            },
1131            new String[] {
1132                String.valueOf(company.getCompanyId()),
1133                company.getMx(),
1134                company.getName(),
1135                group.getName(),
1136                user.getEmailAddress(),
1137                user.getFullName(),
1138                portletName
1139            });
1140
1141        String subjectPrefix = null;
1142        String body = null;
1143        String signature = null;
1144
1145        if (update) {
1146            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(prefs);
1147            body = WikiUtil.getEmailPageUpdatedBody(prefs);
1148            signature = WikiUtil.getEmailPageUpdatedSignature(prefs);
1149        }
1150        else {
1151            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(prefs);
1152            body = WikiUtil.getEmailPageAddedBody(prefs);
1153            signature = WikiUtil.getEmailPageAddedSignature(prefs);
1154        }
1155
1156        if (Validator.isNotNull(signature)) {
1157            body +=  "\n--\n" + signature;
1158        }
1159
1160        subjectPrefix = StringUtil.replace(
1161            subjectPrefix,
1162            new String[] {
1163                "[$COMPANY_ID$]",
1164                "[$COMPANY_MX$]",
1165                "[$COMPANY_NAME$]",
1166                "[$COMMUNITY_NAME$]",
1167                "[$FROM_ADDRESS$]",
1168                "[$FROM_NAME$]",
1169                "[$NODE_NAME$]",
1170                "[$PAGE_CONTENT$]",
1171                "[$PAGE_ID$]",
1172                "[$PAGE_TITLE$]",
1173                "[$PAGE_USER_ADDRESS$]",
1174                "[$PAGE_USER_NAME$]",
1175                "[$PORTAL_URL$]",
1176                "[$PORTLET_NAME$]"
1177            },
1178            new String[] {
1179                String.valueOf(company.getCompanyId()),
1180                company.getMx(),
1181                company.getName(),
1182                group.getName(),
1183                fromAddress,
1184                fromName,
1185                node.getName(),
1186                page.getContent(),
1187                String.valueOf(page.getPageId()),
1188                page.getTitle(),
1189                user.getEmailAddress(),
1190                user.getFullName(),
1191                company.getVirtualHost(),
1192                portletName
1193            });
1194
1195        body = StringUtil.replace(
1196            body,
1197            new String[] {
1198                "[$COMPANY_ID$]",
1199                "[$COMPANY_MX$]",
1200                "[$COMPANY_NAME$]",
1201                "[$COMMUNITY_NAME$]",
1202                "[$FROM_ADDRESS$]",
1203                "[$FROM_NAME$]",
1204                "[$NODE_NAME$]",
1205                "[$PAGE_CONTENT$]",
1206                "[$PAGE_ID$]",
1207                "[$PAGE_TITLE$]",
1208                "[$PAGE_URL$]",
1209                "[$PAGE_USER_ADDRESS$]",
1210                "[$PAGE_USER_NAME$]",
1211                "[$PORTAL_URL$]",
1212                "[$PORTLET_NAME$]"
1213            },
1214            new String[] {
1215                String.valueOf(company.getCompanyId()),
1216                company.getMx(),
1217                company.getName(),
1218                group.getName(),
1219                fromAddress,
1220                fromName,
1221                node.getName(),
1222                page.getContent(),
1223                String.valueOf(page.getPageId()),
1224                page.getTitle(),
1225                pageURL,
1226                user.getEmailAddress(),
1227                user.getFullName(),
1228                company.getVirtualHost(),
1229                portletName
1230            });
1231
1232        String subject = page.getTitle();
1233
1234        if (subject.indexOf(subjectPrefix) == -1) {
1235            subject = subjectPrefix + subject;
1236        }
1237
1238        JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
1239
1240        jsonObj.put("companyId", node.getCompanyId());
1241        jsonObj.put("userId", node.getUserId());
1242        jsonObj.put("nodeId", node.getNodeId());
1243        jsonObj.put("pageResourcePrimKey", page.getResourcePrimKey());
1244        jsonObj.put("fromName", fromName);
1245        jsonObj.put("fromAddress", fromAddress);
1246        jsonObj.put("subject", subject);
1247        jsonObj.put("body", body);
1248        jsonObj.put("replyToAddress", replyToAddress);
1249        jsonObj.put("mailId", mailId);
1250
1251        MessageBusUtil.sendMessage(DestinationNames.WIKI, jsonObj.toString());
1252    }
1253
1254    protected void validate(long nodeId, String content, String format)
1255        throws PortalException {
1256
1257        if (!WikiUtil.validate(nodeId, content, format)) {
1258            throw new PageContentException();
1259        }
1260    }
1261
1262    protected void validate(
1263            String title, long nodeId, String content, String format)
1264        throws PortalException {
1265
1266        if (Validator.isNull(title)) {
1267            throw new PageTitleException();
1268        }
1269
1270        validateTitle(title);
1271
1272        validate(nodeId, content, format);
1273    }
1274
1275    private static Log _log = LogFactory.getLog(WikiPageLocalServiceImpl.class);
1276
1277}