@Override
 public void moveStat(ForeignPK toForeignPK, int actionType, String objectType) {
   SilverTrace.info(
       "statistic", "DefaultStatisticService.deleteHistoryByAction", "root.MSG_GEN_ENTER_METHOD");
   Connection con = getConnection();
   try {
     HistoryObjectDAO.move(con, toForeignPK, actionType, objectType);
   } catch (Exception e) {
     throw new StatisticRuntimeException(
         "DefaultStatisticService().addObjectToHistory()",
         SilverpeasRuntimeException.ERROR,
         "statistic.CANNOT_ADD_VISITE_NODE",
         e);
   } finally {
     DBUtil.close(con);
   }
 }
 @Override
 public Collection<HistoryObjectDetail> getHistoryByObjectAndUser(
     ForeignPK foreignPK, int action, String objectType, String userId) {
   SilverTrace.info(
       "statistic",
       "DefaultStatisticService.getHistoryByObjectAndUser",
       "root.MSG_GEN_ENTER_METHOD");
   Connection con = getConnection();
   try {
     return HistoryObjectDAO.getHistoryDetailByObjectAndUser(con, foreignPK, objectType, userId);
   } catch (Exception e) {
     throw new StatisticRuntimeException(
         "DefaultStatisticService().getHistoryByObjectAndUser()",
         SilverpeasRuntimeException.ERROR,
         "statistic.CANNOT_GET_HISTORY_STATISTICS_PUBLICATION",
         e);
   } finally {
     DBUtil.close(con);
   }
 }
  private Collection<HistoryByUser> getHistoryByObject(
      ForeignPK foreignPK, int action, String objectType, UserDetail[] users) {
    SilverTrace.info(
        "statistic", "DefaultStatisticService.getHistoryByObject()", "root.MSG_GEN_ENTER_METHOD");
    Collection<HistoryObjectDetail> list;
    try {
      list = getHistoryByAction(foreignPK, action, objectType);
    } catch (Exception e) {
      throw new StatisticRuntimeException(
          "DefaultStatisticService.getHistoryByObject()",
          SilverpeasRuntimeException.ERROR,
          "statistic.EX_IMPOSSIBLE_DOBTENIR_LETAT_DES_LECTURES",
          e);
    }
    String[] readerIds = new String[list.size()];
    Date[] date = new Date[list.size()];
    Iterator<HistoryObjectDetail> it = list.iterator();
    int i = 0;
    while (it.hasNext()) {
      HistoryObjectDetail historyObject = it.next();
      readerIds[i] = historyObject.getUserId();
      date[i] = historyObject.getDate();
      i++;
    }
    UserDetail[] controlledUsers =
        OrganizationControllerProvider.getOrganisationController().getUserDetails(readerIds);

    // ajouter à la liste "allUsers" (liste des users des rôles) les users ayant lu mais ne faisant
    // pas partis d'un rôle
    int compteur = 0;
    Collection<UserDetail> allUsers = new ArrayList<>(users.length + controlledUsers.length);
    for (int j = 0; j < users.length; j++) {
      allUsers.add(users[j]);
      compteur = j + 1;
    }
    for (int j = compteur; j < controlledUsers.length; j++) {
      if (!allUsers.contains(controlledUsers[j])) {
        allUsers.add(controlledUsers[j]);
      }
    }

    // création de la liste de tous les utilisateur ayant le droit de lecture
    Collection<HistoryByUser> statByUser = new ArrayList<>(allUsers.size());
    for (UserDetail user : allUsers) {
      if (user != null) {
        HistoryByUser historyByUser = new HistoryByUser(user, null, 0);
        statByUser.add(historyByUser);
      }
    }

    // création d'une liste des accès par utilisateur
    Map<UserDetail, Date> byUser = new HashMap<>(controlledUsers.length);
    Map<UserDetail, Integer> nbAccessbyUser = new HashMap<>(controlledUsers.length);
    for (int j = 0; j < controlledUsers.length; j++) {
      if (controlledUsers[j] != null) {
        // regarder si la date en cours est > à la date enregistrée...
        Object obj = byUser.get(controlledUsers[j]);
        if (obj != null && !obj.toString().equals("Never")) {
          Date dateTab = (Date) obj;
          if (date[j].after(dateTab)) {
            byUser.put(controlledUsers[j], date[j]);
          }
          Object objNb = nbAccessbyUser.get(controlledUsers[j]);
          int nbAccess = 0;
          if (objNb != null) {
            nbAccess = (Integer) objNb;
            nbAccess = nbAccess + 1;
          }
          nbAccessbyUser.put(controlledUsers[j], nbAccess);
        } else {
          byUser.put(controlledUsers[j], date[j]);
          nbAccessbyUser.put(controlledUsers[j], 1);
        }
      }
    }

    // mise à jour de la date de dernier accès et du nombre d'accès pour les utilisateurs ayant lu
    for (final HistoryByUser historyByUser : statByUser) {
      UserDetail user = historyByUser.getUser();
      // recherche de la date de dernier accès
      Date lastAccess = byUser.get(user);
      if (lastAccess != null) {
        historyByUser.setLastAccess(lastAccess);
      }
      // retrieve access number
      Integer nbAccess = nbAccessbyUser.get(user);
      if (nbAccess != null) {
        historyByUser.setNbAccess(nbAccess);
      }
    }

    // Sort list to get readers first
    LastAccessComparatorDesc comparator = new LastAccessComparatorDesc();
    Collections.sort((List<HistoryByUser>) statByUser, comparator);

    SilverTrace.info(
        "statistic", "DefaultStatisticService.getHistoryByObject()", "root.MSG_GEN_EXIT_METHOD");
    return statByUser;
  }