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                            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 = new ArrayList<>();
228    
229                    PermissionChecker permissionChecker = getPermissionChecker();
230    
231                    for (TrashEntry entry : entries) {
232                            String className = entry.getClassName();
233                            long classPK = entry.getClassPK();
234    
235                            try {
236                                    TrashHandler trashHandler =
237                                            TrashHandlerRegistryUtil.getTrashHandler(className);
238    
239                                    if (trashHandler.hasTrashPermission(
240                                                    permissionChecker, 0, classPK, ActionKeys.VIEW)) {
241    
242                                            filteredEntries.add(entry);
243                                    }
244                            }
245                            catch (Exception e) {
246                                    _log.error(e, e);
247                            }
248                    }
249    
250                    int total = filteredEntries.size();
251    
252                    if ((start == QueryUtil.ALL_POS) && (end == QueryUtil.ALL_POS)) {
253                            start = 0;
254                            end = total;
255                    }
256    
257                    int[] startAndEnd = SearchPaginationUtil.calculateStartAndEnd(
258                            start, end, total);
259    
260                    start = startAndEnd[0];
261                    end = startAndEnd[1];
262    
263                    filteredEntries = filteredEntries.subList(start, end);
264    
265                    trashEntriesList.setArray(TrashEntrySoap.toSoapModels(filteredEntries));
266                    trashEntriesList.setCount(total);
267    
268                    return trashEntriesList;
269            }
270    
271            /**
272             * Moves the trash entry with the entity class name and primary key,
273             * restoring it to a new location identified by the destination container
274             * model ID.
275             *
276             * <p>
277             * This method throws a {@link TrashPermissionException} if the user did not
278             * have the permission to perform one of the necessary operations. The
279             * exception is created with a type specific to the operation:
280             * </p>
281             *
282             * <ul>
283             * <li>
284             * {@link TrashPermissionException#MOVE} - if the user did not have
285             * permission to move the trash entry to the new
286             * destination
287             * </li>
288             * <li>
289             * {@link TrashPermissionException#RESTORE} - if the user did not have
290             * permission to restore the trash entry
291             * </li>
292             * </ul>
293             *
294             * @param  className the class name of the entity
295             * @param  classPK the primary key of the entity
296             * @param  destinationContainerModelId the primary key of the new location
297             * @param  serviceContext the service context to be applied (optionally
298             *         <code>null</code>)
299             * @throws PortalException if a matching trash entry could not be found, if
300             *         the user did not have permission to move the trash entry to the
301             *         new location, if the user did not have permission to restore the
302             *         trash entry, if a duplicate trash entry exists at the new
303             *         location, or if a portal exception occurred
304             */
305            @Override
306            public void moveEntry(
307                            String className, long classPK, long destinationContainerModelId,
308                            ServiceContext serviceContext)
309                    throws PortalException {
310    
311                    PermissionChecker permissionChecker = getPermissionChecker();
312    
313                    long scopeGroupId = 0;
314    
315                    if (serviceContext != null) {
316                            scopeGroupId = serviceContext.getScopeGroupId();
317                    }
318    
319                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
320                            className);
321    
322                    destinationContainerModelId =
323                            trashHandler.getDestinationContainerModelId(
324                                    classPK, destinationContainerModelId);
325    
326                    if (!trashHandler.hasTrashPermission(
327                                    permissionChecker, scopeGroupId, destinationContainerModelId,
328                                    TrashActionKeys.MOVE)) {
329    
330                            throw new TrashPermissionException(TrashPermissionException.MOVE);
331                    }
332    
333                    if (trashHandler.isInTrash(classPK) &&
334                            !trashHandler.hasTrashPermission(
335                                    permissionChecker, 0, classPK, TrashActionKeys.RESTORE)) {
336    
337                            throw new TrashPermissionException(
338                                    TrashPermissionException.RESTORE);
339                    }
340    
341                    TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);
342    
343                    if (trashEntry.isTrashEntry(className, classPK)) {
344                            trashHandler.checkRestorableEntry(
345                                    trashEntry, destinationContainerModelId, StringPool.BLANK);
346                    }
347                    else {
348                            trashHandler.checkRestorableEntry(
349                                    classPK, destinationContainerModelId, StringPool.BLANK);
350                    }
351    
352                    trashHandler.moveTrashEntry(
353                            getUserId(), classPK, destinationContainerModelId, serviceContext);
354            }
355    
356            @Override
357            public TrashEntry restoreEntry(long entryId) throws PortalException {
358                    return restoreEntry(entryId, 0, null);
359            }
360    
361            /**
362             * Restores the trash entry to its original location. In order to handle a
363             * duplicate trash entry already existing at the original location, either
364             * pass in the primary key of the existing trash entry's entity to overwrite
365             * or pass in a new name to give to the trash entry being restored.
366             *
367             * <p>
368             * This method throws a {@link TrashPermissionException} if the user did not
369             * have the permission to perform one of the necessary operations. The
370             * exception is created with a type specific to the operation:
371             * </p>
372             *
373             * <ul>
374             * <li>
375             * {@link TrashPermissionException#RESTORE} - if the user did not have
376             * permission to restore the trash entry
377             * </li>
378             * <li>
379             * {@link TrashPermissionException#RESTORE_OVERWRITE} - if the user did not
380             * have permission to delete the existing trash entry
381             * </li>
382             * <li>
383             * {@link TrashPermissionException#RESTORE_RENAME} - if the user did not
384             * have permission to rename the trash entry
385             * </li>
386             * </ul>
387             *
388             * @param  entryId the primary key of the trash entry to restore
389             * @param  overrideClassPK the primary key of the entity to overwrite
390             *         (optionally <code>0</code>)
391             * @param  name a new name to give to the trash entry being restored
392             *         (optionally <code>null</code>)
393             * @return the restored trash entry
394             * @throws PortalException if a matching trash entry could not be found, if
395             *         the user did not have permission to overwrite an existing trash
396             *         entry, to rename the trash entry being restored, or to restore
397             *         the trash entry in general
398             */
399            @Override
400            public TrashEntry restoreEntry(
401                            long entryId, long overrideClassPK, String name)
402                    throws PortalException {
403    
404                    PermissionChecker permissionChecker = getPermissionChecker();
405    
406                    TrashEntry entry = trashEntryPersistence.findByPrimaryKey(entryId);
407    
408                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
409                            entry.getClassName());
410    
411                    if (!trashHandler.hasTrashPermission(
412                                    permissionChecker, 0, entry.getClassPK(),
413                                    TrashActionKeys.RESTORE)) {
414    
415                            throw new TrashPermissionException(
416                                    TrashPermissionException.RESTORE);
417                    }
418    
419                    if (overrideClassPK > 0) {
420                            if (!trashHandler.hasTrashPermission(
421                                            permissionChecker, 0, overrideClassPK,
422                                            TrashActionKeys.OVERWRITE)) {
423    
424                                    throw new TrashPermissionException(
425                                            TrashPermissionException.RESTORE_OVERWRITE);
426                            }
427    
428                            trashHandler.deleteTrashEntry(overrideClassPK);
429    
430                            trashHandler.checkRestorableEntry(
431                                    entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, null);
432                    }
433                    else if (name != null) {
434                            if (!trashHandler.hasTrashPermission(
435                                            permissionChecker, 0, entry.getClassPK(),
436                                            TrashActionKeys.RENAME)) {
437    
438                                    throw new TrashPermissionException(
439                                            TrashPermissionException.RESTORE_RENAME);
440                            }
441    
442                            trashHandler.checkRestorableEntry(
443                                    entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, name);
444    
445                            trashHandler.updateTitle(entry.getClassPK(), name);
446                    }
447    
448                    trashHandler.restoreTrashEntry(getUserId(), entry.getClassPK());
449    
450                    return entry;
451            }
452    
453            @Override
454            public TrashEntry restoreEntry(String className, long classPK)
455                    throws PortalException {
456    
457                    return restoreEntry(className, classPK, 0, null);
458            }
459    
460            @Override
461            public TrashEntry restoreEntry(
462                            String className, long classPK, long overrideClassPK, String name)
463                    throws PortalException {
464    
465                    TrashEntry trashEntry = trashEntryPersistence.fetchByC_C(
466                            classNameLocalService.getClassNameId(className), classPK);
467    
468                    if (trashEntry != null) {
469                            return restoreEntry(trashEntry.getEntryId(), overrideClassPK, name);
470                    }
471    
472                    return null;
473            }
474    
475            protected void deleteEntry(TrashEntry entry) throws PortalException {
476                    PermissionChecker permissionChecker = getPermissionChecker();
477    
478                    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(
479                            entry.getClassName());
480    
481                    if (!trashHandler.hasTrashPermission(
482                                    permissionChecker, 0, entry.getClassPK(), ActionKeys.DELETE)) {
483    
484                            throw new TrashPermissionException(TrashPermissionException.DELETE);
485                    }
486    
487                    trashHandler.deleteTrashEntry(entry.getClassPK());
488            }
489    
490            private static final Log _log = LogFactoryUtil.getLog(
491                    TrashEntryServiceImpl.class);
492    
493    }