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.journal.service.impl;
016    
017    import com.liferay.portal.kernel.dao.orm.QueryDefinition;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.exception.PortalException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.json.JSONFactoryUtil;
022    import com.liferay.portal.kernel.json.JSONObject;
023    import com.liferay.portal.kernel.search.Indexable;
024    import com.liferay.portal.kernel.search.IndexableType;
025    import com.liferay.portal.kernel.search.Indexer;
026    import com.liferay.portal.kernel.search.IndexerRegistryUtil;
027    import com.liferay.portal.kernel.systemevent.SystemEvent;
028    import com.liferay.portal.kernel.util.ContentTypes;
029    import com.liferay.portal.kernel.util.OrderByComparator;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.TreeModelFinder;
032    import com.liferay.portal.kernel.util.TreePathUtil;
033    import com.liferay.portal.kernel.util.UnicodeProperties;
034    import com.liferay.portal.kernel.workflow.WorkflowConstants;
035    import com.liferay.portal.model.ResourceConstants;
036    import com.liferay.portal.model.SystemEventConstants;
037    import com.liferay.portal.model.TreeModel;
038    import com.liferay.portal.model.User;
039    import com.liferay.portal.service.ServiceContext;
040    import com.liferay.portal.util.PropsValues;
041    import com.liferay.portlet.asset.model.AssetEntry;
042    import com.liferay.portlet.asset.model.AssetLinkConstants;
043    import com.liferay.portlet.asset.util.AssetUtil;
044    import com.liferay.portlet.journal.DuplicateFolderNameException;
045    import com.liferay.portlet.journal.FolderNameException;
046    import com.liferay.portlet.journal.model.JournalArticle;
047    import com.liferay.portlet.journal.model.JournalFolder;
048    import com.liferay.portlet.journal.model.JournalFolderConstants;
049    import com.liferay.portlet.journal.service.base.JournalFolderLocalServiceBaseImpl;
050    import com.liferay.portlet.journal.util.comparator.FolderIdComparator;
051    import com.liferay.portlet.social.model.SocialActivityConstants;
052    import com.liferay.portlet.trash.model.TrashEntry;
053    import com.liferay.portlet.trash.model.TrashVersion;
054    import com.liferay.portlet.trash.util.TrashUtil;
055    
056    import java.util.ArrayList;
057    import java.util.Date;
058    import java.util.List;
059    
060    /**
061     * @author Juan Fern??ndez
062     */
063    public class JournalFolderLocalServiceImpl
064            extends JournalFolderLocalServiceBaseImpl {
065    
066            @Override
067            public JournalFolder addFolder(
068                            long userId, long groupId, long parentFolderId, String name,
069                            String description, ServiceContext serviceContext)
070                    throws PortalException, SystemException {
071    
072                    // Folder
073    
074                    User user = userPersistence.findByPrimaryKey(userId);
075                    parentFolderId = getParentFolderId(groupId, parentFolderId);
076                    Date now = new Date();
077    
078                    validateFolder(0, groupId, parentFolderId, name);
079    
080                    long folderId = counterLocalService.increment();
081    
082                    JournalFolder folder = journalFolderPersistence.create(folderId);
083    
084                    folder.setUuid(serviceContext.getUuid());
085                    folder.setGroupId(groupId);
086                    folder.setCompanyId(user.getCompanyId());
087                    folder.setUserId(user.getUserId());
088                    folder.setUserName(user.getFullName());
089                    folder.setCreateDate(serviceContext.getCreateDate(now));
090                    folder.setModifiedDate(serviceContext.getModifiedDate(now));
091                    folder.setParentFolderId(parentFolderId);
092                    folder.setTreePath(folder.buildTreePath());
093                    folder.setName(name);
094                    folder.setDescription(description);
095                    folder.setExpandoBridgeAttributes(serviceContext);
096    
097                    journalFolderPersistence.update(folder);
098    
099                    // Resources
100    
101                    resourceLocalService.addModelResources(folder, serviceContext);
102    
103                    // Asset
104    
105                    updateAsset(
106                            userId, folder, serviceContext.getAssetCategoryIds(),
107                            serviceContext.getAssetTagNames(),
108                            serviceContext.getAssetLinkEntryIds());
109    
110                    return folder;
111            }
112    
113            @Indexable(type = IndexableType.DELETE)
114            @Override
115            @SystemEvent(
116                    action = SystemEventConstants.ACTION_SKIP, send = false,
117                    type = SystemEventConstants.TYPE_DELETE)
118            public JournalFolder deleteFolder(JournalFolder folder)
119                    throws PortalException, SystemException {
120    
121                    return deleteFolder(folder, true);
122            }
123    
124            @Indexable(type = IndexableType.DELETE)
125            @Override
126            @SystemEvent(
127                    action = SystemEventConstants.ACTION_SKIP, send = false,
128                    type = SystemEventConstants.TYPE_DELETE)
129            public JournalFolder deleteFolder(
130                            JournalFolder folder, boolean includeTrashedEntries)
131                    throws PortalException, SystemException {
132    
133                    // Folders
134    
135                    List<JournalFolder> folders = journalFolderPersistence.findByG_P(
136                            folder.getGroupId(), folder.getFolderId());
137    
138                    for (JournalFolder curFolder : folders) {
139                            if (includeTrashedEntries || !curFolder.isInTrashExplicitly()) {
140                                    deleteFolder(curFolder, includeTrashedEntries);
141                            }
142                    }
143    
144                    // Folder
145    
146                    journalFolderPersistence.remove(folder);
147    
148                    // Resources
149    
150                    resourceLocalService.deleteResource(
151                            folder, ResourceConstants.SCOPE_INDIVIDUAL);
152    
153                    // Entries
154    
155                    journalArticleLocalService.deleteArticles(
156                            folder.getGroupId(), folder.getFolderId(), includeTrashedEntries);
157    
158                    // Asset
159    
160                    assetEntryLocalService.deleteEntry(
161                            JournalFolder.class.getName(), folder.getFolderId());
162    
163                    // Expando
164    
165                    expandoValueLocalService.deleteValues(
166                            JournalFolder.class.getName(), folder.getFolderId());
167    
168                    // Trash
169    
170                    trashEntryLocalService.deleteEntry(
171                            JournalFolder.class.getName(), folder.getFolderId());
172    
173                    return folder;
174            }
175    
176            @Indexable(type = IndexableType.DELETE)
177            @Override
178            public JournalFolder deleteFolder(long folderId)
179                    throws PortalException, SystemException {
180    
181                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
182                            folderId);
183    
184                    return journalFolderLocalService.deleteFolder(folder, true);
185            }
186    
187            @Indexable(type = IndexableType.DELETE)
188            @Override
189            public JournalFolder deleteFolder(
190                            long folderId, boolean includeTrashedEntries)
191                    throws PortalException, SystemException {
192    
193                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
194                            folderId);
195    
196                    return journalFolderLocalService.deleteFolder(
197                            folder, includeTrashedEntries);
198            }
199    
200            @Override
201            public void deleteFolders(long groupId)
202                    throws PortalException, SystemException {
203    
204                    List<JournalFolder> folders = journalFolderPersistence.findByGroupId(
205                            groupId);
206    
207                    for (JournalFolder folder : folders) {
208                            journalFolderLocalService.deleteFolder(folder);
209                    }
210            }
211    
212            @Override
213            public JournalFolder fetchFolder(long folderId) throws SystemException {
214                    return journalFolderPersistence.fetchByPrimaryKey(folderId);
215            }
216    
217            @Override
218            public JournalFolder fetchFolder(
219                            long groupId, long parentFolderId, String name)
220                    throws SystemException {
221    
222                    return journalFolderPersistence.fetchByG_P_N(
223                                    groupId, parentFolderId, name);
224            }
225    
226            @Override
227            public JournalFolder fetchFolder(long groupId, String name)
228                    throws SystemException {
229    
230                    return journalFolderPersistence.fetchByG_N(groupId, name);
231            }
232    
233            @Override
234            public List<JournalFolder> getCompanyFolders(
235                            long companyId, int start, int end)
236                    throws SystemException {
237    
238                    return journalFolderPersistence.findByCompanyId(companyId, start, end);
239            }
240    
241            @Override
242            public int getCompanyFoldersCount(long companyId) throws SystemException {
243                    return journalFolderPersistence.countByCompanyId(companyId);
244            }
245    
246            @Override
247            public JournalFolder getFolder(long folderId)
248                    throws PortalException, SystemException {
249    
250                    return journalFolderPersistence.findByPrimaryKey(folderId);
251            }
252    
253            @Override
254            public List<JournalFolder> getFolders(long groupId) throws SystemException {
255                    return journalFolderPersistence.findByGroupId(groupId);
256            }
257    
258            @Override
259            public List<JournalFolder> getFolders(long groupId, long parentFolderId)
260                    throws SystemException {
261    
262                    return getFolders(
263                            groupId, parentFolderId, WorkflowConstants.STATUS_APPROVED);
264            }
265    
266            @Override
267            public List<JournalFolder> getFolders(
268                            long groupId, long parentFolderId, int status)
269                    throws SystemException {
270    
271                    return journalFolderPersistence.findByG_P_S(
272                            groupId, parentFolderId, status);
273            }
274    
275            @Override
276            public List<JournalFolder> getFolders(
277                            long groupId, long parentFolderId, int start, int end)
278                    throws SystemException {
279    
280                    return getFolders(
281                            groupId, parentFolderId, WorkflowConstants.STATUS_APPROVED, start,
282                            end);
283            }
284    
285            @Override
286            public List<JournalFolder> getFolders(
287                            long groupId, long parentFolderId, int status, int start, int end)
288                    throws SystemException {
289    
290                    return journalFolderPersistence.findByG_P_S(
291                                    groupId, parentFolderId, status, start, end);
292            }
293    
294            @Override
295            public List<Object> getFoldersAndArticles(long groupId, long folderId)
296                    throws SystemException {
297    
298                    QueryDefinition queryDefinition = new QueryDefinition(
299                            WorkflowConstants.STATUS_ANY);
300    
301                    return journalFolderFinder.findF_A_ByG_F(
302                            groupId, folderId, queryDefinition);
303            }
304    
305            @Override
306            public List<Object> getFoldersAndArticles(
307                            long groupId, long folderId, int status)
308                    throws SystemException {
309    
310                    QueryDefinition queryDefinition = new QueryDefinition(status);
311    
312                    return journalFolderFinder.findF_A_ByG_F(
313                            groupId, folderId, queryDefinition);
314            }
315    
316            @Override
317            public List<Object> getFoldersAndArticles(
318                            long groupId, long folderId, int start, int end,
319                            OrderByComparator obc)
320                    throws SystemException {
321    
322                    QueryDefinition queryDefinition = new QueryDefinition(
323                            WorkflowConstants.STATUS_ANY, start, end, obc);
324    
325                    return journalFolderFinder.findF_A_ByG_F(
326                            groupId, folderId, queryDefinition);
327            }
328    
329            @Override
330            public int getFoldersAndArticlesCount(
331                            long groupId, List<Long> folderIds, int status)
332                    throws SystemException {
333    
334                    QueryDefinition queryDefinition = new QueryDefinition(status);
335    
336                    if (folderIds.size() <= PropsValues.SQL_DATA_MAX_PARAMETERS) {
337                            return journalArticleFinder.countByG_F(
338                                    groupId, folderIds, queryDefinition);
339                    }
340                    else {
341                            int start = 0;
342                            int end = PropsValues.SQL_DATA_MAX_PARAMETERS;
343    
344                            int articlesCount = journalArticleFinder.countByG_F(
345                                    groupId, folderIds.subList(start, end), queryDefinition);
346    
347                            folderIds.subList(start, end).clear();
348    
349                            articlesCount += getFoldersAndArticlesCount(
350                                    groupId, folderIds, status);
351    
352                            return articlesCount;
353                    }
354            }
355    
356            @Override
357            public int getFoldersAndArticlesCount(long groupId, long folderId)
358                    throws SystemException {
359    
360                    QueryDefinition queryDefinition = new QueryDefinition(
361                            WorkflowConstants.STATUS_ANY);
362    
363                    return journalFolderFinder.countF_A_ByG_F(
364                            groupId, folderId, queryDefinition);
365            }
366    
367            @Override
368            public int getFoldersAndArticlesCount(
369                            long groupId, long folderId, int status)
370                    throws SystemException {
371    
372                    QueryDefinition queryDefinition = new QueryDefinition(status, 0, false);
373    
374                    return journalFolderFinder.countF_A_ByG_F(
375                            groupId, folderId, queryDefinition);
376            }
377    
378            @Override
379            public int getFoldersCount(long groupId, long parentFolderId)
380                    throws SystemException {
381    
382                    return getFoldersCount(
383                            groupId, parentFolderId, WorkflowConstants.STATUS_APPROVED);
384            }
385    
386            @Override
387            public int getFoldersCount(long groupId, long parentFolderId, int status)
388                    throws SystemException {
389    
390                    return journalFolderPersistence.countByG_P_S(
391                            groupId, parentFolderId, status);
392            }
393    
394            @Override
395            public List<JournalFolder> getNoAssetFolders() throws SystemException {
396                    return journalFolderFinder.findF_ByNoAssets();
397            }
398    
399            @Override
400            public void getSubfolderIds(
401                            List<Long> folderIds, long groupId, long folderId)
402                    throws SystemException {
403    
404                    List<JournalFolder> folders = journalFolderPersistence.findByG_P(
405                            groupId, folderId);
406    
407                    for (JournalFolder folder : folders) {
408                            folderIds.add(folder.getFolderId());
409    
410                            getSubfolderIds(
411                                    folderIds, folder.getGroupId(), folder.getFolderId());
412                    }
413            }
414    
415            @Indexable(type = IndexableType.REINDEX)
416            @Override
417            public JournalFolder moveFolder(
418                            long folderId, long parentFolderId, ServiceContext serviceContext)
419                    throws PortalException, SystemException {
420    
421                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
422                            folderId);
423    
424                    parentFolderId = getParentFolderId(folder, parentFolderId);
425    
426                    if (folder.getParentFolderId() == parentFolderId) {
427                            return folder;
428                    }
429    
430                    validateFolder(
431                            folder.getFolderId(), folder.getGroupId(), parentFolderId,
432                            folder.getName());
433    
434                    folder.setModifiedDate(serviceContext.getModifiedDate(null));
435                    folder.setParentFolderId(parentFolderId);
436                    folder.setTreePath(folder.buildTreePath());
437                    folder.setExpandoBridgeAttributes(serviceContext);
438    
439                    journalFolderPersistence.update(folder);
440    
441                    rebuildTree(
442                            folder.getCompanyId(), folderId, folder.getTreePath(), true);
443    
444                    return folder;
445            }
446    
447            @Override
448            public JournalFolder moveFolderFromTrash(
449                            long userId, long folderId, long parentFolderId,
450                            ServiceContext serviceContext)
451                    throws PortalException, SystemException {
452    
453                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
454                            folderId);
455    
456                    if (folder.isInTrashExplicitly()) {
457                            restoreFolderFromTrash(userId, folderId);
458                    }
459                    else {
460    
461                            // Folder
462    
463                            TrashEntry trashEntry = folder.getTrashEntry();
464    
465                            TrashVersion trashVersion =
466                                    trashVersionLocalService.fetchVersion(
467                                            trashEntry.getEntryId(), JournalFolder.class.getName(),
468                                            folderId);
469    
470                            int status = WorkflowConstants.STATUS_APPROVED;
471    
472                            if (trashVersion != null) {
473                                    status = trashVersion.getStatus();
474                            }
475    
476                            updateStatus(userId, folder, status);
477    
478                            // Trash
479    
480                            if (trashVersion != null) {
481                                    trashVersionLocalService.deleteTrashVersion(trashVersion);
482                            }
483    
484                            // Folders and articles
485    
486                            List<Object> foldersAndArticles =
487                                    journalFolderLocalService.getFoldersAndArticles(
488                                            folder.getGroupId(), folder.getFolderId(),
489                                            WorkflowConstants.STATUS_IN_TRASH);
490    
491                            restoreDependentsFromTrash(
492                                    foldersAndArticles, trashEntry.getEntryId());
493                    }
494    
495                    return journalFolderLocalService.moveFolder(
496                            folderId, parentFolderId, serviceContext);
497            }
498    
499            @Override
500            public JournalFolder moveFolderToTrash(long userId, long folderId)
501                    throws PortalException, SystemException {
502    
503                    // Folder
504    
505                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
506                            folderId);
507    
508                    String title = folder.getName();
509    
510                    folder = updateStatus(
511                            userId, folder, WorkflowConstants.STATUS_IN_TRASH);
512    
513                    // Trash
514    
515                    UnicodeProperties typeSettingsProperties = new UnicodeProperties();
516    
517                    typeSettingsProperties.put("title", folder.getName());
518    
519                    TrashEntry trashEntry = trashEntryLocalService.addTrashEntry(
520                            userId, folder.getGroupId(), JournalFolder.class.getName(),
521                            folder.getFolderId(), folder.getUuid(), null,
522                            WorkflowConstants.STATUS_APPROVED, null, typeSettingsProperties);
523    
524                    folder.setName(TrashUtil.getTrashTitle(trashEntry.getEntryId()));
525    
526                    journalFolderPersistence.update(folder);
527    
528                    // Folders and articles
529    
530                    List<Object> foldersAndArticles =
531                            journalFolderLocalService.getFoldersAndArticles(
532                                    folder.getGroupId(), folder.getFolderId());
533    
534                    moveDependentsToTrash(foldersAndArticles, trashEntry.getEntryId());
535    
536                    // Social
537    
538                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
539    
540                    extraDataJSONObject.put("title", title);
541    
542                    socialActivityLocalService.addActivity(
543                            userId, folder.getGroupId(), JournalFolder.class.getName(),
544                            folder.getFolderId(), SocialActivityConstants.TYPE_MOVE_TO_TRASH,
545                            extraDataJSONObject.toString(), 0);
546    
547                    return folder;
548            }
549    
550            @Override
551            public void rebuildTree(long companyId)
552                    throws PortalException, SystemException {
553    
554                    rebuildTree(
555                            companyId, JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID,
556                            StringPool.SLASH, false);
557            }
558    
559            @Override
560            public void rebuildTree(
561                            long companyId, long parentFolderId, String parentTreePath,
562                            final boolean reindex)
563                    throws PortalException, SystemException {
564    
565                    TreePathUtil.rebuildTree(
566                            companyId, parentFolderId, parentTreePath,
567                            new TreeModelFinder<JournalFolder>() {
568    
569                                    @Override
570                                    public List<JournalFolder> findTreeModels(
571                                                    long previousId, long companyId, long parentPrimaryKey,
572                                                    int size)
573                                            throws SystemException {
574    
575                                            return journalFolderPersistence.findByF_C_P_NotS(
576                                                    previousId, companyId, parentPrimaryKey,
577                                                    WorkflowConstants.STATUS_IN_TRASH, QueryUtil.ALL_POS,
578                                                    size, new FolderIdComparator());
579                                    }
580    
581                                    @Override
582                                    public void rebuildDependentModelsTreePaths(
583                                                    long parentPrimaryKey, String treePath)
584                                            throws PortalException, SystemException {
585    
586                                            journalArticleLocalService.setTreePaths(
587                                                    parentPrimaryKey, treePath, false);
588                            }
589    
590                                    @Override
591                                    public void reindexTreeModels(List<TreeModel> treeModels)
592                                            throws PortalException {
593    
594                                            if (!reindex) {
595                                                    return;
596                                            }
597    
598                                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
599                                                    JournalFolder.class);
600    
601                                            for (TreeModel treeModel : treeModels) {
602                                                    indexer.reindex(treeModel);
603                                            }
604                                    }
605                            }
606                    );
607            }
608    
609            @Override
610            public void restoreFolderFromTrash(long userId, long folderId)
611                    throws PortalException, SystemException {
612    
613                    // Folder
614    
615                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
616                            folderId);
617    
618                    folder.setName(TrashUtil.getOriginalTitle(folder.getName()));
619    
620                    journalFolderPersistence.update(folder);
621    
622                    TrashEntry trashEntry = trashEntryLocalService.getEntry(
623                            JournalFolder.class.getName(), folderId);
624    
625                    updateStatus(userId, folder, trashEntry.getStatus());
626    
627                    // Folders and articles
628    
629                    List<Object> foldersAndArticles =
630                            journalFolderLocalService.getFoldersAndArticles(
631                                    folder.getGroupId(), folder.getFolderId(),
632                                    WorkflowConstants.STATUS_IN_TRASH);
633    
634                    restoreDependentsFromTrash(foldersAndArticles, trashEntry.getEntryId());
635    
636                    // Trash
637    
638                    trashEntryLocalService.deleteEntry(
639                            JournalFolder.class.getName(), folder.getFolderId());
640    
641                    // Social
642    
643                    JSONObject extraDataJSONObject = JSONFactoryUtil.createJSONObject();
644    
645                    extraDataJSONObject.put("title", folder.getName());
646    
647                    socialActivityLocalService.addActivity(
648                            userId, folder.getGroupId(), JournalFolder.class.getName(),
649                            folder.getFolderId(),
650                            SocialActivityConstants.TYPE_RESTORE_FROM_TRASH,
651                            extraDataJSONObject.toString(), 0);
652            }
653    
654            @Override
655            public void updateAsset(
656                            long userId, JournalFolder folder, long[] assetCategoryIds,
657                            String[] assetTagNames, long[] assetLinkEntryIds)
658                    throws PortalException, SystemException {
659    
660                    AssetEntry assetEntry = assetEntryLocalService.updateEntry(
661                            userId, folder.getGroupId(), folder.getCreateDate(),
662                            folder.getModifiedDate(), JournalFolder.class.getName(),
663                            folder.getFolderId(), folder.getUuid(), 0, assetCategoryIds,
664                            assetTagNames, true, null, null, null, ContentTypes.TEXT_PLAIN,
665                            folder.getName(), folder.getDescription(), null, null, null, 0, 0,
666                            null, false);
667    
668                    assetLinkLocalService.updateLinks(
669                            userId, assetEntry.getEntryId(), assetLinkEntryIds,
670                            AssetLinkConstants.TYPE_RELATED);
671            }
672    
673            @Indexable(type = IndexableType.REINDEX)
674            @Override
675            public JournalFolder updateFolder(
676                            long userId, long folderId, long parentFolderId, String name,
677                            String description, boolean mergeWithParentFolder,
678                            ServiceContext serviceContext)
679                    throws PortalException, SystemException {
680    
681                    // Merge folders
682    
683                    JournalFolder folder = journalFolderPersistence.findByPrimaryKey(
684                            folderId);
685    
686                    parentFolderId = getParentFolderId(folder, parentFolderId);
687    
688                    if (mergeWithParentFolder && (folderId != parentFolderId)) {
689                            mergeFolders(folder, parentFolderId);
690    
691                            return folder;
692                    }
693    
694                    // Folder
695    
696                    validateFolder(folderId, folder.getGroupId(), parentFolderId, name);
697    
698                    long oldParentFolderId = folder.getParentFolderId();
699    
700                    if (oldParentFolderId != parentFolderId) {
701                            folder.setParentFolderId(parentFolderId);
702                            folder.setTreePath(folder.buildTreePath());
703                    }
704    
705                    folder.setModifiedDate(serviceContext.getModifiedDate(null));
706                    folder.setName(name);
707                    folder.setDescription(description);
708                    folder.setExpandoBridgeAttributes(serviceContext);
709    
710                    journalFolderPersistence.update(folder);
711    
712                    // Asset
713    
714                    updateAsset(
715                            userId, folder, serviceContext.getAssetCategoryIds(),
716                            serviceContext.getAssetTagNames(),
717                            serviceContext.getAssetLinkEntryIds());
718    
719                    if (oldParentFolderId != parentFolderId) {
720                            rebuildTree(
721                                    folder.getCompanyId(), folderId, folder.getTreePath(), true);
722                    }
723    
724                    return folder;
725            }
726    
727            @Override
728            public JournalFolder updateStatus(
729                            long userId, JournalFolder folder, int status)
730                    throws PortalException, SystemException {
731    
732                    // Folder
733    
734                    User user = userPersistence.findByPrimaryKey(userId);
735    
736                    folder.setStatus(status);
737                    folder.setStatusByUserId(userId);
738                    folder.setStatusByUserName(user.getFullName());
739                    folder.setStatusDate(new Date());
740    
741                    journalFolderPersistence.update(folder);
742    
743                    // Asset
744    
745                    if (status == WorkflowConstants.STATUS_APPROVED) {
746                            assetEntryLocalService.updateVisible(
747                                    JournalFolder.class.getName(), folder.getFolderId(), true);
748                    }
749                    else if (status == WorkflowConstants.STATUS_IN_TRASH) {
750                            assetEntryLocalService.updateVisible(
751                                    JournalFolder.class.getName(), folder.getFolderId(), false);
752                    }
753    
754                    // Index
755    
756                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
757                            JournalFolder.class);
758    
759                    indexer.reindex(folder);
760    
761                    return folder;
762            }
763    
764            protected long getParentFolderId(JournalFolder folder, long parentFolderId)
765                    throws SystemException {
766    
767                    if (parentFolderId == JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
768                            return parentFolderId;
769                    }
770    
771                    if (folder.getFolderId() == parentFolderId) {
772                            return folder.getParentFolderId();
773                    }
774    
775                    JournalFolder parentFolder = journalFolderPersistence.fetchByPrimaryKey(
776                            parentFolderId);
777    
778                    if ((parentFolder == null) ||
779                            (folder.getGroupId() != parentFolder.getGroupId())) {
780    
781                            return folder.getParentFolderId();
782                    }
783    
784                    List<Long> subfolderIds = new ArrayList<Long>();
785    
786                    getSubfolderIds(
787                            subfolderIds, folder.getGroupId(), folder.getFolderId());
788    
789                    if (subfolderIds.contains(parentFolderId)) {
790                            return folder.getParentFolderId();
791                    }
792    
793                    return parentFolderId;
794            }
795    
796            protected long getParentFolderId(long groupId, long parentFolderId)
797                    throws SystemException {
798    
799                    if (parentFolderId != JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID) {
800                            JournalFolder parentFolder =
801                                    journalFolderPersistence.fetchByPrimaryKey(parentFolderId);
802    
803                            if ((parentFolder == null) ||
804                                    (groupId != parentFolder.getGroupId())) {
805    
806                                    parentFolderId =
807                                            JournalFolderConstants.DEFAULT_PARENT_FOLDER_ID;
808                            }
809                    }
810    
811                    return parentFolderId;
812            }
813    
814            protected void mergeFolders(JournalFolder fromFolder, long toFolderId)
815                    throws PortalException, SystemException {
816    
817                    List<JournalFolder> folders = journalFolderPersistence.findByG_P(
818                            fromFolder.getGroupId(), fromFolder.getFolderId());
819    
820                    for (JournalFolder folder : folders) {
821                            mergeFolders(folder, toFolderId);
822                    }
823    
824                    List<JournalArticle> articles = journalArticlePersistence.findByG_F(
825                            fromFolder.getGroupId(), fromFolder.getFolderId());
826    
827                    for (JournalArticle article : articles) {
828                            article.setFolderId(toFolderId);
829                            article.setTreePath(article.buildTreePath());
830    
831                            journalArticlePersistence.update(article);
832    
833                            Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
834                                    JournalArticle.class);
835    
836                            indexer.reindex(article);
837                    }
838    
839                    journalFolderLocalService.deleteFolder(fromFolder);
840            }
841    
842            protected void moveDependentsToTrash(
843                            List<Object> foldersAndArticles, long trashEntryId)
844                    throws PortalException, SystemException {
845    
846                    for (Object object : foldersAndArticles) {
847                            if (object instanceof JournalArticle) {
848    
849                                    // Article
850    
851                                    JournalArticle article = (JournalArticle)object;
852    
853                                    if (article.getStatus() == WorkflowConstants.STATUS_IN_TRASH) {
854                                            continue;
855                                    }
856    
857                                    // Articles
858    
859                                    List<JournalArticle> articles =
860                                            journalArticlePersistence.findByG_A(
861                                                    article.getGroupId(), article.getArticleId());
862    
863                                    for (JournalArticle curArticle : articles) {
864    
865                                            // Article
866    
867                                            int curArticleOldStatus = curArticle.getStatus();
868    
869                                            curArticle.setStatus(WorkflowConstants.STATUS_IN_TRASH);
870    
871                                            journalArticlePersistence.update(curArticle);
872    
873                                            // Trash
874    
875                                            int status = curArticleOldStatus;
876    
877                                            if (curArticleOldStatus ==
878                                                            WorkflowConstants.STATUS_PENDING) {
879    
880                                                    status = WorkflowConstants.STATUS_DRAFT;
881                                            }
882    
883                                            if (curArticleOldStatus !=
884                                                            WorkflowConstants.STATUS_APPROVED) {
885    
886                                                    trashVersionLocalService.addTrashVersion(
887                                                            trashEntryId, JournalArticle.class.getName(),
888                                                            curArticle.getId(), status, null);
889                                            }
890    
891                                            // Workflow
892    
893                                            if (curArticleOldStatus ==
894                                                            WorkflowConstants.STATUS_PENDING) {
895    
896                                                    workflowInstanceLinkLocalService.
897                                                            deleteWorkflowInstanceLink(
898                                                                    curArticle.getCompanyId(),
899                                                                    curArticle.getGroupId(),
900                                                                    JournalArticle.class.getName(),
901                                                                    curArticle.getId());
902                                            }
903                                    }
904    
905                                    // Asset
906    
907                                    assetEntryLocalService.updateVisible(
908                                            JournalArticle.class.getName(),
909                                            article.getResourcePrimKey(), false);
910    
911                                    // Indexer
912    
913                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
914                                            JournalArticle.class);
915    
916                                    indexer.reindex(article);
917                            }
918                            else if (object instanceof JournalFolder) {
919    
920                                    // Folder
921    
922                                    JournalFolder folder = (JournalFolder)object;
923    
924                                    if (folder.isInTrashExplicitly()) {
925                                            continue;
926                                    }
927    
928                                    int oldStatus = folder.getStatus();
929    
930                                    folder.setStatus(WorkflowConstants.STATUS_IN_TRASH);
931    
932                                    journalFolderPersistence.update(folder);
933    
934                                    // Trash
935    
936                                    if (oldStatus != WorkflowConstants.STATUS_APPROVED) {
937                                            trashVersionLocalService.addTrashVersion(
938                                                    trashEntryId, JournalFolder.class.getName(),
939                                                    folder.getFolderId(), oldStatus, null);
940                                    }
941    
942                                    // Folders and articles
943    
944                                    List<Object> curFoldersAndArticles = getFoldersAndArticles(
945                                            folder.getGroupId(), folder.getFolderId());
946    
947                                    moveDependentsToTrash(curFoldersAndArticles, trashEntryId);
948    
949                                    // Asset
950    
951                                    assetEntryLocalService.updateVisible(
952                                            JournalFolder.class.getName(), folder.getFolderId(), false);
953    
954                                    // Index
955    
956                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
957                                            JournalFolder.class);
958    
959                                    indexer.reindex(folder);
960                            }
961                    }
962            }
963    
964            protected void restoreDependentsFromTrash(
965                            List<Object> foldersAndArticles, long trashEntryId)
966                    throws PortalException, SystemException {
967    
968                    for (Object object : foldersAndArticles) {
969                            if (object instanceof JournalArticle) {
970    
971                                    // Article
972    
973                                    JournalArticle article = (JournalArticle)object;
974    
975                                    TrashEntry trashEntry = trashEntryLocalService.fetchEntry(
976                                            JournalArticle.class.getName(),
977                                            article.getResourcePrimKey());
978    
979                                    if (trashEntry != null) {
980                                            continue;
981                                    }
982    
983                                    TrashVersion trashVersion =
984                                            trashVersionLocalService.fetchVersion(
985                                                    trashEntryId, JournalArticle.class.getName(),
986                                                    article.getId());
987    
988                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
989    
990                                    if (trashVersion != null) {
991                                            oldStatus = trashVersion.getStatus();
992                                    }
993    
994                                    // Articles
995    
996                                    List<JournalArticle> articles =
997                                            journalArticlePersistence.findByG_A(
998                                                    article.getGroupId(), article.getArticleId());
999    
1000                                    for (JournalArticle curArticle : articles) {
1001    
1002                                            // Article
1003    
1004                                            trashVersion =
1005                                                    trashVersionLocalService.fetchVersion(
1006                                                            trashEntryId, JournalArticle.class.getName(),
1007                                                            curArticle.getId());
1008    
1009                                            int curArticleOldStatus = WorkflowConstants.STATUS_APPROVED;
1010    
1011                                            if (trashVersion != null) {
1012                                                    curArticleOldStatus = trashVersion.getStatus();
1013                                            }
1014    
1015                                            curArticle.setStatus(curArticleOldStatus);
1016    
1017                                            journalArticlePersistence.update(curArticle);
1018    
1019                                            // Trash
1020    
1021                                            if (trashVersion != null) {
1022                                                    trashVersionLocalService.deleteTrashVersion(
1023                                                            trashVersion);
1024                                            }
1025                                    }
1026    
1027                                    // Asset
1028    
1029                                    if (oldStatus == WorkflowConstants.STATUS_APPROVED) {
1030                                            assetEntryLocalService.updateVisible(
1031                                                    JournalArticle.class.getName(),
1032                                                    article.getResourcePrimKey(), true);
1033                                    }
1034    
1035                                    // Indexer
1036    
1037                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1038                                            JournalArticle.class);
1039    
1040                                    indexer.reindex(article);
1041                            }
1042                            else if (object instanceof JournalFolder) {
1043    
1044                                    // Folder
1045    
1046                                    JournalFolder folder = (JournalFolder)object;
1047    
1048                                    TrashEntry trashEntry = trashEntryLocalService.fetchEntry(
1049                                            JournalFolder.class.getName(), folder.getFolderId());
1050    
1051                                    if (trashEntry != null) {
1052                                            continue;
1053                                    }
1054    
1055                                    TrashVersion trashVersion =
1056                                            trashVersionLocalService.fetchVersion(
1057                                                    trashEntryId, JournalFolder.class.getName(),
1058                                                    folder.getFolderId());
1059    
1060                                    int oldStatus = WorkflowConstants.STATUS_APPROVED;
1061    
1062                                    if (trashVersion != null) {
1063                                            oldStatus = trashVersion.getStatus();
1064                                    }
1065    
1066                                    folder.setStatus(oldStatus);
1067    
1068                                    journalFolderPersistence.update(folder);
1069    
1070                                    // Folders and articles
1071    
1072                                    List<Object> curFoldersAndArticles = getFoldersAndArticles(
1073                                            folder.getGroupId(), folder.getFolderId(),
1074                                            WorkflowConstants.STATUS_IN_TRASH);
1075    
1076                                    restoreDependentsFromTrash(curFoldersAndArticles, trashEntryId);
1077    
1078                                    // Trash
1079    
1080                                    if (trashVersion != null) {
1081                                            trashVersionLocalService.deleteTrashVersion(trashVersion);
1082                                    }
1083    
1084                                    // Asset
1085    
1086                                    assetEntryLocalService.updateVisible(
1087                                            JournalFolder.class.getName(), folder.getFolderId(), true);
1088    
1089                                    // Index
1090    
1091                                    Indexer indexer = IndexerRegistryUtil.nullSafeGetIndexer(
1092                                            JournalFolder.class);
1093    
1094                                    indexer.reindex(folder);
1095                            }
1096                    }
1097            }
1098    
1099            protected void validateFolder(
1100                            long folderId, long groupId, long parentFolderId, String name)
1101                    throws PortalException, SystemException {
1102    
1103                    validateFolderName(name);
1104    
1105                    JournalFolder folder = journalFolderPersistence.fetchByG_P_N(
1106                            groupId, parentFolderId, name);
1107    
1108                    if ((folder != null) && (folder.getFolderId() != folderId)) {
1109                            throw new DuplicateFolderNameException(name);
1110                    }
1111            }
1112    
1113            protected void validateFolderName(String name) throws PortalException {
1114                    if (!AssetUtil.isValidWord(name)) {
1115                            throw new FolderNameException();
1116                    }
1117    
1118                    if (name.contains("\\\\") || name.contains("//")) {
1119                            throw new FolderNameException();
1120                    }
1121            }
1122    
1123    }