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