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(),
421             page.getResourcePrimKey());
422 
423         // Social
424 
425         socialActivityLocalService.deleteActivities(
426             WikiPage.class.getName(), page.getResourcePrimKey());
427 
428         // Message boards
429 
430         mbMessageLocalService.deleteDiscussionMessages(
431             WikiPage.class.getName(), page.getResourcePrimKey());
432 
433         // Resources
434 
435         resourceLocalService.deleteResource(
436             page.getCompanyId(), WikiPage.class.getName(),
437             ResourceConstants.SCOPE_INDIVIDUAL, page.getResourcePrimKey());
438 
439         // Resource
440 
441         try {
442             wikiPageResourceLocalService.deletePageResource(
443                 page.getNodeId(), page.getTitle());
444         }
445         catch (NoSuchPageResourceException nspre) {
446         }
447 
448         // All versions
449 
450         wikiPagePersistence.removeByN_T(page.getNodeId(), page.getTitle());
451 
452         // All referrals
453 
454         wikiPagePersistence.removeByN_R(page.getNodeId(), page.getTitle());
455 
456         // Cache
457 
458         clearPageCache(page);
459         clearReferralsCache(page);
460     }
461 
462     public void deletePageAttachment(long nodeId, String title, String fileName)
463         throws PortalException, SystemException {
464 
465         if (Validator.isNull(fileName)) {
466             return;
467         }
468 
469         WikiPage page = getPage(nodeId, title);
470 
471         long companyId = page.getCompanyId();
472         String portletId = CompanyConstants.SYSTEM_STRING;
473         long repositoryId = CompanyConstants.SYSTEM;
474 
475         try {
476             dlService.deleteFile(companyId, portletId, repositoryId, fileName);
477         }
478         catch (NoSuchFileException nsfe) {
479         }
480     }
481 
482     public void deletePages(long nodeId)
483         throws PortalException, SystemException {
484 
485         Iterator<WikiPage> itr = wikiPagePersistence.findByN_H_P(
486             nodeId, true, StringPool.BLANK).iterator();
487 
488         while (itr.hasNext()) {
489             WikiPage page = itr.next();
490 
491             deletePage(page);
492         }
493     }
494 
495     public List<WikiPage> getChildren(
496             long nodeId, boolean head, String parentTitle)
497         throws SystemException {
498 
499         return wikiPagePersistence.findByN_H_P(nodeId, head, parentTitle);
500     }
501 
502     public List<WikiPage> getIncomingLinks(long nodeId, String title)
503         throws PortalException, SystemException {
504 
505         List<WikiPage> links = new UniqueList<WikiPage>();
506 
507         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
508 
509         for (WikiPage page : pages) {
510             if (isLinkedTo(page, title)) {
511                 links.add(page);
512             }
513         }
514 
515         List<WikiPage> referrals = wikiPagePersistence.findByN_R(nodeId, title);
516 
517         for (WikiPage referral : referrals) {
518             for (WikiPage page : pages) {
519                 if (isLinkedTo(page, referral.getTitle())) {
520                     links.add(page);
521                 }
522             }
523         }
524 
525         return ListUtil.sort(links);
526     }
527 
528     public List<WikiPage> getNoAssetPages() throws SystemException {
529         return wikiPageFinder.findByNoAssets();
530     }
531 
532     public List<WikiPage> getOrphans(long nodeId)
533         throws PortalException, SystemException {
534 
535         List<Map<String, Boolean>> pageTitles =
536             new ArrayList<Map<String, Boolean>>();
537 
538         List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
539 
540         for (WikiPage page : pages) {
541             pageTitles.add(WikiCacheUtil.getOutgoingLinks(page));
542         }
543 
544         Set<WikiPage> notOrphans = new HashSet<WikiPage>();
545 
546         for (WikiPage page : pages) {
547             for (Map<String, Boolean> pageTitle : pageTitles) {
548                 if (pageTitle.get(page.getTitle().toLowerCase()) != null) {
549                     notOrphans.add(page);
550 
551                     break;
552                 }
553             }
554         }
555 
556         List<WikiPage> orphans = new ArrayList<WikiPage>();
557 
558         for (WikiPage page : pages) {
559             if (!notOrphans.contains(page)) {
560                 orphans.add(page);
561             }
562         }
563 
564         orphans = ListUtil.sort(orphans);
565 
566         return orphans;
567     }
568 
569     public List<WikiPage> getOutgoingLinks(long nodeId, String title)
570         throws PortalException, SystemException {
571 
572         WikiPage page = getPage(nodeId, title);
573 
574         Map<String, WikiPage> pages = new LinkedHashMap<String, WikiPage>();
575 
576         Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
577 
578         for (String curTitle : links.keySet()) {
579             Boolean exists = links.get(curTitle);
580 
581             if (exists) {
582                 if (!pages.containsKey(curTitle)) {
583                     pages.put(curTitle, getPage(nodeId, curTitle));
584                 }
585             }
586             else {
587                 WikiPageImpl newPage = new WikiPageImpl();
588 
589                 newPage.setNew(true);
590                 newPage.setNodeId(nodeId);
591                 newPage.setTitle(curTitle);
592 
593                 if (!pages.containsKey(curTitle)) {
594                     pages.put(curTitle, newPage);
595                 }
596             }
597         }
598 
599         return ListUtil.fromCollection(pages.values());
600     }
601 
602     public WikiPage getPage(long resourcePrimKey)
603         throws PortalException, SystemException {
604 
605         WikiPageResource wikiPageResource =
606             wikiPageResourceLocalService.getPageResource(resourcePrimKey);
607 
608         return getPage(
609             wikiPageResource.getNodeId(), wikiPageResource.getTitle());
610     }
611 
612     public WikiPage getPage(long nodeId, String title)
613         throws PortalException, SystemException {
614 
615         List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
616             nodeId, title, true, 0, 1);
617 
618         if (pages.size() > 0) {
619             return pages.get(0);
620         }
621         else {
622             throw new NoSuchPageException();
623         }
624     }
625 
626     public WikiPage getPage(long nodeId, String title, double version)
627         throws PortalException, SystemException {
628 
629         WikiPage page = null;
630 
631         if (version == 0) {
632             page = getPage(nodeId, title);
633         }
634         else {
635             page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
636         }
637 
638         return page;
639     }
640 
641     public WikiPageDisplay getPageDisplay(
642             long nodeId, String title, PortletURL viewPageURL,
643             PortletURL editPageURL, String attachmentURLPrefix)
644         throws PortalException, SystemException {
645 
646         WikiPage page = getPage(nodeId, title);
647 
648         String formattedContent = WikiUtil.convert(
649             page, viewPageURL, editPageURL, attachmentURLPrefix);
650 
651         return new WikiPageDisplayImpl(
652             page.getUserId(), page.getNodeId(), page.getTitle(),
653             page.getVersion(), page.getContent(), formattedContent,
654             page.getFormat(), page.getHead(), page.getAttachmentsFiles());
655     }
656 
657     public List<WikiPage> getPages(long nodeId, int start, int end)
658         throws SystemException {
659 
660         return wikiPagePersistence.findByNodeId(
661             nodeId, start, end, new PageCreateDateComparator(false));
662     }
663 
664     public List<WikiPage> getPages(String format) throws SystemException {
665         return wikiPagePersistence.findByFormat(format);
666     }
667 
668     public List<WikiPage> getPages(
669             long nodeId, String title, int start, int end)
670         throws SystemException {
671 
672         return wikiPagePersistence.findByN_T(
673             nodeId, title, start, end, new PageCreateDateComparator(false));
674     }
675 
676     public List<WikiPage> getPages(
677             long nodeId, String title, int start, int end,
678             OrderByComparator obc)
679         throws SystemException {
680 
681         return wikiPagePersistence.findByN_T(nodeId, title, start, end, obc);
682     }
683 
684     public List<WikiPage> getPages(
685             long nodeId, boolean head, int start, int end)
686         throws SystemException {
687 
688         return wikiPagePersistence.findByN_H(
689             nodeId, head, start, end, new PageCreateDateComparator(false));
690     }
691 
692     public List<WikiPage> getPages(
693             long nodeId, String title, boolean head, int start, int end)
694         throws SystemException {
695 
696         return wikiPagePersistence.findByN_T_H(
697             nodeId, title, head, start, end,
698             new PageCreateDateComparator(false));
699     }
700 
701     public int getPagesCount(long nodeId) throws SystemException {
702         return wikiPagePersistence.countByNodeId(nodeId);
703     }
704 
705     public int getPagesCount(long nodeId, String title)
706         throws SystemException {
707 
708         return wikiPagePersistence.countByN_T(nodeId, title);
709     }
710 
711     public int getPagesCount(long nodeId, boolean head)
712         throws SystemException {
713 
714         return wikiPagePersistence.countByN_H(nodeId, head);
715     }
716 
717     public int getPagesCount(long nodeId, String title, boolean head)
718         throws SystemException {
719 
720         return wikiPagePersistence.countByN_T_H(nodeId, title, head);
721     }
722 
723     public int getPagesCount(String format) throws SystemException {
724         return wikiPagePersistence.countByFormat(format);
725     }
726 
727     public List<WikiPage> getRecentChanges(long nodeId, int start, int end)
728         throws SystemException {
729 
730         Calendar cal = CalendarFactoryUtil.getCalendar();
731 
732         cal.add(Calendar.WEEK_OF_YEAR, -1);
733 
734         return wikiPageFinder.findByCreateDate(
735             nodeId, cal.getTime(), false, start, end);
736     }
737 
738     public int getRecentChangesCount(long nodeId) throws SystemException {
739         Calendar cal = CalendarFactoryUtil.getCalendar();
740 
741         cal.add(Calendar.WEEK_OF_YEAR, -1);
742 
743         return wikiPageFinder.countByCreateDate(nodeId, cal.getTime(), false);
744     }
745 
746     public void movePage(
747             long userId, long nodeId, String title, String newTitle,
748             ServiceContext serviceContext)
749         throws PortalException, SystemException {
750 
751         movePage(userId, nodeId, title, newTitle, true, serviceContext);
752     }
753 
754     public void movePage(
755             long userId, long nodeId, String title, String newTitle,
756             boolean strict, ServiceContext serviceContext)
757         throws PortalException, SystemException {
758 
759         validateTitle(newTitle);
760 
761         // Check if the new title already exists
762 
763         if (title.equalsIgnoreCase(newTitle)) {
764             throw new DuplicatePageException(newTitle);
765         }
766 
767         if (isUsedTitle(nodeId, newTitle)) {
768             WikiPage page = getPage(nodeId, newTitle);
769 
770             // Support moving back to a previously moved title
771 
772             if (((page.getVersion() == WikiPageImpl.DEFAULT_VERSION) &&
773                  (page.getContent().length() < 200)) ||
774                 !strict) {
775 
776                 deletePage(nodeId, newTitle);
777             }
778             else {
779                 throw new DuplicatePageException(newTitle);
780             }
781         }
782 
783         // All versions
784 
785         List<WikiPage> pageVersions = wikiPagePersistence.findByN_T(
786             nodeId, title);
787 
788         if (pageVersions.size() == 0) {
789             return;
790         }
791 
792         for (WikiPage page : pageVersions) {
793             page.setTitle(newTitle);
794 
795             wikiPagePersistence.update(page, false);
796         }
797 
798         // Children
799 
800         List<WikiPage> children = wikiPagePersistence.findByN_P(nodeId, title);
801 
802         for (WikiPage page : children) {
803             page.setParentTitle(newTitle);
804 
805             wikiPagePersistence.update(page, false);
806         }
807 
808         WikiPage page = pageVersions.get(pageVersions.size() - 1);
809 
810         long resourcePrimKey = page.getResourcePrimKey();
811 
812         // Page resource
813 
814         WikiPageResource wikiPageResource =
815             wikiPageResourcePersistence.findByPrimaryKey(resourcePrimKey);
816 
817         wikiPageResource.setTitle(newTitle);
818 
819         wikiPageResourcePersistence.update(wikiPageResource, false);
820 
821         // Create stub page at the old location
822 
823         String uuid = null;
824         double version = WikiPageImpl.DEFAULT_VERSION;
825         String summary = WikiPageImpl.MOVED + " to " + title;
826         String format = page.getFormat();
827         boolean head = true;
828         String parentTitle = page.getParentTitle();
829         String redirectTitle = page.getTitle();
830         String content =
831             StringPool.DOUBLE_OPEN_BRACKET + redirectTitle +
832                 StringPool.DOUBLE_CLOSE_BRACKET;
833 
834         serviceContext.setAddCommunityPermissions(true);
835         serviceContext.setAddGuestPermissions(true);
836 
837         addPage(
838             uuid, userId, nodeId, title, version, content, summary, false,
839             format, head, parentTitle, redirectTitle, serviceContext);
840 
841         // Move redirects to point to the page with the new title
842 
843         List<WikiPage> redirectedPages = wikiPagePersistence.findByN_R(
844             nodeId, title);
845 
846         for (WikiPage redirectedPage : redirectedPages) {
847             redirectedPage.setRedirectTitle(newTitle);
848 
849             wikiPagePersistence.update(redirectedPage, false);
850         }
851 
852         // Tags
853 
854         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
855             WikiPage.class.getName(), resourcePrimKey,
856             TagsEntryConstants.FOLKSONOMY_CATEGORY);
857         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
858             WikiPage.class.getName(), resourcePrimKey,
859             TagsEntryConstants.FOLKSONOMY_TAG);
860 
861         updateTagsAsset(userId, page, tagsCategories, tagsEntries);
862 
863         // Indexer
864 
865         try {
866             Indexer.deletePage(page.getCompanyId(), page.getNodeId(), title);
867         }
868         catch (SearchException se) {
869             _log.error("Indexing " + title, se);
870         }
871 
872         reIndex(page);
873     }
874 
875     public void reIndex(long resourcePrimKey) throws SystemException {
876         if (SearchEngineUtil.isIndexReadOnly()) {
877             return;
878         }
879 
880         WikiPage page = null;
881 
882         try {
883             page = wikiPageFinder.findByResourcePrimKey(resourcePrimKey);
884         }
885         catch (NoSuchPageException nspe) {
886             return;
887         }
888 
889         reIndex(page);
890     }
891 
892     public void reIndex(WikiPage page) throws SystemException {
893         if (Validator.isNotNull(page.getRedirectTitle())) {
894             return;
895         }
896 
897         long companyId = page.getCompanyId();
898         long groupId = page.getGroupId();
899         long userId = page.getUserId();
900         long resourcePrimKey = page.getResourcePrimKey();
901         long nodeId = page.getNodeId();
902         String title = page.getTitle();
903         String content = page.getContent();
904         Date modifiedDate = page.getModifiedDate();
905 
906         String[] tagsCategories = tagsEntryLocalService.getEntryNames(
907             WikiPage.class.getName(), resourcePrimKey,
908             TagsEntryConstants.FOLKSONOMY_CATEGORY);
909         String[] tagsEntries = tagsEntryLocalService.getEntryNames(
910             WikiPage.class.getName(), resourcePrimKey);
911 
912         ExpandoBridge expandoBridge = page.getExpandoBridge();
913 
914         try {
915             Indexer.updatePage(
916                 companyId, groupId, userId, resourcePrimKey, nodeId, title,
917                 content, modifiedDate, tagsCategories, tagsEntries,
918                 expandoBridge);
919         }
920         catch (SearchException se) {
921             _log.error("Reindexing " + page.getPrimaryKey(), se);
922         }
923     }
924 
925     public WikiPage revertPage(
926             long userId, long nodeId, String title, double version,
927             ServiceContext serviceContext)
928         throws PortalException, SystemException {
929 
930         WikiPage oldPage = getPage(nodeId, title, version);
931 
932         return updatePage(
933             userId, nodeId, title, 0, oldPage.getContent(),
934             WikiPageImpl.REVERTED + " to " + version, false,
935             oldPage.getFormat(), getParentPageTitle(oldPage),
936             oldPage.getRedirectTitle(), serviceContext);
937     }
938 
939     public void subscribePage(long userId, long nodeId, String title)
940         throws PortalException, SystemException {
941 
942         WikiPage page = getPage(nodeId, title);
943 
944         subscriptionLocalService.addSubscription(
945             userId, WikiPage.class.getName(), page.getResourcePrimKey());
946     }
947 
948     public void unsubscribePage(long userId, long nodeId, String title)
949         throws PortalException, SystemException {
950 
951         WikiPage page = getPage(nodeId, title);
952 
953         subscriptionLocalService.deleteSubscription(
954             userId, WikiPage.class.getName(), page.getResourcePrimKey());
955     }
956 
957     public WikiPage updatePage(
958             long userId, long nodeId, String title, double version,
959             String content, String summary, boolean minorEdit, String format,
960             String parentTitle, String redirectTitle,
961             ServiceContext serviceContext)
962         throws PortalException, SystemException {
963 
964         // Page
965 
966         User user = userPersistence.findByPrimaryKey(userId);
967         Date now = new Date();
968 
969         validate(nodeId, content, format);
970 
971         WikiPage page = null;
972 
973         try {
974             page = getPage(nodeId, title);
975         }
976         catch (NoSuchPageException nspe) {
977             return addPage(
978                 null, userId, nodeId, title, WikiPageImpl.DEFAULT_VERSION,
979                 content, summary, minorEdit, format, true, parentTitle,
980                 redirectTitle, serviceContext);
981         }
982 
983         double oldVersion = page.getVersion();
984 
985         if ((version > 0) && (version != oldVersion)) {
986             throw new PageVersionException();
987         }
988 
989         long resourcePrimKey = page.getResourcePrimKey();
990         long groupId = page.getGroupId();
991 
992         page.setHead(false);
993         page.setModifiedDate(serviceContext.getModifiedDate(now));
994 
995         wikiPagePersistence.update(page, false);
996 
997         double newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
998 
999         long pageId = counterLocalService.increment();
1000
1001        page = wikiPagePersistence.create(pageId);
1002
1003        page.setResourcePrimKey(resourcePrimKey);
1004        page.setGroupId(groupId);
1005        page.setCompanyId(user.getCompanyId());
1006        page.setUserId(user.getUserId());
1007        page.setUserName(user.getFullName());
1008        page.setCreateDate(serviceContext.getModifiedDate(now));
1009        page.setModifiedDate(serviceContext.getModifiedDate(now));
1010        page.setNodeId(nodeId);
1011        page.setTitle(title);
1012        page.setVersion(newVersion);
1013        page.setMinorEdit(minorEdit);
1014        page.setContent(content);
1015        page.setSummary(summary);
1016        page.setFormat(format);
1017        page.setHead(true);
1018
1019        if (Validator.isNotNull(parentTitle)) {
1020            page.setParentTitle(parentTitle);
1021        }
1022
1023        if (Validator.isNotNull(redirectTitle)) {
1024            page.setRedirectTitle(redirectTitle);
1025        }
1026
1027        wikiPagePersistence.update(page, false);
1028
1029        // Node
1030
1031        WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
1032
1033        node.setLastPostDate(serviceContext.getModifiedDate(now));
1034
1035        wikiNodePersistence.update(node, false);
1036
1037        // Social
1038
1039        socialActivityLocalService.addActivity(
1040            userId, page.getGroupId(), WikiPage.class.getName(),
1041            page.getResourcePrimKey(), WikiActivityKeys.UPDATE_PAGE,
1042            StringPool.BLANK, 0);
1043
1044        // Subscriptions
1045
1046        if (!minorEdit && NotificationThreadLocal.isEnabled()) {
1047            notifySubscribers(node, page, serviceContext, true);
1048        }
1049
1050        // Tags
1051
1052        updateTagsAsset(
1053            userId, page, serviceContext.getTagsCategories(),
1054            serviceContext.getTagsEntries());
1055
1056        // Indexer
1057
1058        reIndex(page);
1059
1060        // Cache
1061
1062        clearPageCache(page);
1063
1064        return page;
1065    }
1066
1067    public void updateTagsAsset(
1068            long userId, WikiPage page, String[] tagsCategories,
1069            String[] tagsEntries)
1070        throws PortalException, SystemException {
1071
1072        tagsAssetLocalService.updateAsset(
1073            userId, page.getGroupId(), WikiPage.class.getName(),
1074            page.getResourcePrimKey(), tagsCategories, tagsEntries, true, null,
1075            null, null, null, ContentTypes.TEXT_HTML, page.getTitle(), null,
1076            null, null, 0, 0, null, false);
1077    }
1078
1079    public void validateTitle(String title) throws PortalException {
1080        if (title.equals("all_pages") || title.equals("orphan_pages") ||
1081            title.equals("recent_changes")) {
1082
1083            throw new PageTitleException(title + " is reserved");
1084        }
1085
1086        if (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
1087            Pattern pattern = Pattern.compile(
1088                PropsValues.WIKI_PAGE_TITLES_REGEXP);
1089
1090            Matcher matcher = pattern.matcher(title);
1091
1092            if (!matcher.matches()) {
1093                throw new PageTitleException();
1094            }
1095        }
1096    }
1097
1098    protected void clearPageCache(WikiPage page) {
1099        if (!WikiCacheThreadLocal.isClearCache()) {
1100            return;
1101        }
1102
1103        WikiCacheUtil.clearCache(page.getNodeId(), page.getTitle());
1104    }
1105
1106    protected void clearReferralsCache(WikiPage page)
1107        throws PortalException, SystemException {
1108
1109        if (!WikiCacheThreadLocal.isClearCache()) {
1110            return;
1111        }
1112
1113        List<WikiPage> links = getIncomingLinks(
1114            page.getNodeId(), page.getTitle());
1115
1116        for (WikiPage curPage : links) {
1117            WikiCacheUtil.clearCache(curPage.getNodeId(), curPage.getTitle());
1118        }
1119    }
1120
1121    protected String getParentPageTitle(WikiPage page) {
1122
1123        // LPS-4586
1124
1125        try {
1126            WikiPage parentPage = getPage(
1127                page.getNodeId(), page.getParentTitle());
1128
1129            return parentPage.getTitle();
1130        }
1131        catch (Exception e) {
1132            return null;
1133        }
1134    }
1135
1136    protected WikiPage getPreviousVersionPage(WikiPage page)
1137        throws PortalException, SystemException {
1138
1139        double previousVersion = MathUtil.format(page.getVersion() - 0.1, 1, 1);
1140
1141        if (previousVersion < 1) {
1142            return null;
1143        }
1144
1145        return getPage(page.getNodeId(), page.getTitle(), previousVersion);
1146    }
1147
1148    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1149        throws PortalException {
1150
1151        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1152
1153        Boolean link = links.get(targetTitle.toLowerCase());
1154
1155        if (link != null) {
1156            return true;
1157        }
1158        else {
1159            return false;
1160        }
1161    }
1162
1163    protected boolean isUsedTitle(long nodeId, String title)
1164        throws SystemException {
1165
1166        if (getPagesCount(nodeId, title, true) > 0) {
1167            return true;
1168        }
1169        else {
1170            return false;
1171        }
1172    }
1173
1174    protected void notifySubscribers(
1175            WikiNode node, WikiPage page, ServiceContext serviceContext,
1176            boolean update)
1177        throws PortalException, SystemException {
1178
1179        PortletPreferences preferences =
1180            ServiceContextUtil.getPortletPreferences(serviceContext);
1181
1182        if (preferences == null) {
1183            long ownerId = node.getGroupId();
1184            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1185            long plid = PortletKeys.PREFS_PLID_SHARED;
1186            String portletId = PortletKeys.WIKI;
1187            String defaultPreferences = null;
1188
1189            preferences = portletPreferencesLocalService.getPreferences(
1190                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1191                defaultPreferences);
1192        }
1193
1194        if (!update && WikiUtil.getEmailPageAddedEnabled(preferences)) {
1195        }
1196        else if (update && WikiUtil.getEmailPageUpdatedEnabled(preferences)) {
1197        }
1198        else {
1199            return;
1200        }
1201
1202        Company company = companyPersistence.findByPrimaryKey(
1203            page.getCompanyId());
1204
1205        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1206
1207        User user = userPersistence.findByPrimaryKey(page.getUserId());
1208
1209        String portalURL = serviceContext.getPortalURL();
1210        String layoutFullURL = serviceContext.getLayoutFullURL();
1211
1212        WikiPage previousVersionPage = getPreviousVersionPage(page);
1213
1214        String attachmentURLPrefix =
1215            portalURL + serviceContext.getPathMain() +
1216                "/wiki/get_page_attachment?p_l_id=" + serviceContext.getPlid() +
1217                    "&nodeId=" + page.getNodeId() + "&title=" +
1218                        HttpUtil.encodeURL(page.getTitle()) + "&fileName=";
1219
1220        String pageDiffs = StringPool.BLANK;
1221
1222        try {
1223            pageDiffs = WikiUtil.diffHtml(
1224                previousVersionPage, page, null, null, attachmentURLPrefix);
1225        }
1226        catch (Exception e) {
1227        }
1228
1229        String pageContent = null;
1230
1231        if (Validator.equals(page.getFormat(), "creole")) {
1232            pageContent = WikiUtil.convert(
1233                page, null, null, attachmentURLPrefix);
1234        }
1235        else {
1236            pageContent = page.getContent();
1237            pageContent = WikiUtil.processContent(pageContent);
1238        }
1239
1240        String pageURL = StringPool.BLANK;
1241        String diffsURL = StringPool.BLANK;
1242
1243        if (Validator.isNotNull(layoutFullURL)) {
1244            pageURL =
1245                layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "wiki/" +
1246                    node.getNodeId() + StringPool.SLASH +
1247                        HttpUtil.encodeURL(page.getTitle());
1248
1249            if (previousVersionPage != null) {
1250                StringBundler sb = new StringBundler(16);
1251
1252                sb.append(layoutFullURL);
1253                sb.append("?p_p_id=");
1254                sb.append(PortletKeys.WIKI);
1255                sb.append("&p_p_state=");
1256                sb.append(WindowState.MAXIMIZED);
1257                sb.append("&struts_action=");
1258                sb.append(HttpUtil.encodeURL("/wiki/compare_versions"));
1259                sb.append("&nodeId=");
1260                sb.append(node.getNodeId());
1261                sb.append("&title=");
1262                sb.append(HttpUtil.encodeURL(page.getTitle()));
1263                sb.append("&sourceVersion=");
1264                sb.append(previousVersionPage.getVersion());
1265                sb.append("&targetVersion=");
1266                sb.append(page.getVersion());
1267                sb.append("&type=html");
1268
1269                diffsURL = sb.toString();
1270            }
1271        }
1272
1273        String portletName = PortalUtil.getPortletTitle(PortletKeys.WIKI, user);
1274
1275        String fromName = WikiUtil.getEmailFromName(preferences);
1276        String fromAddress = WikiUtil.getEmailFromAddress(preferences);
1277
1278        String replyToAddress = fromAddress;
1279        String mailId = WikiUtil.getMailId(
1280            company.getMx(), page.getNodeId(), page.getPageId());
1281
1282        fromName = StringUtil.replace(
1283            fromName,
1284            new String[] {
1285                "[$COMPANY_ID$]",
1286                "[$COMPANY_MX$]",
1287                "[$COMPANY_NAME$]",
1288                "[$COMMUNITY_NAME$]",
1289                "[$PAGE_USER_ADDRESS$]",
1290                "[$PAGE_USER_NAME$]",
1291                "[$PORTLET_NAME$]"
1292            },
1293            new String[] {
1294                String.valueOf(company.getCompanyId()),
1295                company.getMx(),
1296                company.getName(),
1297                group.getName(),
1298                user.getEmailAddress(),
1299                user.getFullName(),
1300                portletName
1301            });
1302
1303        fromAddress = StringUtil.replace(
1304            fromAddress,
1305            new String[] {
1306                "[$COMPANY_ID$]",
1307                "[$COMPANY_MX$]",
1308                "[$COMPANY_NAME$]",
1309                "[$COMMUNITY_NAME$]",
1310                "[$PAGE_USER_ADDRESS$]",
1311                "[$PAGE_USER_NAME$]",
1312                "[$PORTLET_NAME$]"
1313            },
1314            new String[] {
1315                String.valueOf(company.getCompanyId()),
1316                company.getMx(),
1317                company.getName(),
1318                group.getName(),
1319                user.getEmailAddress(),
1320                user.getFullName(),
1321                portletName
1322            });
1323
1324        String subjectPrefix = null;
1325        String body = null;
1326        String signature = null;
1327
1328        if (update) {
1329            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(
1330                preferences);
1331            body = WikiUtil.getEmailPageUpdatedBody(preferences);
1332            signature = WikiUtil.getEmailPageUpdatedSignature(preferences);
1333        }
1334        else {
1335            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(
1336                preferences);
1337            body = WikiUtil.getEmailPageAddedBody(preferences);
1338            signature = WikiUtil.getEmailPageAddedSignature(preferences);
1339        }
1340
1341        if (Validator.isNotNull(signature)) {
1342            body +=  "\n" + signature;
1343        }
1344
1345        subjectPrefix = StringUtil.replace(
1346            subjectPrefix,
1347            new String[] {
1348                "[$COMPANY_ID$]",
1349                "[$COMPANY_MX$]",
1350                "[$COMPANY_NAME$]",
1351                "[$COMMUNITY_NAME$]",
1352                "[$FROM_ADDRESS$]",
1353                "[$FROM_NAME$]",
1354                "[$NODE_NAME$]",
1355                "[$PAGE_CONTENT$]",
1356                "[$PAGE_ID$]",
1357                "[$PAGE_TITLE$]",
1358                "[$PAGE_USER_ADDRESS$]",
1359                "[$PAGE_USER_NAME$]",
1360                "[$PORTAL_URL$]",
1361                "[$PORTLET_NAME$]"
1362            },
1363            new String[] {
1364                String.valueOf(company.getCompanyId()),
1365                company.getMx(),
1366                company.getName(),
1367                group.getName(),
1368                fromAddress,
1369                fromName,
1370                node.getName(),
1371                pageContent,
1372                String.valueOf(page.getPageId()),
1373                page.getTitle(),
1374                user.getEmailAddress(),
1375                user.getFullName(),
1376                company.getVirtualHost(),
1377                portletName
1378            });
1379
1380        body = StringUtil.replace(
1381            body,
1382            new String[] {
1383                "[$COMPANY_ID$]",
1384                "[$COMPANY_MX$]",
1385                "[$COMPANY_NAME$]",
1386                "[$COMMUNITY_NAME$]",
1387                "[$DIFFS_URL$]",
1388                "[$FROM_ADDRESS$]",
1389                "[$FROM_NAME$]",
1390                "[$NODE_NAME$]",
1391                "[$PAGE_CONTENT$]",
1392                "[$PAGE_DATE_UPDATE$]",
1393                "[$PAGE_DIFFS$]",
1394                "[$PAGE_ID$]",
1395                "[$PAGE_SUMMARY$]",
1396                "[$PAGE_TITLE$]",
1397                "[$PAGE_URL$]",
1398                "[$PAGE_USER_ADDRESS$]",
1399                "[$PAGE_USER_NAME$]",
1400                "[$PORTAL_URL$]",
1401                "[$PORTLET_NAME$]"
1402            },
1403            new String[] {
1404                String.valueOf(company.getCompanyId()),
1405                company.getMx(),
1406                company.getName(),
1407                group.getName(),
1408                diffsURL,
1409                fromAddress,
1410                fromName,
1411                node.getName(),
1412                pageContent,
1413                String.valueOf(page.getModifiedDate()),
1414                replaceStyles(pageDiffs),
1415                String.valueOf(page.getPageId()),
1416                page.getSummary(),
1417                page.getTitle(),
1418                pageURL,
1419                user.getEmailAddress(),
1420                user.getFullName(),
1421                company.getVirtualHost(),
1422                portletName
1423            });
1424
1425        String subject = page.getTitle();
1426
1427        if (subject.indexOf(subjectPrefix) == -1) {
1428            subject = subjectPrefix + StringPool.SPACE + subject;
1429        }
1430
1431        Message message = new Message();
1432
1433        message.put("companyId", node.getCompanyId());
1434        message.put("userId", node.getUserId());
1435        message.put("groupId", node.getGroupId());
1436        message.put("nodeId", node.getNodeId());
1437        message.put("pageResourcePrimKey", page.getResourcePrimKey());
1438        message.put("fromName", fromName);
1439        message.put("fromAddress", fromAddress);
1440        message.put("subject", subject);
1441        message.put("body", body);
1442        message.put("replyToAddress", replyToAddress);
1443        message.put("mailId", mailId);
1444        message.put("htmlFormat", Boolean.TRUE);
1445
1446        MessageBusUtil.sendMessage(DestinationNames.WIKI, message);
1447    }
1448
1449    protected String replaceStyles(String html) {
1450        return StringUtil.replace(
1451            html,
1452            new String[] {
1453                "class=\"diff-html-added\"",
1454                "class=\"diff-html-removed\"",
1455                "class=\"diff-html-changed\"",
1456                "changeType=\"diff-added-image\"",
1457                "changeType=\"diff-removed-image\"",
1458                "changeType=\"diff-changed-image\""
1459            },
1460            new String[] {
1461                "style=\"background-color: #CFC;\"",
1462                "style=\"background-color: #FDC6C6; text-decoration: " +
1463                        "line-through;\"",
1464                "style=\"border-bottom: 2px dotted blue;\"",
1465                "style=\"border: 10px solid #CFC;\"",
1466                "style=\"border: 10px solid #FDC6C6;\"",
1467                "style=\"border: 10px solid blue;\""
1468            }
1469        );
1470    }
1471
1472    protected void validate(long nodeId, String content, String format)
1473        throws PortalException {
1474
1475        if (!WikiUtil.validate(nodeId, content, format)) {
1476            throw new PageContentException();
1477        }
1478    }
1479
1480    protected void validate(
1481            String title, long nodeId, String content, String format)
1482        throws PortalException, SystemException {
1483
1484        if (Validator.isNull(title)) {
1485            throw new PageTitleException();
1486        }
1487
1488        if (isUsedTitle(nodeId, title)) {
1489            throw new DuplicatePageException();
1490        }
1491
1492        validateTitle(title);
1493
1494        validate(nodeId, content, format);
1495    }
1496
1497    private static Log _log = LogFactoryUtil.getLog(
1498        WikiPageLocalServiceImpl.class);
1499
1500}