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; } } }