package com.thinkbiganalytics.metadata.core.feed;
/*-
* #%L
* thinkbig-metadata-core
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* 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.
* #L%
*/
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterators;
import com.thinkbiganalytics.metadata.api.category.Category;
import com.thinkbiganalytics.metadata.api.datasource.Datasource;
import com.thinkbiganalytics.metadata.api.datasource.Datasource.ID;
import com.thinkbiganalytics.metadata.api.datasource.DatasourceProvider;
import com.thinkbiganalytics.metadata.api.extension.UserFieldDescriptor;
import com.thinkbiganalytics.metadata.api.feed.Feed;
import com.thinkbiganalytics.metadata.api.feed.FeedCriteria;
import com.thinkbiganalytics.metadata.api.feed.FeedDestination;
import com.thinkbiganalytics.metadata.api.feed.FeedProvider;
import com.thinkbiganalytics.metadata.api.feed.FeedSource;
import com.thinkbiganalytics.metadata.api.feed.PreconditionBuilder;
import com.thinkbiganalytics.metadata.core.AbstractMetadataCriteria;
import com.thinkbiganalytics.metadata.core.feed.BaseFeed.FeedId;
import com.thinkbiganalytics.metadata.core.feed.BaseFeed.FeedPreconditionImpl;
import com.thinkbiganalytics.metadata.sla.api.Metric;
import com.thinkbiganalytics.metadata.sla.api.Obligation;
import com.thinkbiganalytics.metadata.sla.api.ObligationGroup.Condition;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement;
import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreementActionConfiguration;
import com.thinkbiganalytics.metadata.sla.spi.ObligationBuilder;
import com.thinkbiganalytics.metadata.sla.spi.ObligationGroupBuilder;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAgreementBuilder;
import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAgreementProvider;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import javax.inject.Inject;
/**
* A provider of {@link Feed} objects that stores everything in memory.
*/
public class InMemoryFeedProvider implements FeedProvider {
private static final Criteria ALL = new Criteria() {
public boolean apply(BaseFeed input) {
return true;
}
;
};
@Inject
private DatasourceProvider datasetProvider;
@Inject
private ServiceLevelAgreementProvider slaProvider;
private Map<Feed.ID, Feed> feeds = new ConcurrentHashMap<>();
public InMemoryFeedProvider() {
super();
}
public InMemoryFeedProvider(DatasourceProvider datasetProvider) {
super();
this.datasetProvider = datasetProvider;
}
@Inject
public void setDatasourceProvider(DatasourceProvider datasetProvider) {
this.datasetProvider = datasetProvider;
}
@Override
public Feed.ID resolveFeed(Serializable fid) {
if (fid instanceof FeedId) {
return (FeedId) fid;
} else {
return new FeedId(fid);
}
}
@Override
public FeedSource ensureFeedSource(Feed.ID feedId, ID dsId) {
return ensureFeedSource(feedId, dsId, null);
}
@Override
public FeedSource ensureFeedSource(Feed.ID feedId, Datasource.ID dsId, ServiceLevelAgreement.ID slaId) {
BaseFeed feed = (BaseFeed) this.feeds.get(feedId);
Datasource ds = this.datasetProvider.getDatasource(dsId);
if (feed == null) {
throw new FeedCreateException("A feed with the given ID does not exists: " + feedId);
}
if (ds == null) {
throw new FeedCreateException("A dataset with the given ID does not exists: " + dsId);
}
return ensureFeedSource(feed, ds, slaId);
}
@Override
public FeedDestination ensureFeedDestination(Feed.ID feedId, Datasource.ID dsId) {
BaseFeed feed = (BaseFeed) this.feeds.get(feedId);
Datasource ds = this.datasetProvider.getDatasource(dsId);
if (feed == null) {
throw new FeedCreateException("A feed with the given ID does not exists: " + feedId);
}
if (ds == null) {
throw new FeedCreateException("A dataset with the given ID does not exists: " + dsId);
}
return ensureFeedDestination(feed, ds);
}
@Override
public Feed ensureFeed(Category.ID categoryId, String feedSystemName) {
throw new UnsupportedOperationException("Unable to ensure feed by categoryId with InMemoryProvider");
}
@Override
public Feed ensureFeed(String categorySystemName, String feedSystemName) {
return ensureFeed(categorySystemName, feedSystemName, null);
}
@Override
public Feed ensureFeed(String categorySystemName, String name, String descr, ID destId) {
Datasource dds = this.datasetProvider.getDatasource(destId);
if (dds == null) {
throw new FeedCreateException("A dataset with the given ID does not exists: " + destId);
}
BaseFeed feed = (BaseFeed) ensureFeed(categorySystemName, name, descr);
ensureFeedDestination(feed, dds);
return feed;
}
@Override
public Feed ensureFeed(String categorySystemName, String name, String descr, ID srcId, ID destId) {
Datasource sds = this.datasetProvider.getDatasource(srcId);
Datasource dds = this.datasetProvider.getDatasource(destId);
if (sds == null) {
throw new FeedCreateException("A dataset with the given ID does not exists: " + srcId);
}
if (dds == null) {
throw new FeedCreateException("A dataset with the given ID does not exists: " + destId);
}
BaseFeed feed = (BaseFeed) ensureFeed(categorySystemName, name, descr);
ensureFeedSource(feed, sds, null);
ensureFeedDestination(feed, dds);
return feed;
}
@Override
public Feed ensureFeed(String categorySystemName, String name, String descr) {
synchronized (this.feeds) {
for (Feed feed : this.feeds.values()) {
if (feed.getName().equals(name)) {
return feed;
}
}
}
BaseFeed newFeed = new BaseFeed(name, descr);
this.feeds.put(newFeed.getId(), newFeed);
return newFeed;
}
@Override
public void removeFeedSources(Feed.ID feedId) {
}
@Override
public void removeFeedSource(Feed.ID feedId, ID dsId) {
}
@Override
public void removeFeedDestination(Feed.ID feedId, ID dsId) {
}
@Override
public void removeFeedDestinations(Feed.ID feedId) {
}
@Override
public Feed createPrecondition(Feed.ID feedId, String descr, List<Metric> metrics) {
BaseFeed feed = (BaseFeed) this.feeds.get(feedId);
if (feed != null) {
// Remove the old one if any
FeedPreconditionImpl precond = (FeedPreconditionImpl) feed.getPrecondition();
if (precond != null) {
this.slaProvider.removeAgreement(precond.getAgreement().getId());
}
ServiceLevelAgreement sla = this.slaProvider.builder()
.name("Precondition for feed " + feed.getName() + " (" + feed.getId() + ")")
.description(descr)
.obligationBuilder(Condition.REQUIRED)
.metric(metrics)
.build()
.build();
return setupPrecondition(feed, sla);
} else {
throw new FeedCreateException("A feed with the given ID does not exists: " + feedId);
}
}
@Override
public PreconditionBuilder buildPrecondition(final Feed.ID feedId) {
BaseFeed feed = (BaseFeed) this.feeds.get(feedId);
if (feed != null) {
ServiceLevelAgreementBuilder slaBldr = this.slaProvider.builder();
return new PreconditionbuilderImpl(slaBldr, feed);
} else {
throw new FeedCreateException("A feed with the given ID does not exists: " + feedId);
}
}
@Override
public Feed addDependent(com.thinkbiganalytics.metadata.api.feed.Feed.ID targetId, com.thinkbiganalytics.metadata.api.feed.Feed.ID dependentId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Feed removeDependent(com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId, com.thinkbiganalytics.metadata.api.feed.Feed.ID depId) {
// TODO Auto-generated method stub
return null;
}
@Override
public FeedCriteria feedCriteria() {
return new Criteria();
}
@Override
public Feed getFeed(Feed.ID id) {
return this.feeds.get(id);
}
@Override
public List<Feed> getFeeds() {
return getFeeds(ALL);
}
@Override
public Feed findBySystemName(String systemName) {
return findBySystemName(null, systemName);
}
@Override
public Feed findBySystemName(String categorySystemName, String systemName) {
FeedCriteria c = feedCriteria();
if (categorySystemName != null) {
c.category(categorySystemName);
}
c.name(systemName);
List<Feed> feeds = getFeeds(c);
if (feeds != null && !feeds.isEmpty()) {
return feeds.get(0);
}
return null;
}
@Override
public List<Feed> getFeeds(FeedCriteria criteria) {
Criteria critImpl = (Criteria) criteria;
Iterator<Feed> filtered = Iterators.filter(this.feeds.values().iterator(), critImpl);
Iterator<Feed> limited = Iterators.limit(filtered, critImpl.getLimit());
return ImmutableList.copyOf(limited);
}
@Override
public boolean enableFeed(Feed.ID id) {
BaseFeed feed = (BaseFeed) getFeed(id);
if (feed != null) {
feed.setState(Feed.State.ENABLED);
return true;
}
return false;
}
@Override
public boolean disableFeed(Feed.ID id) {
BaseFeed feed = (BaseFeed) getFeed(id);
if (feed != null) {
feed.setState(Feed.State.DISABLED);
return true;
}
return false;
}
@Override
public void deleteFeed(@Nonnull final Feed.ID feedId) {
feeds.remove(feedId);
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#create(java.lang.Object)
*/
@Override
public Feed create(Feed t) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#findById(java.io.Serializable)
*/
@Override
public Feed findById(com.thinkbiganalytics.metadata.api.feed.Feed.ID id) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#findAll()
*/
@Override
public List<Feed> findAll() {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#update(java.lang.Object)
*/
@Override
public Feed update(Feed t) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#delete(java.lang.Object)
*/
@Override
public void delete(Feed t) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#deleteById(java.io.Serializable)
*/
@Override
public void deleteById(com.thinkbiganalytics.metadata.api.feed.Feed.ID id) {
// TODO Auto-generated method stub
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.BaseProvider#resolveId(java.io.Serializable)
*/
@Override
public com.thinkbiganalytics.metadata.api.feed.Feed.ID resolveId(Serializable fid) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.feed.FeedProvider#findByTemplateId(com.thinkbiganalytics.metadata.api.template.FeedManagerTemplate.ID)
*/
@Override
public List<? extends Feed> findByTemplateId(com.thinkbiganalytics.metadata.api.template.FeedManagerTemplate.ID templateId) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.feed.FeedProvider#findByCategoryId(com.thinkbiganalytics.metadata.api.category.Category.ID)
*/
@Override
public List<? extends Feed> findByCategoryId(com.thinkbiganalytics.metadata.api.category.Category.ID categoryId) {
// TODO Auto-generated method stub
return null;
}
private FeedSource ensureFeedSource(BaseFeed feed, Datasource ds, ServiceLevelAgreement.ID slaId) {
Map<Datasource.ID, FeedSource> srcIds = new HashMap<>();
for (FeedSource src : feed.getSources()) {
srcIds.put(src.getDatasource().getId(), src);
}
if (srcIds.containsKey(ds.getId())) {
return srcIds.get(ds.getId());
} else {
ServiceLevelAgreement sla = this.slaProvider.getAgreement(slaId);
FeedSource src = feed.addSource(ds, sla);
return src;
}
}
private FeedDestination ensureFeedDestination(BaseFeed feed, Datasource ds) {
FeedDestination dest = feed.getDestination(ds.getId());
if (dest != null) {
return dest;
} else {
dest = feed.addDestination(ds);
return dest;
}
}
private Feed setupPrecondition(BaseFeed feed, ServiceLevelAgreement sla) {
feed.setPrecondition(sla);
return feed;
}
@Override
public Feed updateFeedServiceLevelAgreement(Feed.ID feedId, ServiceLevelAgreement sla) {
return null;
}
@Override
public Map<String, Object> mergeFeedProperties(Feed.ID feedId, Map<String, Object> properties) {
return null;
}
@Override
public Map<String, Object> replaceProperties(Feed.ID feedId, Map<String, Object> properties) {
return null;
}
@Nonnull
@Override
public Set<UserFieldDescriptor> getUserFields() {
return Collections.emptySet();
}
@Override
public void setUserFields(@Nonnull Set<UserFieldDescriptor> userFields) {
}
@Override
public void populateInverseFeedDependencies() {
}
private static class Criteria extends AbstractMetadataCriteria<FeedCriteria> implements FeedCriteria, Predicate<Feed> {
private String name;
private Set<Datasource.ID> sourceIds = new HashSet<>();
private Set<Datasource.ID> destIds = new HashSet<>();
private String category;
@Override
public boolean apply(Feed input) {
if (this.name != null && !name.equals(input.getName())) {
return false;
}
if (this.category != null && input.getCategory() != null && !this.category.equals(input.getCategory().getName())) {
return false;
}
if (!this.destIds.isEmpty()) {
List<? extends FeedDestination> destinations = input.getDestinations();
for (FeedDestination dest : destinations) {
if (this.destIds.contains(dest.getDatasource().getId())) {
return true;
}
}
return false;
}
if (!this.sourceIds.isEmpty()) {
List<? extends FeedSource> sources = input.getSources();
for (FeedSource src : sources) {
if (this.sourceIds.contains(src.getDatasource().getId())) {
return true;
}
}
return false;
}
return true;
}
@Override
public FeedCriteria sourceDatasource(ID id, ID... others) {
this.sourceIds.add(id);
for (ID other : others) {
this.sourceIds.add(other);
}
return this;
}
@Override
public FeedCriteria destinationDatasource(ID id, ID... others) {
this.destIds.add(id);
for (ID other : others) {
this.destIds.add(other);
}
return this;
}
@Override
public FeedCriteria name(String name) {
this.name = name;
return this;
}
@Override
public FeedCriteria category(String category) {
this.category = category;
return this;
}
}
private class PreconditionbuilderImpl implements PreconditionBuilder {
private final ServiceLevelAgreementBuilder slaBuilder;
private final BaseFeed feed;
public PreconditionbuilderImpl(ServiceLevelAgreementBuilder slaBuilder, BaseFeed feed) {
super();
this.slaBuilder = slaBuilder;
this.feed = feed;
}
public ServiceLevelAgreementBuilder name(String name) {
return slaBuilder.name(name);
}
public ServiceLevelAgreementBuilder description(String description) {
return slaBuilder.description(description);
}
public ServiceLevelAgreementBuilder obligation(Obligation obligation) {
return slaBuilder.obligation(obligation);
}
public ObligationBuilder<ServiceLevelAgreementBuilder> obligationBuilder() {
return slaBuilder.obligationBuilder();
}
public ObligationBuilder<ServiceLevelAgreementBuilder> obligationBuilder(Condition condition) {
return slaBuilder.obligationBuilder(condition);
}
public ObligationGroupBuilder obligationGroupBuilder(Condition condition) {
return slaBuilder.obligationGroupBuilder(condition);
}
public ServiceLevelAgreement build() {
ServiceLevelAgreement sla = slaBuilder.build();
setupPrecondition(feed, sla);
return sla;
}
@Override
public ServiceLevelAgreementBuilder actionConfigurations(List<? extends ServiceLevelAgreementActionConfiguration> actionConfigurations) {
return null;
}
}
}