001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.wiki.service.impl;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.json.JSONFactoryUtil;
020    import com.liferay.portal.kernel.json.JSONObject;
021    import com.liferay.portal.kernel.repository.model.FileEntry;
022    import com.liferay.portal.kernel.sanitizer.SanitizerUtil;
023    import com.liferay.portal.kernel.search.Indexer;
024    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
025    import com.liferay.portal.kernel.util.CalendarFactoryUtil;
026    import com.liferay.portal.kernel.util.ContentTypes;
027    import com.liferay.portal.kernel.util.FileUtil;
028    import com.liferay.portal.kernel.util.HttpUtil;
029    import com.liferay.portal.kernel.util.ListUtil;
030    import com.liferay.portal.kernel.util.MathUtil;
031    import com.liferay.portal.kernel.util.MimeTypesUtil;
032    import com.liferay.portal.kernel.util.NotificationThreadLocal;
033    import com.liferay.portal.kernel.util.ObjectValuePair;
034    import com.liferay.portal.kernel.util.OrderByComparator;
035    import com.liferay.portal.kernel.util.StringBundler;
036    import com.liferay.portal.kernel.util.StringPool;
037    import com.liferay.portal.kernel.util.StringUtil;
038    import com.liferay.portal.kernel.util.TempFileUtil;
039    import com.liferay.portal.kernel.util.UnicodeProperties;
040    import com.liferay.portal.kernel.util.UniqueList;
041    import com.liferay.portal.kernel.util.Validator;
042    import com.liferay.portal.kernel.workflow.WorkflowConstants;
043    import com.liferay.portal.kernel.workflow.WorkflowHandlerRegistryUtil;
044    import com.liferay.portal.model.ResourceConstants;
045    import com.liferay.portal.model.User;
046    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
047    import com.liferay.portal.service.ServiceContext;
048    import com.liferay.portal.service.ServiceContextUtil;
049    import com.liferay.portal.util.Portal;
050    import com.liferay.portal.util.PortletKeys;
051    import com.liferay.portal.util.PropsValues;
052    import com.liferay.portal.util.SubscriptionSender;
053    import com.liferay.portlet.asset.NoSuchEntryException;
054    import com.liferay.portlet.asset.model.AssetEntry;
055    import com.liferay.portlet.asset.model.AssetLink;
056    import com.liferay.portlet.asset.model.AssetLinkConstants;
057    import com.liferay.portlet.expando.model.ExpandoBridge;
058    import com.liferay.portlet.social.model.SocialActivity;
059    import com.liferay.portlet.social.model.SocialActivityConstants;
060    import com.liferay.portlet.trash.model.TrashEntry;
061    import com.liferay.portlet.trash.util.TrashUtil;
062    import com.liferay.portlet.wiki.DuplicatePageException;
063    import com.liferay.portlet.wiki.NoSuchPageException;
064    import com.liferay.portlet.wiki.NoSuchPageResourceException;
065    import com.liferay.portlet.wiki.PageContentException;
066    import com.liferay.portlet.wiki.PageTitleException;
067    import com.liferay.portlet.wiki.PageVersionException;
068    import com.liferay.portlet.wiki.model.WikiNode;
069    import com.liferay.portlet.wiki.model.WikiPage;
070    import com.liferay.portlet.wiki.model.WikiPageConstants;
071    import com.liferay.portlet.wiki.model.WikiPageDisplay;
072    import com.liferay.portlet.wiki.model.WikiPageResource;
073    import com.liferay.portlet.wiki.model.impl.WikiPageDisplayImpl;
074    import com.liferay.portlet.wiki.model.impl.WikiPageImpl;
075    import com.liferay.portlet.wiki.service.base.WikiPageLocalServiceBaseImpl;
076    import com.liferay.portlet.wiki.social.WikiActivityKeys;
077    import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
078    import com.liferay.portlet.wiki.util.WikiCacheUtil;
079    import com.liferay.portlet.wiki.util.WikiUtil;
080    import com.liferay.portlet.wiki.util.comparator.PageCreateDateComparator;
081    import com.liferay.portlet.wiki.util.comparator.PageVersionComparator;
082    
083    import java.io.File;
084    import java.io.IOException;
085    import java.io.InputStream;
086    
087    import java.util.Calendar;
088    import java.util.Date;
089    import java.util.LinkedHashMap;
090    import java.util.List;
091    import java.util.Map;
092    import java.util.regex.Matcher;
093    import java.util.regex.Pattern;
094    
095    import javax.portlet.PortletPreferences;
096    import javax.portlet.PortletURL;
097    import javax.portlet.WindowState;
098    
099    /**
100     * @author Brian Wing Shun Chan
101     * @author Jorge Ferrer
102     * @author Raymond Augé
103     * @author Bruno Farache
104     * @author Julio Camarero
105     * @author Wesley Gong
106     * @author Marcellus Tavares
107     * @author Zsigmond Rab
108     * @author Zsolt Berentey
109     */
110    public class WikiPageLocalServiceImpl extends WikiPageLocalServiceBaseImpl {
111    
112            public WikiPage addPage(
113                            long userId, long nodeId, String title, double version,
114                            String content, String summary, boolean minorEdit, String format,
115                            boolean head, String parentTitle, String redirectTitle,
116                            ServiceContext serviceContext)
117                    throws PortalException, SystemException {
118    
119                    // Page
120    
121                    User user = userPersistence.findByPrimaryKey(userId);
122                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
123                    Date now = new Date();
124    
125                    long pageId = counterLocalService.increment();
126    
127                    content = SanitizerUtil.sanitize(
128                            user.getCompanyId(), node.getGroupId(), userId,
129                            WikiPage.class.getName(), pageId, "text/" + format, content);
130    
131                    validate(title, nodeId, content, format);
132    
133                    long resourcePrimKey =
134                            wikiPageResourceLocalService.getPageResourcePrimKey(nodeId, title);
135    
136                    WikiPage page = wikiPagePersistence.create(pageId);
137    
138                    page.setUuid(serviceContext.getUuid());
139                    page.setResourcePrimKey(resourcePrimKey);
140                    page.setGroupId(node.getGroupId());
141                    page.setCompanyId(user.getCompanyId());
142                    page.setUserId(user.getUserId());
143                    page.setUserName(user.getFullName());
144                    page.setCreateDate(serviceContext.getCreateDate(now));
145                    page.setModifiedDate(serviceContext.getModifiedDate(now));
146                    page.setNodeId(nodeId);
147                    page.setTitle(title);
148                    page.setVersion(version);
149                    page.setMinorEdit(minorEdit);
150                    page.setContent(content);
151                    page.setStatus(WorkflowConstants.STATUS_DRAFT);
152                    page.setSummary(summary);
153                    page.setFormat(format);
154                    page.setHead(head);
155                    page.setParentTitle(parentTitle);
156                    page.setRedirectTitle(redirectTitle);
157    
158                    wikiPagePersistence.update(page);
159    
160                    // Resources
161    
162                    if (serviceContext.isAddGroupPermissions() ||
163                            serviceContext.isAddGuestPermissions()) {
164    
165                            addPageResources(
166                                    page, serviceContext.isAddGroupPermissions(),
167                                    serviceContext.isAddGuestPermissions());
168                    }
169                    else {
170                            addPageResources(
171                                    page, serviceContext.getGroupPermissions(),
172                                    serviceContext.getGuestPermissions());
173                    }
174    
175                    // Node
176    
177                    node.setLastPostDate(serviceContext.getModifiedDate(now));
178    
179                    wikiNodePersistence.update(node);
180    
181                    // Asset
182    
183                    updateAsset(
184                            userId, page, serviceContext.getAssetCategoryIds(),
185                            serviceContext.getAssetTagNames(),
186                            serviceContext.getAssetLinkEntryIds());
187    
188                    // Expando
189    
190                    ExpandoBridge expandoBridge = page.getExpandoBridge();
191    
192                    expandoBridge.setAttributes(serviceContext);
193    
194                    // Message boards
195    
196                    if (PropsValues.WIKI_PAGE_COMMENTS_ENABLED) {
197                            mbMessageLocalService.addDiscussionMessage(
198                                    userId, page.getUserName(), page.getGroupId(),
199                                    WikiPage.class.getName(), resourcePrimKey,
200                                    WorkflowConstants.ACTION_PUBLISH);
201                    }
202    
203                    // Workflow
204    
205                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
206                            user.getCompanyId(), page.getGroupId(), userId,
207                            WikiPage.class.getName(), page.getPageId(), page, serviceContext);
208    
209                    return page;
210            }
211    
212            public WikiPage addPage(
213                            long userId, long nodeId, String title, String content,
214                            String summary, boolean minorEdit, ServiceContext serviceContext)
215                    throws PortalException, SystemException {
216    
217                    double version = WikiPageConstants.VERSION_DEFAULT;
218                    String format = WikiPageConstants.DEFAULT_FORMAT;
219                    boolean head = false;
220                    String parentTitle = null;
221                    String redirectTitle = null;
222    
223                    return addPage(
224                            userId, nodeId, title, version, content, summary, minorEdit, format,
225                            head, parentTitle, redirectTitle, serviceContext);
226            }
227    
228            public void addPageAttachment(
229                            long userId, long nodeId, String title, String fileName, File file,
230                            String mimeType)
231                    throws PortalException, SystemException {
232    
233                    WikiPage page = getPage(nodeId, title);
234    
235                    FileEntry fileEntry = PortletFileRepositoryUtil.addPortletFileEntry(
236                            page.getGroupId(), userId, WikiPage.class.getName(),
237                            page.getResourcePrimKey(), PortletKeys.WIKI,
238                            page.getAttachmentsFolderId(), file, fileName, mimeType);
239    
240                    if (userId == 0) {
241                            userId = page.getUserId();
242                    }
243    
244                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
245    
246                    extraDataJSONObject.put("fileEntryId", fileEntry.getFileEntryId());
247                    extraDataJSONObject.put("title", fileEntry.getTitle());
248    
249                    socialActivityLocalService.addActivity(
250                            userId, page.getGroupId(), WikiPage.class.getName(),
251                            page.getResourcePrimKey(),
252                            SocialActivityConstants.TYPE_ADD_ATTACHMENT,
253                            extraDataJSONObject.toString(), 0);
254            }
255    
256            public void addPageAttachment(
257                            long userId, long nodeId, String title, String fileName,
258                            InputStream inputStream, String mimeType)
259                    throws PortalException, SystemException {
260    
261                    WikiPage page = getPage(nodeId, title);
262    
263                    FileEntry fileEntry = PortletFileRepositoryUtil.addPortletFileEntry(
264                            page.getGroupId(), userId, WikiPage.class.getName(),
265                            page.getResourcePrimKey(), PortletKeys.WIKI,
266                            page.getAttachmentsFolderId(), inputStream, fileName, mimeType);
267    
268                    if (userId == 0) {
269                            userId = page.getUserId();
270                    }
271    
272                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
273    
274                    extraDataJSONObject.put("fileEntryId", fileEntry.getFileEntryId());
275                    extraDataJSONObject.put("title", fileEntry.getTitle());
276    
277                    socialActivityLocalService.addActivity(
278                            userId, page.getGroupId(), WikiPage.class.getName(),
279                            page.getResourcePrimKey(),
280                            SocialActivityConstants.TYPE_ADD_ATTACHMENT,
281                            extraDataJSONObject.toString(), 0);
282            }
283    
284            public void addPageAttachments(
285                            long userId, long nodeId, String title,
286                            List<ObjectValuePair<String, InputStream>> inputStreamOVPs)
287                    throws PortalException, SystemException {
288    
289                    if (inputStreamOVPs.size() == 0) {
290                            return;
291                    }
292    
293                    for (int i = 0; i < inputStreamOVPs.size(); i++) {
294                            ObjectValuePair<String, InputStream> inputStreamOVP =
295                                    inputStreamOVPs.get(i);
296    
297                            String fileName = inputStreamOVP.getKey();
298                            InputStream inputStream = inputStreamOVP.getValue();
299    
300                            File file = null;
301    
302                            try {
303                                    file = FileUtil.createTempFile(inputStream);
304    
305                                    String mimeType = MimeTypesUtil.getContentType(file, fileName);
306    
307                                    addPageAttachment(
308                                            userId, nodeId, title, fileName, file, mimeType);
309                            }
310                            catch (IOException ioe) {
311                                    throw new SystemException(
312                                            "Unable to write temporary file", ioe);
313                            }
314                            finally {
315                                    FileUtil.delete(file);
316                            }
317                    }
318            }
319    
320            public void addPageResources(
321                            long nodeId, String title, boolean addGroupPermissions,
322                            boolean addGuestPermissions)
323                    throws PortalException, SystemException {
324    
325                    WikiPage page = getPage(nodeId, title);
326    
327                    addPageResources(page, addGroupPermissions, addGuestPermissions);
328            }
329    
330            public void addPageResources(
331                            long nodeId, String title, String[] groupPermissions,
332                            String[] guestPermissions)
333                    throws PortalException, SystemException {
334    
335                    WikiPage page = getPage(nodeId, title);
336    
337                    addPageResources(page, groupPermissions, guestPermissions);
338            }
339    
340            public void addPageResources(
341                            WikiPage page, boolean addGroupPermissions,
342                            boolean addGuestPermissions)
343                    throws PortalException, SystemException {
344    
345                    resourceLocalService.addResources(
346                            page.getCompanyId(), page.getGroupId(), page.getUserId(),
347                            WikiPage.class.getName(), page.getResourcePrimKey(), false,
348                            addGroupPermissions, addGuestPermissions);
349            }
350    
351            public void addPageResources(
352                            WikiPage page, String[] groupPermissions, String[] guestPermissions)
353                    throws PortalException, SystemException {
354    
355                    resourceLocalService.addModelResources(
356                            page.getCompanyId(), page.getGroupId(), page.getUserId(),
357                            WikiPage.class.getName(), page.getResourcePrimKey(),
358                            groupPermissions, guestPermissions);
359            }
360    
361            public void addTempPageAttachment(
362                            long groupId, long userId, String fileName, String tempFolderName,
363                            InputStream inputStream, String mimeType)
364                    throws PortalException, SystemException {
365    
366                    TempFileUtil.addTempFile(
367                            groupId, userId, fileName, tempFolderName, inputStream, mimeType);
368            }
369    
370            public void changeParent(
371                            long userId, long nodeId, String title, String newParentTitle,
372                            ServiceContext serviceContext)
373                    throws PortalException, SystemException {
374    
375                    if (Validator.isNotNull(newParentTitle)) {
376                            WikiPage parentPage = getPage(nodeId, newParentTitle);
377    
378                            if (Validator.isNotNull(parentPage.getRedirectTitle())) {
379                                    newParentTitle = parentPage.getRedirectTitle();
380                            }
381                    }
382    
383                    WikiPage page = getPage(nodeId, title);
384    
385                    String originalParentTitle = page.getParentTitle();
386    
387                    double version = page.getVersion();
388                    String content = page.getContent();
389                    String summary = serviceContext.translate(
390                            "changed-parent-from-x", originalParentTitle);
391                    boolean minorEdit = false;
392                    String format = page.getFormat();
393                    String redirectTitle = page.getRedirectTitle();
394    
395                    long[] assetCategoryIds = assetCategoryLocalService.getCategoryIds(
396                            WikiPage.class.getName(), page.getResourcePrimKey());
397    
398                    serviceContext.setAssetCategoryIds(assetCategoryIds);
399    
400                    serviceContext.setAssetLinkEntryIds(null);
401    
402                    String[] assetTagNames = assetTagLocalService.getTagNames(
403                            WikiPage.class.getName(), page.getResourcePrimKey());
404    
405                    serviceContext.setAssetTagNames(assetTagNames);
406    
407                    updatePage(
408                            userId, nodeId, title, version, content, summary, minorEdit, format,
409                            newParentTitle, redirectTitle, serviceContext);
410    
411                    List<WikiPage> oldPages = wikiPagePersistence.findByN_T_H(
412                            nodeId, title, false);
413    
414                    for (WikiPage oldPage : oldPages) {
415                            oldPage.setParentTitle(originalParentTitle);
416    
417                            wikiPagePersistence.update(oldPage);
418                    }
419            }
420    
421            public void deletePage(long nodeId, String title)
422                    throws PortalException, SystemException {
423    
424                    List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
425                            nodeId, title, true, 0, 1);
426    
427                    if (!pages.isEmpty()) {
428                            deletePage(pages.get(0));
429                    }
430            }
431    
432            public void deletePage(long nodeId, String title, double version)
433                    throws PortalException, SystemException {
434    
435                    wikiPagePersistence.removeByN_T_V(nodeId, title, version);
436            }
437    
438            public void deletePage(WikiPage page)
439                    throws PortalException, SystemException {
440    
441                    // Children
442    
443                    List<WikiPage> children = wikiPagePersistence.findByN_H_P(
444                            page.getNodeId(), true, page.getTitle());
445    
446                    for (WikiPage curPage : children) {
447                            deletePage(curPage);
448                    }
449    
450                    wikiPagePersistence.removeByN_T(page.getNodeId(), page.getTitle());
451    
452                    // References
453    
454                    wikiPagePersistence.removeByN_R(page.getNodeId(), page.getTitle());
455    
456                    // Resources
457    
458                    resourceLocalService.deleteResource(
459                            page.getCompanyId(), WikiPage.class.getName(),
460                            ResourceConstants.SCOPE_INDIVIDUAL, page.getResourcePrimKey());
461    
462                    // Resource
463    
464                    try {
465                            wikiPageResourceLocalService.deletePageResource(
466                                    page.getNodeId(), page.getTitle());
467                    }
468                    catch (NoSuchPageResourceException nspre) {
469                    }
470    
471                    // Attachments
472    
473                    PortletFileRepositoryUtil.deleteFolder(page.getAttachmentsFolderId());
474    
475                    // Subscriptions
476    
477                    subscriptionLocalService.deleteSubscriptions(
478                            page.getCompanyId(), WikiPage.class.getName(),
479                            page.getResourcePrimKey());
480    
481                    // Asset
482    
483                    List<WikiPage> versionPages = wikiPagePersistence.findByN_T(
484                            page.getNodeId(), page.getTitle());
485    
486                    for (WikiPage versionPage : versionPages) {
487                            assetEntryLocalService.deleteEntry(
488                                    WikiPage.class.getName(), versionPage.getPrimaryKey());
489                    }
490    
491                    assetEntryLocalService.deleteEntry(
492                            WikiPage.class.getName(), page.getResourcePrimKey());
493    
494                    // Expando
495    
496                    expandoValueLocalService.deleteValues(
497                            WikiPage.class.getName(), page.getResourcePrimKey());
498    
499                    // Message boards
500    
501                    mbMessageLocalService.deleteDiscussionMessages(
502                            WikiPage.class.getName(), page.getResourcePrimKey());
503    
504                    // Trash
505    
506                    if (page.isInTrash()) {
507                            page.setTitle(TrashUtil.getOriginalTitle(page.getTitle()));
508    
509                            trashEntryLocalService.deleteEntry(
510                                    WikiPage.class.getName(), page.getResourcePrimKey());
511                    }
512    
513                    // Indexer
514    
515                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
516                            WikiPage.class);
517    
518                    indexer.delete(page);
519    
520                    // Cache
521    
522                    clearPageCache(page);
523    
524                    // All versions
525    
526                    List<WikiPage> pages = wikiPagePersistence.findByN_T(
527                            page.getNodeId(), page.getTitle());
528    
529                    for (WikiPage curPage : pages) {
530    
531                            // Workflow
532    
533                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLinks(
534                                    curPage.getCompanyId(), curPage.getGroupId(),
535                                    WikiPage.class.getName(), curPage.getPageId());
536                    }
537            }
538    
539            public void deletePageAttachment(long nodeId, String title, String fileName)
540                    throws PortalException, SystemException {
541    
542                    WikiPage page = getPage(nodeId, title);
543    
544                    FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
545                            page.getGroupId(), page.getAttachmentsFolderId(), fileName);
546    
547                    deletePageAttachment(fileEntry.getFileEntryId());
548            }
549    
550            public void deletePageAttachments(long nodeId, String title)
551                    throws PortalException, SystemException {
552    
553                    WikiPage page = getPage(nodeId, title);
554    
555                    PortletFileRepositoryUtil.deletePortletFileEntries(
556                            page.getGroupId(), page.getAttachmentsFolderId());
557            }
558    
559            public void deletePages(long nodeId)
560                    throws PortalException, SystemException {
561    
562                    List<WikiPage> pages = wikiPagePersistence.findByN_H_P(
563                            nodeId, true, StringPool.BLANK);
564    
565                    for (WikiPage page : pages) {
566                            deletePage(page);
567                    }
568    
569                    pages = wikiPagePersistence.findByN_H_P(
570                            nodeId, false, StringPool.BLANK);
571    
572                    for (WikiPage page : pages) {
573                            deletePage(page);
574                    }
575            }
576    
577            public void deleteTempPageAttachment(
578                            long groupId, long userId, String fileName, String tempFolderName)
579                    throws PortalException, SystemException {
580    
581                    TempFileUtil.deleteTempFile(groupId, userId, fileName, tempFolderName);
582            }
583    
584            public void deleteTrashPageAttachments(long nodeId, String title)
585                    throws PortalException, SystemException {
586    
587                    WikiPage page = getPage(nodeId, title);
588    
589                    PortletFileRepositoryUtil.deletePortletFileEntries(
590                            page.getGroupId(), page.getAttachmentsFolderId(),
591                            WorkflowConstants.STATUS_IN_TRASH);
592            }
593    
594            public WikiPage fetchPage(long nodeId, String title, double version)
595                    throws SystemException {
596    
597                    return wikiPagePersistence.fetchByN_T_V(nodeId, title, version);
598            }
599    
600            public List<WikiPage> getChildren(
601                            long nodeId, boolean head, String parentTitle)
602                    throws SystemException {
603    
604                    return wikiPagePersistence.findByN_H_P_S(
605                            nodeId, head, parentTitle, WorkflowConstants.STATUS_APPROVED);
606            }
607    
608            public WikiPage getDraftPage(long nodeId, String title)
609                    throws PortalException, SystemException {
610    
611                    List<WikiPage> pages = wikiPagePersistence.findByN_T_S(
612                            nodeId, title, WorkflowConstants.STATUS_DRAFT, 0, 1);
613    
614                    if (!pages.isEmpty()) {
615                            return pages.get(0);
616                    }
617                    else {
618                            pages = wikiPagePersistence.findByN_T_S(
619                                    nodeId, title, WorkflowConstants.STATUS_PENDING, 0, 1);
620    
621                            if (!pages.isEmpty()) {
622                                    return pages.get(0);
623                            }
624                            else {
625                                    throw new NoSuchPageException();
626                            }
627                    }
628    
629            }
630    
631            public List<WikiPage> getIncomingLinks(long nodeId, String title)
632                    throws PortalException, SystemException {
633    
634                    List<WikiPage> links = new UniqueList<WikiPage>();
635    
636                    List<WikiPage> pages = wikiPagePersistence.findByN_H(nodeId, true);
637    
638                    for (WikiPage page : pages) {
639                            if (isLinkedTo(page, title)) {
640                                    links.add(page);
641                            }
642                    }
643    
644                    List<WikiPage> referrals = wikiPagePersistence.findByN_R(nodeId, title);
645    
646                    for (WikiPage referral : referrals) {
647                            for (WikiPage page : pages) {
648                                    if (isLinkedTo(page, referral.getTitle())) {
649                                            links.add(page);
650                                    }
651                            }
652                    }
653    
654                    return ListUtil.sort(links);
655            }
656    
657            public List<WikiPage> getNoAssetPages() throws SystemException {
658                    return wikiPageFinder.findByNoAssets();
659            }
660    
661            public List<WikiPage> getOrphans(long nodeId)
662                    throws PortalException, SystemException {
663    
664                    List<WikiPage> pages = wikiPagePersistence.findByN_H_S(
665                            nodeId, true, WorkflowConstants.STATUS_APPROVED);
666    
667                    return WikiUtil.filterOrphans(pages);
668            }
669    
670            public List<WikiPage> getOutgoingLinks(long nodeId, String title)
671                    throws PortalException, SystemException {
672    
673                    WikiPage page = getPage(nodeId, title);
674    
675                    Map<String, WikiPage> pages = new LinkedHashMap<String, WikiPage>();
676    
677                    Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
678    
679                    for (Map.Entry<String, Boolean> entry : links.entrySet()) {
680                            String curTitle = entry.getKey();
681                            Boolean exists = entry.getValue();
682    
683                            if (exists) {
684                                    WikiPage curPage = getPage(nodeId, curTitle);
685    
686                                    if (!pages.containsKey(curPage.getTitle())) {
687                                            pages.put(curPage.getTitle(), curPage);
688                                    }
689                            }
690                            else {
691                                    WikiPageImpl newPage = new WikiPageImpl();
692    
693                                    newPage.setNew(true);
694                                    newPage.setNodeId(nodeId);
695                                    newPage.setTitle(curTitle);
696    
697                                    if (!pages.containsKey(curTitle)) {
698                                            pages.put(curTitle, newPage);
699                                    }
700                            }
701                    }
702    
703                    return ListUtil.fromMapValues(pages);
704            }
705    
706            public WikiPage getPage(long resourcePrimKey)
707                    throws PortalException, SystemException {
708    
709                    return getPage(resourcePrimKey, Boolean.TRUE);
710            }
711    
712            public WikiPage getPage(long resourcePrimKey, Boolean head)
713                    throws PortalException, SystemException {
714    
715                    WikiPageResource pageResource =
716                            wikiPageResourceLocalService.getPageResource(resourcePrimKey);
717    
718                    return getPage(pageResource.getNodeId(), pageResource.getTitle(), head);
719            }
720    
721            public WikiPage getPage(long nodeId, String title)
722                    throws PortalException, SystemException {
723    
724                    List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
725                            nodeId, title, true, 0, 1);
726    
727                    if (!pages.isEmpty()) {
728                            return pages.get(0);
729                    }
730                    else {
731                            throw new NoSuchPageException();
732                    }
733            }
734    
735            public WikiPage getPage(long nodeId, String title, Boolean head)
736                    throws PortalException, SystemException {
737    
738                    List<WikiPage> pages;
739    
740                    if (head == null) {
741                            pages = wikiPagePersistence.findByN_T(nodeId, title, 0, 1);
742                    }
743                    else {
744                            pages = wikiPagePersistence.findByN_T_H(nodeId, title, head, 0, 1);
745                    }
746    
747                    if (!pages.isEmpty()) {
748                            return pages.get(0);
749                    }
750                    else {
751                            throw new NoSuchPageException();
752                    }
753            }
754    
755            public WikiPage getPage(long nodeId, String title, double version)
756                    throws PortalException, SystemException {
757    
758                    WikiPage page = null;
759    
760                    if (version == 0) {
761                            page = getPage(nodeId, title);
762                    }
763                    else {
764                            page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
765                    }
766    
767                    return page;
768            }
769    
770            public WikiPage getPageByPageId(long pageId)
771                    throws PortalException, SystemException {
772    
773                    return wikiPagePersistence.findByPrimaryKey(pageId);
774            }
775    
776            public WikiPageDisplay getPageDisplay(
777                            long nodeId, String title, PortletURL viewPageURL,
778                            PortletURL editPageURL, String attachmentURLPrefix)
779                    throws PortalException, SystemException {
780    
781                    WikiPage page = getPage(nodeId, title);
782    
783                    return getPageDisplay(
784                            page, viewPageURL, editPageURL, attachmentURLPrefix);
785            }
786    
787            public WikiPageDisplay getPageDisplay(
788                            WikiPage page, PortletURL viewPageURL, PortletURL editPageURL,
789                            String attachmentURLPrefix)
790                    throws PortalException, SystemException {
791    
792                    String formattedContent = WikiUtil.convert(
793                            page, viewPageURL, editPageURL, attachmentURLPrefix);
794    
795                    return new WikiPageDisplayImpl(
796                            page.getUserId(), page.getNodeId(), page.getTitle(),
797                            page.getVersion(), page.getContent(), formattedContent,
798                            page.getFormat(), page.getHead(), page.getAttachmentsFileEntries());
799            }
800    
801            public List<WikiPage> getPages(
802                            long nodeId, boolean head, int start, int end)
803                    throws SystemException {
804    
805                    return getPages(
806                            nodeId, head, start, end, new PageCreateDateComparator(false));
807            }
808    
809            public List<WikiPage> getPages(
810                            long nodeId, boolean head, int status, int start, int end,
811                            OrderByComparator obc)
812                    throws SystemException {
813    
814                    if (status == WorkflowConstants.STATUS_ANY) {
815                            return wikiPagePersistence.findByN_H(nodeId, head, start, end, obc);
816                    }
817                    else {
818                            return wikiPagePersistence.findByN_H_S(
819                                    nodeId, head, status, start, end, obc);
820                    }
821            }
822    
823            public List<WikiPage> getPages(
824                            long nodeId, boolean head, int start, int end,
825                            OrderByComparator obc)
826                    throws SystemException {
827    
828                    return getPages(
829                            nodeId, head, WorkflowConstants.STATUS_APPROVED, start, end, obc);
830            }
831    
832            public List<WikiPage> getPages(long nodeId, int start, int end)
833                    throws SystemException {
834    
835                    return getPages(
836                            nodeId, start, end, new PageCreateDateComparator(false));
837            }
838    
839            public List<WikiPage> getPages(
840                            long nodeId, int start, int end, OrderByComparator obc)
841                    throws SystemException {
842    
843                    return wikiPagePersistence.findByNodeId(nodeId, start, end, obc);
844            }
845    
846            public List<WikiPage> getPages(
847                            long resourcePrimKey, long nodeId, int status)
848                    throws SystemException {
849    
850                    return wikiPagePersistence.findByR_N_S(resourcePrimKey, nodeId, status);
851            }
852    
853            public List<WikiPage> getPages(
854                            long userId, long nodeId, int status, int start, int end)
855                    throws SystemException {
856    
857                    if (userId > 0) {
858                            return wikiPagePersistence.findByU_N_S(
859                                    userId, nodeId, status, start, end,
860                                    new PageCreateDateComparator(false));
861                    }
862                    else {
863                            return wikiPagePersistence.findByN_S(
864                                    nodeId, status, start, end,
865                                    new PageCreateDateComparator(false));
866                    }
867            }
868    
869            public List<WikiPage> getPages(
870                            long nodeId, String title, boolean head, int start, int end)
871                    throws SystemException {
872    
873                    return wikiPagePersistence.findByN_T_H(
874                            nodeId, title, head, start, end,
875                            new PageCreateDateComparator(false));
876            }
877    
878            public List<WikiPage> getPages(
879                            long nodeId, String title, int start, int end)
880                    throws SystemException {
881    
882                    return wikiPagePersistence.findByN_T(
883                            nodeId, title, start, end, new PageCreateDateComparator(false));
884            }
885    
886            public List<WikiPage> getPages(
887                            long nodeId, String title, int start, int end,
888                            OrderByComparator obc)
889                    throws SystemException {
890    
891                    return wikiPagePersistence.findByN_T(nodeId, title, start, end, obc);
892            }
893    
894            public List<WikiPage> getPages(String format) throws SystemException {
895                    return wikiPagePersistence.findByFormat(format);
896            }
897    
898            public int getPagesCount(long nodeId) throws SystemException {
899                    return wikiPagePersistence.countByNodeId(nodeId);
900            }
901    
902            public int getPagesCount(long nodeId, boolean head) throws SystemException {
903                    return wikiPagePersistence.countByN_H_S(
904                            nodeId, head, WorkflowConstants.STATUS_APPROVED);
905            }
906    
907            public int getPagesCount(long nodeId, boolean head, int status)
908                    throws SystemException {
909    
910                    if (status == WorkflowConstants.STATUS_ANY) {
911                            return wikiPagePersistence.countByN_H(nodeId, head);
912                    }
913                    else {
914                            return wikiPagePersistence.countByN_H_S(nodeId, head, status);
915                    }
916            }
917    
918            public int getPagesCount(long nodeId, int status) throws SystemException {
919                    return wikiPagePersistence.countByN_S(nodeId, status);
920            }
921    
922            public int getPagesCount(long userId, long nodeId, int status)
923                    throws SystemException {
924    
925                    if (userId > 0) {
926                            return wikiPagePersistence.countByU_N_S(userId, nodeId, status);
927                    }
928                    else {
929                            return wikiPagePersistence.countByN_S(nodeId, status);
930                    }
931            }
932    
933            public int getPagesCount(long nodeId, String title) throws SystemException {
934                    return wikiPagePersistence.countByN_T(nodeId, title);
935            }
936    
937            public int getPagesCount(long nodeId, String title, boolean head)
938                    throws SystemException {
939    
940                    return wikiPagePersistence.countByN_T_H(nodeId, title, head);
941            }
942    
943            public int getPagesCount(String format) throws SystemException {
944                    return wikiPagePersistence.countByFormat(format);
945            }
946    
947            /**
948             * @deprecated {@link #getRecentChanges(long, long, int, int)}
949             */
950            public List<WikiPage> getRecentChanges(long nodeId, int start, int end)
951                    throws PortalException, SystemException {
952    
953                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
954    
955                    return getRecentChanges(node.getGroupId(), nodeId, start, end);
956            }
957    
958            public List<WikiPage> getRecentChanges(
959                            long groupId, long nodeId, int start, int end)
960                    throws SystemException {
961    
962                    Calendar cal = CalendarFactoryUtil.getCalendar();
963    
964                    cal.add(Calendar.WEEK_OF_YEAR, -1);
965    
966                    return wikiPageFinder.findByCreateDate(
967                            groupId, nodeId, cal.getTime(), false, start, end);
968            }
969    
970            /**
971             * @deprecated {@link #getRecentChangesCount(long, long)}
972             */
973            public int getRecentChangesCount(long nodeId)
974                    throws PortalException, SystemException {
975    
976                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
977    
978                    return getRecentChangesCount(node.getGroupId(), nodeId);
979            }
980    
981            public int getRecentChangesCount(long groupId, long nodeId)
982                    throws SystemException {
983    
984                    Calendar cal = CalendarFactoryUtil.getCalendar();
985    
986                    cal.add(Calendar.WEEK_OF_YEAR, -1);
987    
988                    return wikiPageFinder.countByCreateDate(
989                            groupId, nodeId, cal.getTime(), false);
990            }
991    
992            public String[] getTempPageAttachmentNames(
993                            long groupId, long userId, String tempFolderName)
994                    throws PortalException, SystemException {
995    
996                    return TempFileUtil.getTempFileEntryNames(
997                            groupId, userId, tempFolderName);
998            }
999    
1000            public boolean hasDraftPage(long nodeId, String title)
1001                    throws SystemException {
1002    
1003                    int count = wikiPagePersistence.countByN_T_S(
1004                            nodeId, title, WorkflowConstants.STATUS_DRAFT);
1005    
1006                    if (count > 0) {
1007                            return true;
1008                    }
1009                    else {
1010                            return false;
1011                    }
1012            }
1013    
1014            public void movePage(
1015                            long userId, long nodeId, String title, String newTitle,
1016                            boolean strict, ServiceContext serviceContext)
1017                    throws PortalException, SystemException {
1018    
1019                    validateTitle(newTitle);
1020    
1021                    // Check if the new title already exists
1022    
1023                    if (title.equalsIgnoreCase(newTitle)) {
1024                            throw new DuplicatePageException(newTitle);
1025                    }
1026    
1027                    if (isUsedTitle(nodeId, newTitle)) {
1028                            WikiPage page = getPage(nodeId, newTitle);
1029    
1030                            // Support moving back to a previously moved title
1031    
1032                            if (((page.getVersion() == WikiPageConstants.VERSION_DEFAULT) &&
1033                                     (page.getContent().length() < 200)) ||
1034                                    !strict) {
1035    
1036                                    deletePage(nodeId, newTitle);
1037                            }
1038                            else {
1039                                    throw new DuplicatePageException(newTitle);
1040                            }
1041                    }
1042    
1043                    // All versions
1044    
1045                    List<WikiPage> versionPages = wikiPagePersistence.findByN_T(
1046                            nodeId, title);
1047    
1048                    if (versionPages.size() == 0) {
1049                            return;
1050                    }
1051    
1052                    for (WikiPage page : versionPages) {
1053                            page.setTitle(newTitle);
1054    
1055                            wikiPagePersistence.update(page);
1056                    }
1057    
1058                    // Children
1059    
1060                    List<WikiPage> children = wikiPagePersistence.findByN_P(nodeId, title);
1061    
1062                    for (WikiPage page : children) {
1063                            page.setParentTitle(newTitle);
1064    
1065                            wikiPagePersistence.update(page);
1066                    }
1067    
1068                    WikiPage page = versionPages.get(versionPages.size() - 1);
1069    
1070                    long resourcePrimKey = page.getResourcePrimKey();
1071    
1072                    // Page resource
1073    
1074                    WikiPageResource pageResource =
1075                            wikiPageResourcePersistence.findByPrimaryKey(resourcePrimKey);
1076    
1077                    pageResource.setTitle(newTitle);
1078    
1079                    wikiPageResourcePersistence.update(pageResource);
1080    
1081                    // Create stub page at the old location
1082    
1083                    double version = WikiPageConstants.VERSION_DEFAULT;
1084                    String summary = WikiPageConstants.MOVED + " to " + title;
1085                    String format = page.getFormat();
1086                    boolean head = true;
1087                    String parentTitle = page.getParentTitle();
1088                    String redirectTitle = page.getTitle();
1089                    String content =
1090                            StringPool.DOUBLE_OPEN_BRACKET + redirectTitle +
1091                                    StringPool.DOUBLE_CLOSE_BRACKET;
1092    
1093                    serviceContext.setAddGroupPermissions(true);
1094                    serviceContext.setAddGuestPermissions(true);
1095    
1096                    AssetEntry assetEntry = assetEntryLocalService.getEntry(
1097                            WikiPage.class.getName(), page.getResourcePrimKey());
1098    
1099                    List<AssetLink> assetLinks = assetLinkLocalService.getDirectLinks(
1100                            assetEntry.getEntryId(), AssetLinkConstants.TYPE_RELATED);
1101    
1102                    long[] assetLinkEntryIds = StringUtil.split(
1103                            ListUtil.toString(assetLinks, AssetLink.ENTRY_ID2_ACCESSOR), 0L);
1104    
1105                    serviceContext.setAssetLinkEntryIds(assetLinkEntryIds);
1106    
1107                    addPage(
1108                            userId, nodeId, title, version, content, summary, false, format,
1109                            head, parentTitle, redirectTitle, serviceContext);
1110    
1111                    // Move redirects to point to the page with the new title
1112    
1113                    List<WikiPage> redirectedPages = wikiPagePersistence.findByN_R(
1114                            nodeId, title);
1115    
1116                    for (WikiPage redirectedPage : redirectedPages) {
1117                            redirectedPage.setRedirectTitle(newTitle);
1118    
1119                            wikiPagePersistence.update(redirectedPage);
1120                    }
1121    
1122                    // Asset
1123    
1124                    updateAsset(userId, page, null, null, null);
1125    
1126                    // Indexer
1127    
1128                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1129                            WikiPage.class);
1130    
1131                    indexer.delete(
1132                            new Object[] {page.getCompanyId(), page.getNodeId(), title});
1133    
1134                    indexer.reindex(page);
1135            }
1136    
1137            public void movePage(
1138                            long userId, long nodeId, String title, String newTitle,
1139                            ServiceContext serviceContext)
1140                    throws PortalException, SystemException {
1141    
1142                    movePage(userId, nodeId, title, newTitle, true, serviceContext);
1143            }
1144    
1145            public long movePageAttachmentToTrash(
1146                            long userId, long nodeId, String title, String fileName)
1147                    throws PortalException, SystemException {
1148    
1149                    WikiPage page = getPage(nodeId, title);
1150    
1151                    FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
1152                            page.getGroupId(), page.getAttachmentsFolderId(), fileName);
1153    
1154                    PortletFileRepositoryUtil.movePortletFileEntryToTrash(
1155                            userId, fileEntry.getFileEntryId());
1156    
1157                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1158    
1159                    extraDataJSONObject.put("fileEntryId", fileEntry.getFileEntryId());
1160                    extraDataJSONObject.put(
1161                            "title", TrashUtil.getOriginalTitle(fileEntry.getTitle()));
1162    
1163                    socialActivityLocalService.addActivity(
1164                            userId, page.getGroupId(), WikiPage.class.getName(),
1165                            page.getResourcePrimKey(),
1166                            SocialActivityConstants.TYPE_MOVE_ATTACHMENT_TO_TRASH,
1167                            extraDataJSONObject.toString(), 0);
1168    
1169                    return fileEntry.getFileEntryId();
1170            }
1171    
1172            public WikiPage movePageToTrash(long userId, long nodeId, String title)
1173                    throws PortalException, SystemException {
1174    
1175                    List<WikiPage> wikiPages = wikiPagePersistence.findByN_T_H(
1176                            nodeId, title, true, 0, 1);
1177    
1178                    if (!wikiPages.isEmpty()) {
1179                            return movePageToTrash(userId, wikiPages.get(0));
1180                    }
1181    
1182                    return null;
1183            }
1184    
1185            public WikiPage movePageToTrash(
1186                            long userId, long nodeId, String title, double version)
1187                    throws PortalException, SystemException {
1188    
1189                    WikiPage page = wikiPagePersistence.findByN_T_V(nodeId, title, version);
1190    
1191                    return movePageToTrash(userId, page);
1192            }
1193    
1194            public WikiPage movePageToTrash(long userId, WikiPage page)
1195                    throws PortalException, SystemException {
1196    
1197                    page = updateStatus(
1198                            userId, page, WorkflowConstants.STATUS_IN_TRASH,
1199                            new ServiceContext());
1200    
1201                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
1202                            WikiPage.class.getName(), page.getResourcePrimKey());
1203    
1204                    String trashTitle = TrashUtil.getTrashTitle(trashEntry.getEntryId());
1205    
1206                    List<WikiPage> versionPages = wikiPagePersistence.findByR_N_H(
1207                            page.getResourcePrimKey(), page.getNodeId(), false);
1208    
1209                    for (WikiPage versionPage : versionPages) {
1210                            versionPage.setTitle(trashTitle);
1211    
1212                            wikiPagePersistence.update(versionPage);
1213                    }
1214    
1215                    WikiPageResource pageResource =
1216                            wikiPageResourcePersistence.fetchByPrimaryKey(
1217                                    page.getResourcePrimKey());
1218    
1219                    pageResource.setTitle(trashTitle);
1220    
1221                    wikiPageResourcePersistence.update(pageResource);
1222    
1223                    page.setTitle(trashTitle);
1224    
1225                    return wikiPagePersistence.update(page);
1226            }
1227    
1228            public void restorePageAttachmentFromTrash(
1229                            long userId, long nodeId, String title, String fileName)
1230                    throws PortalException, SystemException {
1231    
1232                    WikiPage page = getPage(nodeId, title);
1233    
1234                    FileEntry fileEntry = PortletFileRepositoryUtil.getPortletFileEntry(
1235                            page.getGroupId(), page.getAttachmentsFolderId(), fileName);
1236    
1237                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
1238    
1239                    extraDataJSONObject.put("fileEntryId", fileEntry.getFileEntryId());
1240                    extraDataJSONObject.put("title", TrashUtil.getOriginalTitle(
1241                            fileEntry.getTitle()));
1242    
1243                    PortletFileRepositoryUtil.restorePortletFileEntryFromTrash(
1244                            userId, fileEntry.getFileEntryId());
1245    
1246                    socialActivityLocalService.addActivity(
1247                            userId, page.getGroupId(), WikiPage.class.getName(),
1248                            page.getResourcePrimKey(),
1249                            SocialActivityConstants.TYPE_RESTORE_ATTACHMENT_FROM_TRASH,
1250                            extraDataJSONObject.toString(), 0);
1251            }
1252    
1253            public void restorePageFromTrash(long userId, WikiPage page)
1254                    throws PortalException, SystemException {
1255    
1256                    String title = TrashUtil.getOriginalTitle(page.getTitle());
1257    
1258                    page.setTitle(title);
1259    
1260                    wikiPagePersistence.update(page);
1261    
1262                    List<WikiPage> versionPages = wikiPagePersistence.findByR_N_H(
1263                            page.getResourcePrimKey(), page.getNodeId(), false);
1264    
1265                    for (WikiPage versionPage : versionPages) {
1266                            versionPage.setTitle(title);
1267    
1268                            wikiPagePersistence.update(versionPage);
1269                    }
1270    
1271                    WikiPageResource pageResource =
1272                            wikiPageResourcePersistence.fetchByPrimaryKey(
1273                                    page.getResourcePrimKey());
1274    
1275                    pageResource.setTitle(title);
1276    
1277                    wikiPageResourcePersistence.update(pageResource);
1278    
1279                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
1280                            WikiPage.class.getName(), page.getResourcePrimKey());
1281    
1282                    updateStatus(
1283                            userId, page, trashEntry.getStatus(), new ServiceContext());
1284            }
1285    
1286            public WikiPage revertPage(
1287                            long userId, long nodeId, String title, double version,
1288                            ServiceContext serviceContext)
1289                    throws PortalException, SystemException {
1290    
1291                    WikiPage oldPage = getPage(nodeId, title, version);
1292    
1293                    long[] assetCategoryIds = assetCategoryLocalService.getCategoryIds(
1294                            WikiPage.class.getName(), oldPage.getResourcePrimKey());
1295    
1296                    serviceContext.setAssetCategoryIds(assetCategoryIds);
1297    
1298                    AssetEntry assetEntry = assetEntryLocalService.getEntry(
1299                            WikiPage.class.getName(), oldPage.getResourcePrimKey());
1300    
1301                    List<AssetLink> assetLinks = assetLinkLocalService.getLinks(
1302                            assetEntry.getEntryId());
1303    
1304                    long[] assetLinkEntryIds = StringUtil.split(
1305                            ListUtil.toString(assetLinks, AssetLink.ENTRY_ID2_ACCESSOR), 0L);
1306    
1307                    serviceContext.setAssetLinkEntryIds(assetLinkEntryIds);
1308    
1309                    String[] assetTagNames = assetTagLocalService.getTagNames(
1310                            WikiPage.class.getName(), oldPage.getResourcePrimKey());
1311    
1312                    serviceContext.setAssetTagNames(assetTagNames);
1313    
1314                    return updatePage(
1315                            userId, nodeId, title, 0, oldPage.getContent(),
1316                            WikiPageConstants.REVERTED + " to " + version, false,
1317                            oldPage.getFormat(), getParentPageTitle(oldPage),
1318                            oldPage.getRedirectTitle(), serviceContext);
1319            }
1320    
1321            public void subscribePage(long userId, long nodeId, String title)
1322                    throws PortalException, SystemException {
1323    
1324                    WikiPage page = getPage(nodeId, title);
1325    
1326                    subscriptionLocalService.addSubscription(
1327                            userId, page.getGroupId(), WikiPage.class.getName(),
1328                            page.getResourcePrimKey());
1329            }
1330    
1331            public void unsubscribePage(long userId, long nodeId, String title)
1332                    throws PortalException, SystemException {
1333    
1334                    WikiPage page = getPage(nodeId, title);
1335    
1336                    subscriptionLocalService.deleteSubscription(
1337                            userId, WikiPage.class.getName(), page.getResourcePrimKey());
1338            }
1339    
1340            public void updateAsset(
1341                            long userId, WikiPage page, long[] assetCategoryIds,
1342                            String[] assetTagNames, long[] assetLinkEntryIds)
1343                    throws PortalException, SystemException {
1344    
1345                    boolean addDraftAssetEntry = false;
1346    
1347                    if (!page.isApproved() &&
1348                            (page.getVersion() != WikiPageConstants.VERSION_DEFAULT)) {
1349    
1350                            int approvedPagesCount = wikiPagePersistence.countByN_T_S(
1351                                    page.getNodeId(), page.getTitle(),
1352                                    WorkflowConstants.STATUS_APPROVED);
1353    
1354                            if (approvedPagesCount > 0) {
1355                                    addDraftAssetEntry = true;
1356                            }
1357                    }
1358    
1359                    AssetEntry assetEntry = null;
1360    
1361                    if (addDraftAssetEntry) {
1362                            assetEntry = assetEntryLocalService.updateEntry(
1363                                    userId, page.getGroupId(), page.getCreateDate(),
1364                                    page.getModifiedDate(), WikiPage.class.getName(),
1365                                    page.getPrimaryKey(), page.getUuid(), 0, assetCategoryIds,
1366                                    assetTagNames, false, null, null, null, ContentTypes.TEXT_HTML,
1367                                    page.getTitle(), null, null, null, null, 0, 0, null, false);
1368                    }
1369                    else {
1370                            assetEntry = assetEntryLocalService.updateEntry(
1371                                    userId, page.getGroupId(), page.getCreateDate(),
1372                                    page.getModifiedDate(), WikiPage.class.getName(),
1373                                    page.getResourcePrimKey(), page.getUuid(), 0, assetCategoryIds,
1374                                    assetTagNames, page.isApproved(), null, null, null,
1375                                    ContentTypes.TEXT_HTML, page.getTitle(), null, null, null, null,
1376                                    0, 0, null, false);
1377                    }
1378    
1379                    assetLinkLocalService.updateLinks(
1380                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
1381                            AssetLinkConstants.TYPE_RELATED);
1382            }
1383    
1384            public WikiPage updatePage(
1385                            long userId, long nodeId, String title, double version,
1386                            String content, String summary, boolean minorEdit, String format,
1387                            String parentTitle, String redirectTitle,
1388                            ServiceContext serviceContext)
1389                    throws PortalException, SystemException {
1390    
1391                    // Page
1392    
1393                    User user = userPersistence.findByPrimaryKey(userId);
1394                    Date now = new Date();
1395    
1396                    WikiPage oldPage = null;
1397    
1398                    try {
1399                            oldPage = wikiPagePersistence.findByN_T_First(nodeId, title, null);
1400                    }
1401                    catch (NoSuchPageException nspe) {
1402                            return addPage(
1403                                    userId, nodeId, title, WikiPageConstants.VERSION_DEFAULT,
1404                                    content, summary, minorEdit, format, true, parentTitle,
1405                                    redirectTitle, serviceContext);
1406                    }
1407    
1408                    long pageId = 0;
1409    
1410                    if (oldPage.isApproved()) {
1411                            pageId = counterLocalService.increment();
1412                    }
1413                    else {
1414                            pageId = oldPage.getPageId();
1415                    }
1416    
1417                    content = SanitizerUtil.sanitize(
1418                            user.getCompanyId(), oldPage.getGroupId(), userId,
1419                            WikiPage.class.getName(), pageId, "text/" + format, content);
1420    
1421                    validate(nodeId, content, format);
1422    
1423                    double oldVersion = oldPage.getVersion();
1424    
1425                    if ((version > 0) && (version != oldVersion)) {
1426                            throw new PageVersionException();
1427                    }
1428    
1429                    serviceContext.validateModifiedDate(
1430                            oldPage, PageVersionException.class);
1431    
1432                    long resourcePrimKey =
1433                            wikiPageResourceLocalService.getPageResourcePrimKey(nodeId, title);
1434                    long groupId = oldPage.getGroupId();
1435    
1436                    WikiPage page = oldPage;
1437    
1438                    double newVersion = oldVersion;
1439    
1440                    if (oldPage.isApproved()) {
1441                            newVersion = MathUtil.format(oldVersion + 0.1, 1, 1);
1442    
1443                            page = wikiPagePersistence.create(pageId);
1444                    }
1445    
1446                    page.setResourcePrimKey(resourcePrimKey);
1447                    page.setGroupId(groupId);
1448                    page.setCompanyId(user.getCompanyId());
1449                    page.setUserId(user.getUserId());
1450                    page.setUserName(user.getFullName());
1451                    page.setCreateDate(serviceContext.getModifiedDate(now));
1452                    page.setModifiedDate(serviceContext.getModifiedDate(now));
1453                    page.setNodeId(nodeId);
1454                    page.setTitle(title);
1455                    page.setVersion(newVersion);
1456                    page.setMinorEdit(minorEdit);
1457                    page.setContent(content);
1458    
1459                    if (oldPage.isPending()) {
1460                            page.setStatus(oldPage.getStatus());
1461                    }
1462                    else {
1463                            page.setStatus(WorkflowConstants.STATUS_DRAFT);
1464                    }
1465    
1466                    page.setSummary(summary);
1467                    page.setFormat(format);
1468    
1469                    if (Validator.isNotNull(parentTitle)) {
1470                            page.setParentTitle(parentTitle);
1471                    }
1472    
1473                    if (Validator.isNotNull(redirectTitle)) {
1474                            page.setRedirectTitle(redirectTitle);
1475                    }
1476    
1477                    wikiPagePersistence.update(page);
1478    
1479                    // Expando
1480    
1481                    ExpandoBridge expandoBridge = page.getExpandoBridge();
1482    
1483                    expandoBridge.setAttributes(serviceContext);
1484    
1485                    // Node
1486    
1487                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
1488    
1489                    node.setLastPostDate(serviceContext.getModifiedDate(now));
1490    
1491                    wikiNodePersistence.update(node);
1492    
1493                    // Asset
1494    
1495                    updateAsset(
1496                            userId, page, serviceContext.getAssetCategoryIds(),
1497                            serviceContext.getAssetTagNames(),
1498                            serviceContext.getAssetLinkEntryIds());
1499    
1500                    // Social
1501    
1502                    if (!page.isMinorEdit() ||
1503                            PropsValues.WIKI_PAGE_MINOR_EDIT_ADD_SOCIAL_ACTIVITY) {
1504    
1505                            if (oldVersion == newVersion) {
1506                                    SocialActivity lastSocialActivity =
1507                                            socialActivityLocalService.fetchFirstActivity(
1508                                                    WikiPage.class.getName(), page.getResourcePrimKey(),
1509                                                    WikiActivityKeys.UPDATE_PAGE);
1510    
1511                                    if (lastSocialActivity != null) {
1512                                            lastSocialActivity.setCreateDate(now.getTime() + 1);
1513                                            lastSocialActivity.setUserId(serviceContext.getUserId());
1514    
1515                                            socialActivityPersistence.update(lastSocialActivity);
1516                                    }
1517                            }
1518                            else {
1519                                    JSONObject extraDataJSONObject =
1520                                            JSONFactoryUtil.createJSONObject();
1521    
1522                                    extraDataJSONObject.put("version", page.getVersion());
1523    
1524                                    socialActivityLocalService.addActivity(
1525                                            userId, page.getGroupId(), WikiPage.class.getName(),
1526                                            page.getResourcePrimKey(), WikiActivityKeys.UPDATE_PAGE,
1527                                            extraDataJSONObject.toString(), 0);
1528                            }
1529                    }
1530    
1531                    // Workflow
1532    
1533                    WorkflowHandlerRegistryUtil.startWorkflowInstance(
1534                            user.getCompanyId(), page.getGroupId(), userId,
1535                            WikiPage.class.getName(), page.getPageId(), page, serviceContext);
1536    
1537                    return page;
1538            }
1539    
1540            public WikiPage updateStatus(
1541                            long userId, long resourcePrimKey, int status,
1542                            ServiceContext serviceContext)
1543                    throws PortalException, SystemException {
1544    
1545                    WikiPageResource pageResource =
1546                            wikiPageResourceLocalService.getPageResource(resourcePrimKey);
1547    
1548                    List<WikiPage> pages = wikiPagePersistence.findByN_T(
1549                            pageResource.getNodeId(), pageResource.getTitle(), 0, 1,
1550                            new PageVersionComparator());
1551    
1552                    WikiPage page = null;
1553    
1554                    if (!pages.isEmpty()) {
1555                            page = pages.get(0);
1556                    }
1557                    else {
1558                            throw new NoSuchPageException();
1559                    }
1560    
1561                    return updateStatus(userId, page, status, serviceContext);
1562            }
1563    
1564            public WikiPage updateStatus(
1565                            long userId, WikiPage page, int status,
1566                            ServiceContext serviceContext)
1567                    throws PortalException, SystemException {
1568    
1569                    // Page
1570    
1571                    User user = userPersistence.findByPrimaryKey(userId);
1572                    WikiNode node = wikiNodePersistence.findByPrimaryKey(page.getNodeId());
1573    
1574                    Date now = new Date();
1575    
1576                    int oldStatus = page.getStatus();
1577    
1578                    page.setStatus(status);
1579                    page.setStatusByUserId(userId);
1580                    page.setStatusByUserName(user.getFullName());
1581                    page.setStatusDate(now);
1582    
1583                    if (status == WorkflowConstants.STATUS_APPROVED) {
1584    
1585                            // Asset
1586    
1587                            if ((oldStatus != WorkflowConstants.STATUS_APPROVED) &&
1588                                    (page.getVersion() != WikiPageConstants.VERSION_DEFAULT)) {
1589    
1590                                    try {
1591                                            AssetEntry draftAssetEntry =
1592                                                    assetEntryLocalService.getEntry(
1593                                                            WikiPage.class.getName(), page.getPrimaryKey());
1594    
1595                                            long[] assetCategoryIds = draftAssetEntry.getCategoryIds();
1596                                            String[] assetTagNames = draftAssetEntry.getTagNames();
1597    
1598                                            List<AssetLink> assetLinks =
1599                                                    assetLinkLocalService.getDirectLinks(
1600                                                            draftAssetEntry.getEntryId(),
1601                                                            AssetLinkConstants.TYPE_RELATED);
1602    
1603                                            long[] assetLinkEntryIds = StringUtil.split(
1604                                                    ListUtil.toString(
1605                                                            assetLinks, AssetLink.ENTRY_ID2_ACCESSOR), 0L);
1606    
1607                                            AssetEntry assetEntry = assetEntryLocalService.updateEntry(
1608                                                    userId, page.getGroupId(), page.getCreateDate(),
1609                                                    page.getModifiedDate(), WikiPage.class.getName(),
1610                                                    page.getResourcePrimKey(), page.getUuid(), 0,
1611                                                    assetCategoryIds, assetTagNames, true, null, null, null,
1612                                                    ContentTypes.TEXT_HTML, page.getTitle(), null, null,
1613                                                    null, null, 0, 0, null, false);
1614    
1615                                            // Asset Links
1616    
1617                                            assetLinkLocalService.updateLinks(
1618                                                    userId, assetEntry.getEntryId(), assetLinkEntryIds,
1619                                                    AssetLinkConstants.TYPE_RELATED);
1620    
1621                                            assetEntryLocalService.deleteEntry(
1622                                                    draftAssetEntry.getEntryId());
1623                                    }
1624                                    catch (NoSuchEntryException nsee) {
1625                                    }
1626                            }
1627    
1628                            assetEntryLocalService.updateVisible(
1629                                    WikiPage.class.getName(), page.getResourcePrimKey(), true);
1630    
1631                            // Social
1632    
1633                            if ((page.getVersion() == WikiPageConstants.VERSION_DEFAULT) &&
1634                                    (!page.isMinorEdit() ||
1635                                            PropsValues.WIKI_PAGE_MINOR_EDIT_ADD_SOCIAL_ACTIVITY)) {
1636    
1637                                    JSONObject extraDataJSONObject =
1638                                            JSONFactoryUtil.createJSONObject();
1639    
1640                                    extraDataJSONObject.put("version", page.getVersion());
1641    
1642                                    socialActivityLocalService.addActivity(
1643                                            userId, page.getGroupId(), WikiPage.class.getName(),
1644                                            page.getResourcePrimKey(), WikiActivityKeys.ADD_PAGE,
1645                                            extraDataJSONObject.toString(), 0);
1646                            }
1647    
1648                            // Subscriptions
1649    
1650                            if (NotificationThreadLocal.isEnabled() &&
1651                                    (!page.isMinorEdit() ||
1652                                     PropsValues.WIKI_PAGE_MINOR_EDIT_SEND_EMAIL)) {
1653    
1654                                    boolean update = false;
1655    
1656                                    if (page.getVersion() > WikiPageConstants.VERSION_DEFAULT) {
1657                                            update = true;
1658                                    }
1659    
1660                                    notifySubscribers(node, page, serviceContext, update);
1661                            }
1662    
1663                            // Indexer
1664    
1665                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1666                                    WikiPage.class);
1667    
1668                            indexer.reindex(page);
1669    
1670                            // Cache
1671    
1672                            clearPageCache(page);
1673                    }
1674    
1675                    if ((oldStatus == WorkflowConstants.STATUS_IN_TRASH) &&
1676                            (status != WorkflowConstants.STATUS_IN_TRASH)) {
1677    
1678                            // Trash
1679    
1680                            trashEntryLocalService.deleteEntry(
1681                                    WikiPage.class.getName(), page.getResourcePrimKey());
1682                    }
1683                    else if (status == WorkflowConstants.STATUS_IN_TRASH) {
1684    
1685                            // Asset
1686    
1687                            assetEntryLocalService.updateVisible(
1688                                    WikiPage.class.getName(), page.getResourcePrimKey(), false);
1689    
1690                            // Trash
1691    
1692                            UnicodeProperties typeSettingsProperties = new UnicodeProperties();
1693    
1694                            typeSettingsProperties.put("title", page.getTitle());
1695    
1696                            trashEntryLocalService.addTrashEntry(
1697                                    userId, page.getGroupId(), WikiPage.class.getName(),
1698                                    page.getResourcePrimKey(), oldStatus, null,
1699                                    typeSettingsProperties);
1700    
1701                            // Indexer
1702    
1703                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1704                                    WikiPage.class);
1705    
1706                            indexer.reindex(page);
1707    
1708                            // Cache
1709    
1710                            clearPageCache(page);
1711                    }
1712    
1713                    // Head
1714    
1715                    if (status == WorkflowConstants.STATUS_APPROVED) {
1716                            page.setHead(true);
1717    
1718                            List<WikiPage> pages = wikiPagePersistence.findByN_T_H(
1719                                    page.getNodeId(), page.getTitle(), true);
1720    
1721                            for (WikiPage curPage : pages) {
1722                                    if (!curPage.equals(page)) {
1723                                            curPage.setHead(false);
1724    
1725                                            wikiPagePersistence.update(curPage);
1726                                    }
1727                            }
1728                    }
1729                    else if (status != WorkflowConstants.STATUS_IN_TRASH) {
1730                            page.setHead(false);
1731    
1732                            List<WikiPage> pages = wikiPagePersistence.findByN_T_S(
1733                                    page.getNodeId(), page.getTitle(),
1734                                    WorkflowConstants.STATUS_APPROVED);
1735    
1736                            for (WikiPage curPage : pages) {
1737                                    if (!curPage.equals(page)) {
1738                                            curPage.setHead(true);
1739    
1740                                            wikiPagePersistence.update(curPage);
1741    
1742                                            break;
1743                                    }
1744                            }
1745                    }
1746    
1747                    return wikiPagePersistence.update(page);
1748            }
1749    
1750            public void validateTitle(String title) throws PortalException {
1751                    if (title.equals("all_pages") || title.equals("orphan_pages") ||
1752                            title.equals("recent_changes")) {
1753    
1754                            throw new PageTitleException(title + " is reserved");
1755                    }
1756    
1757                    if (Validator.isNotNull(PropsValues.WIKI_PAGE_TITLES_REGEXP)) {
1758                            Pattern pattern = Pattern.compile(
1759                                    PropsValues.WIKI_PAGE_TITLES_REGEXP);
1760    
1761                            Matcher matcher = pattern.matcher(title);
1762    
1763                            if (!matcher.matches()) {
1764                                    throw new PageTitleException();
1765                            }
1766                    }
1767            }
1768    
1769            protected void clearPageCache(WikiPage page) {
1770                    if (!WikiCacheThreadLocal.isClearCache()) {
1771                            return;
1772                    }
1773    
1774                    WikiCacheUtil.clearCache(page.getNodeId());
1775            }
1776    
1777            protected void deletePageAttachment(long fileEntryId)
1778                    throws PortalException, SystemException {
1779    
1780                    PortletFileRepositoryUtil.deletePortletFileEntry(fileEntryId);
1781            }
1782    
1783            protected String getParentPageTitle(WikiPage page) {
1784    
1785                    // LPS-4586
1786    
1787                    try {
1788                            WikiPage parentPage = getPage(
1789                                    page.getNodeId(), page.getParentTitle());
1790    
1791                            return parentPage.getTitle();
1792                    }
1793                    catch (Exception e) {
1794                            return null;
1795                    }
1796            }
1797    
1798            protected WikiPage getPreviousVersionPage(WikiPage page)
1799                    throws PortalException, SystemException {
1800    
1801                    double previousVersion = MathUtil.format(page.getVersion() - 0.1, 1, 1);
1802    
1803                    if (previousVersion < 1) {
1804                            return null;
1805                    }
1806    
1807                    return getPage(page.getNodeId(), page.getTitle(), previousVersion);
1808            }
1809    
1810            protected boolean isLinkedTo(WikiPage page, String targetTitle)
1811                    throws PortalException {
1812    
1813                    Map<String, Boolean> links = WikiCacheUtil.getOutgoingLinks(page);
1814    
1815                    Boolean link = links.get(targetTitle.toLowerCase());
1816    
1817                    if (link != null) {
1818                            return true;
1819                    }
1820                    else {
1821                            return false;
1822                    }
1823            }
1824    
1825            protected boolean isUsedTitle(long nodeId, String title)
1826                    throws SystemException {
1827    
1828                    if (getPagesCount(nodeId, title, true) > 0) {
1829                            return true;
1830                    }
1831                    else {
1832                            return false;
1833                    }
1834            }
1835    
1836            protected void notifySubscribers(
1837                            WikiNode node, WikiPage page, ServiceContext serviceContext,
1838                            boolean update)
1839                    throws PortalException, SystemException {
1840    
1841                    PortletPreferences preferences = null;
1842    
1843                    String rootPortletId = serviceContext.getRootPortletId();
1844    
1845                    if (Validator.isNull(rootPortletId) ||
1846                            !rootPortletId.equals(PortletKeys.WIKI_DISPLAY)) {
1847    
1848                            preferences = ServiceContextUtil.getPortletPreferences(
1849                                    serviceContext);
1850                    }
1851    
1852                    if (preferences == null) {
1853                            preferences = portletPreferencesLocalService.getPreferences(
1854                                    node.getCompanyId(), node.getGroupId(),
1855                                    PortletKeys.PREFS_OWNER_TYPE_GROUP,
1856                                    PortletKeys.PREFS_PLID_SHARED, PortletKeys.WIKI_ADMIN, null);
1857                    }
1858    
1859                    if (!update && WikiUtil.getEmailPageAddedEnabled(preferences)) {
1860                    }
1861                    else if (update && WikiUtil.getEmailPageUpdatedEnabled(preferences)) {
1862                    }
1863                    else {
1864                            return;
1865                    }
1866    
1867                    String portalURL = serviceContext.getPortalURL();
1868                    String layoutFullURL = serviceContext.getLayoutFullURL();
1869    
1870                    WikiPage previousVersionPage = getPreviousVersionPage(page);
1871    
1872                    String attachmentURLPrefix =
1873                            portalURL + serviceContext.getPathMain() +
1874                                    "/wiki/get_page_attachment?p_l_id=" + serviceContext.getPlid() +
1875                                            "&nodeId=" + page.getNodeId() + "&title=" +
1876                                                    HttpUtil.encodeURL(page.getTitle()) + "&fileName=";
1877    
1878                    String pageDiffs = StringPool.BLANK;
1879    
1880                    try {
1881                            pageDiffs = WikiUtil.diffHtml(
1882                                    previousVersionPage, page, null, null, attachmentURLPrefix);
1883                    }
1884                    catch (Exception e) {
1885                    }
1886    
1887                    String pageContent = null;
1888    
1889                    if (Validator.equals(page.getFormat(), "creole")) {
1890                            pageContent = WikiUtil.convert(
1891                                    page, null, null, attachmentURLPrefix);
1892                    }
1893                    else {
1894                            pageContent = page.getContent();
1895                            pageContent = WikiUtil.processContent(pageContent);
1896                    }
1897    
1898                    String pageURL = StringPool.BLANK;
1899                    String diffsURL = StringPool.BLANK;
1900    
1901                    if (Validator.isNotNull(layoutFullURL)) {
1902                            pageURL =
1903                                    layoutFullURL + Portal.FRIENDLY_URL_SEPARATOR + "wiki/" +
1904                                            node.getNodeId() + StringPool.SLASH +
1905                                                    HttpUtil.encodeURL(page.getTitle());
1906    
1907                            if (previousVersionPage != null) {
1908                                    StringBundler sb = new StringBundler(16);
1909    
1910                                    sb.append(layoutFullURL);
1911                                    sb.append("?p_p_id=");
1912                                    sb.append(PortletKeys.WIKI);
1913                                    sb.append("&p_p_state=");
1914                                    sb.append(WindowState.MAXIMIZED);
1915                                    sb.append("&struts_action=");
1916                                    sb.append(HttpUtil.encodeURL("/wiki/compare_versions"));
1917                                    sb.append("&nodeId=");
1918                                    sb.append(node.getNodeId());
1919                                    sb.append("&title=");
1920                                    sb.append(HttpUtil.encodeURL(page.getTitle()));
1921                                    sb.append("&sourceVersion=");
1922                                    sb.append(previousVersionPage.getVersion());
1923                                    sb.append("&targetVersion=");
1924                                    sb.append(page.getVersion());
1925                                    sb.append("&type=html");
1926    
1927                                    diffsURL = sb.toString();
1928                            }
1929                    }
1930    
1931                    String fromName = WikiUtil.getEmailFromName(
1932                            preferences, page.getCompanyId());
1933                    String fromAddress = WikiUtil.getEmailFromAddress(
1934                            preferences, page.getCompanyId());
1935    
1936                    String subjectPrefix = null;
1937                    String body = null;
1938                    String signature = null;
1939    
1940                    if (update) {
1941                            subjectPrefix = WikiUtil.getEmailPageUpdatedSubjectPrefix(
1942                                    preferences);
1943                            body = WikiUtil.getEmailPageUpdatedBody(preferences);
1944                            signature = WikiUtil.getEmailPageUpdatedSignature(preferences);
1945                    }
1946                    else {
1947                            subjectPrefix = WikiUtil.getEmailPageAddedSubjectPrefix(
1948                                    preferences);
1949                            body = WikiUtil.getEmailPageAddedBody(preferences);
1950                            signature = WikiUtil.getEmailPageAddedSignature(preferences);
1951                    }
1952    
1953                    String subject = page.getTitle();
1954    
1955                    if (!subject.contains(subjectPrefix)) {
1956                            subject = subjectPrefix + StringPool.SPACE + subject;
1957                    }
1958    
1959                    if (Validator.isNotNull(signature)) {
1960                            body += "\n" + signature;
1961                    }
1962    
1963                    SubscriptionSender subscriptionSender = new SubscriptionSender();
1964    
1965                    subscriptionSender.setBody(body);
1966                    subscriptionSender.setCompanyId(page.getCompanyId());
1967                    subscriptionSender.setContextAttributes(
1968                            "[$DIFFS_URL$]", diffsURL, "[$NODE_NAME$]", node.getName(),
1969                            "[$PAGE_DATE_UPDATE$]", page.getModifiedDate(), "[$PAGE_ID$]",
1970                            page.getPageId(), "[$PAGE_SUMMARY$]", page.getSummary(),
1971                            "[$PAGE_TITLE$]", page.getTitle(), "[$PAGE_URL$]", pageURL);
1972                    subscriptionSender.setContextAttribute(
1973                            "[$PAGE_CONTENT$]", pageContent, false);
1974                    subscriptionSender.setContextAttribute(
1975                            "[$PAGE_DIFFS$]", replaceStyles(pageDiffs), false);
1976                    subscriptionSender.setContextUserPrefix("PAGE");
1977                    subscriptionSender.setFrom(fromAddress, fromName);
1978                    subscriptionSender.setHtmlFormat(true);
1979                    subscriptionSender.setMailId(
1980                            "wiki_page", page.getNodeId(), page.getPageId());
1981                    subscriptionSender.setPortletId(PortletKeys.WIKI);
1982                    subscriptionSender.setReplyToAddress(fromAddress);
1983                    subscriptionSender.setScopeGroupId(node.getGroupId());
1984                    subscriptionSender.setServiceContext(serviceContext);
1985                    subscriptionSender.setSubject(subject);
1986                    subscriptionSender.setUserId(page.getUserId());
1987    
1988                    subscriptionSender.addPersistedSubscribers(
1989                            WikiNode.class.getName(), node.getNodeId());
1990                    subscriptionSender.addPersistedSubscribers(
1991                            WikiPage.class.getName(), page.getResourcePrimKey());
1992    
1993                    subscriptionSender.flushNotificationsAsync();
1994            }
1995    
1996            protected String replaceStyles(String html) {
1997                    return StringUtil.replace(
1998                            html,
1999                            new String[] {
2000                                    "class=\"diff-html-added\"", "class=\"diff-html-removed\"",
2001                                    "class=\"diff-html-changed\"",
2002                                    "changeType=\"diff-added-image\"",
2003                                    "changeType=\"diff-removed-image\"",
2004                                    "changeType=\"diff-changed-image\""
2005                            },
2006                            new String[] {
2007                                    "style=\"background-color: #CFC;\"",
2008                                    "style=\"background-color: #FDC6C6; text-decoration: " +
2009                                            "line-through;\"",
2010                                    "style=\"border-bottom: 2px dotted blue;\"",
2011                                    "style=\"border: 10px solid #CFC;\"",
2012                                    "style=\"border: 10px solid #FDC6C6;\"",
2013                                    "style=\"border: 10px solid blue;\""
2014                            }
2015                    );
2016            }
2017    
2018            protected void validate(long nodeId, String content, String format)
2019                    throws PortalException {
2020    
2021                    if (!WikiUtil.validate(nodeId, content, format)) {
2022                            throw new PageContentException();
2023                    }
2024            }
2025    
2026            protected void validate(
2027                            String title, long nodeId, String content, String format)
2028                    throws PortalException, SystemException {
2029    
2030                    if (Validator.isNull(title)) {
2031                            throw new PageTitleException();
2032                    }
2033    
2034                    if (isUsedTitle(nodeId, title)) {
2035                            throw new DuplicatePageException();
2036                    }
2037    
2038                    validateTitle(title);
2039    
2040                    validate(nodeId, content, format);
2041            }
2042    
2043    }