001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.wiki.service.impl;
016    
017    import com.liferay.portal.kernel.configuration.Filter;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.search.Indexer;
023    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
024    import com.liferay.portal.kernel.systemevent.SystemEvent;
025    import com.liferay.portal.kernel.util.InstancePool;
026    import com.liferay.portal.kernel.util.PropsKeys;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.UnicodeProperties;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.kernel.workflow.WorkflowConstants;
031    import com.liferay.portal.model.Group;
032    import com.liferay.portal.model.ResourceConstants;
033    import com.liferay.portal.model.SystemEventConstants;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.portletfilerepository.PortletFileRepositoryUtil;
036    import com.liferay.portal.service.ServiceContext;
037    import com.liferay.portal.util.PortletKeys;
038    import com.liferay.portal.util.PropsUtil;
039    import com.liferay.portal.util.PropsValues;
040    import com.liferay.portlet.documentlibrary.model.DLFolderConstants;
041    import com.liferay.portlet.trash.model.TrashEntry;
042    import com.liferay.portlet.trash.util.TrashUtil;
043    import com.liferay.portlet.wiki.DuplicateNodeNameException;
044    import com.liferay.portlet.wiki.NodeNameException;
045    import com.liferay.portlet.wiki.importers.WikiImporter;
046    import com.liferay.portlet.wiki.model.WikiNode;
047    import com.liferay.portlet.wiki.model.WikiPage;
048    import com.liferay.portlet.wiki.service.base.WikiNodeLocalServiceBaseImpl;
049    import com.liferay.portlet.wiki.util.WikiCacheThreadLocal;
050    import com.liferay.portlet.wiki.util.WikiCacheUtil;
051    
052    import java.io.InputStream;
053    
054    import java.util.ArrayList;
055    import java.util.Date;
056    import java.util.HashMap;
057    import java.util.List;
058    import java.util.Map;
059    
060    /**
061     * Provides the local service for accessing, adding, deleting, importing,
062     * subscription handling of, trash handling of, and updating wiki nodes.
063     *
064     * @author Brian Wing Shun Chan
065     * @author Charles May
066     * @author Raymond Aug??
067     */
068    public class WikiNodeLocalServiceImpl extends WikiNodeLocalServiceBaseImpl {
069    
070            @Override
071            public WikiNode addDefaultNode(long userId, ServiceContext serviceContext)
072                    throws PortalException, SystemException {
073    
074                    return addNode(
075                            userId, PropsValues.WIKI_INITIAL_NODE_NAME, StringPool.BLANK,
076                            serviceContext);
077            }
078    
079            @Override
080            public WikiNode addNode(
081                            long userId, String name, String description,
082                            ServiceContext serviceContext)
083                    throws PortalException, SystemException {
084    
085                    // Node
086    
087                    User user = userPersistence.findByPrimaryKey(userId);
088                    long groupId = serviceContext.getScopeGroupId();
089                    Date now = new Date();
090    
091                    validate(groupId, name);
092    
093                    long nodeId = counterLocalService.increment();
094    
095                    WikiNode node = wikiNodePersistence.create(nodeId);
096    
097                    node.setUuid(serviceContext.getUuid());
098                    node.setGroupId(groupId);
099                    node.setCompanyId(user.getCompanyId());
100                    node.setUserId(user.getUserId());
101                    node.setUserName(user.getFullName());
102                    node.setCreateDate(serviceContext.getCreateDate(now));
103                    node.setModifiedDate(serviceContext.getModifiedDate(now));
104                    node.setName(name);
105                    node.setDescription(description);
106    
107                    try {
108                            wikiNodePersistence.update(node);
109                    }
110                    catch (SystemException se) {
111                            if (_log.isWarnEnabled()) {
112                                    _log.warn(
113                                            "Add failed, fetch {groupId=" + groupId + ", name=" +
114                                                    name + "}");
115                            }
116    
117                            node = wikiNodePersistence.fetchByG_N(groupId, name, false);
118    
119                            if (node == null) {
120                                    throw se;
121                            }
122    
123                            return node;
124                    }
125    
126                    // Resources
127    
128                    if (serviceContext.isAddGroupPermissions() ||
129                            serviceContext.isAddGuestPermissions()) {
130    
131                            addNodeResources(
132                                    node, serviceContext.isAddGroupPermissions(),
133                                    serviceContext.isAddGuestPermissions());
134                    }
135                    else {
136                            addNodeResources(
137                                    node, serviceContext.getGroupPermissions(),
138                                    serviceContext.getGuestPermissions());
139                    }
140    
141                    return node;
142            }
143    
144            @Override
145            public void addNodeResources(
146                            long nodeId, boolean addGroupPermissions,
147                            boolean addGuestPermissions)
148                    throws PortalException, SystemException {
149    
150                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
151    
152                    addNodeResources(node, addGroupPermissions, addGuestPermissions);
153            }
154    
155            @Override
156            public void addNodeResources(
157                            long nodeId, String[] groupPermissions, String[] guestPermissions)
158                    throws PortalException, SystemException {
159    
160                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
161    
162                    addNodeResources(node, groupPermissions, guestPermissions);
163            }
164    
165            @Override
166            public void addNodeResources(
167                            WikiNode node, boolean addGroupPermissions,
168                            boolean addGuestPermissions)
169                    throws PortalException, SystemException {
170    
171                    resourceLocalService.addResources(
172                            node.getCompanyId(), node.getGroupId(), node.getUserId(),
173                            WikiNode.class.getName(), node.getNodeId(), false,
174                            addGroupPermissions, addGuestPermissions);
175            }
176    
177            @Override
178            public void addNodeResources(
179                            WikiNode node, String[] groupPermissions, String[] guestPermissions)
180                    throws PortalException, SystemException {
181    
182                    resourceLocalService.addModelResources(
183                            node.getCompanyId(), node.getGroupId(), node.getUserId(),
184                            WikiNode.class.getName(), node.getNodeId(), groupPermissions,
185                            guestPermissions);
186            }
187    
188            @Override
189            public void deleteNode(long nodeId)
190                    throws PortalException, SystemException {
191    
192                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
193    
194                    wikiNodeLocalService.deleteNode(node);
195            }
196    
197            @Override
198            @SystemEvent(
199                    action = SystemEventConstants.ACTION_SKIP,
200                    type = SystemEventConstants.TYPE_DELETE)
201            public void deleteNode(WikiNode node)
202                    throws PortalException, SystemException {
203    
204                    // Pages
205    
206                    wikiPageLocalService.deletePages(node.getNodeId());
207    
208                    // Node
209    
210                    wikiNodePersistence.remove(node);
211    
212                    // Resources
213    
214                    resourceLocalService.deleteResource(
215                            node.getCompanyId(), WikiNode.class.getName(),
216                            ResourceConstants.SCOPE_INDIVIDUAL, node.getNodeId());
217    
218                    // Attachments
219    
220                    long folderId = node.getAttachmentsFolderId();
221    
222                    if (folderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
223                            PortletFileRepositoryUtil.deleteFolder(folderId);
224                    }
225    
226                    // Subscriptions
227    
228                    subscriptionLocalService.deleteSubscriptions(
229                            node.getCompanyId(), WikiNode.class.getName(), node.getNodeId());
230    
231                    if (node.isInTrash()) {
232                            node.setName(TrashUtil.getOriginalTitle(node.getName()));
233    
234                            // Trash
235    
236                            trashEntryLocalService.deleteEntry(
237                                    WikiNode.class.getName(), node.getNodeId());
238    
239                            // Indexer
240    
241                            Indexer wikiNodeIndexer = IndexerRegistryUtil.nullSafeGetIndexer(
242                                    WikiNode.class);
243    
244                            wikiNodeIndexer.delete(node);
245                    }
246    
247                    // Indexer
248    
249                    Indexer wikiPageIndexer = IndexerRegistryUtil.nullSafeGetIndexer(
250                            WikiPage.class);
251    
252                    wikiPageIndexer.delete(node);
253            }
254    
255            @Override
256            public void deleteNodes(long groupId)
257                    throws PortalException, SystemException {
258    
259                    List<WikiNode> nodes = wikiNodePersistence.findByGroupId(groupId);
260    
261                    for (WikiNode node : nodes) {
262                            wikiNodeLocalService.deleteNode(node);
263                    }
264    
265                    PortletFileRepositoryUtil.deletePortletRepository(
266                            groupId, PortletKeys.WIKI);
267            }
268    
269            @Override
270            public WikiNode fetchNode(long groupId, String name)
271                    throws SystemException {
272    
273                    return wikiNodePersistence.fetchByG_N(groupId, name);
274            }
275    
276            @Override
277            public WikiNode fetchNodeByUuidAndGroupId(String uuid, long groupId)
278                    throws SystemException {
279    
280                    return wikiNodePersistence.fetchByUUID_G(uuid, groupId);
281            }
282    
283            @Override
284            public List<WikiNode> getCompanyNodes(long companyId, int start, int end)
285                    throws SystemException {
286    
287                    return wikiNodePersistence.findByC_S(
288                            companyId, WorkflowConstants.STATUS_APPROVED, start, end);
289            }
290    
291            @Override
292            public List<WikiNode> getCompanyNodes(
293                            long companyId, int status, int start, int end)
294                    throws SystemException {
295    
296                    return wikiNodePersistence.findByC_S(companyId, status, start, end);
297            }
298    
299            @Override
300            public int getCompanyNodesCount(long companyId) throws SystemException {
301                    return wikiNodePersistence.countByC_S(
302                            companyId, WorkflowConstants.STATUS_APPROVED);
303            }
304    
305            @Override
306            public int getCompanyNodesCount(long companyId, int status)
307                    throws SystemException {
308    
309                    return wikiNodePersistence.countByC_S(companyId, status);
310            }
311    
312            @Override
313            public WikiNode getNode(long nodeId)
314                    throws PortalException, SystemException {
315    
316                    return wikiNodePersistence.findByPrimaryKey(nodeId);
317            }
318    
319            @Override
320            public WikiNode getNode(long groupId, String nodeName)
321                    throws PortalException, SystemException {
322    
323                    return wikiNodePersistence.findByG_N(groupId, nodeName);
324            }
325    
326            @Override
327            public List<WikiNode> getNodes(long groupId)
328                    throws PortalException, SystemException {
329    
330                    return getNodes(groupId, WorkflowConstants.STATUS_APPROVED);
331            }
332    
333            @Override
334            public List<WikiNode> getNodes(long groupId, int status)
335                    throws PortalException, SystemException {
336    
337                    List<WikiNode> nodes = wikiNodePersistence.findByG_S(groupId, status);
338    
339                    if (nodes.isEmpty()) {
340                            nodes = addDefaultNode(groupId);
341                    }
342    
343                    return nodes;
344            }
345    
346            @Override
347            public List<WikiNode> getNodes(long groupId, int start, int end)
348                    throws PortalException, SystemException {
349    
350                    return getNodes(groupId, WorkflowConstants.STATUS_APPROVED, start, end);
351            }
352    
353            @Override
354            public List<WikiNode> getNodes(long groupId, int status, int start, int end)
355                    throws PortalException, SystemException {
356    
357                    List<WikiNode> nodes = wikiNodePersistence.findByG_S(
358                            groupId, status, start, end);
359    
360                    if (nodes.isEmpty()) {
361                            nodes = addDefaultNode(groupId);
362                    }
363    
364                    return nodes;
365            }
366    
367            @Override
368            public int getNodesCount(long groupId) throws SystemException {
369                    return wikiNodePersistence.countByG_S(
370                            groupId, WorkflowConstants.STATUS_APPROVED);
371            }
372    
373            @Override
374            public int getNodesCount(long groupId, int status) throws SystemException {
375                    return wikiNodePersistence.countByG_S(groupId, status);
376            }
377    
378            @Override
379            public void importPages(
380                            long userId, long nodeId, String importer,
381                            InputStream[] inputStreams, Map<String, String[]> options)
382                    throws PortalException, SystemException {
383    
384                    WikiNode node = getNode(nodeId);
385    
386                    WikiImporter wikiImporter = getWikiImporter(importer);
387    
388                    wikiImporter.importPages(userId, node, inputStreams, options);
389            }
390    
391            @Override
392            public WikiNode moveNodeToTrash(long userId, long nodeId)
393                    throws PortalException, SystemException {
394    
395                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
396    
397                    return moveNodeToTrash(userId, node);
398            }
399    
400            @Override
401            public WikiNode moveNodeToTrash(long userId, WikiNode node)
402                    throws PortalException, SystemException {
403    
404                    node = updateStatus(
405                            userId, node, WorkflowConstants.STATUS_IN_TRASH,
406                            new ServiceContext());
407    
408                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
409                            WikiNode.class.getName(), node.getNodeId());
410    
411                    String trashTitle = TrashUtil.getTrashTitle(trashEntry.getEntryId());
412    
413                    node.setName(trashTitle);
414    
415                    return wikiNodePersistence.update(node);
416            }
417    
418            @Override
419            public void restoreNodeFromTrash(long userId, WikiNode node)
420                    throws PortalException, SystemException {
421    
422                    String name = TrashUtil.getOriginalTitle(node.getName());
423    
424                    node.setName(name);
425    
426                    wikiNodePersistence.update(node);
427    
428                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
429                            WikiNode.class.getName(), node.getNodeId());
430    
431                    updateStatus(
432                            userId, node, trashEntry.getStatus(), new ServiceContext());
433            }
434    
435            @Override
436            public void subscribeNode(long userId, long nodeId)
437                    throws PortalException, SystemException {
438    
439                    WikiNode node = getNode(nodeId);
440    
441                    subscriptionLocalService.addSubscription(
442                            userId, node.getGroupId(), WikiNode.class.getName(), nodeId);
443            }
444    
445            @Override
446            public void unsubscribeNode(long userId, long nodeId)
447                    throws PortalException, SystemException {
448    
449                    subscriptionLocalService.deleteSubscription(
450                            userId, WikiNode.class.getName(), nodeId);
451            }
452    
453            @Override
454            public WikiNode updateNode(
455                            long nodeId, String name, String description,
456                            ServiceContext serviceContext)
457                    throws PortalException, SystemException {
458    
459                    WikiNode node = wikiNodePersistence.findByPrimaryKey(nodeId);
460    
461                    validate(nodeId, node.getGroupId(), name);
462    
463                    node.setModifiedDate(serviceContext.getModifiedDate(null));
464                    node.setName(name);
465                    node.setDescription(description);
466    
467                    wikiNodePersistence.update(node);
468    
469                    return node;
470            }
471    
472            @Override
473            public WikiNode updateStatus(
474                            long userId, WikiNode node, int status,
475                            ServiceContext serviceContext)
476                    throws PortalException, SystemException {
477    
478                    // Node
479    
480                    int oldStatus = node.getStatus();
481    
482                    User user = userPersistence.findByPrimaryKey(userId);
483    
484                    Date now = new Date();
485    
486                    node.setStatus(status);
487                    node.setStatusByUserId(userId);
488                    node.setStatusByUserName(user.getFullName());
489                    node.setStatusDate(now);
490    
491                    wikiNodePersistence.update(node);
492    
493                    // Pages
494    
495                    updateDependentStatus(node.getNodeId(), status);
496    
497                    // Trash
498    
499                    if (oldStatus == WorkflowConstants.STATUS_IN_TRASH) {
500                            trashEntryLocalService.deleteEntry(
501                                    WikiNode.class.getName(), node.getNodeId());
502                    }
503                    else if (status == WorkflowConstants.STATUS_IN_TRASH) {
504                            UnicodeProperties typeSettingsProperties = new UnicodeProperties();
505    
506                            typeSettingsProperties.put("title", node.getName());
507    
508                            trashEntryLocalService.addTrashEntry(
509                                    userId, node.getGroupId(), WikiNode.class.getName(),
510                                    node.getNodeId(), oldStatus, null, typeSettingsProperties);
511                    }
512    
513                    // Indexer
514    
515                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
516                            WikiNode.class);
517    
518                    if (status == WorkflowConstants.STATUS_IN_TRASH) {
519                            indexer.reindex(node);
520                    }
521                    else {
522                            indexer.delete(node);
523                    }
524    
525                    return node;
526            }
527    
528            protected List<WikiNode> addDefaultNode(long groupId)
529                    throws PortalException, SystemException {
530    
531                    Group group = groupPersistence.findByPrimaryKey(groupId);
532    
533                    long defaultUserId = userLocalService.getDefaultUserId(
534                            group.getCompanyId());
535    
536                    ServiceContext serviceContext = new ServiceContext();
537    
538                    serviceContext.setAddGroupPermissions(true);
539                    serviceContext.setAddGuestPermissions(true);
540                    serviceContext.setScopeGroupId(groupId);
541    
542                    WikiNode node = wikiNodeLocalService.addDefaultNode(
543                            defaultUserId, serviceContext);
544    
545                    List<WikiNode> nodes = new ArrayList<WikiNode>(1);
546    
547                    nodes.add(node);
548    
549                    return nodes;
550            }
551    
552            protected WikiImporter getWikiImporter(String importer)
553                    throws SystemException {
554    
555                    WikiImporter wikiImporter = _wikiImporters.get(importer);
556    
557                    if (wikiImporter == null) {
558                            String importerClass = PropsUtil.get(
559                                    PropsKeys.WIKI_IMPORTERS_CLASS, new Filter(importer));
560    
561                            if (importerClass != null) {
562                                    wikiImporter = (WikiImporter)InstancePool.get(importerClass);
563    
564                                    _wikiImporters.put(importer, wikiImporter);
565                            }
566    
567                            if (importer == null) {
568                                    throw new SystemException(
569                                            "Unable to instantiate wiki importer class " +
570                                                    importerClass);
571                            }
572                    }
573    
574                    return wikiImporter;
575            }
576    
577            protected void updateDependentStatus(long nodeId, int status)
578                    throws PortalException, SystemException {
579    
580                    List<WikiPage> pages = wikiPagePersistence.findByNodeId(nodeId);
581    
582                    for (WikiPage page : pages) {
583                            if (status == WorkflowConstants.STATUS_IN_TRASH) {
584                                    if (page.getStatus() == WorkflowConstants.STATUS_APPROVED) {
585                                            assetEntryLocalService.updateVisible(
586                                                    WikiPage.class.getName(), page.getResourcePrimKey(),
587                                                    false);
588                                    }
589    
590                                    // Index
591    
592                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
593                                            WikiPage.class);
594    
595                                    indexer.reindex(page);
596    
597                                    // Cache
598    
599                                    if (WikiCacheThreadLocal.isClearCache()) {
600                                            WikiCacheUtil.clearCache(page.getNodeId());
601                                    }
602    
603                                    if (page.getStatus() == WorkflowConstants.STATUS_PENDING) {
604                                            page.setStatus(WorkflowConstants.STATUS_DRAFT);
605    
606                                            wikiPagePersistence.update(page);
607    
608                                            workflowInstanceLinkLocalService.deleteWorkflowInstanceLink(
609                                                    page.getCompanyId(), page.getGroupId(),
610                                                    WikiPage.class.getName(), page.getResourcePrimKey());
611                                    }
612                            }
613                            else {
614    
615                                    // Asset
616    
617                                    if (page.getStatus() == WorkflowConstants.STATUS_APPROVED) {
618                                            assetEntryLocalService.updateVisible(
619                                                    WikiPage.class.getName(), page.getResourcePrimKey(),
620                                                    true);
621                                    }
622    
623                                    // Index
624    
625                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
626                                            WikiPage.class);
627    
628                                    indexer.reindex(page);
629                            }
630                    }
631            }
632    
633            protected void validate(long nodeId, long groupId, String name)
634                    throws PortalException, SystemException {
635    
636                    if (name.equalsIgnoreCase("tag")) {
637                            throw new NodeNameException(name + " is reserved");
638                    }
639    
640                    if (Validator.isNull(name)) {
641                            throw new NodeNameException();
642                    }
643    
644                    WikiNode node = wikiNodePersistence.fetchByG_N(groupId, name);
645    
646                    if ((node != null) && (node.getNodeId() != nodeId)) {
647                            throw new DuplicateNodeNameException();
648                    }
649            }
650    
651            protected void validate(long groupId, String name)
652                    throws PortalException, SystemException {
653    
654                    validate(0, groupId, name);
655            }
656    
657            private static Log _log = LogFactoryUtil.getLog(
658                    WikiNodeLocalServiceImpl.class);
659    
660            private Map<String, WikiImporter> _wikiImporters =
661                    new HashMap<String, WikiImporter>();
662    
663    }