/** * */ package com.thinkbiganalytics.metadata.core.feed; /*- * #%L * thinkbig-feed-manager-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.thinkbiganalytics.metadata.api.MetadataAccess; import com.thinkbiganalytics.metadata.api.event.MetadataEventListener; import com.thinkbiganalytics.metadata.api.event.MetadataEventService; import com.thinkbiganalytics.metadata.api.event.feed.FeedOperationStatusEvent; import com.thinkbiganalytics.metadata.api.event.feed.OperationStatus; import com.thinkbiganalytics.metadata.api.event.feed.PreconditionTriggerEvent; import com.thinkbiganalytics.metadata.api.feed.Feed; import com.thinkbiganalytics.metadata.api.feed.FeedPrecondition; import com.thinkbiganalytics.metadata.api.feed.FeedProvider; import com.thinkbiganalytics.metadata.api.op.FeedOperation; import com.thinkbiganalytics.metadata.api.sla.FeedExecutedSinceFeed; import com.thinkbiganalytics.metadata.sla.api.AssessmentResult; import com.thinkbiganalytics.metadata.sla.api.Metric; import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAgreement; import com.thinkbiganalytics.metadata.sla.api.ServiceLevelAssessment; import com.thinkbiganalytics.metadata.sla.spi.ServiceLevelAssessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.inject.Inject; /** * Service for assessing {@link FeedPrecondition} */ public class FeedPreconditionService { private static final Logger log = LoggerFactory.getLogger(FeedPreconditionService.class); @Inject private ServiceLevelAssessor assessor; @Inject private FeedProvider feedProvider; @Inject private MetadataAccess metadata; @Inject private MetadataEventService eventService; private FeedOperationListener listener = new FeedOperationListener(); @PostConstruct public void addEventListener() { this.eventService.addListener(this.listener); } @PreDestroy public void removeEventListener() { this.eventService.removeListener(this.listener); } public ServiceLevelAssessment assess(FeedPrecondition precond) { ServiceLevelAgreement sla = precond.getAgreement(); return this.assessor.assess(sla); } private void checkPrecondition(Feed feed, OperationStatus operationStatus) { FeedPrecondition precond = feed.getPrecondition(); if (precond != null) { log.debug("Checking precondition of feed: {} ({})", feed.getName(), feed.getId()); ServiceLevelAgreement sla = precond.getAgreement(); boolean isAssess = sla.getObligationGroups().stream() .flatMap(obligationGroup -> obligationGroup.getObligations().stream()) .flatMap(obligation -> obligation.getMetrics().stream()) .anyMatch(metric -> isMetricDependentOnStatus(metric, operationStatus)); if (isAssess) { ServiceLevelAssessment assessment = this.assessor.assess(sla); if (assessment.getResult() == AssessmentResult.SUCCESS) { log.info("Firing precondition trigger event for feed:{} ({})", feed.getName(), feed.getId()); this.eventService.notify(new PreconditionTriggerEvent(feed.getId())); } } else { log.debug("Feed {}.{} does not depend on feed {}", feed.getCategory(), feed.getName(), operationStatus.getFeedName()); } } } /** * To avoid feeds being triggered by feeds they do not depend on */ private boolean isMetricDependentOnStatus(Metric metric, OperationStatus operationStatus) { return !(metric instanceof FeedExecutedSinceFeed) || operationStatus.getFeedName().equalsIgnoreCase(((FeedExecutedSinceFeed) metric).getCategoryAndFeed()); } private class FeedOperationListener implements MetadataEventListener<FeedOperationStatusEvent> { @Override public void notify(FeedOperationStatusEvent event) { FeedOperation.State state = event.getData().getState(); // TODO as precondition check criteria are not implemented yet, // check all preconditions of feeds that have them. if (state == FeedOperation.State.SUCCESS) { metadata.read(() -> { for (Feed feed : feedProvider.getFeeds()) { // Don't check the precondition of the feed that that generated this change event. // TODO: this might not be the correct behavior but none of our current metrics // need to be assessed when the feed itself containing the precondition has changed state. if (!feed.getQualifiedName().equals(event.getData().getFeedName())) { checkPrecondition(feed, event.getData()); } } return null; }, MetadataAccess.SERVICE); } } } }