001    /**
002     * Copyright (c) 2000-present 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.trash.service.impl;
016    
017    import com.liferay.portal.TrashPermissionException;
018    import com.liferay.portal.kernel.dao.orm.QueryUtil;
019    import com.liferay.portal.kernel.dao.search.SearchPaginationUtil;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.log.Log;
022    import com.liferay.portal.kernel.log.LogFactoryUtil;
023    import com.liferay.portal.kernel.transaction.Transactional;
024    import com.liferay.portal.kernel.trash.TrashActionKeys;
025    import com.liferay.portal.kernel.trash.TrashHandler;
026    import com.liferay.portal.kernel.trash.TrashHandlerRegistryUtil;
027    import com.liferay.portal.kernel.util.OrderByComparator;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.security.auth.PrincipalException;
030    import com.liferay.portal.security.permission.ActionKeys;
031    import com.liferay.portal.security.permission.PermissionChecker;
032    import com.liferay.portal.service.ServiceContext;
033    import com.liferay.portal.util.PropsValues;
034    import com.liferay.portlet.trash.model.TrashEntry;
035    import com.liferay.portlet.trash.model.TrashEntryConstants;
036    import com.liferay.portlet.trash.model.TrashEntryList;
037    import com.liferay.portlet.trash.model.TrashEntrySoap;
038    import com.liferay.portlet.trash.model.impl.TrashEntryImpl;
039    import com.liferay.portlet.trash.service.base.TrashEntryServiceBaseImpl;
040    
041    import java.util.ArrayList;
042    import java.util.List;
043    
044    /**
045     * The trash entry remote service is responsible for returning trash entries.
046     * For more information on trash entries services and TrashEntry, see {@link
047     * com.liferay.portlet.trash.service.impl.TrashEntryLocalServiceImpl}.
048     *
049     * @author Julio Camarero
050     * @author Zsolt Berentey
051     */
052    public class TrashEntryServiceImpl extends TrashEntryServiceBaseImpl {
053    
054            /**
055             * Deletes the trash entries with the matching group ID considering
056             * permissions.
057             *
058             * @param  groupId the primary key of the group
059             * @throws PortalException if a portal exception occurred
060             */
061            @Override
062            @Transactional(noRollbackFor = {TrashPermissionException.class})
063            public void deleteEntries(long groupId) throws PortalException {
064                    boolean throwTrashPermissionException = false;
065    
066                    List<TrashEntry> entries = trashEntryPersistence.findByGroupId(groupId);
067    
068                    PermissionChecker permissionChecker = getPermissionChecker();
069    
070                    for (TrashEntry entry : entries) {
071                            entry = trashEntryPersistence.fetchByPrimaryKey(entry.getEntryId());
072    
073                            if (entry == null) {
074                                    continue;
075                            }
076    
077                            try {
078                                    TrashHandler trashHandler =
079                                            TrashHandlerRegistryUtil.getTrashHandler(
080                                                    entry.getClassName());
081    
082                                    if (!trashHandler.hasTrashPermission(
083                                                    permissionChecker, 0, entry.getClassPK(),
084                                                    ActionKeys.VIEW)) {
085    
086                                            continue;
087                                    }
088    
089                                    deleteEntry(entry);
090                            }
091                            catch (TrashPermissionException tpe) {
092                                    throwTrashPermissionException = true;
093                            }
094                            catch (Exception e) {
095                                    _log.error(e, e);
096                            }
097                    }
098    
099                    if (throwTrashPermissionException) {
100                            throw new TrashPermissionException(
101                                    TrashPermissionException.EMPTY_TRASH);
102                    }
103            }
104    
105            /**
106             * Deletes the trash entries with the primary keys.
107             *
108             * @param  entryIds the primary keys of the trash entries
109             * @throws PortalException if a trash entry with the primary key could not
110             *         be found or if the user did not have permission to delete any one
111             *         of the trash entries
112             */
113            @Override
114            @Transactional(noRollbackFor = {TrashPermissionException.class})
115            public void deleteEntries(long[] entryIds) throws PortalException {
116                    boolean throwTrashPermissionException = false;
117    
118                    for (long entryId : entryIds) {
119                            try {
120                                    deleteEntry(entryId);
121                            }
122                            catch (TrashPermissionException tpe) {
123                                    throwTrashPermissionException = true;
124                            }
125                    }
126    
127                    if (throwTrashPermissionException) {
128                            throw new TrashPermissionException(
129                                    TrashPermissionException.EMPTY_TRASH);
130                    }
131            }
132    
133            /**
134             * Deletes the trash entry with the primary key.
135             *
136             * <p>
137             * This method throws a {@link TrashPermissionException} with type {@link
138             * TrashPermissionException#DELETE} if the user did not have permission to
139             * delete the trash entry.
140             * </p>
141             *
142             * @param  entryId the primary key of the trash entry
143             * @throws PortalException if a trash entry with the primary key could not
144             *         be found or if the user did not have permission to delete the
145             *         trash entry
146             */
147            @Override
148            public void deleteEntry(long entryId) throws PortalException {
149                    TrashEntry entry = trashEntryPersistence.findByPrimaryKey(entryId);
150    
151                    deleteEntry(entry);
152            }
153    
154            /**
155             * Deletes the trash entry with the entity class name and class primary key.
156             *
157             * <p>
158             * This method throws a {@link TrashPermissionException} with type {@link
159             * TrashPermissionException#DELETE} if the user did not have permission to
160             * delete the trash entry.
161             * </p>
162             *
163             * @param  className the class name of the entity
164             * @param  classPK the primary key of the entity
165             * @throws PortalException if a trash entry with the entity class name and
166             *         primary key could not be found or if the user did not have
167             *         permission to delete the entry
168             */
169            @Override
170            public void deleteEntry(String className, long classPK)
171                    throws PortalException {
172    
173                    TrashEntry entry = trashEntryLocalService.fetchEntry(
174                            className, classPK);
175    
176                    if (entry == null) {
177                            entry = new TrashEntryImpl();
178    
179                            entry.setClassName(className);
180                            entry.setClassPK(classPK);
181                    }
182    
183                    deleteEntry(entry);
184            }
185    
186            /**
187             * Returns the trash entries with the matching group ID.
188             *
189             * @param  groupId the primary key of the group
190             * @return the matching trash entries
191             * @throws PrincipalException if a principal exception occurred
192             */
193            @Override
194            public TrashEntryList getEntries(long groupId) throws PrincipalException {
195                    return getEntries(groupId, QueryUtil.ALL_POS, QueryUtil.ALL_POS, null);
196            }
197    
198            /**
199             * Returns a range of all the trash entries matching the group ID.
200             *
201             * @param  groupId the primary key of the group
202             * @param  start the lower bound of the range of trash entries to return
203             * @param  end the upper bound of the range of trash entries to return (not
204             *         inclusive)
205             * @param  obc the comparator to order the trash entries (optionally
206             *         <code>null</code>)
207             * @return the range of matching trash entries ordered by comparator
208             *         <code>obc</code>
209             * @throws PrincipalException if a system exception occurred
210             */
211            @Override
212            public TrashEntryList getEntries(
213                            long groupId, int start, int end, OrderByComparator<TrashEntry> obc)
214                    throws PrincipalException {
215    
216                    TrashEntryList trashEntriesList = new TrashEntryList();
217    
218                    int entriesCount = trashEntryPersistence.countByGroupId(groupId);
219    
220                    boolean approximate = entriesCount > PropsValues.TRASH_SEARCH_LIMIT;
221    
222                    trashEntriesList.setApproximate(approximate);
223    
224                    List<TrashEntry> entries = trashEntryPersistence.findByGroupId(
225                            groupId, 0, end + PropsValues.TRASH_SEARCH_LIMIT, obc);
226    
227                    List<TrashEntry> filteredEntries = filterEntries(entries);
228    
229                    int total = filteredEntries.size();
230    
231                    if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
232                            start = 0;
233                            end = total;
234                    }
235    
236                    int[] startAndEnd = SearchPaginationUtil.calculateStartAndEnd(
237                            start, end, total);
238    
239                    start = startAndEnd[0];
240                    end = startAndEnd[1];
241    
242                    filteredEntries = filteredEntries.subList(start, end);
243    
244                    trashEntriesList.setArray(TrashEntrySoap.toSoapModels(filteredEntries));
245                    trashEntriesList.setCount(total);
246    
247                    return trashEntriesList;
248            }
249    
250            @Override
251            public List<TrashEntry> getEntries(long groupId, String className)
252                    throws PrincipalException {
253    
254                    long classNameId = classNameLocalService.getClassNameId(className);
255    
256                    List<TrashEntry> entries = trashEntryPersistence.findByG_C(
257                            groupId, classNameId);
258    
259                    return filterEntries(entries);
260            }
261    
262            /**
263             * Moves the trash entry with the entity class name and primary key,
264             * restoring it to a new location identified by the destination container
265             * model ID.
266             *
267             * <p>
268             * This method throws a {@link TrashPermissionException} if the user did not
269             * have the permission to perform one of the necessary operations. The
270             * exception is created with a type specific to the operation:
271             * </p>
272             *
273             * <ul>
274             * <li>
275             * {@link TrashPermissionException#MOVE} - if the user did not have
276             * permission to move the trash entry to the new
277             * destination
278             * </li>
279             * <li>
280             * {@link TrashPermissionException#RESTORE} - if the user did not have
281             * permission to restore the trash entry
282             * </li>
283             * </ul>
284             *
285             * @param  className the class name of the entity
286             * @param  classPK the primary key of the entity
287             * @param  destinationContainerModelId the primary key of the new location
288             * @param  serviceContext the service context to be applied (optionally
289             *         <code>null</code>)
290             * @throws PortalException if a matching trash entry could not be found, if
291             *         the user did not have permission to move the trash entry to the
292             *         new location, if the user did not have permission to restore the
293             *         trash entry, if a duplicate trash entry exists at the new
294             *         location, or if a portal exception occurred
295             */
296            @Override
297            public void moveEntry(
298                            String className, long classPK, long destinationContainerModelId,
299                            ServiceContext serviceContext)
300                    throws PortalException {
301    
302                    PermissionChecker permissionChecker = getPermissionChecker();
303    
304                    long scopeGroupId = 0;
305    
306                    if (serviceContext != null) {
307                            scopeGroupId = serviceContext.getScopeGroupId();
308                    }
309    
310                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
311                            className);
312    
313                    destinationContainerModelId =
314                            trashHandler.getDestinationContainerModelId(
315                                    classPK, destinationContainerModelId);
316    
317                    if (!trashHandler.hasTrashPermission(
318                                    permissionChecker, scopeGroupId, destinationContainerModelId,
319                                    TrashActionKeys.MOVE)) {
320    
321                            throw new TrashPermissionException(TrashPermissionException.MOVE);
322                    }
323    
324                    if (trashHandler.isInTrash(classPK) &&
325                            !trashHandler.hasTrashPermission(
326                                    permissionChecker, 0, classPK, TrashActionKeys.RESTORE)) {
327    
328                            throw new TrashPermissionException(
329                                    TrashPermissionException.RESTORE);
330                    }
331    
332                    TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);
333    
334                    if (trashEntry.isTrashEntry(className, classPK)) {
335                            trashHandler.checkRestorableEntry(
336                                    trashEntry, destinationContainerModelId, StringPool.BLANK);
337                    }
338                    else {
339                            trashHandler.checkRestorableEntry(
340                                    classPK, destinationContainerModelId, StringPool.BLANK);
341                    }
342    
343                    trashHandler.moveTrashEntry(
344                            getUserId(), classPK, destinationContainerModelId, serviceContext);
345            }
346    
347            @Override
348            public TrashEntry restoreEntry(long entryId) throws PortalException {
349                    return restoreEntry(entryId, 0, null);
350            }
351    
352            /**
353             * Restores the trash entry to its original location. In order to handle a
354             * duplicate trash entry already existing at the original location, either
355             * pass in the primary key of the existing trash entry's entity to overwrite
356             * or pass in a new name to give to the trash entry being restored.
357             *
358             * <p>
359             * This method throws a {@link TrashPermissionException} if the user did not
360             * have the permission to perform one of the necessary operations. The
361             * exception is created with a type specific to the operation:
362             * </p>
363             *
364             * <ul>
365             * <li>
366             * {@link TrashPermissionException#RESTORE} - if the user did not have
367             * permission to restore the trash entry
368             * </li>
369             * <li>
370             * {@link TrashPermissionException#RESTORE_OVERWRITE} - if the user did not
371             * have permission to delete the existing trash entry
372             * </li>
373             * <li>
374             * {@link TrashPermissionException#RESTORE_RENAME} - if the user did not
375             * have permission to rename the trash entry
376             * </li>
377             * </ul>
378             *
379             * @param  entryId the primary key of the trash entry to restore
380             * @param  overrideClassPK the primary key of the entity to overwrite
381             *         (optionally <code>0</code>)
382             * @param  name a new name to give to the trash entry being restored
383             *         (optionally <code>null</code>)
384             * @return the restored trash entry
385             * @throws PortalException if a matching trash entry could not be found, if
386             *         the user did not have permission to overwrite an existing trash
387             *         entry, to rename the trash entry being restored, or to restore
388             *         the trash entry in general
389             */
390            @Override
391            public TrashEntry restoreEntry(
392                            long entryId, long overrideClassPK, String name)
393                    throws PortalException {
394    
395                    PermissionChecker permissionChecker = getPermissionChecker();
396    
397                    TrashEntry entry = trashEntryPersistence.findByPrimaryKey(entryId);
398    
399                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
400                            entry.getClassName());
401    
402                    if (!trashHandler.hasTrashPermission(
403                                    permissionChecker, 0, entry.getClassPK(),
404                                    TrashActionKeys.RESTORE)) {
405    
406                            throw new TrashPermissionException(
407                                    TrashPermissionException.RESTORE);
408                    }
409    
410                    if (overrideClassPK > 0) {
411                            if (!trashHandler.hasTrashPermission(
412                                            permissionChecker, 0, overrideClassPK,
413                                            TrashActionKeys.OVERWRITE)) {
414    
415                                    throw new TrashPermissionException(
416                                            TrashPermissionException.RESTORE_OVERWRITE);
417                            }
418    
419                            trashHandler.deleteTrashEntry(overrideClassPK);
420    
421                            trashHandler.checkRestorableEntry(
422                                    entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, null);
423                    }
424                    else if (name != null) {
425                            if (!trashHandler.hasTrashPermission(
426                                            permissionChecker, 0, entry.getClassPK(),
427                                            TrashActionKeys.RENAME)) {
428    
429                                    throw new TrashPermissionException(
430                                            TrashPermissionException.RESTORE_RENAME);
431                            }
432    
433                            trashHandler.checkRestorableEntry(
434                                    entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, name);
435    
436                            trashHandler.updateTitle(entry.getClassPK(), name);
437                    }
438    
439                    trashHandler.restoreTrashEntry(getUserId(), entry.getClassPK());
440    
441                    return entry;
442            }
443    
444            @Override
445            public TrashEntry restoreEntry(String className, long classPK)
446                    throws PortalException {
447    
448                    return restoreEntry(className, classPK, 0, null);
449            }
450    
451            @Override
452            public TrashEntry restoreEntry(
453                            String className, long classPK, long overrideClassPK, String name)
454                    throws PortalException {
455    
456                    TrashEntry trashEntry = trashEntryPersistence.fetchByC_C(
457                            classNameLocalService.getClassNameId(className), classPK);
458    
459                    if (trashEntry != null) {
460                            return restoreEntry(trashEntry.getEntryId(), overrideClassPK, name);
461                    }
462    
463                    return null;
464            }
465    
466            protected void deleteEntry(TrashEntry entry) throws PortalException {
467                    PermissionChecker permissionChecker = getPermissionChecker();
468    
469                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
470                            entry.getClassName());
471    
472                    if (!trashHandler.hasTrashPermission(
473                                    permissionChecker, 0, entry.getClassPK(), ActionKeys.DELETE)) {
474    
475                            throw new TrashPermissionException(TrashPermissionException.DELETE);
476                    }
477    
478                    trashHandler.deleteTrashEntry(entry.getClassPK());
479            }
480    
481            protected List<TrashEntry> filterEntries(List<TrashEntry> entries)
482                    throws PrincipalException {
483    
484                    List<TrashEntry> filteredEntries = new ArrayList<>();
485    
486                    PermissionChecker permissionChecker = getPermissionChecker();
487    
488                    for (TrashEntry entry : entries) {
489                            String className = entry.getClassName();
490                            long classPK = entry.getClassPK();
491    
492                            try {
493                                    TrashHandler trashHandler =
494                                            TrashHandlerRegistryUtil.getTrashHandler(className);
495    
496                                    if (trashHandler.hasTrashPermission(
497                                                    permissionChecker, 0, classPK, ActionKeys.VIEW)) {
498    
499                                            filteredEntries.add(entry);
500                                    }
501                            }
502                            catch (Exception e) {
503                                    _log.error(e, e);
504                            }
505                    }
506    
507                    return filteredEntries;
508            }
509    
510            private static final Log _log = LogFactoryUtil.getLog(
511                    TrashEntryServiceImpl.class);
512    
513    }