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 (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
980             Pattern pattern = Pattern.compile(
981                 PropsValues.WIKI_PAGE_TITLES_REGEXP);
982 
983             Matcher matcher = pattern.matcher(title);
984 
985             if (!matcher.matches()) {
986                 throw new PageTitleException();
987             }
988         }
989     }
990 
991     protected void clearPageCache(WikiPage page) {
992         if (!WikiCacheThreadLocal.isClearCache()) {
993             return;
994         }
995 
996         WikiCacheUtil.clearCache(page.getNodeId(), page.getTitle());
997     }
998 
999     protected void clearReferralsCache(WikiPage page)
1000        throws PortalException, SystemException {
1001
1002        if (!WikiCacheThreadLocal.isClearCache()) {
1003            return;
1004        }
1005
1006        List<WikiPage> links = getIncomingLinks(
1007            page.getNodeId(), page.getTitle());
1008
1009        for (WikiPage curPage : links) {
1010            WikiCacheUtil.clearCache(curPage.getNodeId(), curPage.getTitle());
1011        }
1012    }
1013
1014    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1015        throws PortalException {
1016
1017        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1018
1019        Boolean link = links.get(targetTitle);
1020
1021        if (link != null) {
1022            return true;
1023        }
1024        else {
1025            return false;
1026        }
1027    }
1028
1029    protected boolean isUsedTitle(long nodeId, String title)
1030        throws SystemException {
1031
1032        if (getPagesCount(nodeId, title, true) > 0) {
1033            return true;
1034        }
1035        else {
1036            return false;
1037        }
1038    }
1039
1040    protected void notifySubscribers(
1041            WikiNode node, WikiPage page, PortletPreferences prefs,
1042            ThemeDisplay themeDisplay, boolean update)
1043        throws PortalException, SystemException {
1044
1045        if (prefs == null) {
1046            long ownerId = node.getGroupId();
1047            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1048            long plid = PortletKeys.PREFS_PLID_SHARED;
1049            String portletId = PortletKeys.WIKI;
1050            String defaultPreferences = null;
1051
1052            prefs = portletPreferencesLocalService.getPreferences(
1053                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1054                defaultPreferences);
1055        }
1056
1057        if (!update && WikiUtil.getEmailPageAddedEnabled(prefs)) {
1058        }
1059        else if (update && WikiUtil.getEmailPageUpdatedEnabled(prefs)) {
1060        }
1061        else {
1062            return;
1063        }
1064
1065        Company company = companyPersistence.findByPrimaryKey(
1066            page.getCompanyId());
1067
1068        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1069
1070        User user = userPersistence.findByPrimaryKey(page.getUserId());
1071
1072        String pageURL = StringPool.BLANK;
1073
1074        if (themeDisplay != null) {
1075            String portalURL = PortalUtil.getPortalURL(themeDisplay);
1076            String layoutURL = PortalUtil.getLayoutURL(themeDisplay);
1077
1078            pageURL =
1079                portalURL + layoutURL + "/wiki/" + node.getNodeId() + "/" +
1080                    page.getTitle();
1081        }
1082
1083        String portletName = PortalUtil.getPortletTitle(
1084            PortletKeys.WIKI, user);
1085
1086        String fromName = WikiUtil.getEmailFromName(prefs);
1087        String fromAddress = WikiUtil.getEmailFromAddress(prefs);
1088
1089        String replyToAddress = fromAddress;
1090        String mailId = WikiUtil.getMailId(
1091            company.getMx(), page.getNodeId(), page.getPageId());
1092
1093        fromName = StringUtil.replace(
1094            fromName,
1095            new String[] {
1096                "[$COMPANY_ID$]",
1097                "[$COMPANY_MX$]",
1098                "[$COMPANY_NAME$]",
1099                "[$COMMUNITY_NAME$]",
1100                "[$PAGE_USER_ADDRESS$]",
1101                "[$PAGE_USER_NAME$]",
1102                "[$PORTLET_NAME$]"
1103            },
1104            new String[] {
1105                String.valueOf(company.getCompanyId()),
1106                company.getMx(),
1107                company.getName(),
1108                group.getName(),
1109                user.getEmailAddress(),
1110                user.getFullName(),
1111                portletName
1112            });
1113
1114        fromAddress = StringUtil.replace(
1115            fromAddress,
1116            new String[] {
1117                "[$COMPANY_ID$]",
1118                "[$COMPANY_MX$]",
1119                "[$COMPANY_NAME$]",
1120                "[$COMMUNITY_NAME$]",
1121                "[$PAGE_USER_ADDRESS$]",
1122                "[$PAGE_USER_NAME$]",
1123                "[$PORTLET_NAME$]"
1124            },
1125            new String[] {
1126                String.valueOf(company.getCompanyId()),
1127                company.getMx(),
1128                company.getName(),
1129                group.getName(),
1130                user.getEmailAddress(),
1131                user.getFullName(),
1132                portletName
1133            });
1134
1135        String subjectPrefix = null;
1136        String body = null;
1137        String signature = null;
1138
1139        if (update) {
1140            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(prefs);
1141            body = WikiUtil.getEmailPageUpdatedBody(prefs);
1142            signature = WikiUtil.getEmailPageUpdatedSignature(prefs);
1143        }
1144        else {
1145            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(prefs);
1146            body = WikiUtil.getEmailPageAddedBody(prefs);
1147            signature = WikiUtil.getEmailPageAddedSignature(prefs);
1148        }
1149
1150        if (Validator.isNotNull(signature)) {
1151            body +=  "\n--\n" + signature;
1152        }
1153
1154        subjectPrefix = StringUtil.replace(
1155            subjectPrefix,
1156            new String[] {
1157                "[$COMPANY_ID$]",
1158                "[$COMPANY_MX$]",
1159                "[$COMPANY_NAME$]",
1160                "[$COMMUNITY_NAME$]",
1161                "[$FROM_ADDRESS$]",
1162                "[$FROM_NAME$]",
1163                "[$NODE_NAME$]",
1164                "[$PAGE_CONTENT$]",
1165                "[$PAGE_ID$]",
1166                "[$PAGE_TITLE$]",
1167                "[$PAGE_USER_ADDRESS$]",
1168                "[$PAGE_USER_NAME$]",
1169                "[$PORTAL_URL$]",
1170                "[$PORTLET_NAME$]"
1171            },
1172            new String[] {
1173                String.valueOf(company.getCompanyId()),
1174                company.getMx(),
1175                company.getName(),
1176                group.getName(),
1177                fromAddress,
1178                fromName,
1179                node.getName(),
1180                page.getContent(),
1181                String.valueOf(page.getPageId()),
1182                page.getTitle(),
1183                user.getEmailAddress(),
1184                user.getFullName(),
1185                company.getVirtualHost(),
1186                portletName
1187            });
1188
1189        body = StringUtil.replace(
1190            body,
1191            new String[] {
1192                "[$COMPANY_ID$]",
1193                "[$COMPANY_MX$]",
1194                "[$COMPANY_NAME$]",
1195                "[$COMMUNITY_NAME$]",
1196                "[$FROM_ADDRESS$]",
1197                "[$FROM_NAME$]",
1198                "[$NODE_NAME$]",
1199                "[$PAGE_CONTENT$]",
1200                "[$PAGE_ID$]",
1201                "[$PAGE_TITLE$]",
1202                "[$PAGE_URL$]",
1203                "[$PAGE_USER_ADDRESS$]",
1204                "[$PAGE_USER_NAME$]",
1205                "[$PORTAL_URL$]",
1206                "[$PORTLET_NAME$]"
1207            },
1208            new String[] {
1209                String.valueOf(company.getCompanyId()),
1210                company.getMx(),
1211                company.getName(),
1212                group.getName(),
1213                fromAddress,
1214                fromName,
1215                node.getName(),
1216                page.getContent(),
1217                String.valueOf(page.getPageId()),
1218                page.getTitle(),
1219                pageURL,
1220                user.getEmailAddress(),
1221                user.getFullName(),
1222                company.getVirtualHost(),
1223                portletName
1224            });
1225
1226        String subject = page.getTitle();
1227
1228        if (subject.indexOf(subjectPrefix) == -1) {
1229            subject = subjectPrefix + subject;
1230        }
1231
1232        JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
1233
1234        jsonObj.put("companyId", node.getCompanyId());
1235        jsonObj.put("userId", node.getUserId());
1236        jsonObj.put("nodeId", node.getNodeId());
1237        jsonObj.put("pageResourcePrimKey", page.getResourcePrimKey());
1238        jsonObj.put("fromName", fromName);
1239        jsonObj.put("fromAddress", fromAddress);
1240        jsonObj.put("subject", subject);
1241        jsonObj.put("body", body);
1242        jsonObj.put("replyToAddress", replyToAddress);
1243        jsonObj.put("mailId", mailId);
1244
1245        MessageBusUtil.sendMessage(DestinationNames.WIKI, jsonObj.toString());
1246    }
1247
1248    protected void validate(long nodeId, String content, String format)
1249        throws PortalException {
1250
1251        if (!WikiUtil.validate(nodeId, content, format)) {
1252            throw new PageContentException();
1253        }
1254    }
1255
1256    protected void validate(
1257            String title, long nodeId, String content, String format)
1258        throws PortalException {
1259
1260        if (Validator.isNull(title)) {
1261            throw new PageTitleException();
1262        }
1263
1264        validateTitle(title);
1265
1266        validate(nodeId, content, format);
1267    }
1268
1269    private static Log _log = LogFactory.getLog(WikiPageLocalServiceImpl.class);
1270
1271}