/*
* Copyright © 2014-2015 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.notifications.feeds.service;
import co.cask.cdap.api.dataset.DatasetDefinition;
import co.cask.cdap.api.dataset.DatasetProperties;
import co.cask.cdap.api.dataset.table.Table;
import co.cask.cdap.data2.datafabric.dataset.DatasetsUtil;
import co.cask.cdap.data2.dataset2.DatasetFramework;
import co.cask.cdap.data2.dataset2.lib.table.MDSKey;
import co.cask.cdap.data2.dataset2.lib.table.MetadataStoreDataset;
import co.cask.cdap.data2.dataset2.tx.Transactional;
import co.cask.cdap.proto.Id;
import co.cask.tephra.TransactionExecutor;
import co.cask.tephra.TransactionExecutorFactory;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterators;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.List;
/**
* Implementation of {@link NotificationFeedStore} that access MDS directly.
*/
public final class MDSNotificationFeedStore implements NotificationFeedStore {
private static final Logger LOG = LoggerFactory.getLogger(MDSNotificationFeedStore.class);
// note: these constants should be same as in DefaultStore - this needs refactoring, but currently these pieces
// dependent
private static final String NOTIFICATION_FEED_TABLE = "app.meta";
private static final String TYPE_NOTIFICATION_FEED = "feed";
private Transactional<NotificationFeedMds, MetadataStoreDataset> txnl;
@Inject
public MDSNotificationFeedStore(TransactionExecutorFactory txExecutorFactory, final DatasetFramework dsFramework) {
txnl = Transactional.of(txExecutorFactory, new Supplier<NotificationFeedMds>() {
@Override
public NotificationFeedMds get() {
try {
Id.DatasetInstance notificationsDatasetInstanceId = Id.DatasetInstance.from(Id.Namespace.SYSTEM,
NOTIFICATION_FEED_TABLE);
Table mdsTable = DatasetsUtil.getOrCreateDataset(dsFramework, notificationsDatasetInstanceId, "table",
DatasetProperties.EMPTY, DatasetDefinition.NO_ARGUMENTS,
null);
return new NotificationFeedMds(new MetadataStoreDataset(mdsTable));
} catch (Exception e) {
LOG.debug("Failed to access app.meta table", e);
throw Throwables.propagate(e);
}
}
});
}
@Override
public Id.NotificationFeed createNotificationFeed(final Id.NotificationFeed feed) {
return txnl.executeUnchecked(new TransactionExecutor.Function<NotificationFeedMds, Id.NotificationFeed>() {
@Override
public Id.NotificationFeed apply(NotificationFeedMds input) throws Exception {
MDSKey feedKey = getKey(TYPE_NOTIFICATION_FEED, feed.getNamespaceId(), feed.getCategory(), feed.getName());
Id.NotificationFeed existing = input.feeds.getFirst(feedKey, Id.NotificationFeed.class);
if (existing != null) {
return existing;
}
input.feeds.write(feedKey, feed);
return null;
}
});
}
@Override
public Id.NotificationFeed getNotificationFeed(final Id.NotificationFeed feed) {
return txnl.executeUnchecked(new TransactionExecutor.Function<NotificationFeedMds, Id.NotificationFeed>() {
@Override
public Id.NotificationFeed apply(NotificationFeedMds input) throws Exception {
MDSKey feedKey = getKey(TYPE_NOTIFICATION_FEED, feed.getNamespaceId(), feed.getCategory(), feed.getName());
return input.feeds.getFirst(feedKey, Id.NotificationFeed.class);
}
});
}
@Override
public Id.NotificationFeed deleteNotificationFeed(final Id.NotificationFeed feed) {
return txnl.executeUnchecked(new TransactionExecutor.Function<NotificationFeedMds, Id.NotificationFeed>() {
@Override
public Id.NotificationFeed apply(NotificationFeedMds input) throws Exception {
MDSKey feedKey = getKey(TYPE_NOTIFICATION_FEED, feed.getNamespaceId(), feed.getCategory(), feed.getName());
Id.NotificationFeed existing = input.feeds.getFirst(feedKey, Id.NotificationFeed.class);
if (existing != null) {
input.feeds.deleteAll(feedKey);
}
return existing;
}
});
}
@Override
public List<Id.NotificationFeed> listNotificationFeeds(final Id.Namespace namespace) {
return txnl.executeUnchecked(new TransactionExecutor.Function<NotificationFeedMds, List<Id.NotificationFeed>>() {
@Override
public List<Id.NotificationFeed> apply(NotificationFeedMds input) throws Exception {
MDSKey mdsKey = getKey(TYPE_NOTIFICATION_FEED, namespace.getId());
return input.feeds.list(mdsKey, Id.NotificationFeed.class);
}
});
}
private MDSKey getKey(String... parts) {
return new MDSKey.Builder().add(parts).build();
}
private static final class NotificationFeedMds implements Iterable<MetadataStoreDataset> {
private final MetadataStoreDataset feeds;
private NotificationFeedMds(MetadataStoreDataset metaTable) {
this.feeds = metaTable;
}
@Override
public Iterator<MetadataStoreDataset> iterator() {
return Iterators.singletonIterator(feeds);
}
}
}