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