

package co.cask.cdap.notifications.service.inmemory;

import co.cask.cdap.data2.dataset2.DatasetFramework;
import co.cask.cdap.notifications.feeds.NotificationFeedManager;
import co.cask.cdap.notifications.service.AbstractNotificationService;
import co.cask.cdap.notifications.service.NotificationException;
import co.cask.cdap.proto.Id;
import co.cask.tephra.TransactionSystemClient;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.inject.Inject;
import org.apache.twill.common.Threads;

import java.lang.reflect.Type;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

/**
 * In-memory Notification service that pushes notifications to subscribers.
 */
public class InMemoryNotificationService extends AbstractNotificationService {
  private ListeningExecutorService executorService;

  @Inject
  public InMemoryNotificationService(DatasetFramework dsFramework, TransactionSystemClient transactionSystemClient,
                                     NotificationFeedManager feedManager) {
    super(dsFramework, transactionSystemClient, feedManager);
  }

  @Override
  protected void startUp() throws Exception {
    executorService = MoreExecutors.listeningDecorator(
      Executors.newSingleThreadExecutor(Threads.createDaemonThreadFactory("notification-publisher-executor")));
  }

  @Override
  protected void shutDown() throws Exception {
    executorService.shutdownNow();
  }

  @Override
  public <N> ListenableFuture<N> publish(final Id.NotificationFeed feed, final N notification,
                                         final Type notificationType)
    throws NotificationException {
    if (executorService == null) {
      throw new IllegalStateException("Publish attempted before Notification service is started.");
    }
    return executorService.submit(new Callable<N>() {
      @Override
      public N call() throws Exception {
        notificationReceived(feed, createGson().toJsonTree(notification, notificationType));
        return notification;
      }
    });
  }
}
