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