/**
   * Deletes the trash entries with the matching group ID considering permissions.
   *
   * @param groupId the primary key of the group
   * @throws PortalException if a portal exception occurred
   * @throws SystemException if a system exception occurred
   */
  @Override
  @Transactional(noRollbackFor = {TrashPermissionException.class})
  public void deleteEntries(long groupId) throws PortalException, SystemException {

    boolean throwTrashPermissionException = false;

    List<TrashEntry> entries = trashEntryPersistence.findByGroupId(groupId);

    PermissionChecker permissionChecker = getPermissionChecker();

    for (TrashEntry entry : entries) {
      try {
        TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(entry.getClassName());

        if (!trashHandler.hasTrashPermission(
            permissionChecker, 0, entry.getClassPK(), ActionKeys.VIEW)) {

          continue;
        }

        deleteEntry(entry);
      } catch (TrashPermissionException tpe) {
        throwTrashPermissionException = true;
      } catch (Exception e) {
        _log.error(e, e);
      }
    }

    if (throwTrashPermissionException) {
      throw new TrashPermissionException(TrashPermissionException.EMPTY_TRASH);
    }
  }
  /**
   * Moves the trash entry with the entity class name and primary key, restoring it to a new
   * location identified by the destination container model ID.
   *
   * <p>This method throws a {@link TrashPermissionException} if the user did not have the
   * permission to perform one of the necessary operations. The exception is created with a type
   * specific to the operation:
   *
   * <ul>
   *   <li>{@link TrashPermissionException#MOVE} - if the user did not have permission to move the
   *       trash entry to the new destination
   *   <li>{@link TrashPermissionException#RESTORE} - if the user did not have permission to restore
   *       the trash entry
   * </ul>
   *
   * @param className the class name of the entity
   * @param classPK the primary key of the entity
   * @param destinationContainerModelId the primary key of the new location
   * @param serviceContext the service context to be applied (optionally <code>null</code>)
   * @throws PortalException if a matching trash entry could not be found, if the user did not have
   *     permission to move the trash entry to the new location, if the user did not have permission
   *     to restore the trash entry, if a duplicate trash entry exists at the new location, or if a
   *     portal exception occurred
   */
  @Override
  public void moveEntry(
      String className,
      long classPK,
      long destinationContainerModelId,
      ServiceContext serviceContext)
      throws PortalException {

    PermissionChecker permissionChecker = getPermissionChecker();

    long scopeGroupId = 0;

    if (serviceContext != null) {
      scopeGroupId = serviceContext.getScopeGroupId();
    }

    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);

    destinationContainerModelId =
        trashHandler.getDestinationContainerModelId(classPK, destinationContainerModelId);

    if (!trashHandler.hasTrashPermission(
        permissionChecker, scopeGroupId, destinationContainerModelId, TrashActionKeys.MOVE)) {

      throw new TrashPermissionException(TrashPermissionException.MOVE);
    }

    if (trashHandler.isInTrash(classPK)
        && !trashHandler.hasTrashPermission(
            permissionChecker, 0, classPK, TrashActionKeys.RESTORE)) {

      throw new TrashPermissionException(TrashPermissionException.RESTORE);
    }

    TrashEntry trashEntry = trashHandler.getTrashEntry(classPK);

    if (trashEntry.isTrashEntry(className, classPK)) {
      trashHandler.checkRestorableEntry(trashEntry, destinationContainerModelId, StringPool.BLANK);
    } else {
      trashHandler.checkRestorableEntry(classPK, destinationContainerModelId, StringPool.BLANK);
    }

    trashHandler.moveTrashEntry(getUserId(), classPK, destinationContainerModelId, serviceContext);
  }
  /**
   * Restores the trash entry to its original location. In order to handle a duplicate trash entry
   * already existing at the original location, either pass in the primary key of the existing trash
   * entry's entity to overwrite or pass in a new name to give to the trash entry being restored.
   *
   * <p>This method throws a {@link TrashPermissionException} if the user did not have the
   * permission to perform one of the necessary operations. The exception is created with a type
   * specific to the operation:
   *
   * <ul>
   *   <li>{@link TrashPermissionException#RESTORE} - if the user did not have permission to restore
   *       the trash entry
   *   <li>{@link TrashPermissionException#RESTORE_OVERWRITE} - if the user did not have permission
   *       to delete the existing trash entry
   *   <li>{@link TrashPermissionException#RESTORE_RENAME} - if the user did not have permission to
   *       rename the trash entry
   * </ul>
   *
   * @param entryId the primary key of the trash entry to restore
   * @param overrideClassPK the primary key of the entity to overwrite (optionally <code>0</code>)
   * @param name a new name to give to the trash entry being restored (optionally <code>null</code>)
   * @return the restored trash entry
   * @throws PortalException if a matching trash entry could not be found, if the user did not have
   *     permission to overwrite an existing trash entry, to rename the trash entry being restored,
   *     or to restore the trash entry in general
   */
  @Override
  public TrashEntry restoreEntry(long entryId, long overrideClassPK, String name)
      throws PortalException {

    PermissionChecker permissionChecker = getPermissionChecker();

    TrashEntry entry = trashEntryPersistence.findByPrimaryKey(entryId);

    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(entry.getClassName());

    if (!trashHandler.hasTrashPermission(
        permissionChecker, 0, entry.getClassPK(), TrashActionKeys.RESTORE)) {

      throw new TrashPermissionException(TrashPermissionException.RESTORE);
    }

    if (overrideClassPK > 0) {
      if (!trashHandler.hasTrashPermission(
          permissionChecker, 0, overrideClassPK, TrashActionKeys.OVERWRITE)) {

        throw new TrashPermissionException(TrashPermissionException.RESTORE_OVERWRITE);
      }

      trashHandler.deleteTrashEntry(overrideClassPK);

      trashHandler.checkRestorableEntry(entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, null);
    } else if (name != null) {
      if (!trashHandler.hasTrashPermission(
          permissionChecker, 0, entry.getClassPK(), TrashActionKeys.RENAME)) {

        throw new TrashPermissionException(TrashPermissionException.RESTORE_RENAME);
      }

      trashHandler.checkRestorableEntry(entry, TrashEntryConstants.DEFAULT_CONTAINER_ID, name);

      trashHandler.updateTitle(entry.getClassPK(), name);
    }

    trashHandler.restoreTrashEntry(getUserId(), entry.getClassPK());

    return entry;
  }
  /**
   * Returns a range of all the trash entries matching the group ID.
   *
   * @param groupId the primary key of the group
   * @param start the lower bound of the range of trash entries to return
   * @param end the upper bound of the range of trash entries to return (not inclusive)
   * @param obc the comparator to order the trash entries (optionally <code>null</code>)
   * @return the range of matching trash entries ordered by comparator <code>obc</code>
   * @throws PrincipalException if a system exception occurred
   * @throws SystemException if a system exception occurred
   */
  @Override
  public TrashEntryList getEntries(long groupId, int start, int end, OrderByComparator obc)
      throws PrincipalException, SystemException {

    TrashEntryList trashEntriesList = new TrashEntryList();

    int entriesCount = trashEntryPersistence.countByGroupId(groupId);

    boolean approximate = entriesCount > PropsValues.TRASH_SEARCH_LIMIT;

    trashEntriesList.setApproximate(approximate);

    List<TrashEntry> entries =
        trashEntryPersistence.findByGroupId(groupId, 0, end + PropsValues.TRASH_SEARCH_LIMIT, obc);

    List<TrashEntry> filteredEntries = new ArrayList<TrashEntry>();

    PermissionChecker permissionChecker = getPermissionChecker();

    for (TrashEntry entry : entries) {
      String className = entry.getClassName();
      long classPK = entry.getClassPK();

      try {
        TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);

        if (trashHandler.hasTrashPermission(permissionChecker, 0, classPK, ActionKeys.VIEW)) {

          filteredEntries.add(entry);
        }
      } catch (Exception e) {
        _log.error(e, e);
      }
    }

    int filteredEntriesCount = filteredEntries.size();

    if ((end != QueryUtil.ALL_POS) && (start != QueryUtil.ALL_POS)) {
      if (end > filteredEntriesCount) {
        end = filteredEntriesCount;
      }

      if (start > filteredEntriesCount) {
        start = filteredEntriesCount;
      }

      filteredEntries = filteredEntries.subList(start, end);
    }

    trashEntriesList.setArray(TrashEntrySoap.toSoapModels(filteredEntries));
    trashEntriesList.setCount(filteredEntriesCount);

    return trashEntriesList;
  }
  protected void deleteEntry(TrashEntry entry) throws PortalException {
    PermissionChecker permissionChecker = getPermissionChecker();

    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(entry.getClassName());

    if (!trashHandler.hasTrashPermission(
        permissionChecker, 0, entry.getClassPK(), ActionKeys.DELETE)) {

      throw new TrashPermissionException(TrashPermissionException.DELETE);
    }

    trashHandler.deleteTrashEntry(entry.getClassPK());
  }
  /**
   * Moves the trash entry with the entity class name and primary key, restoring it to a new
   * location identified by the destination container model ID.
   *
   * <p>This method throws a {@link TrashPermissionException} if the user did not have the
   * permission to perform one of the necessary operations. The exception is created with a type
   * specific to the operation:
   *
   * <ul>
   *   <li>{@link TrashPermissionException#MOVE} - if the user did not have permission to move the
   *       trash entry to the new destination
   *   <li>{@link TrashPermissionException#RESTORE} - if the user did not have permission to restore
   *       the trash entry
   * </ul>
   *
   * @param className the class name of the entity
   * @param classPK the primary key of the entity
   * @param destinationContainerModelId the primary key of the new location
   * @param serviceContext the service context to be applied (optionally <code>null</code>)
   * @throws PortalException if a matching trash entry could not be found, if the user did not have
   *     permission to move the trash entry to the new location, if the user did not have permission
   *     to restore the trash entry, if a duplicate trash entry exists at the new location, or if a
   *     portal exception occurred
   * @throws SystemException if a system exception occurred
   */
  @Override
  public void moveEntry(
      String className,
      long classPK,
      long destinationContainerModelId,
      ServiceContext serviceContext)
      throws PortalException, SystemException {

    PermissionChecker permissionChecker = getPermissionChecker();

    TrashEntry entry = trashEntryLocalService.getEntry(className, classPK);

    TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);

    if (!trashHandler.hasTrashPermission(
        permissionChecker, entry.getGroupId(), destinationContainerModelId, TrashActionKeys.MOVE)) {

      throw new TrashPermissionException(TrashPermissionException.MOVE);
    }

    if (trashHandler.isInTrash(classPK)
        && !trashHandler.hasTrashPermission(
            permissionChecker, 0, classPK, TrashActionKeys.RESTORE)) {

      throw new TrashPermissionException(TrashPermissionException.RESTORE);
    }

    trashHandler.checkDuplicateTrashEntry(entry, destinationContainerModelId, StringPool.BLANK);

    if (trashHandler.isInTrash(classPK)) {
      trashHandler.moveTrashEntry(
          getUserId(), classPK, destinationContainerModelId, serviceContext);
    } else {
      trashHandler.moveEntry(getUserId(), classPK, destinationContainerModelId, serviceContext);
    }
  }
  protected List<TrashEntry> filterEntries(List<TrashEntry> entries) throws PrincipalException {

    List<TrashEntry> filteredEntries = new ArrayList<>();

    PermissionChecker permissionChecker = getPermissionChecker();

    for (TrashEntry entry : entries) {
      String className = entry.getClassName();
      long classPK = entry.getClassPK();

      try {
        TrashHandler trashHandler = TrashHandlerRegistryUtil.getTrashHandler(className);

        if (trashHandler.hasTrashPermission(permissionChecker, 0, classPK, ActionKeys.VIEW)) {

          filteredEntries.add(entry);
        }
      } catch (Exception e) {
        _log.error(e, e);
      }
    }

    return filteredEntries;
  }