@Override
  public void save(NotificationInfo message) throws Exception {
    boolean created = NotificationSessionManager.createSystemProvider();
    SessionProvider sProvider = NotificationSessionManager.getSessionProvider();
    final ReentrantLock localLock = lock;
    try {
      localLock.lock();
      Node messageHomeNode =
          getOrCreateMessageParent(sProvider, workspace, message.getKey().getId());
      Node messageNode = messageHomeNode.addNode(message.getId(), NTF_MESSAGE);
      messageNode.setProperty(NTF_FROM, message.getFrom());
      messageNode.setProperty(NTF_ORDER, message.getOrder());
      messageNode.setProperty(NTF_PROVIDER_TYPE, message.getKey().getId());
      messageNode.setProperty(NTF_OWNER_PARAMETER, message.getArrayOwnerParameter());
      messageNode.setProperty(NTF_SEND_TO_DAILY, message.getSendToDaily());
      messageNode.setProperty(NTF_SEND_TO_WEEKLY, message.getSendToWeekly());
      messageHomeNode.getSession().save();

      // record statistics insert entity
      if (NotificationContextFactory.getInstance().getStatistics().isStatisticsEnabled()) {
        NotificationContextFactory.getInstance().getStatisticsCollector().insertEntity(NTF_MESSAGE);
      }

    } catch (Exception e) {
      LOG.error("Failed to save the NotificationMessage", e);
    } finally {
      NotificationSessionManager.closeSessionProvider(created);
      localLock.unlock();
    }
  }
  @Override
  public void removeMessageAfterSent() throws Exception {
    final boolean stats =
        NotificationContextFactory.getInstance().getStatistics().isStatisticsEnabled();
    boolean created = NotificationSessionManager.createSystemProvider();
    SessionProvider sProvider = NotificationSessionManager.getSessionProvider();

    try {
      Node notificationHome = getNotificationHomeNode(sProvider, workspace);
      Session session = notificationHome.getSession();
      // remove all
      Set<String> listPaths = removeByCallBack.get(REMOVE_ALL);
      removeByCallBack.remove(REMOVE_ALL);
      if (listPaths != null && listPaths.size() > 0) {
        for (String nodePath : listPaths) {
          try {
            session.getItem(nodePath).remove();
            // record entity delete here
            if (stats) {
              NotificationContextFactory.getInstance()
                  .getStatisticsCollector()
                  .deleteEntity(NTF_MESSAGE);
            }

            LOG.debug("Remove NotificationMessage " + nodePath);
          } catch (Exception e) {
            LOG.warn(
                "Failed to remove node of NotificationMessage " + nodePath + "\n" + e.getMessage());
            LOG.debug("Remove NotificationMessage " + nodePath, e);
          }
        }
        session.save();
      }

      listPaths = removeByCallBack.get(REMOVE_DAILY);
      if (listPaths != null && listPaths.size() > 0) {
        for (String nodePath : listPaths) {
          try {
            Item item = session.getItem(nodePath);
            if (item.isNode()) {
              Node node = (Node) item;
              node.setProperty(NTF_SEND_TO_DAILY, new String[] {""});
            }
            LOG.debug("Remove SendToDaily property " + nodePath);
          } catch (Exception e) {
            LOG.warn(
                "Failed to remove SendToDaily property of " + nodePath + "\n" + e.getMessage());
            LOG.debug("Remove SendToDaily property " + nodePath, e);
          }
        }
        session.save();
      }
    } catch (Exception e) {
      LOG.warn("Failed to remove message after sent email notification", e);
    } finally {
      NotificationSessionManager.closeSessionProvider(created);
    }
  }
  @Override
  public Map<PluginKey, List<NotificationInfo>> getByUser(
      NotificationContext context, UserSetting setting) {
    boolean created = NotificationSessionManager.createSystemProvider();
    SessionProvider sProvider = NotificationSessionManager.getSessionProvider();

    Map<PluginKey, List<NotificationInfo>> notificationData =
        new LinkedHashMap<PluginKey, List<NotificationInfo>>();
    try {
      boolean isWeekly = context.value(NotificationJob.JOB_WEEKLY);
      if (isWeekly) {
        for (String pluginId : setting.getWeeklyPlugins()) {
          putMap(
              notificationData,
              PluginKey.key(pluginId),
              getWeeklyNotifs(sProvider, pluginId, setting.getUserId()));
        }
      }
      //
      boolean isDaily = context.value(NotificationJob.JOB_DAILY);
      if (isDaily) {
        for (String pluginId : setting.getDailyPlugins()) {
          putMap(
              notificationData,
              PluginKey.key(pluginId),
              getDailyNotifs(sProvider, context, pluginId, setting.getUserId()));
        }
      }
    } catch (Exception e) {
      LOG.error("Failed to get the NotificationMessage by user: " + setting.getUserId(), e);
    } finally {
      NotificationSessionManager.closeSessionProvider(created);
    }

    return notificationData;
  }