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