/**
*
*/
package com.thinkbiganalytics.metadata.modeshape.op;
/*-
* #%L
* thinkbig-metadata-modeshape
* %%
* 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 java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import javax.inject.Inject;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thinkbiganalytics.jobrepo.query.model.ExecutedJob;
import com.thinkbiganalytics.jobrepo.query.model.ExecutionStatus;
import com.thinkbiganalytics.metadata.api.MetadataAccess;
import com.thinkbiganalytics.metadata.api.feed.Feed;
import com.thinkbiganalytics.metadata.api.feed.FeedNotFoundExcepton;
import com.thinkbiganalytics.metadata.api.feed.OpsManagerFeedProvider;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchJobExecution;
import com.thinkbiganalytics.metadata.api.jobrepo.job.BatchJobExecutionProvider;
import com.thinkbiganalytics.metadata.api.op.FeedDependencyDeltaResults;
import com.thinkbiganalytics.metadata.api.op.FeedOperation;
import com.thinkbiganalytics.metadata.api.op.FeedOperation.ID;
import com.thinkbiganalytics.metadata.api.op.FeedOperation.State;
import com.thinkbiganalytics.metadata.api.op.FeedOperationCriteria;
import com.thinkbiganalytics.metadata.api.op.FeedOperationsProvider;
import com.thinkbiganalytics.metadata.core.AbstractMetadataCriteria;
import com.thinkbiganalytics.metadata.modeshape.feed.JcrFeedProvider;
import com.thinkbiganalytics.metadata.modeshape.op.FeedOperationExecutedJobWrapper.OpId;
import com.thinkbiganalytics.support.FeedNameUtil;
/**
*
*/
public class JobRepoFeedOperationsProvider implements FeedOperationsProvider {
private static final Logger LOG = LoggerFactory.getLogger(JobRepoFeedOperationsProvider.class);
@Inject
OpsManagerFeedProvider opsManagerFeedProvider;
// @Inject
// private FeedRepository feedRepo;
// @Inject
// private JobRepository jobRepo;
@Inject
private JcrFeedProvider feedProvider;
@Inject
private BatchJobExecutionProvider jobExecutionProvider;
@Inject
private MetadataAccess metadata;
protected static FeedOperation.State asOperationState(ExecutionStatus status) {
switch (status) {
case ABANDONED:
return State.CANCELED;
case COMPLETED:
return State.SUCCESS;
case FAILED:
return State.FAILURE;
case STARTED:
return State.STARTED;
case STARTING:
return State.STARTED;
case STOPPING:
return State.STARTED;
case STOPPED:
return State.CANCELED;
case UNKNOWN:
return State.STARTED;
default:
return State.FAILURE;
}
}
protected static FeedOperation.State asOperationState(BatchJobExecution.JobStatus status) {
switch (status) {
case ABANDONED:
return State.CANCELED;
case COMPLETED:
return State.SUCCESS;
case FAILED:
return State.FAILURE;
case STARTED:
return State.STARTED;
case STARTING:
return State.STARTED;
case STOPPING:
return State.STARTED;
case STOPPED:
return State.CANCELED;
case UNKNOWN:
return State.STARTED;
default:
return State.FAILURE;
}
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.op.FeedOperationsProvider#criteria()
*/
@Override
public FeedOperationCriteria criteria() {
return new Criteria();
}
public boolean isFeedRunning(Feed.ID feedId) {
if (feedId != null) {
return opsManagerFeedProvider.isFeedRunning(opsManagerFeedProvider.resolveId(feedId.toString()));
}
return false;
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.op.FeedOperationsProvider#getOperation(com.thinkbiganalytics.metadata.api.op.FeedOperation.ID)
*/
@Override
public FeedOperation getOperation(ID id) {
OpId opId = (OpId) id;
BatchJobExecution jobExecution = jobExecutionProvider.findByJobExecutionId(new Long(opId.toString()));
if (jobExecution != null) {
return createOperation(jobExecution);
} else {
return null;
}
}
@Override
public List<FeedOperation> findLatestCompleted(Feed.ID feedId) {
return metadata.read(() -> {
List<FeedOperation> operations = new ArrayList<>();
Feed feed = this.feedProvider.getFeed(feedId);
if (feed != null) {
BatchJobExecution latestJobExecution = this.jobExecutionProvider.findLatestCompletedJobForFeed(feed.getQualifiedName());
if (latestJobExecution != null) {
LOG.debug("Latest completed job execution id {} ", latestJobExecution.getJobExecutionId());
operations.add(createOperation(latestJobExecution));
}
}
return operations;
});
}
@Override
public List<FeedOperation> findLatest(Feed.ID feedId) {
return metadata.read(() -> {
List<FeedOperation> operations = new ArrayList<>();
Feed feed = this.feedProvider.getFeed(feedId);
if (feed != null) {
BatchJobExecution latestJobExecution = this.jobExecutionProvider.findLatestJobForFeed(feed.getQualifiedName());
if (latestJobExecution != null) {
operations.add(createOperation(latestJobExecution));
}
}
return operations;
});
}
@Override
public FeedDependencyDeltaResults getDependentDeltaResults(Feed.ID feedId, Set<String> props) {
Feed feed = this.feedProvider.getFeed(feedId);
if (feed != null) {
String systemFeedName = FeedNameUtil.fullName(feed.getCategory().getName(), feed.getName());
FeedDependencyDeltaResults results = new FeedDependencyDeltaResults(feed.getId().toString(), systemFeedName);
//find this feeds latest completion
BatchJobExecution latest = jobExecutionProvider.findLatestCompletedJobForFeed(systemFeedName);
//get the dependent feeds
List<Feed> dependents = feed.getDependentFeeds();
if (dependents != null) {
for (Feed depFeed : dependents) {
String depFeedSystemName = FeedNameUtil.fullName(depFeed.getCategory().getName(), depFeed.getName());
//find Completed feeds executed since time
Set<BatchJobExecution> jobs = null;
if (latest != null) {
jobs = (Set<BatchJobExecution>) jobExecutionProvider.findJobsForFeedCompletedSince(depFeedSystemName, latest.getStartTime());
} else {
BatchJobExecution job = jobExecutionProvider.findLatestCompletedJobForFeed(depFeedSystemName);
if (job != null) {
jobs = new HashSet<>();
jobs.add(job);
}
}
if (jobs != null) {
for (BatchJobExecution job : jobs) {
DateTime endTime = job.getEndTime();
Map<String, String> executionContext = job.getJobExecutionContextAsMap();
Map<String, Object> map = new HashMap<>();
//filter the map
if (executionContext != null) {
//add those requested to the results map
for (Entry<String, String> entry : executionContext.entrySet()) {
if (props == null || props.isEmpty() || props.contains(entry.getKey())) {
map.put(entry.getKey(), entry.getValue());
}
}
}
results.addFeedExecutionContext(depFeedSystemName, job.getJobExecutionId(), job.getStartTime(), endTime, map);
}
} else {
results.getDependentFeedNames().add(depFeedSystemName);
}
}
}
return results;
} else {
throw new FeedNotFoundExcepton(feedId);
}
}
/*
@Override
public Map<DateTime, Map<String, Object>> getAllResults(FeedOperationCriteria criteria, Set<String> props) {
Map<DateTime, Map<String, Object>> results = new HashMap<DateTime, Map<String,Object>>();
// List<FeedOperation> ops = find(criteria);
for (FeedOperation op : ops) {
DateTime time = op.getStopTime();
Map<String, Object> map = results.get(time);
for (Entry<String, Object> entry : op.getResults().entrySet()) {
if (props.isEmpty() || props.contains(entry.getKey())) {
if (map == null) {
map = new HashMap<>();
results.put(time, map);
}
map.put(entry.getKey(), entry.getValue());
}
}
}
return results;
}
private FeedOperationExecutedJobWrapper createOperation(ExecutedJob exec) {
Long id = exec.getExecutionId();
// TODO Inefficient
ExecutedJob fullExec = this.jobRepo.findByExecutionId(id.toString());
return new FeedOperationExecutedJobWrapper(fullExec);
}
*/
private FeedOperationBatchJobExecutionJobWrapper createOperation(BatchJobExecution exec) {
return new FeedOperationBatchJobExecutionJobWrapper(exec);
}
private class Criteria extends AbstractMetadataCriteria<FeedOperationCriteria> implements FeedOperationCriteria, Predicate<ExecutedJob> {
private Set<State> states = new HashSet<>();
private Set<Feed.ID> feedIds = new HashSet<>();
private DateTime startedBefore;
private DateTime startedSince;
private DateTime stoppedBefore;
private DateTime stoppedSince;
// TODO This is a temporary filtering solution. Replace with an implementation that uses
// the criteria to create SQL.
@Override
public boolean test(ExecutedJob job) {
Feed.ID id = null;
if (!feedIds.isEmpty()) {
String[] jobName = job.getJobName().split("\\.");
Feed feed = feedProvider.findBySystemName(jobName[0], jobName[1]);
id = feed != null ? feed.getId() : null;
}
return
(states.isEmpty() || states.contains(asOperationState(job.getStatus()))) &&
(feedIds.isEmpty() || (id != null && feedIds.contains(id))) &&
(this.startedBefore == null || this.startedBefore.isAfter(job.getStartTime())) &&
(this.startedSince == null || this.startedSince.isBefore(job.getStartTime())) &&
(this.stoppedBefore == null || this.stoppedBefore.isAfter(job.getEndTime())) &&
(this.stoppedSince == null || this.stoppedSince.isBefore(job.getEndTime()));
}
@Override
public FeedOperationCriteria state(State... states) {
this.states.addAll(Arrays.asList(states));
return this;
}
@Override
public FeedOperationCriteria feed(Feed.ID... feedIds) {
this.feedIds.addAll(Arrays.asList(feedIds));
return this;
}
@Override
public FeedOperationCriteria startedSince(DateTime time) {
this.startedSince = time;
return this;
}
@Override
public FeedOperationCriteria startedBefore(DateTime time) {
this.startedBefore = time;
return this;
}
@Override
public FeedOperationCriteria startedBetween(DateTime after, DateTime before) {
startedSince(after);
startedBefore(before);
return this;
}
@Override
public FeedOperationCriteria stoppedSince(DateTime time) {
this.stoppedSince = time;
return this;
}
@Override
public FeedOperationCriteria stoppedBefore(DateTime time) {
this.stoppedBefore = time;
return this;
}
@Override
public FeedOperationCriteria stoppedBetween(DateTime after, DateTime before) {
stoppedSince(after);
stoppedBefore(before);
return this;
}
}
}