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