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