1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   * 
13   */
14  
15  package com.liferay.portlet.wiki.service.impl;
16  
17  import com.liferay.documentlibrary.DuplicateDirectoryException;
18  import com.liferay.documentlibrary.DuplicateFileException;
19  import com.liferay.documentlibrary.NoSuchDirectoryException;
20  import com.liferay.documentlibrary.NoSuchFileException;
21  import com.liferay.portal.PortalException;
22  import com.liferay.portal.SystemException;
23  import com.liferay.portal.kernel.language.LanguageUtil;
24  import com.liferay.portal.kernel.log.Log;
25  import com.liferay.portal.kernel.log.LogFactoryUtil;
26  import com.liferay.portal.kernel.messaging.DestinationNames;
27  import com.liferay.portal.kernel.messaging.Message;
28  import com.liferay.portal.kernel.messaging.MessageBusUtil;
29  import com.liferay.portal.kernel.search.SearchEngineUtil;
30  import com.liferay.portal.kernel.search.SearchException;
31  import com.liferay.portal.kernel.util.CalendarFactoryUtil;
32  import com.liferay.portal.kernel.util.ContentTypes;
33  import com.liferay.portal.kernel.util.HttpUtil;
34  import com.liferay.portal.kernel.util.ListUtil;
35  import com.liferay.portal.kernel.util.MathUtil;
36  import com.liferay.portal.kernel.util.NotificationThreadLocal;
37  import com.liferay.portal.kernel.util.ObjectValuePair;
38  import com.liferay.portal.kernel.util.OrderByComparator;
39  import com.liferay.portal.kernel.util.StringBundler;
40  import com.liferay.portal.kernel.util.StringPool;
41  import com.liferay.portal.kernel.util.StringUtil;
42  import com.liferay.portal.kernel.util.Validator;
43  import com.liferay.portal.model.Company;
44  import com.liferay.portal.model.CompanyConstants;
45  import com.liferay.portal.model.Group;
46  import com.liferay.portal.model.GroupConstants;
47  import com.liferay.portal.model.ResourceConstants;
48  import com.liferay.portal.model.User;
49  import com.liferay.portal.service.ServiceContext;
50  import com.liferay.portal.service.ServiceContextUtil;
51  import com.liferay.portal.util.Portal;
52  import com.liferay.portal.util.PortalUtil;
53  import com.liferay.portal.util.PortletKeys;
54  import com.liferay.portal.util.PropsValues;
55  import com.liferay.portlet.expando.model.ExpandoBridge;
56  import com.liferay.portlet.tags.model.TagsEntryConstants;
57  import com.liferay.portlet.wiki.DuplicatePageException;
58  import com.liferay.portlet.wiki.NoSuchPageException;
59  import com.liferay.portlet.wiki.NoSuchPageResourceException;
60  import com.liferay.portlet.wiki.PageContentException;
61  import com.liferay.portlet.wiki.PageTitleException;
62  import com.liferay.portlet.wiki.PageVersionException;
63  import com.liferay.portlet.wiki.model.WikiNode;
64  import com.liferay.portlet.wiki.model.WikiPage;
65  import com.liferay.portlet.wiki.model.WikiPageDisplay;
66  import com.liferay.portlet.wiki.model.WikiPageResource;
67  import com.liferay.portlet.wiki.model.impl.WikiPageDisplayImpl;
68  import com.liferay.portlet.wiki.model.impl.WikiPageImpl;
69  import com.liferay.portlet.wiki.service.base.WikiPageLocalServiceBaseImpl;
70  import com.liferay.portlet.wiki.social.WikiActivityKeys;
71  import com.liferay.portlet.wiki.util.Indexer;
72  import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
73  import com.liferay.portlet.wiki.util.WikiCacheUtil;
74  import com.liferay.portlet.wiki.util.WikiUtil;
75  import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
76  import com.liferay.util.UniqueList;
77  
78  import java.util.ArrayList;
79  import java.util.Calendar;
80  import java.util.Date;
81  import java.util.HashSet;
82  import java.util.Iterator;
83  import java.util.LinkedHashMap;
84  import java.util.List;
85  import java.util.Map;
86  import java.util.Set;
87  import java.util.regex.Matcher;
88  import java.util.regex.Pattern;
89  
90  import javax.portlet.PortletPreferences;
91  import javax.portlet.PortletURL;
92  import javax.portlet.WindowState;
93  
94  /**
95   * <a href="WikiPageLocalServiceImpl.java.html"><b><i>View Source</i></b></a>
96   *
97   * @author Brian Wing Shun Chan
98   * @author Jorge Ferrer
99   * @author Raymond Augé
100  * @author Bruno Farache
101  * @author Julio Camarero
102  * @author Wesley Gong
103  */
104 public class WikiPageLocalServiceImpl extends WikiPageLocalServiceBaseImpl {
105 
106     public WikiPage addPage(
107             long userId, long nodeId, String title, String content,
108             String summary, boolean minorEdit, ServiceContext serviceContext)
109         throws PortalException, SystemException {
110 
111         String uuid = null;
112         double version = WikiPageImpl.DEFAULT_VERSION;
113         String format = WikiPageImpl.DEFAULT_FORMAT;
114         boolean head = true;
115         String parentTitle = null;
116         String redirectTitle = null;
117 
118         return addPage(
119             uuid, userId, nodeId, title, version, content, summary, minorEdit,
120             format, head, parentTitle, redirectTitle, serviceContext);
121     }
122 
123     public WikiPage addPage(
124             String uuid, long userId, long nodeId, String title, double version,
125             String content, String summary, boolean minorEdit, String format,
126             boolean head, String parentTitle, String redirectTitle,
127             ServiceContext serviceContext)
128         throws PortalException, SystemException {
129 
130         // Page
131 
132         User user = userPersistence.findByPrimaryKey(userId);
133         WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
134 
135         Date now = new Date();
136 
137         validate(title, nodeId, content, format);
138 
139         long pageId = counterLocalService.increment();
140 
141         long resourcePrimKey =
142             wikiPageResourceLocalService.getPageResourcePrimKey(nodeId, title);
143 
144         WikiPage page = wikiPagePersistence.create(pageId);
145 
146         page.setUuid(uuid);
147         page.setResourcePrimKey(resourcePrimKey);
148         page.setGroupId(node.getGroupId());
149         page.setCompanyId(user.getCompanyId());
150         page.setUserId(user.getUserId());
151         page.setUserName(user.getFullName());
152         page.setCreateDate(serviceContext.getCreateDate(now));
153         page.setModifiedDate(serviceContext.getModifiedDate(now));
154         page.setNodeId(nodeId);
155         page.setTitle(title);
156         page.setVersion(version);
157         page.setMinorEdit(minorEdit);
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         if (serviceContext.getAddCommunityPermissions() ||
170             serviceContext.getAddGuestPermissions()) {
171 
172             addPageResources(
173                 page, serviceContext.getAddCommunityPermissions(),
174                 serviceContext.getAddGuestPermissions());
175         }
176         else {
177             addPageResources(
178                 page, serviceContext.getCommunityPermissions(),
179                 serviceContext.getGuestPermissions());
180         }
181 
182         // Node
183 
184         node.setLastPostDate(serviceContext.getModifiedDate(now));
185 
186         wikiNodePersistence.update(node, false);
187 
188         // Message boards
189 
190         if (PropsValues.WIKI_PAGE_COMMENTS_ENABLED) {
191             mbMessageLocalService.addDiscussionMessage(
192                 userId, page.getUserName(), WikiPage.class.getName(),
193                 resourcePrimKey);
194         }
195 
196         // Social
197 
198         socialActivityLocalService.addActivity(
199             userId, page.getGroupId(), WikiPage.class.getName(),
200             resourcePrimKey, WikiActivityKeys.ADD_PAGE, StringPool.BLANK, 0);
201 
202         // Subscriptions
203 
204         if (!minorEdit && NotificationThreadLocal.isEnabled()) {
205             notifySubscribers(node, page, serviceContext, false);
206         }
207 
208         // Tags
209 
210         updateTagsAsset(
211             userId, page, serviceContext.getTagsCategories(),
212             serviceContext.getTagsEntries());
213 
214         // Indexer
215 
216         reIndex(page);
217 
218         // Cache
219 
220         clearPageCache(page);
221         clearReferralsCache(page);
222 
223         return page;
224     }
225 
226     public void addPageAttachments(
227             long nodeId, String title,
228             List<ObjectValuePair<String, byte[]>> files)
229         throws PortalException, SystemException {
230 
231         if (files.size() == 0) {
232             return;
233         }
234 
235         WikiPage page = getPage(nodeId, title);
236 
237         long companyId = page.getCompanyId();
238         String portletId = CompanyConstants.SYSTEM_STRING;
239         long groupId = GroupConstants.DEFAULT_PARENT_GROUP_ID;
240         long repositoryId = CompanyConstants.SYSTEM;
241         String dirName = page.getAttachmentsDir();
242 
243         try {
244             dlService.addDirectory(companyId, repositoryId, dirName);
245         }
246         catch (DuplicateDirectoryException dde) {
247         }
248 
249         for (int i = 0; i < files.size(); i++) {
250             ObjectValuePair<String, byte[]> ovp = files.get(i);
251 
252             String fileName = ovp.getKey();
253             byte[] bytes = ovp.getValue();
254 
255             if (Validator.isNull(fileName)) {
256                 continue;
257             }
258 
259             try {
260                 dlService.addFile(
261                     companyId, portletId, groupId, repositoryId,
262                     dirName + "/" + fileName, 0, StringPool.BLANK,
263                     page.getModifiedDate(), new String[0], new String[0],
264                     bytes);
265             }
266             catch (DuplicateFileException dfe) {
267             }
268         }
269     }
270 
271     public void addPageResources(
272             long nodeId, String title, boolean addCommunityPermissions,
273             boolean addGuestPermissions)
274         throws PortalException, SystemException {
275 
276         WikiPage page = getPage(nodeId, title);
277 
278         addPageResources(page, addCommunityPermissions, addGuestPermissions);
279     }
280 
281     public void addPageResources(
282             WikiPage page, boolean addCommunityPermissions,
283             boolean addGuestPermissions)
284         throws PortalException, SystemException {
285 
286         resourceLocalService.addResources(
287             page.getCompanyId(), page.getGroupId(), page.getUserId(),
288             WikiPage.class.getName(), page.getResourcePrimKey(), false,
289             addCommunityPermissions, addGuestPermissions);
290     }
291 
292     public void addPageResources(
293             long nodeId, String title, String[] communityPermissions,
294             String[] guestPermissions)
295         throws PortalException, SystemException {
296 
297         WikiPage page = getPage(nodeId, title);
298 
299         addPageResources(page, communityPermissions, guestPermissions);
300     }
301 
302     public void addPageResources(
303             WikiPage page, String[] communityPermissions,
304             String[] guestPermissions)
305         throws PortalException, SystemException {
306 
307         resourceLocalService.addModelResources(
308             page.getCompanyId(), page.getGroupId(), page.getUserId(),
309             WikiPage.class.getName(), page.getResourcePrimKey(),
310             communityPermissions, guestPermissions);
311     }
312 
313     public void changeParent(
314             long userId, long nodeId, String title, String newParentTitle,
315             ServiceContext serviceContext)
316         throws PortalException, SystemException {
317 
318         if (Validator.isNotNull(newParentTitle)) {
319             WikiPage parentPage = getPage(nodeId, newParentTitle);
320 
321             if (Validator.isNotNull(parentPage.getRedirectTitle())) {
322                 newParentTitle = parentPage.getRedirectTitle();
323             }
324         }
325 
326         WikiPage page = getPage(nodeId, title);
327 
328         String originalParentTitle = page.getParentTitle();
329 
330         double version = page.getVersion();
331         String content = page.getContent();
332         String summary = LanguageUtil.format(
333             ServiceContextUtil.getLocale(serviceContext),
334             "changed-parent-from-x", originalParentTitle);
335         boolean minorEdit = false;
336         String format = page.getFormat();
337         String redirectTitle = page.getRedirectTitle();
338 
339         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
340             WikiPage.class.getName(), page.getResourcePrimKey(),
341             TagsEntryConstants.FOLKSONOMY_CATEGORY);
342         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
343             WikiPage.class.getName(), page.getResourcePrimKey(),
344             TagsEntryConstants.FOLKSONOMY_TAG);
345 
346         serviceContext.setTagsCategories(tagsCategories);
347         serviceContext.setTagsEntries(tagsEntries);
348 
349         updatePage(
350             userId, nodeId, title, version, content, summary, minorEdit,
351             format, newParentTitle, redirectTitle, serviceContext);
352 
353         List<WikiPage> oldPages = wikiPagePersistence.findByN_T_H(
354             nodeId, title, false);
355 
356         for (WikiPage oldPage : oldPages) {
357             oldPage.setParentTitle(originalParentTitle);
358 
359             wikiPagePersistence.update(oldPage, false);
360         }
361     }
362 
363     public void deletePage(long nodeId, String title)
364         throws PortalException, SystemException {
365 
366         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
367             nodeId, title, true, 0, 1);
368 
369         if (pages.size() > 0) {
370             WikiPage page = pages.iterator().next();
371 
372             deletePage(page);
373         }
374     }
375 
376     public void deletePage(WikiPage page)
377         throws PortalException, SystemException {
378 
379         // Children
380 
381         List<WikiPage> children = wikiPagePersistence.findByN_H_P(
382             page.getNodeId(), true, page.getTitle());
383 
384         for (WikiPage curPage : children) {
385             deletePage(curPage);
386         }
387 
388         // Indexer
389 
390         try {
391             Indexer.deletePage(
392                 page.getCompanyId(), page.getNodeId(), page.getTitle());
393         }
394         catch (SearchException se) {
395             _log.error("Deleting index " + page.getPrimaryKey(), se);
396         }
397 
398         // Attachments
399 
400         long companyId = page.getCompanyId();
401         String portletId = CompanyConstants.SYSTEM_STRING;
402         long repositoryId = CompanyConstants.SYSTEM;
403         String dirName = page.getAttachmentsDir();
404 
405         try {
406             dlService.deleteDirectory(
407                 companyId, portletId, repositoryId, dirName);
408         }
409         catch (NoSuchDirectoryException nsde) {
410         }
411 
412         // Tags
413 
414         tagsAssetLocalService.deleteAsset(
415             WikiPage.class.getName(), page.getResourcePrimKey());
416 
417         // Subscriptions
418 
419         subscriptionLocalService.deleteSubscriptions(
420             page.getCompanyId(), WikiPage.class.getName(), page.getPageId());
421 
422         // Social
423 
424         socialActivityLocalService.deleteActivities(
425             WikiPage.class.getName(), page.getResourcePrimKey());
426 
427         // Message boards
428 
429         mbMessageLocalService.deleteDiscussionMessages(
430             WikiPage.class.getName(), page.getResourcePrimKey());
431 
432         // Resources
433 
434         resourceLocalService.deleteResource(
435             page.getCompanyId(), WikiPage.class.getName(),
436             ResourceConstants.SCOPE_INDIVIDUAL, page.getResourcePrimKey());
437 
438         // Resource
439 
440         try {
441             wikiPageResourceLocalService.deletePageResource(
442                 page.getNodeId(), page.getTitle());
443         }
444         catch (NoSuchPageResourceException nspre) {
445         }
446 
447         // All versions
448 
449         wikiPagePersistence.removeByN_T(page.getNodeId(), page.getTitle());
450 
451         // All referrals
452 
453         wikiPagePersistence.removeByN_R(page.getNodeId(), page.getTitle());
454 
455         // Cache
456 
457         clearPageCache(page);
458         clearReferralsCache(page);
459     }
460 
461     public void deletePageAttachment(long nodeId, String title, String fileName)
462         throws PortalException, SystemException {
463 
464         if (Validator.isNull(fileName)) {
465             return;
466         }
467 
468         WikiPage page = getPage(nodeId, title);
469 
470         long companyId = page.getCompanyId();
471         String portletId = CompanyConstants.SYSTEM_STRING;
472         long repositoryId = CompanyConstants.SYSTEM;
473 
474         try {
475             dlService.deleteFile(companyId, portletId, repositoryId, fileName);
476         }
477         catch (NoSuchFileException nsfe) {
478         }
479     }
480 
481     public void deletePages(long nodeId)
482         throws PortalException, SystemException {
483 
484         Iterator<WikiPage> itr = wikiPagePersistence.findByN_H_P(
485             nodeId, true, StringPool.BLANK).iterator();
486 
487         while (itr.hasNext()) {
488             WikiPage page = itr.next();
489 
490             deletePage(page);
491         }
492     }
493 
494     public List<WikiPage> getChildren(
495             long nodeId, boolean head, String parentTitle)
496         throws SystemException {
497 
498         return wikiPagePersistence.findByN_H_P(nodeId, head, parentTitle);
499     }
500 
501     public List<WikiPage> getIncomingLinks(long nodeId, String title)
502         throws PortalException, SystemException {
503 
504         List<WikiPage> links = new UniqueList<WikiPage>();
505 
506         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
507 
508         for (WikiPage page : pages) {
509             if (isLinkedTo(page, title)) {
510                 links.add(page);
511             }
512         }
513 
514         List<WikiPage> referrals = wikiPagePersistence.findByN_R(nodeId, title);
515 
516         for (WikiPage referral : referrals) {
517             for (WikiPage page : pages) {
518                 if (isLinkedTo(page, referral.getTitle())) {
519                     links.add(page);
520                 }
521             }
522         }
523 
524         return ListUtil.sort(links);
525     }
526 
527     public List<WikiPage> getNoAssetPages() throws SystemException {
528         return wikiPageFinder.findByNoAssets();
529     }
530 
531     public List<WikiPage> getOrphans(long nodeId)
532         throws PortalException, SystemException {
533 
534         List<Map<String, Boolean>> pageTitles =
535             new ArrayList<Map<String, Boolean>>();
536 
537         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
538 
539         for (WikiPage page : pages) {
540             pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
541         }
542 
543         Set<WikiPage> notOrphans = new HashSet<WikiPage>();
544 
545         for (WikiPage page : pages) {
546             for (Map<String, Boolean> pageTitle : pageTitles) {
547                 if (pageTitle.get(page.getTitle().toLowerCase()) != null) {
548                     notOrphans.add(page);
549 
550                     break;
551                 }
552             }
553         }
554 
555         List<WikiPage> orphans = new ArrayList<WikiPage>();
556 
557         for (WikiPage page : pages) {
558             if (!notOrphans.contains(page)) {
559                 orphans.add(page);
560             }
561         }
562 
563         orphans = ListUtil.sort(orphans);
564 
565         return orphans;
566     }
567 
568     public List<WikiPage> getOutgoingLinks(long nodeId, String title)
569         throws PortalException, SystemException {
570 
571         WikiPage page = getPage(nodeId, title);
572 
573         Map<String, WikiPage> pages = new LinkedHashMap<String, WikiPage>();
574 
575         Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
576 
577         for (String curTitle : links.keySet()) {
578             Boolean exists = links.get(curTitle);
579 
580             if (exists) {
581                 if (!pages.containsKey(curTitle)) {
582                     pages.put(curTitle, getPage(nodeId, curTitle));
583                 }
584             }
585             else {
586                 WikiPageImpl newPage = new WikiPageImpl();
587 
588                 newPage.setNew(true);
589                 newPage.setNodeId(nodeId);
590                 newPage.setTitle(curTitle);
591 
592                 if (!pages.containsKey(curTitle)) {
593                     pages.put(curTitle, newPage);
594                 }
595             }
596         }
597 
598         return ListUtil.fromCollection(pages.values());
599     }
600 
601     public WikiPage getPage(long resourcePrimKey)
602         throws PortalException, SystemException {
603 
604         WikiPageResource wikiPageResource =
605             wikiPageResourceLocalService.getPageResource(resourcePrimKey);
606 
607         return getPage(
608             wikiPageResource.getNodeId(), wikiPageResource.getTitle());
609     }
610 
611     public WikiPage getPage(long nodeId, String title)
612         throws PortalException, SystemException {
613 
614         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
615             nodeId, title, true, 0, 1);
616 
617         if (pages.size() > 0) {
618             return pages.get(0);
619         }
620         else {
621             throw new NoSuchPageException();
622         }
623     }
624 
625     public WikiPage getPage(long nodeId, String title, double version)
626         throws PortalException, SystemException {
627 
628         WikiPage page = null;
629 
630         if (version == 0) {
631             page = getPage(nodeId, title);
632         }
633         else {
634             page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
635         }
636 
637         return page;
638     }
639 
640     public WikiPageDisplay getPageDisplay(
641             long nodeId, String title, PortletURL viewPageURL,
642             PortletURL editPageURL, String attachmentURLPrefix)
643         throws PortalException, SystemException {
644 
645         WikiPage page = getPage(nodeId, title);
646 
647         String formattedContent = WikiUtil.convert(
648             page, viewPageURL, editPageURL, attachmentURLPrefix);
649 
650         return new WikiPageDisplayImpl(
651             page.getUserId(), page.getNodeId(), page.getTitle(),
652             page.getVersion(), page.getContent(), formattedContent,
653             page.getFormat(), page.getHead(), page.getAttachmentsFiles());
654     }
655 
656     public List<WikiPage> getPages(long nodeId, int start, int end)
657         throws SystemException {
658 
659         return wikiPagePersistence.findByNodeId(
660             nodeId, start, end, new PageCreateDateComparator(false));
661     }
662 
663     public List<WikiPage> getPages(String format) throws SystemException {
664         return wikiPagePersistence.findByFormat(format);
665     }
666 
667     public List<WikiPage> getPages(
668             long nodeId, String title, int start, int end)
669         throws SystemException {
670 
671         return wikiPagePersistence.findByN_T(
672             nodeId, title, start, end, new PageCreateDateComparator(false));
673     }
674 
675     public List<WikiPage> getPages(
676             long nodeId, String title, int start, int end,
677             OrderByComparator obc)
678         throws SystemException {
679 
680         return wikiPagePersistence.findByN_T(nodeId, title, start, end, obc);
681     }
682 
683     public List<WikiPage> getPages(
684             long nodeId, boolean head, int start, int end)
685         throws SystemException {
686 
687         return wikiPagePersistence.findByN_H(
688             nodeId, head, start, end, new PageCreateDateComparator(false));
689     }
690 
691     public List<WikiPage> getPages(
692             long nodeId, String title, boolean head, int start, int end)
693         throws SystemException {
694 
695         return wikiPagePersistence.findByN_T_H(
696             nodeId, title, head, start, end,
697             new PageCreateDateComparator(false));
698     }
699 
700     public int getPagesCount(long nodeId) throws SystemException {
701         return wikiPagePersistence.countByNodeId(nodeId);
702     }
703 
704     public int getPagesCount(long nodeId, String title)
705         throws SystemException {
706 
707         return wikiPagePersistence.countByN_T(nodeId, title);
708     }
709 
710     public int getPagesCount(long nodeId, boolean head)
711         throws SystemException {
712 
713         return wikiPagePersistence.countByN_H(nodeId, head);
714     }
715 
716     public int getPagesCount(long nodeId, String title, boolean head)
717         throws SystemException {
718 
719         return wikiPagePersistence.countByN_T_H(nodeId, title, head);
720     }
721 
722     public int getPagesCount(String format) throws SystemException {
723         return wikiPagePersistence.countByFormat(format);
724     }
725 
726     public List<WikiPage> getRecentChanges(long nodeId, int start, int end)
727         throws SystemException {
728 
729         Calendar cal = CalendarFactoryUtil.getCalendar();
730 
731         cal.add(Calendar.WEEK_OF_YEAR, -1);
732 
733         return wikiPageFinder.findByCreateDate(
734             nodeId, cal.getTime(), false, start, end);
735     }
736 
737     public int getRecentChangesCount(long nodeId) throws SystemException {
738         Calendar cal = CalendarFactoryUtil.getCalendar();
739 
740         cal.add(Calendar.WEEK_OF_YEAR, -1);
741 
742         return wikiPageFinder.countByCreateDate(nodeId, cal.getTime(), false);
743     }
744 
745     public void movePage(
746             long userId, long nodeId, String title, String newTitle,
747             ServiceContext serviceContext)
748         throws PortalException, SystemException {
749 
750         movePage(userId, nodeId, title, newTitle, true, serviceContext);
751     }
752 
753     public void movePage(
754             long userId, long nodeId, String title, String newTitle,
755             boolean strict, ServiceContext serviceContext)
756         throws PortalException, SystemException {
757 
758         validateTitle(newTitle);
759 
760         // Check if the new title already exists
761 
762         if (title.equalsIgnoreCase(newTitle)) {
763             throw new DuplicatePageException(newTitle);
764         }
765 
766         if (isUsedTitle(nodeId, newTitle)) {
767             WikiPage page = getPage(nodeId, newTitle);
768 
769             // Support moving back to a previously moved title
770 
771             if (((page.getVersion() == WikiPageImpl.DEFAULT_VERSION) &&
772                  (page.getContent().length() < 200)) ||
773                 !strict) {
774 
775                 deletePage(nodeId, newTitle);
776             }
777             else {
778                 throw new DuplicatePageException(newTitle);
779             }
780         }
781 
782         // All versions
783 
784         List<WikiPage> pageVersions = wikiPagePersistence.findByN_T(
785             nodeId, title);
786 
787         if (pageVersions.size() == 0) {
788             return;
789         }
790 
791         for (WikiPage page : pageVersions) {
792             page.setTitle(newTitle);
793 
794             wikiPagePersistence.update(page, false);
795         }
796 
797         // Children
798 
799         List<WikiPage> children = wikiPagePersistence.findByN_P(nodeId, title);
800 
801         for (WikiPage page : children) {
802             page.setParentTitle(newTitle);
803 
804             wikiPagePersistence.update(page, false);
805         }
806 
807         WikiPage page = pageVersions.get(pageVersions.size() - 1);
808 
809         long resourcePrimKey = page.getResourcePrimKey();
810 
811         // Page resource
812 
813         WikiPageResource wikiPageResource =
814             wikiPageResourcePersistence.findByPrimaryKey(resourcePrimKey);
815 
816         wikiPageResource.setTitle(newTitle);
817 
818         wikiPageResourcePersistence.update(wikiPageResource, false);
819 
820         // Create stub page at the old location
821 
822         String uuid = null;
823         double version = WikiPageImpl.DEFAULT_VERSION;
824         String summary = WikiPageImpl.MOVED + " to " + title;
825         String format = page.getFormat();
826         boolean head = true;
827         String parentTitle = page.getParentTitle();
828         String redirectTitle = page.getTitle();
829         String content =
830             StringPool.DOUBLE_OPEN_BRACKET + redirectTitle +
831                 StringPool.DOUBLE_CLOSE_BRACKET;
832 
833         addPage(
834             uuid, userId, nodeId, title, version, content, summary, false,
835             format, head, parentTitle, redirectTitle, serviceContext);
836 
837         // Move redirects to point to the page with the new title
838 
839         List<WikiPage> redirectedPages = wikiPagePersistence.findByN_R(
840             nodeId, title);
841 
842         for (WikiPage redirectedPage : redirectedPages) {
843             redirectedPage.setRedirectTitle(newTitle);
844 
845             wikiPagePersistence.update(redirectedPage, false);
846         }
847 
848         // Tags
849 
850         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
851             WikiPage.class.getName(), resourcePrimKey,
852             TagsEntryConstants.FOLKSONOMY_CATEGORY);
853         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
854             WikiPage.class.getName(), resourcePrimKey,
855             TagsEntryConstants.FOLKSONOMY_TAG);
856 
857         updateTagsAsset(userId, page, tagsCategories, tagsEntries);
858 
859         // Indexer
860 
861         try {
862             Indexer.deletePage(page.getCompanyId(), page.getNodeId(), title);
863         }
864         catch (SearchException se) {
865             _log.error("Indexing " + title, se);
866         }
867 
868         reIndex(page);
869     }
870 
871     public void reIndex(long resourcePrimKey) throws SystemException {
872         if (SearchEngineUtil.isIndexReadOnly()) {
873             return;
874         }
875 
876         WikiPage page = null;
877 
878         try {
879             page = wikiPageFinder.findByResourcePrimKey(resourcePrimKey);
880         }
881         catch (NoSuchPageException nspe) {
882             return;
883         }
884 
885         reIndex(page);
886     }
887 
888     public void reIndex(WikiPage page) throws SystemException {
889         if (Validator.isNotNull(page.getRedirectTitle())) {
890             return;
891         }
892 
893         long companyId = page.getCompanyId();
894         long groupId = page.getGroupId();
895         long userId = page.getUserId();
896         long resourcePrimKey = page.getResourcePrimKey();
897         long nodeId = page.getNodeId();
898         String title = page.getTitle();
899         String content = page.getContent();
900         Date modifiedDate = page.getModifiedDate();
901 
902         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
903             WikiPage.class.getName(), resourcePrimKey,
904             TagsEntryConstants.FOLKSONOMY_CATEGORY);
905         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
906             WikiPage.class.getName(), resourcePrimKey);
907 
908         ExpandoBridge expandoBridge = page.getExpandoBridge();
909 
910         try {
911             Indexer.updatePage(
912                 companyId, groupId, userId, resourcePrimKey, nodeId, title,
913                 content, modifiedDate, tagsCategories, tagsEntries,
914                 expandoBridge);
915         }
916         catch (SearchException se) {
917             _log.error("Reindexing " + page.getPrimaryKey(), se);
918         }
919     }
920 
921     public WikiPage revertPage(
922             long userId, long nodeId, String title, double version,
923             ServiceContext serviceContext)
924         throws PortalException, SystemException {
925 
926         WikiPage oldPage = getPage(nodeId, title, version);
927 
928         return updatePage(
929             userId, nodeId, title, 0, oldPage.getContent(),
930             WikiPageImpl.REVERTED + " to " + version, false,
931             oldPage.getFormat(), getParentPageTitle(oldPage),
932             oldPage.getRedirectTitle(), serviceContext);
933     }
934 
935     public void subscribePage(long userId, long nodeId, String title)
936         throws PortalException, SystemException {
937 
938         WikiPage page = getPage(nodeId, title);
939 
940         subscriptionLocalService.addSubscription(
941             userId, WikiPage.class.getName(), page.getResourcePrimKey());
942     }
943 
944     public void unsubscribePage(long userId, long nodeId, String title)
945         throws PortalException, SystemException {
946 
947         WikiPage page = getPage(nodeId, title);
948 
949         subscriptionLocalService.deleteSubscription(
950             userId, WikiPage.class.getName(), page.getResourcePrimKey());
951     }
952 
953     public WikiPage updatePage(
954             long userId, long nodeId, String title, double version,
955             String content, String summary, boolean minorEdit, String format,
956             String parentTitle, String redirectTitle,
957             ServiceContext serviceContext)
958         throws PortalException, SystemException {
959 
960         // Page
961 
962         User user = userPersistence.findByPrimaryKey(userId);
963         Date now = new Date();
964 
965         validate(nodeId, content, format);
966 
967         WikiPage page = null;
968 
969         try {
970             page = getPage(nodeId, title);
971         }
972         catch (NoSuchPageException nspe) {
973             return addPage(
974                 null, userId, nodeId, title, WikiPageImpl.DEFAULT_VERSION,
975                 content, summary, minorEdit, format, true, parentTitle,
976                 redirectTitle, serviceContext);
977         }
978 
979         double oldVersion = page.getVersion();
980 
981         if ((version > 0) && (version != oldVersion)) {
982             throw new PageVersionException();
983         }
984 
985         long resourcePrimKey = page.getResourcePrimKey();
986         long groupId = page.getGroupId();
987 
988         page.setHead(false);
989         page.setModifiedDate(serviceContext.getModifiedDate(now));
990 
991         wikiPagePersistence.update(page, false);
992 
993         double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
994 
995         long pageId = counterLocalService.increment();
996 
997         page = wikiPagePersistence.create(pageId);
998 
999         page.setResourcePrimKey(resourcePrimKey);
1000        page.setGroupId(groupId);
1001        page.setCompanyId(user.getCompanyId());
1002        page.setUserId(user.getUserId());
1003        page.setUserName(user.getFullName());
1004        page.setCreateDate(serviceContext.getModifiedDate(now));
1005        page.setModifiedDate(serviceContext.getModifiedDate(now));
1006        page.setNodeId(nodeId);
1007        page.setTitle(title);
1008        page.setVersion(newVersion);
1009        page.setMinorEdit(minorEdit);
1010        page.setContent(content);
1011        page.setSummary(summary);
1012        page.setFormat(format);
1013        page.setHead(true);
1014
1015        if (Validator.isNotNull(parentTitle)) {
1016            page.setParentTitle(parentTitle);
1017        }
1018
1019        if (Validator.isNotNull(redirectTitle)) {
1020            page.setRedirectTitle(redirectTitle);
1021        }
1022
1023        wikiPagePersistence.update(page, false);
1024
1025        // Node
1026
1027        WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
1028
1029        node.setLastPostDate(serviceContext.getModifiedDate(now));
1030
1031        wikiNodePersistence.update(node, false);
1032
1033        // Social
1034
1035        socialActivityLocalService.addActivity(
1036            userId, page.getGroupId(), WikiPage.class.getName(),
1037            page.getResourcePrimKey(), WikiActivityKeys.UPDATE_PAGE,
1038            StringPool.BLANK, 0);
1039
1040        // Subscriptions
1041
1042        if (!minorEdit && NotificationThreadLocal.isEnabled()) {
1043            notifySubscribers(node, page, serviceContext, true);
1044        }
1045
1046        // Tags
1047
1048        updateTagsAsset(
1049            userId, page, serviceContext.getTagsCategories(),
1050            serviceContext.getTagsEntries());
1051
1052        // Indexer
1053
1054        reIndex(page);
1055
1056        // Cache
1057
1058        clearPageCache(page);
1059
1060        return page;
1061    }
1062
1063    public void updateTagsAsset(
1064            long userId, WikiPage page, String[] tagsCategories,
1065            String[] tagsEntries)
1066        throws PortalException, SystemException {
1067
1068        tagsAssetLocalService.updateAsset(
1069            userId, page.getGroupId(), WikiPage.class.getName(),
1070            page.getResourcePrimKey(), tagsCategories, tagsEntries, true, null,
1071            null, null, null, ContentTypes.TEXT_HTML, page.getTitle(), null,
1072            null, null, 0, 0, null, false);
1073    }
1074
1075    public void validateTitle(String title) throws PortalException {
1076        if (title.equals("all_pages") || title.equals("orphan_pages") ||
1077            title.equals("recent_changes")) {
1078
1079            throw new PageTitleException(title + " is reserved");
1080        }
1081
1082        if (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
1083            Pattern pattern = Pattern.compile(
1084                PropsValues.WIKI_PAGE_TITLES_REGEXP);
1085
1086            Matcher matcher = pattern.matcher(title);
1087
1088            if (!matcher.matches()) {
1089                throw new PageTitleException();
1090            }
1091        }
1092    }
1093
1094    protected void clearPageCache(WikiPage page) {
1095        if (!WikiCacheThreadLocal.isClearCache()) {
1096            return;
1097        }
1098
1099        WikiCacheUtil.clearCache(page.getNodeId(), page.getTitle());
1100    }
1101
1102    protected void clearReferralsCache(WikiPage page)
1103        throws PortalException, SystemException {
1104
1105        if (!WikiCacheThreadLocal.isClearCache()) {
1106            return;
1107        }
1108
1109        List<WikiPage> links = getIncomingLinks(
1110            page.getNodeId(), page.getTitle());
1111
1112        for (WikiPage curPage : links) {
1113            WikiCacheUtil.clearCache(curPage.getNodeId(), curPage.getTitle());
1114        }
1115    }
1116
1117    protected String getParentPageTitle(WikiPage page) {
1118
1119        // LPS-4586
1120
1121        try {
1122            WikiPage parentPage = getPage(
1123                page.getNodeId(), page.getParentTitle());
1124
1125            return parentPage.getTitle();
1126        }
1127        catch (Exception e) {
1128            return null;
1129        }
1130    }
1131
1132    protected WikiPage getPreviousVersionPage(WikiPage page)
1133        throws PortalException, SystemException {
1134
1135        double previousVersion = MathUtil.format(page.getVersion() - 0.1, 1, 1);
1136
1137        if (previousVersion < 1) {
1138            return null;
1139        }
1140
1141        return getPage(page.getNodeId(), page.getTitle(), previousVersion);
1142    }
1143
1144    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1145        throws PortalException {
1146
1147        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1148
1149        Boolean link = links.get(targetTitle.toLowerCase());
1150
1151        if (link != null) {
1152            return true;
1153        }
1154        else {
1155            return false;
1156        }
1157    }
1158
1159    protected boolean isUsedTitle(long nodeId, String title)
1160        throws SystemException {
1161
1162        if (getPagesCount(nodeId, title, true) > 0) {
1163            return true;
1164        }
1165        else {
1166            return false;
1167        }
1168    }
1169
1170    protected void notifySubscribers(
1171            WikiNode node, WikiPage page, ServiceContext serviceContext,
1172            boolean update)
1173        throws PortalException, SystemException {
1174
1175        PortletPreferences preferences =
1176            ServiceContextUtil.getPortletPreferences(serviceContext);
1177
1178        if (preferences == null) {
1179            long ownerId = node.getGroupId();
1180            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1181            long plid = PortletKeys.PREFS_PLID_SHARED;
1182            String portletId = PortletKeys.WIKI;
1183            String defaultPreferences = null;
1184
1185            preferences = portletPreferencesLocalService.getPreferences(
1186                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1187                defaultPreferences);
1188        }
1189
1190        if (!update && WikiUtil.getEmailPageAddedEnabled(preferences)) {
1191        }
1192        else if (update && WikiUtil.getEmailPageUpdatedEnabled(preferences)) {
1193        }
1194        else {
1195            return;
1196        }
1197
1198        Company company = companyPersistence.findByPrimaryKey(
1199            page.getCompanyId());
1200
1201        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1202
1203        User user = userPersistence.findByPrimaryKey(page.getUserId());
1204
1205        String portalURL = serviceContext.getPortalURL();
1206        String layoutFullURL = serviceContext.getLayoutFullURL();
1207
1208        WikiPage previousVersionPage = getPreviousVersionPage(page);
1209
1210        String attachmentURLPrefix =
1211            portalURL + serviceContext.getPathMain() +
1212                "/wiki/get_page_attachment?p_l_id=" + serviceContext.getPlid() +
1213                    "&nodeId=" + page.getNodeId() + "&title=" +
1214                        HttpUtil.encodeURL(page.getTitle()) + "&fileName=";
1215
1216        String pageDiffs = StringPool.BLANK;
1217
1218        try {
1219            pageDiffs = WikiUtil.diffHtml(
1220                previousVersionPage, page, null, null, attachmentURLPrefix);
1221        }
1222        catch (Exception e) {
1223        }
1224
1225        String pageContent = null;
1226
1227        if (Validator.equals(page.getFormat(), "creole")) {
1228            pageContent = WikiUtil.convert(
1229                page, null, null, attachmentURLPrefix);
1230        }
1231        else {
1232            pageContent = page.getContent();
1233            pageContent = WikiUtil.processContent(pageContent);
1234        }
1235
1236        String pageURL = StringPool.BLANK;
1237        String diffsURL = StringPool.BLANK;
1238
1239        if (Validator.isNotNull(layoutFullURL)) {
1240            pageURL =
1241                layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "wiki/" +
1242                    node.getNodeId() + StringPool.SLASH +
1243                        HttpUtil.encodeURL(page.getTitle());
1244
1245            if (previousVersionPage != null) {
1246                StringBundler sb = new StringBundler(16);
1247
1248                sb.append(layoutFullURL);
1249                sb.append("?p_p_id=");
1250                sb.append(PortletKeys.WIKI);
1251                sb.append("&p_p_state=");
1252                sb.append(WindowState.MAXIMIZED);
1253                sb.append("&struts_action=");
1254                sb.append(HttpUtil.encodeURL("/wiki/compare_versions"));
1255                sb.append("&nodeId=");
1256                sb.append(node.getNodeId());
1257                sb.append("&title=");
1258                sb.append(HttpUtil.encodeURL(page.getTitle()));
1259                sb.append("&sourceVersion=");
1260                sb.append(previousVersionPage.getVersion());
1261                sb.append("&targetVersion=");
1262                sb.append(page.getVersion());
1263                sb.append("&type=html");
1264
1265                diffsURL = sb.toString();
1266            }
1267        }
1268
1269        String portletName = PortalUtil.getPortletTitle(PortletKeys.WIKI, user);
1270
1271        String fromName = WikiUtil.getEmailFromName(preferences);
1272        String fromAddress = WikiUtil.getEmailFromAddress(preferences);
1273
1274        String replyToAddress = fromAddress;
1275        String mailId = WikiUtil.getMailId(
1276            company.getMx(), page.getNodeId(), page.getPageId());
1277
1278        fromName = StringUtil.replace(
1279            fromName,
1280            new String[] {
1281                "[$COMPANY_ID$]",
1282                "[$COMPANY_MX$]",
1283                "[$COMPANY_NAME$]",
1284                "[$COMMUNITY_NAME$]",
1285                "[$PAGE_USER_ADDRESS$]",
1286                "[$PAGE_USER_NAME$]",
1287                "[$PORTLET_NAME$]"
1288            },
1289            new String[] {
1290                String.valueOf(company.getCompanyId()),
1291                company.getMx(),
1292                company.getName(),
1293                group.getName(),
1294                user.getEmailAddress(),
1295                user.getFullName(),
1296                portletName
1297            });
1298
1299        fromAddress = StringUtil.replace(
1300            fromAddress,
1301            new String[] {
1302                "[$COMPANY_ID$]",
1303                "[$COMPANY_MX$]",
1304                "[$COMPANY_NAME$]",
1305                "[$COMMUNITY_NAME$]",
1306                "[$PAGE_USER_ADDRESS$]",
1307                "[$PAGE_USER_NAME$]",
1308                "[$PORTLET_NAME$]"
1309            },
1310            new String[] {
1311                String.valueOf(company.getCompanyId()),
1312                company.getMx(),
1313                company.getName(),
1314                group.getName(),
1315                user.getEmailAddress(),
1316                user.getFullName(),
1317                portletName
1318            });
1319
1320        String subjectPrefix = null;
1321        String body = null;
1322        String signature = null;
1323
1324        if (update) {
1325            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(
1326                preferences);
1327            body = WikiUtil.getEmailPageUpdatedBody(preferences);
1328            signature = WikiUtil.getEmailPageUpdatedSignature(preferences);
1329        }
1330        else {
1331            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(
1332                preferences);
1333            body = WikiUtil.getEmailPageAddedBody(preferences);
1334            signature = WikiUtil.getEmailPageAddedSignature(preferences);
1335        }
1336
1337        if (Validator.isNotNull(signature)) {
1338            body +=  "\n" + signature;
1339        }
1340
1341        subjectPrefix = StringUtil.replace(
1342            subjectPrefix,
1343            new String[] {
1344                "[$COMPANY_ID$]",
1345                "[$COMPANY_MX$]",
1346                "[$COMPANY_NAME$]",
1347                "[$COMMUNITY_NAME$]",
1348                "[$FROM_ADDRESS$]",
1349                "[$FROM_NAME$]",
1350                "[$NODE_NAME$]",
1351                "[$PAGE_CONTENT$]",
1352                "[$PAGE_ID$]",
1353                "[$PAGE_TITLE$]",
1354                "[$PAGE_USER_ADDRESS$]",
1355                "[$PAGE_USER_NAME$]",
1356                "[$PORTAL_URL$]",
1357                "[$PORTLET_NAME$]"
1358            },
1359            new String[] {
1360                String.valueOf(company.getCompanyId()),
1361                company.getMx(),
1362                company.getName(),
1363                group.getName(),
1364                fromAddress,
1365                fromName,
1366                node.getName(),
1367                pageContent,
1368                String.valueOf(page.getPageId()),
1369                page.getTitle(),
1370                user.getEmailAddress(),
1371                user.getFullName(),
1372                company.getVirtualHost(),
1373                portletName
1374            });
1375
1376        body = StringUtil.replace(
1377            body,
1378            new String[] {
1379                "[$COMPANY_ID$]",
1380                "[$COMPANY_MX$]",
1381                "[$COMPANY_NAME$]",
1382                "[$COMMUNITY_NAME$]",
1383                "[$DIFFS_URL$]",
1384                "[$FROM_ADDRESS$]",
1385                "[$FROM_NAME$]",
1386                "[$NODE_NAME$]",
1387                "[$PAGE_CONTENT$]",
1388                "[$PAGE_DATE_UPDATE$]",
1389                "[$PAGE_DIFFS$]",
1390                "[$PAGE_ID$]",
1391                "[$PAGE_SUMMARY$]",
1392                "[$PAGE_TITLE$]",
1393                "[$PAGE_URL$]",
1394                "[$PAGE_USER_ADDRESS$]",
1395                "[$PAGE_USER_NAME$]",
1396                "[$PORTAL_URL$]",
1397                "[$PORTLET_NAME$]"
1398            },
1399            new String[] {
1400                String.valueOf(company.getCompanyId()),
1401                company.getMx(),
1402                company.getName(),
1403                group.getName(),
1404                diffsURL,
1405                fromAddress,
1406                fromName,
1407                node.getName(),
1408                pageContent,
1409                String.valueOf(page.getModifiedDate()),
1410                replaceStyles(pageDiffs),
1411                String.valueOf(page.getPageId()),
1412                page.getSummary(),
1413                page.getTitle(),
1414                pageURL,
1415                user.getEmailAddress(),
1416                user.getFullName(),
1417                company.getVirtualHost(),
1418                portletName
1419            });
1420
1421        String subject = page.getTitle();
1422
1423        if (subject.indexOf(subjectPrefix) == -1) {
1424            subject = subjectPrefix + StringPool.SPACE + subject;
1425        }
1426
1427        Message message = new Message();
1428
1429        message.put("companyId", node.getCompanyId());
1430        message.put("userId", node.getUserId());
1431        message.put("nodeId", node.getNodeId());
1432        message.put("pageResourcePrimKey", page.getResourcePrimKey());
1433        message.put("fromName", fromName);
1434        message.put("fromAddress", fromAddress);
1435        message.put("subject", subject);
1436        message.put("body", body);
1437        message.put("replyToAddress", replyToAddress);
1438        message.put("mailId", mailId);
1439        message.put("htmlFormat", Boolean.TRUE);
1440
1441        MessageBusUtil.sendMessage(DestinationNames.WIKI, message);
1442    }
1443
1444    protected String replaceStyles(String html) {
1445        return StringUtil.replace(
1446            html,
1447            new String[] {
1448                "class=\"diff-html-added\"",
1449                "class=\"diff-html-removed\"",
1450                "class=\"diff-html-changed\"",
1451                "changeType=\"diff-added-image\"",
1452                "changeType=\"diff-removed-image\"",
1453                "changeType=\"diff-changed-image\""
1454            },
1455            new String[] {
1456                "style=\"background-color: #CFC;\"",
1457                "style=\"background-color: #FDC6C6; text-decoration: " +
1458                        "line-through;\"",
1459                "style=\"border-bottom: 2px dotted blue;\"",
1460                "style=\"border: 10px solid #CFC;\"",
1461                "style=\"border: 10px solid #FDC6C6;\"",
1462                "style=\"border: 10px solid blue;\""
1463            }
1464        );
1465    }
1466
1467    protected void validate(long nodeId, String content, String format)
1468        throws PortalException {
1469
1470        if (!WikiUtil.validate(nodeId, content, format)) {
1471            throw new PageContentException();
1472        }
1473    }
1474
1475    protected void validate(
1476            String title, long nodeId, String content, String format)
1477        throws PortalException, SystemException {
1478
1479        if (Validator.isNull(title)) {
1480            throw new PageTitleException();
1481        }
1482
1483        if (isUsedTitle(nodeId, title)) {
1484            throw new DuplicatePageException();
1485        }
1486
1487        validateTitle(title);
1488
1489        validate(nodeId, content, format);
1490    }
1491
1492    private static Log _log = LogFactoryUtil.getLog(
1493        WikiPageLocalServiceImpl.class);
1494
1495}