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