@Override
  public ServiceResults postCollection(ServiceContext context) throws Exception {
    logger.info("NotificationService: start request.");
    Timer.Context timer = postTimer.time();
    postMeter.mark();
    try {
      validate(null, context.getPayload());
      Notification.PathTokens pathTokens =
          getPathTokens(context.getRequest().getOriginalParameters());
      context.getProperties().put("state", Notification.State.CREATED);
      context.getProperties().put("pathQuery", pathTokens);
      context.setOwner(sm.getApplication());
      ServiceResults results = super.postCollection(context);
      Notification notification = (Notification) results.getEntity();

      // update Notification properties
      if (notification.getStarted() == null || notification.getStarted() == 0) {
        long now = System.currentTimeMillis();
        notification.setStarted(System.currentTimeMillis());
        Map<String, Object> properties = new HashMap<String, Object>(2);
        properties.put("started", notification.getStarted());
        properties.put("state", notification.getState());
        notification.addProperties(properties);
        logger.info(
            "ApplicationQueueMessage: notification {} properties updated in duration {} ms",
            notification.getUuid(),
            System.currentTimeMillis() - now);
      }

      long now = System.currentTimeMillis();
      notificationQueueManager.queueNotification(notification, null);
      logger.info(
          "NotificationService: notification {} post queue duration {} ms ",
          notification.getUuid(),
          System.currentTimeMillis() - now);
      // future: somehow return 202?
      return results;
    } catch (Exception e) {
      logger.error("serialization failed", e);
      throw e;
    } finally {
      timer.stop();
    }
  }
  @Override
  public Entity updateEntity(ServiceRequest request, EntityRef ref, ServicePayload payload)
      throws Exception {

    validate(ref, payload);

    Notification notification = em.get(ref, Notification.class);

    if ("restart".equals(payload.getProperty("restart"))) { // for emergency
      // use only
      payload.getProperties().clear();
      payload.setProperty("restart", "");
      payload.setProperty("errorMessage", "");
      payload.setProperty("deliver", System.currentTimeMillis() + gracePeriod);

      // once finished, immutable
    } else if (notification.getFinished() != null) {
      throw new ForbiddenServiceOperationException(request, "Notification immutable once sent.");

      // once started, only cancel is allowed
    } else if (notification.getStarted() != null) {
      if (payload.getProperty("canceled") != Boolean.TRUE) {
        throw new ForbiddenServiceOperationException(
            request, "Notification has started. You may only set canceled.");
      }
      payload.getProperties().clear();
      payload.setProperty("canceled", Boolean.TRUE);
    }

    Entity response = super.updateEntity(request, ref, payload);

    Long deliver = (Long) payload.getProperty("deliver");
    if (deliver != null) {
      if (!deliver.equals(notification.getDeliver())) {
        notificationQueueManager.queueNotification((Notification) response, null);
      }
    }
    return response;
  }