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.isNotificationEnabled()) {
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()) != 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(), null, oldPage.getRedirectTitle(),
937             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.isNotificationEnabled()) {
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 WikiPage getPreviousVersionPage(WikiPage page)
1123        throws PortalException, SystemException {
1124
1125        double previousVersion = MathUtil.format(page.getVersion() - 0.1, 1, 1);
1126
1127        if (previousVersion < 1) {
1128            return null;
1129        }
1130
1131        return getPage(page.getNodeId(), page.getTitle(), previousVersion);
1132    }
1133
1134    protected boolean isLinkedTo(WikiPage page, String targetTitle)
1135        throws PortalException {
1136
1137        Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1138
1139        Boolean link = links.get(targetTitle);
1140
1141        if (link != null) {
1142            return true;
1143        }
1144        else {
1145            return false;
1146        }
1147    }
1148
1149    protected boolean isUsedTitle(long nodeId, String title)
1150        throws SystemException {
1151
1152        if (getPagesCount(nodeId, title, true) > 0) {
1153            return true;
1154        }
1155        else {
1156            return false;
1157        }
1158    }
1159
1160    protected void notifySubscribers(
1161            WikiNode node, WikiPage page, ServiceContext serviceContext,
1162            boolean update)
1163        throws PortalException, SystemException {
1164
1165        PortletPreferences preferences =
1166            ServiceContextUtil.getPortletPreferences(serviceContext);
1167
1168        if (preferences == null) {
1169            long ownerId = node.getGroupId();
1170            int ownerType = PortletKeys.PREFS_OWNER_TYPE_GROUP;
1171            long plid = PortletKeys.PREFS_PLID_SHARED;
1172            String portletId = PortletKeys.WIKI;
1173            String defaultPreferences = null;
1174
1175            preferences = portletPreferencesLocalService.getPreferences(
1176                node.getCompanyId(), ownerId, ownerType, plid, portletId,
1177                defaultPreferences);
1178        }
1179
1180        if (!update && WikiUtil.getEmailPageAddedEnabled(preferences)) {
1181        }
1182        else if (update && WikiUtil.getEmailPageUpdatedEnabled(preferences)) {
1183        }
1184        else {
1185            return;
1186        }
1187
1188        Company company = companyPersistence.findByPrimaryKey(
1189            page.getCompanyId());
1190
1191        Group group = groupPersistence.findByPrimaryKey(node.getGroupId());
1192
1193        User user = userPersistence.findByPrimaryKey(page.getUserId());
1194
1195        String portalURL = serviceContext.getPortalURL();
1196        String layoutFullURL = serviceContext.getLayoutFullURL();
1197
1198        WikiPage previousVersionPage = getPreviousVersionPage(page);
1199
1200        String attachmentURLPrefix =
1201            portalURL + serviceContext.getPathMain() +
1202                "/wiki/get_page_attachment?p_l_id=" + serviceContext.getPlid() +
1203                    "&nodeId=" + page.getNodeId() + "&title=" +
1204                        HttpUtil.encodeURL(page.getTitle()) + "&fileName=";
1205
1206        String pageDiffs = StringPool.BLANK;
1207
1208        try {
1209            pageDiffs = WikiUtil.diffHtml(
1210                previousVersionPage, page, null, null, attachmentURLPrefix);
1211        }
1212        catch (Exception e) {
1213        }
1214
1215        String pageContent = null;
1216
1217        if (Validator.equals(page.getFormat(), "creole")) {
1218            pageContent = WikiUtil.convert(
1219                page, null, null, attachmentURLPrefix);
1220        }
1221        else {
1222            pageContent = page.getContent();
1223            pageContent = WikiUtil.processContent(pageContent);
1224        }
1225
1226        String pageURL = StringPool.BLANK;
1227        String diffsURL = StringPool.BLANK;
1228
1229        if (Validator.isNotNull(layoutFullURL)) {
1230            pageURL =
1231                layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "wiki/" +
1232                    node.getNodeId() + StringPool.SLASH +
1233                        HttpUtil.encodeURL(page.getTitle());
1234
1235            if (previousVersionPage != null) {
1236                StringBuilder sb = new StringBuilder();
1237
1238                sb.append(layoutFullURL);
1239                sb.append("?p_p_id=");
1240                sb.append(PortletKeys.WIKI);
1241                sb.append("&p_p_state=");
1242                sb.append(WindowState.MAXIMIZED);
1243                sb.append("&struts_action=");
1244                sb.append(HttpUtil.encodeURL("/wiki/compare_versions"));
1245                sb.append("&nodeId=");
1246                sb.append(node.getNodeId());
1247                sb.append("&title=");
1248                sb.append(HttpUtil.encodeURL(page.getTitle()));
1249                sb.append("&sourceVersion=");
1250                sb.append(previousVersionPage.getVersion());
1251                sb.append("&targetVersion=");
1252                sb.append(page.getVersion());
1253                sb.append("&type=html");
1254
1255                diffsURL = sb.toString();
1256            }
1257        }
1258
1259        String portletName = PortalUtil.getPortletTitle(PortletKeys.WIKI, user);
1260
1261        String fromName = WikiUtil.getEmailFromName(preferences);
1262        String fromAddress = WikiUtil.getEmailFromAddress(preferences);
1263
1264        String replyToAddress = fromAddress;
1265        String mailId = WikiUtil.getMailId(
1266            company.getMx(), page.getNodeId(), page.getPageId());
1267
1268        fromName = StringUtil.replace(
1269            fromName,
1270            new String[] {
1271                "[$COMPANY_ID$]",
1272                "[$COMPANY_MX$]",
1273                "[$COMPANY_NAME$]",
1274                "[$COMMUNITY_NAME$]",
1275                "[$PAGE_USER_ADDRESS$]",
1276                "[$PAGE_USER_NAME$]",
1277                "[$PORTLET_NAME$]"
1278            },
1279            new String[] {
1280                String.valueOf(company.getCompanyId()),
1281                company.getMx(),
1282                company.getName(),
1283                group.getName(),
1284                user.getEmailAddress(),
1285                user.getFullName(),
1286                portletName
1287            });
1288
1289        fromAddress = StringUtil.replace(
1290            fromAddress,
1291            new String[] {
1292                "[$COMPANY_ID$]",
1293                "[$COMPANY_MX$]",
1294                "[$COMPANY_NAME$]",
1295                "[$COMMUNITY_NAME$]",
1296                "[$PAGE_USER_ADDRESS$]",
1297                "[$PAGE_USER_NAME$]",
1298                "[$PORTLET_NAME$]"
1299            },
1300            new String[] {
1301                String.valueOf(company.getCompanyId()),
1302                company.getMx(),
1303                company.getName(),
1304                group.getName(),
1305                user.getEmailAddress(),
1306                user.getFullName(),
1307                portletName
1308            });
1309
1310        String subjectPrefix = null;
1311        String body = null;
1312        String signature = null;
1313
1314        if (update) {
1315            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(
1316                preferences);
1317            body = WikiUtil.getEmailPageUpdatedBody(preferences);
1318            signature = WikiUtil.getEmailPageUpdatedSignature(preferences);
1319        }
1320        else {
1321            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(
1322                preferences);
1323            body = WikiUtil.getEmailPageAddedBody(preferences);
1324            signature = WikiUtil.getEmailPageAddedSignature(preferences);
1325        }
1326
1327        if (Validator.isNotNull(signature)) {
1328            body +=  "\n" + signature;
1329        }
1330
1331        subjectPrefix = StringUtil.replace(
1332            subjectPrefix,
1333            new String[] {
1334                "[$COMPANY_ID$]",
1335                "[$COMPANY_MX$]",
1336                "[$COMPANY_NAME$]",
1337                "[$COMMUNITY_NAME$]",
1338                "[$FROM_ADDRESS$]",
1339                "[$FROM_NAME$]",
1340                "[$NODE_NAME$]",
1341                "[$PAGE_CONTENT$]",
1342                "[$PAGE_ID$]",
1343                "[$PAGE_TITLE$]",
1344                "[$PAGE_USER_ADDRESS$]",
1345                "[$PAGE_USER_NAME$]",
1346                "[$PORTAL_URL$]",
1347                "[$PORTLET_NAME$]"
1348            },
1349            new String[] {
1350                String.valueOf(company.getCompanyId()),
1351                company.getMx(),
1352                company.getName(),
1353                group.getName(),
1354                fromAddress,
1355                fromName,
1356                node.getName(),
1357                pageContent,
1358                String.valueOf(page.getPageId()),
1359                page.getTitle(),
1360                user.getEmailAddress(),
1361                user.getFullName(),
1362                company.getVirtualHost(),
1363                portletName
1364            });
1365
1366        body = StringUtil.replace(
1367            body,
1368            new String[] {
1369                "[$COMPANY_ID$]",
1370                "[$COMPANY_MX$]",
1371                "[$COMPANY_NAME$]",
1372                "[$COMMUNITY_NAME$]",
1373                "[$DIFFS_URL$]",
1374                "[$FROM_ADDRESS$]",
1375                "[$FROM_NAME$]",
1376                "[$NODE_NAME$]",
1377                "[$PAGE_CONTENT$]",
1378                "[$PAGE_DATE_UPDATE$]",
1379                "[$PAGE_DIFFS$]",
1380                "[$PAGE_ID$]",
1381                "[$PAGE_SUMMARY$]",
1382                "[$PAGE_TITLE$]",
1383                "[$PAGE_URL$]",
1384                "[$PAGE_USER_ADDRESS$]",
1385                "[$PAGE_USER_NAME$]",
1386                "[$PORTAL_URL$]",
1387                "[$PORTLET_NAME$]"
1388            },
1389            new String[] {
1390                String.valueOf(company.getCompanyId()),
1391                company.getMx(),
1392                company.getName(),
1393                group.getName(),
1394                diffsURL,
1395                fromAddress,
1396                fromName,
1397                node.getName(),
1398                pageContent,
1399                String.valueOf(page.getModifiedDate()),
1400                replaceStyles(pageDiffs),
1401                String.valueOf(page.getPageId()),
1402                page.getSummary(),
1403                page.getTitle(),
1404                pageURL,
1405                user.getEmailAddress(),
1406                user.getFullName(),
1407                company.getVirtualHost(),
1408                portletName
1409            });
1410
1411        String subject = page.getTitle();
1412
1413        if (subject.indexOf(subjectPrefix) == -1) {
1414            subject = subjectPrefix + StringPool.SPACE + subject;
1415        }
1416
1417        Message message = new Message();
1418
1419        message.put("companyId", node.getCompanyId());
1420        message.put("userId", node.getUserId());
1421        message.put("nodeId", node.getNodeId());
1422        message.put("pageResourcePrimKey", page.getResourcePrimKey());
1423        message.put("fromName", fromName);
1424        message.put("fromAddress", fromAddress);
1425        message.put("subject", subject);
1426        message.put("body", body);
1427        message.put("replyToAddress", replyToAddress);
1428        message.put("mailId", mailId);
1429        message.put("htmlFormat", Boolean.TRUE);
1430
1431        MessageBusUtil.sendMessage(DestinationNames.WIKI, message);
1432    }
1433
1434    protected String replaceStyles(String html) {
1435        return StringUtil.replace(
1436            html,
1437            new String[] {
1438                "class=\"diff-html-added\"",
1439                "class=\"diff-html-removed\"",
1440                "class=\"diff-html-changed\"",
1441                "changeType=\"diff-added-image\"",
1442                "changeType=\"diff-removed-image\"",
1443                "changeType=\"diff-changed-image\""
1444            },
1445            new String[] {
1446                "style=\"background-color: #CFC;\"",
1447                "style=\"background-color: #FDC6C6; text-decoration: " +
1448                        "line-through;\"",
1449                "style=\"border-bottom: 2px dotted blue;\"",
1450                "style=\"border: 10px solid #CFC;\"",
1451                "style=\"border: 10px solid #FDC6C6;\"",
1452                "style=\"border: 10px solid blue;\""
1453            }
1454        );
1455    }
1456
1457    protected void validate(long nodeId, String content, String format)
1458        throws PortalException {
1459
1460        if (!WikiUtil.validate(nodeId, content, format)) {
1461            throw new PageContentException();
1462        }
1463    }
1464
1465    protected void validate(
1466            String title, long nodeId, String content, String format)
1467        throws PortalException, SystemException {
1468
1469        if (Validator.isNull(title)) {
1470            throw new PageTitleException();
1471        }
1472
1473        if (isUsedTitle(nodeId, title)) {
1474            throw new DuplicatePageException();
1475        }
1476
1477        validateTitle(title);
1478
1479        validate(nodeId, content, format);
1480    }
1481
1482    private static Log _log =
1483        LogFactoryUtil.getLog(WikiPageLocalServiceImpl.class);
1484
1485}