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