package com.thinkbiganalytics.feedmgr.rest.controller; /*- * #%L * thinkbig-feed-manager-controller * %% * 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.feedmgr.rest.FeedLineageBuilder; import com.thinkbiganalytics.feedmgr.rest.Model; import com.thinkbiganalytics.feedmgr.security.FeedServicesAccessControl; import com.thinkbiganalytics.feedmgr.service.datasource.DatasourceModelTransform; import com.thinkbiganalytics.feedmgr.service.datasource.DatasourceService; import com.thinkbiganalytics.feedmgr.service.security.SecurityService; import com.thinkbiganalytics.feedmgr.sla.ServiceLevelAgreementModelTransform; import com.thinkbiganalytics.metadata.api.MetadataAccess; import com.thinkbiganalytics.metadata.api.datasource.Datasource; import com.thinkbiganalytics.metadata.api.datasource.DatasourceProvider; import com.thinkbiganalytics.metadata.api.feed.FeedProvider; import com.thinkbiganalytics.metadata.api.op.FeedDependencyDeltaResults; import com.thinkbiganalytics.metadata.api.op.FeedOperationsProvider; import com.thinkbiganalytics.metadata.core.feed.FeedPreconditionService; import com.thinkbiganalytics.metadata.rest.MetadataModelTransform; import com.thinkbiganalytics.metadata.rest.model.feed.Feed; import com.thinkbiganalytics.metadata.rest.model.feed.FeedCriteria; import com.thinkbiganalytics.metadata.rest.model.feed.FeedDependencyGraph; import com.thinkbiganalytics.metadata.rest.model.feed.FeedDestination; import com.thinkbiganalytics.metadata.rest.model.feed.FeedLineage; import com.thinkbiganalytics.metadata.rest.model.feed.FeedPrecondition; import com.thinkbiganalytics.metadata.rest.model.feed.FeedSource; import com.thinkbiganalytics.metadata.rest.model.feed.InitializationStatus; import com.thinkbiganalytics.metadata.rest.model.sla.ServiceLevelAssessment; import com.thinkbiganalytics.rest.model.RestResponseStatus; import com.thinkbiganalytics.security.AccessController; import com.thinkbiganalytics.security.action.AllowedEntityActionsProvider; import com.thinkbiganalytics.security.rest.controller.SecurityModelTransform; import com.thinkbiganalytics.security.rest.model.ActionGroup; import com.thinkbiganalytics.security.rest.model.PermissionsChange; import com.thinkbiganalytics.security.rest.model.PermissionsChange.ChangeType; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.security.Principal; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response.Status; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; /** * Manages Feed Metadata and allows feeds to be updated with various Metadata Properties. */ @Component @Api(tags = "Feed Manager - Feeds", produces = "application/json") @Path("/v1/metadata/feed") public class FeedsController { private static final Logger LOG = LoggerFactory.getLogger(FeedsController.class); @Inject private FeedProvider feedProvider; @Inject private FeedOperationsProvider feedOpsProvider; @Inject private DatasourceProvider datasetProvider; @Inject private DatasourceService datasourceService; @Inject private AllowedEntityActionsProvider actionsProvider; @Inject private FeedPreconditionService preconditionService; @Inject private SecurityService securityService; @Inject private MetadataAccess metadata; @Inject private MetadataModelTransform metadataTransform; @Inject private SecurityModelTransform actionsTransform; @Inject private AccessController accessController; @Inject private Model model; @Inject private DatasourceModelTransform datasourceTransform; @GET @Path("{id}/actions/available") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the list of available actions that may be permitted or revoked on a feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the actions.", response = ActionGroup.class), @ApiResponse(code = 404, message = "A feed with the given ID does not exist.", response = RestResponseStatus.class) }) public ActionGroup getAvailableActions(@PathParam("id") String feedIdStr) { LOG.debug("Get available actions for feed: {}", feedIdStr); return this.securityService.getAvailableFeedActions(feedIdStr) .orElseThrow(() -> new WebApplicationException("A feed with the given ID does not exist: " + feedIdStr, Status.NOT_FOUND)); } @GET @Path("{id}/actions/allowed") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the list of actions permitted for the given username and/or groups.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the actions.", response = ActionGroup.class), @ApiResponse(code = 404, message = "A feed with the given ID does not exist.", response = RestResponseStatus.class) }) public ActionGroup getAllowedActions(@PathParam("id") String feedIdStr, @QueryParam("user") Set<String> userNames, @QueryParam("group") Set<String> groupNames) { LOG.debug("Get allowed actions for feed: {}", feedIdStr); Set<? extends Principal> users = Arrays.stream(this.actionsTransform.asUserPrincipals(userNames)).collect(Collectors.toSet()); Set<? extends Principal> groups = Arrays.stream(this.actionsTransform.asGroupPrincipals(groupNames)).collect(Collectors.toSet()); return this.securityService.getAllowedFeedActions(feedIdStr, Stream.concat(users.stream(), groups.stream()).collect(Collectors.toSet())) .orElseThrow(() -> new WebApplicationException("A feed with the given ID does not exist: " + feedIdStr, Status.NOT_FOUND)); } @POST @Path("{id}/actions/allowed") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Updates the permissions for a feed using the supplied permission change request.") @ApiResponses({ @ApiResponse(code = 200, message = "The permissions were changed successfully.", response = ActionGroup.class), @ApiResponse(code = 400, message = "The type is not valid.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "No feed exists with the specified ID.", response = RestResponseStatus.class) }) public ActionGroup postPermissionsChange(@PathParam("id") String feedIdStr, PermissionsChange changes) { return this.securityService.changeFeedPermissions(feedIdStr, changes) .orElseThrow(() -> new WebApplicationException("A feed with the given ID does not exist: " + feedIdStr, Status.NOT_FOUND)); } @GET @Path("{id}/actions/change/allowed") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Constructs and returns a permission change request for a set of users/groups containing the actions that the requester may permit or revoke.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the change request that may be modified by the client and re-posted.", response = PermissionsChange.class), @ApiResponse(code = 400, message = "The type is not valid.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "No feed exists with the specified ID.", response = RestResponseStatus.class) }) public PermissionsChange getAllowedPermissionsChange(@PathParam("id") String feedIdStr, @QueryParam("type") String changeType, @QueryParam("user") Set<String> userNames, @QueryParam("group") Set<String> groupNames) { if (StringUtils.isBlank(changeType)) { throw new WebApplicationException("The query parameter \"type\" is required", Status.BAD_REQUEST); } Set<? extends Principal> users = Arrays.stream(this.actionsTransform.asUserPrincipals(userNames)).collect(Collectors.toSet()); Set<? extends Principal> groups = Arrays.stream(this.actionsTransform.asGroupPrincipals(groupNames)).collect(Collectors.toSet()); return this.securityService.createFeedPermissionChange(feedIdStr, ChangeType.valueOf(changeType.toUpperCase()), Stream.concat(users.stream(), groups.stream()).collect(Collectors.toSet())) .orElseThrow(() -> new WebApplicationException("A feed with the given ID does not exist: " + feedIdStr, Status.NOT_FOUND)); } @GET @Path("{id}/initstatus") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the registration status for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the registration status.", response = InitializationStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public InitializationStatus getInitializationStatus(@PathParam("id") String feedIdStr) { LOG.debug("Get feed initialization status {}", feedIdStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { return metadataTransform.domainToInitStatus().apply(feed.getCurrentInitStatus()); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{id}/initstatus/history") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the registration history for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the registration history.", response = InitializationStatus.class, responseContainer = "List"), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public List<InitializationStatus> getInitializationStatusHistory(@PathParam("id") String feedIdStr) { LOG.debug("Get feed initialization history {}", feedIdStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { return feed.getInitHistory().stream().map(metadataTransform.domainToInitStatus()).collect(Collectors.toList()); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @PUT @Path("{id}/initstatus") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @ApiOperation("Sets the registration status for the specified feed.") @ApiResponses({ @ApiResponse(code = 204, message = "The registration status was updated."), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The registration status could not be updated.", response = RestResponseStatus.class) }) public void putInitializationStatus(@PathParam("id") String feedIdStr, InitializationStatus status) { LOG.debug("Get feed initialization status {}", feedIdStr); this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { com.thinkbiganalytics.metadata.api.feed.InitializationStatus.State newState = com.thinkbiganalytics.metadata.api.feed.InitializationStatus.State.valueOf(status.getState().name()); feed.updateInitStatus(new com.thinkbiganalytics.metadata.api.feed.InitializationStatus(newState)); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{id}/watermark") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the HighWaterMarks used by the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the HighWaterMark names.", response = String.class, responseContainer = "List"), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public List<String> getHighWaterMarks(@PathParam("id") String feedIdStr) { LOG.debug("Get feed watermarks {}", feedIdStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { List<String> list = feed.getWaterMarkNames().stream().collect(Collectors.toList()); Collections.sort(list); return list; } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{id}/watermark/{name}") @Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON}) @ApiOperation("Gets the value for a specific HighWaterMark.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the HighWaterMark value.", response = String.class), @ApiResponse(code = 404, message = "The HighWaterMark could not be found.", response = RestResponseStatus.class) }) public String getHighWaterMark(@PathParam("id") String feedIdStr, @PathParam("name") String waterMarkName) { LOG.debug("Get feed watermark {}: {}", feedIdStr, waterMarkName); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { return feed.getWaterMarkValue(waterMarkName) .orElseThrow(() -> new WebApplicationException("A feed high-water mark with the given name does not exist: " + waterMarkName, Status.NOT_FOUND)); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @PUT @Path("{id}/watermark/{name}") @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Sets the value for a specific HighWaterMark.") @ApiResponses({ @ApiResponse(code = 204, message = "The HighWaterMark value has been changed."), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The HighWaterMark value could not be changed.", response = RestResponseStatus.class) }) public void putHighWaterMark(@PathParam("id") String feedIdStr, @PathParam("name") String waterMarkName, String value) { LOG.debug("Get feed watermark {}: {}", feedIdStr, waterMarkName); this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { feed.setWaterMarkValue(waterMarkName, value); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @DELETE @Path("{id}/watermark/{name}") @Consumes(MediaType.TEXT_PLAIN) @ApiOperation("Deletes the specified HighWaterMark.") @ApiResponses({ @ApiResponse(code = 204, message = "The HighWaterMark has been deleted."), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The HighWaterMark could not be deleted.", response = RestResponseStatus.class) }) public void deleteHighWaterMark(@PathParam("id") String feedIdStr, @PathParam("name") String waterMarkName) { LOG.debug("Get feed watermark {}: {}", feedIdStr, waterMarkName); this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed feed = feedProvider.getFeed(feedId); if (feed != null) { feed.setWaterMarkValue(waterMarkName, null); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets a list of feeds.") @ApiResponses( @ApiResponse(code = 200, message = "Returns the matching feeds.", response = Feed.class, responseContainer = "List") ) public List<Feed> getFeeds(@QueryParam(FeedCriteria.CATEGORY) final String category, @QueryParam(FeedCriteria.NAME) final String name, @QueryParam(FeedCriteria.SRC_ID) final String srcId, @QueryParam(FeedCriteria.DEST_ID) final String destId) { LOG.debug("Get feeds {}/{}/{}", name, srcId, destId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.FeedCriteria criteria = createFeedCriteria(category, name, srcId, destId); Collection<com.thinkbiganalytics.metadata.api.feed.Feed> domainFeeds = feedProvider.getFeeds(criteria); return domainFeeds.stream().map(metadataTransform.domainToFeed()).collect(Collectors.toList()); }); } @GET @Path("{id}") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed.", response = Feed.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be found.", response = RestResponseStatus.class) }) public Feed getFeed(@PathParam("id") final String feedId) { LOG.debug("Get feed {}", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); return this.metadataTransform.domainToFeed().apply(domain); }); } /* @GET @Path("{id}/op") @Produces(MediaType.APPLICATION_JSON) public List<FeedOperation> getFeedOperations(@PathParam("id") final String feedId, @QueryParam("since") @DefaultValue("1970-01-01T00:00:00Z") String sinceStr, @QueryParam("limit") @DefaultValue("-1") int limit) { final DateTime since = Formatters.parseDateTime(sinceStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); FeedOperationCriteria criteria = feedOpsProvider.criteria() .feed(domainId) .stoppedSince(since) .state(State.SUCCESS); List<com.thinkbiganalytics.metadata.api.op.FeedOperation> list = feedOpsProvider.find(criteria); return list.stream().map(op -> Model.DOMAIN_TO_FEED_OP.apply(op)).collect(Collectors.toList()); }); } @GET @Path("{id}/op/results") @Produces(MediaType.APPLICATION_JSON) public Map<DateTime, Map<String, Object>> collectFeedOperationsResults(@PathParam("id") final String feedId, @QueryParam("since") @DefaultValue("1970-01-01T00:00:00Z") String sinceStr) { final DateTime since = Formatters.TIME_FORMATTER.parseDateTime(sinceStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); FeedOperationCriteria criteria = feedOpsProvider.criteria() .feed(domainId) .stoppedSince(since) .state(State.SUCCESS); Map<DateTime, Map<String, Object>> results = feedOpsProvider.getAllResults(criteria, null); return results.entrySet().stream() .collect(Collectors.toMap(te -> te.getKey(), te -> (Map<String, Object>) te.getValue().entrySet().stream() .collect(Collectors.toMap(ve -> ve.getKey(), ve -> (Object) ve.getValue().toString())))); }); } */ @GET @Path("{id}/depfeeds") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the dependencies of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the dependency graph.", response = FeedDependencyGraph.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public FeedDependencyGraph getDependencyGraph(@PathParam("id") final String feedId, @QueryParam("preconds") @DefaultValue("false") final boolean assessPrecond) { LOG.debug("Get feed dependencies {}", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed startDomain = feedProvider.getFeed(domainId); if (startDomain != null) { return collectFeedDependencies(startDomain, assessPrecond); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @POST @Path("{feedId}/depfeeds") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Adds a dependency to the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the new dependency graph.", response = FeedDependencyGraph.class), @ApiResponse(code = 500, message = "The dependency could not be added.", response = RestResponseStatus.class) }) public FeedDependencyGraph addDependent(@PathParam("feedId") final String feedIdStr, @QueryParam("dependentId") final String depIdStr) { com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = this.feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed.ID depId = this.feedProvider.resolveFeed(depIdStr); this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); this.feedProvider.addDependent(feedId, depId); return null; }); return getDependencyGraph(feedId.toString(), false); } @DELETE @Path("{feedId}/depfeeds") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Removes a dependency from the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the new dependency graph.", response = FeedDependencyGraph.class), @ApiResponse(code = 500, message = "The dependency could not be removed.", response = RestResponseStatus.class) }) public FeedDependencyGraph removeDependent(@PathParam("feedId") final String feedIdStr, @QueryParam("dependentId") final String depIdStr) { com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = this.feedProvider.resolveFeed(feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed.ID depId = this.feedProvider.resolveFeed(depIdStr); this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); this.feedProvider.removeDependent(feedId, depId); return null; }); return getDependencyGraph(feedId.toString(), false); } @GET @Path("{feedId}/depfeeds/delta") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the dependencies delta for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the dependencies deltas.", response = FeedDependencyDeltaResults.class), @ApiResponse(code = 500, message = "The feed could not be found.", response = RestResponseStatus.class) }) public FeedDependencyDeltaResults getDependentResultDeltas(@PathParam("feedId") final String feedIdStr) { LOG.info("Get feed dependencies delta for {}", feedIdStr); com.thinkbiganalytics.metadata.api.feed.Feed.ID feedId = this.feedProvider.resolveFeed(feedIdStr); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); FeedDependencyDeltaResults results = this.feedOpsProvider.getDependentDeltaResults(feedId, null); return results; }); } @GET @Path("{id}/source") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the sources of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed sources.", response = FeedSource.class, responseContainer = "List"), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public List<FeedSource> getFeedSources(@PathParam("id") final String feedId) { LOG.debug("Get feed {} sources", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { return domain.getSources().stream().map(this.metadataTransform.domainToFeedSource()).collect(Collectors.toList()); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } // // @GET // @Path("{fid}/source/{sid}") // @Produces(MediaType.APPLICATION_JSON) // public FeedSource getFeedSource(@PathParam("fid") final String feedId, @PathParam("sid") final String srcId) { // LOG.debug("Get feed {} source {}", feedId, srcId); // // return this.metadata.read(() -> { // com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); // com.thinkbiganalytics.metadata.api.feed.FeedSource.ID domainSrcId = feedProvider.resolveSource(srcId); // com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); // // if (domain != null) { // com.thinkbiganalytics.metadata.api.feed.FeedSource domainSrc = domain.getSource(domainSrcId); // // if (domainSrc != null) { // return Model.domainToFeedSource.apply(domainSrc); // } else { // throw new WebApplicationException("A feed source with the given ID does not exist: " + srcId, Status.NOT_FOUND); // } // } else { // throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); // } // }); // } @GET @Path("{id}/destination") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the destinations of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed destinations.", response = FeedDestination.class, responseContainer = "List"), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public List<FeedDestination> getFeedDestinations(@PathParam("id") final String feedId) { LOG.debug("Get feed {} destinations", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { return domain.getDestinations().stream().map(this.metadataTransform.domainToFeedDestination()).collect(Collectors.toList()); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } // // @GET // @Path("{fid}/destination/{sid}") // @Produces(MediaType.APPLICATION_JSON) // public FeedDestination getFeedDestination(@PathParam("fid") final String feedId, @PathParam("sid") final String destId) { // LOG.debug("Get feed {} destination {}", feedId, destId); // // return this.metadata.read(() -> { // com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); // com.thinkbiganalytics.metadata.api.feed.FeedDestination.ID domainDestId = feedProvider.resolveDestination(destId); // com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); // // if (domain != null) { // com.thinkbiganalytics.metadata.api.feed.FeedDestination domainDest = domain.getDestination(domainDestId); // // if (domainDest != null) { // return Model.domainToFeedDestination.apply(domainDest); // } else { // throw new WebApplicationException("A feed destination with the given ID does not exist: " + destId, Status.NOT_FOUND); // } // } else { // throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); // } // }); // } @GET @Path("{id}/precondition") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the precondition for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed precondition.", response = FeedPrecondition.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public FeedPrecondition getFeedPrecondition(@PathParam("id") final String feedId) { LOG.debug("Get feed {} precondition", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { return this.metadataTransform.domainToFeedPrecond().apply(domain.getPrecondition()); } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{id}/precondition/assessment") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Assess the precondition of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the assessment.", response = ServiceLevelAssessment.class), @ApiResponse(code = 400, message = "The id is not a valid UUID or the feed does not have a precondition.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public ServiceLevelAssessment assessPrecondition(@PathParam("id") final String feedId) { LOG.debug("Assess feed {} precondition", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { com.thinkbiganalytics.metadata.api.feed.FeedPrecondition precond = domain.getPrecondition(); if (precond != null) { return generateModelAssessment(precond); } else { throw new WebApplicationException("The feed with the given ID does not have a precondition: " + feedId, Status.BAD_REQUEST); } } else { throw new WebApplicationException("A feed with the given ID does not exist: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{id}/precondition/assessment/result") @Produces(MediaType.TEXT_PLAIN) @ApiOperation("Assess the precondition of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the assessment result.", response = ServiceLevelAssessment.class), @ApiResponse(code = 400, message = "The id is not a valid UUID or the feed does not have a precondition.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class) }) public String assessPreconditionResult(@PathParam("id") final String feedId) { return assessPrecondition(feedId).getResult().toString(); } @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Creates a new feed.") @ApiResponses({ @ApiResponse(code = 200, message = "The feed was created.", response = Feed.class), @ApiResponse(code = 400, message = "The name is already in use.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be created.", response = RestResponseStatus.class) }) public Feed createFeed(final Feed feed, @QueryParam("ensure") @DefaultValue("true") final boolean ensure) { LOG.debug("Create feed (ensure={}) {}", ensure, feed); this.metadataTransform.validateCreate(feed); return this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); com.thinkbiganalytics.metadata.api.feed.FeedCriteria crit = feedProvider.feedCriteria().name(feed.getSystemName()).category(feed.getCategory().getSystemName()); Collection<com.thinkbiganalytics.metadata.api.feed.Feed> existing = feedProvider.getFeeds(crit); if (existing.isEmpty()) { com.thinkbiganalytics.metadata.api.feed.Feed domainFeed = feedProvider.ensureFeed(feed.getCategory().getSystemName(), feed.getSystemName(), feed.getDescription()); ensureDependentDatasources(feed, domainFeed); ensurePrecondition(feed, domainFeed); ensureProperties(feed, domainFeed); return this.metadataTransform.domainToFeed().apply(feedProvider.getFeed(domainFeed.getId())); } else if (ensure) { return this.metadataTransform.domainToFeed().apply(existing.iterator().next()); } else { throw new WebApplicationException("A feed with the given name already exists: " + feed.getSystemName(), Status.BAD_REQUEST); } }); } /** * Updates an existing feed. Note that POST is used here rather than PUT since it behaves more like a PATCH; which isn't supported in Jersey. */ @POST @Path("{id}") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Updates the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "The feed was updated.", response = Feed.class), @ApiResponse(code = 404, message = "The feed was not found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be updated.", response = RestResponseStatus.class) }) public Feed updateFeed(@PathParam("id") final String feedId, final Feed feed) { LOG.debug("Update feed: {}", feed); this.metadataTransform.validateCreate(feed); return this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { domain = this.metadataTransform.updateDomain(feed, domain); return this.metadataTransform.domainToFeed().apply(domain); } else { throw new WebApplicationException("No feed exist with the ID: " + feed.getId(), Status.NOT_FOUND); } }); } /** * Gets the properties for the specified feed. * * @param feedId the feed id or the feed category and name * @return the metadata properties */ @GET @Path("{id}/props") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the properties of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed properties.", response = Map.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed was not found.", response = RestResponseStatus.class) }) public Map<String, Object> getFeedProperties(@PathParam("id") final String feedId) { LOG.debug("Get feed properties ID: {}", feedId); return this.metadata.read(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.ACCESS_FEEDS); String[] parts = feedId.split("\\.", 2); com.thinkbiganalytics.metadata.api.feed.Feed domain = (parts.length == 2) ? feedProvider.findBySystemName(parts[0], parts[1]) : feedProvider.getFeed(feedProvider.resolveFeed(feedId)); if (domain != null) { return domain.getProperties(); } else { throw new WebApplicationException("No feed exist with the ID: " + feedId, Status.NOT_FOUND); } }); } /** * Merges the properties for the specified feeds. New properties will be added and existing properties will be overwritten. * * @param feedId the feed id or the feed category and name * @param props the properties to be merged * @return the merged metadata properties */ @POST @Path("{id}/props") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Merges the properties for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the updated properties.", response = Map.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The properties could not be updated.", response = RestResponseStatus.class) }) public Map<String, Object> mergeFeedProperties(@PathParam("id") final String feedId, final Properties props) { LOG.debug("Merge feed properties ID: {}, properties: {}", feedId, props); return this.metadata.commit(() -> { String[] parts = feedId.split("\\.", 2); com.thinkbiganalytics.metadata.api.feed.Feed domain = (parts.length == 2) ? feedProvider.findBySystemName(parts[0], parts[1]) : feedProvider.getFeed(feedProvider.resolveFeed(feedId)); if (domain != null) { return updateProperties(props, domain, false); } else { throw new WebApplicationException("No feed exist with the ID: " + feedId, Status.NOT_FOUND); } }); } @PUT @Path("{id}/props") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Sets the properties for the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the updated properties.", response = Properties.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class), @ApiResponse(code = 404, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The properties could not be updated.", response = RestResponseStatus.class) }) public Properties replaceFeedProperties(@PathParam("id") final String feedId, final Properties props) { LOG.debug("Replace feed properties ID: {}, properties: {}", feedId, props); return this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainId = feedProvider.resolveFeed(feedId); com.thinkbiganalytics.metadata.api.feed.Feed domain = feedProvider.getFeed(domainId); if (domain != null) { Map<String, Object> domainProps = updateProperties(props, domain, true); Properties newProps = new Properties(); newProps.putAll(domainProps); return newProps; } else { throw new WebApplicationException("No feed exist with the ID: " + feedId, Status.NOT_FOUND); } }); } @GET @Path("{feedId}/lineage") @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Gets the lineage of the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the feed lineage.", response = FeedLineage.class), @ApiResponse(code = 400, message = "The id is not a valid UUID.", response = RestResponseStatus.class) }) public FeedLineage getFeedLineage(@PathParam("feedId") final String feedId) { return this.metadata.read(() -> { com.thinkbiganalytics.metadata.api.feed.Feed domainFeed = feedProvider.getFeed(feedProvider.resolveFeed(feedId)); if (domainFeed != null) { FeedLineageBuilder builder = new FeedLineageBuilder(domainFeed, model, datasourceTransform); Feed feed = builder.build();//Model.DOMAIN_TO_FEED_WITH_DEPENDENCIES.apply(domainFeed); return new FeedLineage(feed, datasourceService.getFeedLineageStyleMap()); } return null; }); } /* @GET @Path("remove-sources") @Produces(MediaType.APPLICATION_JSON) public RestResponseStatus removeSources(){ try { this.metadata.commit(() -> { List<? extends com.thinkbiganalytics.metadata.api.feed.Feed> feeds = feedProvider.getFeeds(); feeds.stream().forEach(feed -> { feedProvider.removeFeedSources(feed.getId()); }); }, MetadataAccess.SERVICE); }catch (Exception e){ e.printStackTrace(); } this.metadata.commit(() -> { List<? extends com.thinkbiganalytics.metadata.api.feed.Feed> feeds = feedProvider.getFeeds(); feeds.stream().forEach(feed -> { feedProvider.removeFeedDestinations(feed.getId()); }); }, MetadataAccess.SERVICE); this.metadata.commit(() -> { List<Datasource> datasources = datasetProvider.getDatasources(); datasources.stream().forEach(datasource -> { datasetProvider.removeDatasource(datasource.getId()); }); }, MetadataAccess.SERVICE); return new RestResponseStatus.ResponseStatusBuilder().buildSuccess(); } */ @POST @Path("{feedId}/source") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Adds a source to the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the updated feed.", response = Feed.class), @ApiResponse(code = 400, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be updated.", response = RestResponseStatus.class) }) public Feed addFeedSource(@PathParam("feedId") final String feedId, @FormParam("datasourceId") final String datasourceId) { LOG.debug("Add feed source, feed ID: {}, datasource ID: {}", feedId, datasourceId); return this.metadata.commit(() -> { com.thinkbiganalytics.metadata.api.feed.Feed.ID domainFeedId = feedProvider.resolveFeed(feedId); Datasource.ID domainDsId = datasetProvider.resolve(datasourceId); com.thinkbiganalytics.metadata.api.feed.FeedSource domainDest = feedProvider.ensureFeedSource(domainFeedId, domainDsId); return this.metadataTransform.domainToFeed().apply(domainDest.getFeed()); }); } @POST @Path("{feedId}/destination") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Adds a destination to the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the updated feed.", response = Feed.class), @ApiResponse(code = 400, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be updated.", response = RestResponseStatus.class) }) public Feed addFeedDestination(@PathParam("feedId") final String feedId, @FormParam("datasourceId") final String datasourceId) { LOG.debug("Add feed destination, feed ID: {}, datasource ID: {}", feedId, datasourceId); return this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainFeedId = feedProvider.resolveFeed(feedId); Datasource.ID domainDsId = datasetProvider.resolve(datasourceId); com.thinkbiganalytics.metadata.api.feed.FeedDestination domainDest = feedProvider.ensureFeedDestination(domainFeedId, domainDsId); return this.metadataTransform.domainToFeed().apply(domainDest.getFeed()); }); } @POST @Path("{feedId}/precondition") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @ApiOperation("Adds a precondition to the specified feed.") @ApiResponses({ @ApiResponse(code = 200, message = "Returns the updated feed.", response = Feed.class), @ApiResponse(code = 400, message = "The feed could not be found.", response = RestResponseStatus.class), @ApiResponse(code = 500, message = "The feed could not be updated.", response = RestResponseStatus.class) }) public Feed setPrecondition(@PathParam("feedId") final String feedId, final FeedPrecondition precond) { LOG.debug("Add feed precondition, feed ID: {}, precondition: {}", feedId, precond); return this.metadata.commit(() -> { this.accessController.checkPermission(AccessController.SERVICES, FeedServicesAccessControl.EDIT_FEEDS); com.thinkbiganalytics.metadata.api.feed.Feed.ID domainFeedId = feedProvider.resolveFeed(feedId); List<com.thinkbiganalytics.metadata.sla.api.Metric> domainMetrics = precond.getSla().getObligations().stream() .flatMap((grp) -> grp.getMetrics().stream()) .map((metric) -> metric) .collect(Collectors.toList()); com.thinkbiganalytics.metadata.api.feed.Feed domainFeed = feedProvider.createPrecondition(domainFeedId, "", domainMetrics); return this.metadataTransform.domainToFeed().apply(domainFeed); }); } private Map<String, Object> updateProperties(final Properties props, com.thinkbiganalytics.metadata.api.feed.Feed domain, boolean replace) { return metadata.commit(() -> { Map<String, Object> newProperties = new HashMap<String, Object>(); for (String name : props.stringPropertyNames()) { newProperties.put(name, props.getProperty(name)); } if (replace) { feedProvider.replaceProperties(domain.getId(), newProperties); } else { feedProvider.mergeFeedProperties(domain.getId(), newProperties); } return domain.getProperties(); }); } private ServiceLevelAssessment generateModelAssessment(com.thinkbiganalytics.metadata.api.feed.FeedPrecondition precond) { com.thinkbiganalytics.metadata.sla.api.ServiceLevelAssessment assmt = this.preconditionService.assess(precond); return ServiceLevelAgreementModelTransform.DOMAIN_TO_SLA_ASSMT.apply(assmt); } private void ensurePrecondition(Feed feed, com.thinkbiganalytics.metadata.api.feed.Feed domainFeed) { FeedPrecondition precond = feed.getPrecondition(); if (precond != null) { List<com.thinkbiganalytics.metadata.sla.api.Metric> domainMetrics = precond.getSla().getObligations().stream() .flatMap((grp) -> grp.getMetrics().stream()) .map((metric) -> metric) .collect(Collectors.toList()); feedProvider.createPrecondition(domainFeed.getId(), "", domainMetrics); } } private void ensureDependentDatasources(Feed feed, com.thinkbiganalytics.metadata.api.feed.Feed domainFeed) { for (FeedSource src : feed.getSources()) { Datasource.ID dsId = this.datasetProvider.resolve(src.getId()); feedProvider.ensureFeedSource(domainFeed.getId(), dsId); } for (FeedDestination src : feed.getDestinations()) { Datasource.ID dsId = this.datasetProvider.resolve(src.getId()); feedProvider.ensureFeedDestination(domainFeed.getId(), dsId); } } private void ensureProperties(Feed feed, com.thinkbiganalytics.metadata.api.feed.Feed domainFeed) { Map<String, Object> domainProps = domainFeed.getProperties(); Properties props = feed.getProperties(); for (String key : feed.getProperties().stringPropertyNames()) { domainProps.put(key, props.getProperty(key)); } } private com.thinkbiganalytics.metadata.api.feed.FeedCriteria createFeedCriteria(String category, String name, String srcId, String destId) { com.thinkbiganalytics.metadata.api.feed.FeedCriteria criteria = feedProvider.feedCriteria(); if (StringUtils.isNotEmpty(category)) { criteria.category(category); } if (StringUtils.isNotEmpty(name)) { criteria.name(name); } if (StringUtils.isNotEmpty(srcId)) { Datasource.ID dsId = this.datasetProvider.resolve(srcId); criteria.sourceDatasource(dsId); } if (StringUtils.isNotEmpty(destId)) { Datasource.ID dsId = this.datasetProvider.resolve(destId); criteria.destinationDatasource(dsId); } return criteria; } private FeedDependencyGraph collectFeedDependencies(com.thinkbiganalytics.metadata.api.feed.Feed currentFeed, boolean assessPrecond) { List<com.thinkbiganalytics.metadata.api.feed.Feed> domainDeps = currentFeed.getDependentFeeds(); FeedDependencyGraph feedDep = new FeedDependencyGraph(this.metadataTransform.domainToFeed().apply(currentFeed), null); if (!domainDeps.isEmpty()) { for (com.thinkbiganalytics.metadata.api.feed.Feed depFeed : domainDeps) { FeedDependencyGraph childDep = collectFeedDependencies(depFeed, assessPrecond); feedDep.addDependecy(childDep); } } if (assessPrecond && currentFeed.getPrecondition() != null) { feedDep.setPreconditonResult(generateModelAssessment(currentFeed.getPrecondition())); } return feedDep; } }