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