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