Java tutorial
/** * JBoss, Home of Professional Open Source. * Copyright 2014-2019 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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. */ package org.jboss.pnc.rest.provider; import org.hibernate.envers.AuditReaderFactory; import org.hibernate.envers.DefaultRevisionEntity; import org.hibernate.envers.query.AuditEntity; import org.hibernate.envers.query.criteria.AuditDisjunction; import org.jboss.pnc.common.graph.GraphBuilder; import org.jboss.pnc.common.graph.GraphUtils; import org.jboss.pnc.common.graph.NameUniqueVertex; import org.jboss.pnc.common.util.StringUtils; import org.jboss.pnc.model.BuildConfigSetRecord; import org.jboss.pnc.model.BuildConfiguration; import org.jboss.pnc.model.BuildConfigurationAudited; import org.jboss.pnc.model.BuildRecord; import org.jboss.pnc.model.IdRev; import org.jboss.pnc.model.Project; import org.jboss.pnc.model.User; import org.jboss.pnc.rest.provider.collection.CollectionInfo; import org.jboss.pnc.rest.provider.collection.CollectionInfoCollector; import org.jboss.pnc.rest.restmodel.BuildConfigurationAuditedRest; import org.jboss.pnc.rest.restmodel.BuildRecordRest; import org.jboss.pnc.rest.restmodel.RunningBuildsCountRest; import org.jboss.pnc.rest.restmodel.UserRest; import org.jboss.pnc.rest.restmodel.graph.GraphRest; import org.jboss.pnc.rest.restmodel.response.Page; import org.jboss.pnc.rest.trigger.BuildConfigurationSetTriggerResult; import org.jboss.pnc.rest.utils.RestGraphBuilder; import org.jboss.pnc.spi.SshCredentials; import org.jboss.pnc.spi.coordinator.BuildCoordinator; import org.jboss.pnc.spi.coordinator.BuildTask; import org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates; import org.jboss.pnc.spi.datastore.predicates.ProjectPredicates; import org.jboss.pnc.spi.datastore.repositories.BuildConfigSetRecordRepository; import org.jboss.pnc.spi.datastore.repositories.BuildConfigurationAuditedRepository; import org.jboss.pnc.spi.datastore.repositories.GraphWithMetadata; import org.jboss.pnc.spi.datastore.repositories.BuildRecordRepository; import org.jboss.pnc.spi.datastore.repositories.PageInfoProducer; import org.jboss.pnc.spi.datastore.repositories.ProjectRepository; import org.jboss.pnc.spi.datastore.repositories.SortInfoProducer; import org.jboss.pnc.spi.datastore.repositories.api.PageInfo; import org.jboss.pnc.spi.datastore.repositories.api.Predicate; import org.jboss.pnc.spi.datastore.repositories.api.RSQLPredicateProducer; import org.jboss.pnc.spi.datastore.repositories.api.SortInfo; import org.jboss.pnc.spi.datastore.repositories.api.impl.DefaultPageInfo; import org.jboss.pnc.spi.executor.BuildExecutionSession; import org.jboss.pnc.spi.executor.BuildExecutor; import org.jboss.util.graph.Edge; import org.jboss.util.graph.Graph; import org.jboss.util.graph.Vertex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ejb.Stateless; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriInfo; import java.io.BufferedWriter; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.invoke.MethodHandles; import java.net.URI; import java.util.ArrayList; 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.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import static org.jboss.pnc.common.util.StreamHelper.nullableStreamOf; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withArtifactDistributedInMilestone; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withAttribute; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withBuildConfigSetId; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withBuildConfigSetRecordId; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withBuildConfigurationId; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withBuildConfigurationIdAndStatusExecuted; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withBuildConfigurationIdRev; import static org.jboss.pnc.spi.datastore.predicates.BuildRecordPredicates.withUserId; @Stateless public class BuildRecordProvider extends AbstractProvider<BuildRecord, BuildRecordRest> { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final String QUERY_BY_USER = "user.id==%d"; private static final String QUERY_BY_BUILD_CONFIGURATION_ID = "buildConfigurationId==%d"; protected BuildRecordRepository repository; private BuildExecutor buildExecutor; private BuildCoordinator buildCoordinator; private BuildConfigurationAuditedRepository buildConfigurationAuditedRepository; ProjectRepository projectRepository; BuildConfigSetRecordRepository buildConfigSetRecordRepository; EntityManager entityManager; @Deprecated public BuildRecordProvider() { } @Inject public BuildRecordProvider(BuildRecordRepository buildRecordRepository, BuildCoordinator buildCoordinator, PageInfoProducer pageInfoProducer, RSQLPredicateProducer rsqlPredicateProducer, SortInfoProducer sortInfoProducer, BuildExecutor buildExecutor, BuildRecordRepository repository, BuildConfigurationAuditedRepository buildConfigurationAuditedRepository, ProjectRepository projectRepository, BuildConfigSetRecordRepository buildConfigSetRecordRepository, EntityManager entityManager) { super(buildRecordRepository, rsqlPredicateProducer, sortInfoProducer, pageInfoProducer); this.buildCoordinator = buildCoordinator; this.buildExecutor = buildExecutor; this.repository = repository; this.buildConfigurationAuditedRepository = buildConfigurationAuditedRepository; this.projectRepository = projectRepository; this.entityManager = entityManager; this.buildConfigSetRecordRepository = buildConfigSetRecordRepository; } public CollectionInfo<BuildRecordRest> getAllRunning(Integer pageIndex, Integer pageSize, String search, String sort) { List<BuildTask> x = buildCoordinator.getSubmittedBuildTasks(); return nullableStreamOf(x).filter(rsqlPredicateProducer.getStreamPredicate(BuildTask.class, search)) .sorted(sortInfoProducer.getSortInfo(sort).getComparator()).skip(pageIndex * pageSize) .limit(pageSize).map(submittedBuild -> createNewBuildRecordRest(submittedBuild)) .collect(new CollectionInfoCollector<>(pageIndex, pageSize, (int) Math.ceil((double) buildCoordinator.getSubmittedBuildTasks().size() / pageSize))); } public CollectionInfo<BuildRecordRest> getAllRunningForBuildConfiguration(int pageIndex, int pageSize, String search, String sort, Integer bcId) { List<BuildTask> x = buildCoordinator.getSubmittedBuildTasks(); return nullableStreamOf(x).filter(t -> t != null) .filter(t -> t.getBuildConfigurationAudited() != null && bcId.equals(t.getBuildConfigurationAudited().getId())) .filter(rsqlPredicateProducer.getStreamPredicate(BuildTask.class, search)) .sorted(sortInfoProducer.getSortInfo(sort).getComparator()).skip(pageIndex * pageSize) .limit(pageSize).map(submittedBuild -> createNewBuildRecordRest(submittedBuild)) .collect(new CollectionInfoCollector<>(pageIndex, pageSize, (int) Math.ceil((double) buildCoordinator.getSubmittedBuildTasks().size() / pageSize))); } public CollectionInfo<BuildRecordRest> getAllRunningOfUser(int pageIndex, int pageSize, String search, String sort, Integer userId) { List<BuildTask> x = buildCoordinator.getSubmittedBuildTasks(); return nullableStreamOf(x).filter(t -> t != null) .filter(t -> t.getUser() != null && userId.equals(t.getUser().getId())) .filter(rsqlPredicateProducer.getStreamPredicate(BuildTask.class, search)) .sorted(sortInfoProducer.getSortInfo(sort).getComparator()).skip(pageIndex * pageSize) .limit(pageSize).map(submittedBuild -> createNewBuildRecordRest(submittedBuild)) .collect(new CollectionInfoCollector<>(pageIndex, pageSize, (int) Math.ceil((double) buildCoordinator.getSubmittedBuildTasks().size() / pageSize))); } public GraphRest<BuildRecordRest> getDependencyGraphRest(Integer buildId) { GraphWithMetadata<BuildRecordRest, Integer> buildRecordGraph = getDependencyGraph(buildId); Map<String, String> metadata = getGraphMetadata(buildRecordGraph.getMissingNodeIds()); RestGraphBuilder restGraphBuilder = new RestGraphBuilder(metadata); return restGraphBuilder.from(buildRecordGraph.getGraph(), BuildRecordRest.class); } public RunningBuildsCountRest getRunningCount() { List<BuildTask> x = buildCoordinator.getSubmittedBuildTasks(); int waitingForDependencies = 0; int running = 0; int enqueued = 0; for (BuildTask task : x) { switch (task.getStatus()) { case ENQUEUED: enqueued++; continue; case BUILDING: running++; continue; case WAITING_FOR_DEPENDENCIES: waitingForDependencies++; continue; } } return new RunningBuildsCountRest(running, enqueued, waitingForDependencies); } private GraphWithMetadata<BuildRecordRest, Integer> getDependencyGraph(Integer buildId) { BuildTask buildTask = getSubmittedBuild(buildId); GraphWithMetadata<BuildRecordRest, Integer> buildRecordGraph; if (buildTask == null) { logger.debug("Looking for stored buildRecordId: {}.", buildId); BuildRecord buildRecord = repository.queryById(buildId); if (buildRecord == null) { logger.warn("Cannot find build {}", buildId); return null; } else { GraphWithMetadata dependencyGraph = repository.getDependencyGraph(buildId); Graph<BuildRecordRest> buildRecordRestGraph = convertBuildRecordToRest(dependencyGraph.getGraph()); logger.trace("Rest graph for buildRecordId {} {}; Graph edges {}.", buildId, buildRecordRestGraph, buildRecordRestGraph.getEdges()); buildRecordGraph = new GraphWithMetadata<>(buildRecordRestGraph, dependencyGraph.getMissingNodeIds()); } } else { logger.debug("Getting dependency graph for running build: {}.", buildId); Graph<BuildTask> graph = getBuiltTaskDependencyGraph(buildId); Graph<BuildRecordRest> buildRecordRestGraph = convertBuildTaskToRecordRest(graph); buildRecordGraph = new GraphWithMetadata<>(buildRecordRestGraph, new ArrayList<>()); } return buildRecordGraph; } private Graph<BuildTask> getBuiltTaskDependencyGraph(Integer buildId) { Graph<BuildTask> graph = new Graph<>(); GraphBuilder graphBuilder = new GraphBuilder<BuildTask>(id -> Optional.ofNullable(getSubmittedBuild(id)), bt -> bt.getDependencies().stream().map(BuildTask::getId).collect(Collectors.toList()), bt -> bt.getDependants().stream().map(BuildTask::getId).collect(Collectors.toList())); Vertex<BuildTask> current = graphBuilder.buildDependencyGraph(graph, buildId); if (current != null) { BuildTask currentTask = current.getData(); graphBuilder.buildDependentGraph(graph, currentTask.getId()); } return graph; } private Graph<BuildRecordRest> convertBuildTaskToRecordRest(Graph<BuildTask> taskGraph) { Graph<BuildRecordRest> buildRecordGraph = new Graph<>(); for (Vertex<BuildTask> buildTaskVertex : taskGraph.getVerticies()) { BuildRecordRest recordRest = createBuildRecordForTask(buildTaskVertex.getData()); Vertex<BuildRecordRest> buildRecordVertex = new NameUniqueVertex<>(Integer.toString(recordRest.getId()), recordRest); buildRecordGraph.addVertex(buildRecordVertex); } //create edges for (Vertex<BuildTask> vertex : taskGraph.getVerticies()) { for (Object o : vertex.getOutgoingEdges()) { Edge<BuildTask> edge = (Edge<BuildTask>) o; buildRecordGraph.addEdge(buildRecordGraph.findVertexByName(edge.getFrom().getName()), buildRecordGraph.findVertexByName(edge.getTo().getName()), edge.getCost()); } } return buildRecordGraph; } private Graph<BuildRecordRest> convertBuildRecordToRest(Graph<BuildRecord> recordGraph) { Graph<BuildRecordRest> buildRecordGraph = new Graph<>(); for (Vertex<BuildRecord> buildRecordVertex : recordGraph.getVerticies()) { BuildRecordRest recordRest = new BuildRecordRest(buildRecordVertex.getData()); Vertex<BuildRecordRest> buildRecordRestVertex = new NameUniqueVertex<>( Integer.toString(recordRest.getId()), recordRest); buildRecordGraph.addVertex(buildRecordRestVertex); } //create edges for (Edge<BuildRecord> edge : recordGraph.getEdges()) { buildRecordGraph.addEdge(buildRecordGraph.findVertexByName(edge.getFrom().getName()), buildRecordGraph.findVertexByName(edge.getTo().getName()), edge.getCost()); } return buildRecordGraph; } BuildRecordRest createNewBuildRecordRest(BuildTask buildTask) { //TODO do not mix executor and coordinator data in the same endpoint BuildExecutionSession runningExecution = buildExecutor.getRunningExecution(buildTask.getId()); UserRest user = new UserRest(buildTask.getUser()); //refresh entity IdRev idRev = buildTask.getBuildConfigurationAudited().getIdRev(); logger.debug("Loading entity by idRev: {}.", idRev); BuildConfigurationAudited buildConfigurationAudited = buildConfigurationAuditedRepository.queryById(idRev); BuildConfigurationAuditedRest buildConfigAuditedRest = new BuildConfigurationAuditedRest( buildConfigurationAudited); Integer[] dependencyIds = buildTask.getDependencies().stream().map(BuildTask::getId) .toArray(Integer[]::new); Integer[] dependentIds = buildTask.getDependants().stream().map(BuildTask::getId).toArray(Integer[]::new); BuildRecordRest buildRecRest; if (runningExecution != null) { buildRecRest = new BuildRecordRest(runningExecution, buildTask.getSubmitTime(), user, buildConfigAuditedRest, dependencyIds, dependentIds); } else { buildRecRest = new BuildRecordRest(buildTask.getId(), buildTask.getStatus(), buildTask.getSubmitTime(), buildTask.getStartTime(), buildTask.getEndTime(), user, buildConfigAuditedRest, buildTask.getBuildOptions().isTemporaryBuild(), dependencyIds, dependentIds); } return buildRecRest; } public CollectionInfo<Object> getAllRunningForBCSetRecord(int pageIndex, int pageSize, String search, Integer bcSetRecordId) { return nullableStreamOf(buildCoordinator.getSubmittedBuildTasks()).filter(t -> t != null) .filter(t -> t.getBuildSetTask() != null && bcSetRecordId.equals(t.getBuildSetTask().getId())) .filter(task -> search == null || "".equals(search) || String.valueOf(task.getId()).contains(search) || (task.getBuildConfigurationAudited() != null && task.getBuildConfigurationAudited().getName() != null && task.getBuildConfigurationAudited().getName().contains(search))) .sorted((t1, t2) -> t1.getId() - t2.getId()) .map(submittedBuild -> createNewBuildRecordRest(submittedBuild)).skip(pageIndex * pageSize) .limit(pageSize).collect(new CollectionInfoCollector<>(pageIndex, pageSize, (int) Math.ceil((double) buildCoordinator.getSubmittedBuildTasks().size() / pageSize))); } public GraphRest<BuildRecordRest> getBCSetRecordRestGraph(Integer bcSetRecordId) { Graph<BuildTask> runningBuildGraph = getRunningBCSetRecordGraph(bcSetRecordId); Graph<BuildRecordRest> runningBuildRecordGraph = convertBuildTaskToRecordRest(runningBuildGraph); GraphWithMetadata<BuildRecordRest, Integer> buildConfigSetRecordGraph = getBuildConfigSetRecordGraph( bcSetRecordId); Graph graph = buildConfigSetRecordGraph.getGraph(); GraphUtils.merge(graph, runningBuildRecordGraph); Map<String, String> metadata = getGraphMetadata(buildConfigSetRecordGraph.getMissingNodeIds()); RestGraphBuilder graphBuilder = new RestGraphBuilder(metadata); GraphRest<BuildRecordRest> graphRest = graphBuilder.from(graph, BuildRecordRest.class); return graphRest; } private Map<String, String> getGraphMetadata(List<Integer> missingBuildRecordIds) { Map<String, String> metadata = new HashMap<>(); if (missingBuildRecordIds.size() > 0) { metadata.put("status", "INCOMPLETE"); for (Integer buildRecordId : missingBuildRecordIds) { metadata.put("description", "Missing some Build Records: " + buildRecordId); } } return metadata; } Graph<BuildTask> getRunningBCSetRecordGraph(Integer bcSetRecordId) { //get all build tasks that are in the group List<BuildTask> buildTasks = nullableStreamOf(buildCoordinator.getSubmittedBuildTasks()) .filter(t -> t != null) .filter(t -> t.getBuildSetTask() != null && bcSetRecordId.equals(t.getBuildSetTask().getId())) .sorted((t1, t2) -> t1.getId() - t2.getId()).collect(Collectors.toList()); Graph<BuildTask> buildGraph = new Graph<>(); for (BuildTask buildTask : buildTasks) { //Adds buildTask and related tasks (dependencies and dependents) to the graph if they don't already exists Graph<BuildTask> dependencyGraph = getBuiltTaskDependencyGraph(buildTask.getId()); GraphUtils.merge(buildGraph, dependencyGraph); } return buildGraph; } private GraphWithMetadata<BuildRecordRest, Integer> getBuildConfigSetRecordGraph(Integer bcSetRecordId) { BuildConfigSetRecord buildConfigSetRecord = buildConfigSetRecordRepository.queryById(bcSetRecordId); Graph<BuildRecordRest> buildGraph = new Graph<>(); List<Integer> missingBuildRecordId = new ArrayList<>(); for (BuildRecord buildRecord : buildConfigSetRecord.getBuildRecords()) { GraphWithMetadata<BuildRecordRest, Integer> dependencyGraph = getDependencyGraph(buildRecord.getId()); GraphUtils.merge(buildGraph, dependencyGraph.getGraph()); logger.trace("Merged graph from buildRecordId {} to BuildConfigSetRecordGraph {}; Edges {},", buildRecord.getId(), buildGraph, buildGraph.getEdges()); missingBuildRecordId.addAll(dependencyGraph.getMissingNodeIds()); } return new GraphWithMetadata<>(buildGraph, missingBuildRecordId); } public CollectionInfo<BuildRecordRest> getAllForBuildConfiguration(int pageIndex, int pageSize, String sortingRsql, String query, Integer configurationId) { return queryForCollection(pageIndex, pageSize, sortingRsql, query, withBuildConfigurationId(configurationId)); } public CollectionInfo<BuildRecordRest> getAllOfUser(int pageIndex, int pageSize, String sortingRsql, String query, Integer userId) { return queryForCollection(pageIndex, pageSize, sortingRsql, query, withUserId(userId)); } public CollectionInfo<BuildRecordRest> getAllForProject(int pageIndex, int pageSize, String sortingRsql, String query, Integer projectId) { List<Object[]> buildConfigurationRevisions = AuditReaderFactory.get(entityManager).createQuery() .forRevisionsOfEntity(BuildConfiguration.class, false, false) .add(AuditEntity.relatedId("project").eq(projectId)).addOrder(AuditEntity.revisionNumber().desc()) .getResultList(); return queryForBuildRecords(pageIndex, pageSize, sortingRsql, query, buildConfigurationRevisions); } public CollectionInfo<BuildRecordRest> getAllForConfigurationOrProjectName(int pageIndex, int pageSize, String sortingRsql, String query, String name) { List<Project> projectsMatchingName = projectRepository .queryWithPredicates(ProjectPredicates.searchByProjectName(name)); AuditDisjunction disjunction = AuditEntity.disjunction(); projectsMatchingName.forEach(project -> { disjunction.add(AuditEntity.relatedId("project").eq(project.getId())); }); disjunction.add(AuditEntity.property("name").like(name)); List<Object[]> buildConfigurationRevisions = AuditReaderFactory.get(entityManager).createQuery() .forRevisionsOfEntity(BuildConfiguration.class, false, false).add(disjunction) .addOrder(AuditEntity.revisionNumber().desc()).getResultList(); return queryForBuildRecords(pageIndex, pageSize, sortingRsql, query, buildConfigurationRevisions); } private CollectionInfo<BuildRecordRest> queryForBuildRecords(int pageIndex, int pageSize, String sortingRsql, String query, List<Object[]> buildConfigurationRevisions) { List<IdRev> buildConfigurationsWithProjectIdRevs = buildConfigurationRevisions.stream() .map(o -> toIdRev(o[0], o[1])).collect(Collectors.toList()); if (buildConfigurationsWithProjectIdRevs.isEmpty()) { return new CollectionInfo<>(0, 0, 0, Collections.EMPTY_SET); } else { return queryForCollection(pageIndex, pageSize, sortingRsql, query, withBuildConfigurationIdRev(buildConfigurationsWithProjectIdRevs)); } } private IdRev toIdRev(Object entity, Object revision) { BuildConfiguration buildConfiguration = (BuildConfiguration) entity; DefaultRevisionEntity revisionEntity = (DefaultRevisionEntity) revision; return new IdRev(buildConfiguration.getId(), revisionEntity.getId()); } public CollectionInfo<BuildRecordRest> getAllBuildRecordsWithArtifactsDistributedInProductMilestone( int pageIndex, int pageSize, String sortingRsql, String query, Integer milestoneId) { return queryForCollection(pageIndex, pageSize, sortingRsql, query, withArtifactDistributedInMilestone(milestoneId)); } /** * @deprecated Use getAllBuildRecordsWithArtifactsDistributedInProductMilestone */ @Deprecated public Collection<Integer> getAllBuildsInDistributedRecordsetOfProductMilestone(Integer milestoneId) { return getAllBuildRecordsWithArtifactsDistributedInProductMilestone(0, 50, null, null, milestoneId) .getContent().stream().map(BuildRecordRest::getId).collect(Collectors.toList()); } public CollectionInfo<BuildRecordRest> getAllForBuildConfigSetRecord(int pageIndex, int pageSize, String sortingRsql, String rsql, Integer buildConfigurationSetRecordId) { return queryForCollection(pageIndex, pageSize, sortingRsql, rsql, withBuildConfigSetRecordId(buildConfigurationSetRecordId)); } public CollectionInfo<BuildRecordRest> getAllForBuildConfigSet(int pageIndex, int pageSize, String sortingRsql, String rsql, Integer buildConfigurationSetId) { return queryForCollection(pageIndex, pageSize, sortingRsql, rsql, withBuildConfigSetId(buildConfigurationSetId)); } @Override protected Function<? super BuildRecord, ? extends BuildRecordRest> toRESTModel() { return (buildRecord) -> { Integer revision = buildRecord.getBuildConfigurationRev(); BuildConfigurationAudited buildConfigurationAudited = buildConfigurationAuditedRepository .queryById(new IdRev(buildRecord.getBuildConfigurationId(), revision)); buildRecord.setBuildConfigurationAudited(buildConfigurationAudited); return new BuildRecordRest(buildRecord); }; } private void preloadBuildConfigurationRelations(BuildConfiguration buildConfiguration) { buildConfiguration.getGenericParameters().forEach((k, v) -> k.equals(null)); } @Override protected Function<? super BuildRecordRest, ? extends BuildRecord> toDBModel() { throw new UnsupportedOperationException("Not supported by BuildRecordProvider"); } public String getBuildRecordLog(Integer id) { BuildRecord buildRecord = ((BuildRecordRepository) repository).findByIdFetchAllProperties(id); if (buildRecord != null) return buildRecord.getBuildLog(); else return null; } public String getBuildRecordRepourLog(Integer id) { BuildRecord buildRecord = ((BuildRecordRepository) repository).findByIdFetchAllProperties(id); if (buildRecord != null) { return buildRecord.getRepourLog(); } else { return null; } } public StreamingOutput getLogsForBuild(String buildRecordLog) { if (buildRecordLog == null) return null; return outputStream -> { Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)); writer.write(buildRecordLog); writer.flush(); }; } public StreamingOutput getRepourLogsForBuild(String repourLog) { if (repourLog == null) return null; return outputStream -> { Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream)); writer.write(repourLog); writer.flush(); }; } public BuildRecordRest getSpecificRunning(Integer id) { if (id == null) { return null; } BuildTask buildTask = getSubmittedBuild(id); return createBuildRecordForTask(buildTask); } public BuildRecordRest createBuildRecordForTask(BuildTask task) { return task == null ? null : createNewBuildRecordRest(task); } private BuildTask getSubmittedBuild(Integer id) { return buildCoordinator.getSubmittedBuildTasks().stream() .filter(submittedBuild -> id.equals(submittedBuild.getId())).findFirst().orElse(null); } public BuildConfigurationAuditedRest getBuildConfigurationAudited(Integer id) { BuildRecord buildRecord = repository.queryById(id); if (buildRecord == null) { return null; } if (buildRecord.getBuildConfigurationAudited() != null) { return new BuildConfigurationAuditedRest(buildRecord.getBuildConfigurationAudited()); } else { BuildConfigurationAudited buildConfigurationAudited = buildConfigurationAuditedRepository.queryById( new IdRev(buildRecord.getBuildConfigurationId(), buildRecord.getBuildConfigurationRev())); return new BuildConfigurationAuditedRest(buildConfigurationAudited); } } public BuildRecordRest getLatestBuildRecord(Integer configId, boolean executedOnly) { PageInfo pageInfo = this.pageInfoProducer.getPageInfo(0, 1); SortInfo sortInfo = this.sortInfoProducer.getSortInfo(SortInfo.SortingDirection.DESC, "endTime"); List<BuildRecord> buildRecords; if (executedOnly) { buildRecords = repository.queryWithPredicates(pageInfo, sortInfo, withBuildConfigurationIdAndStatusExecuted(configId)); } else { buildRecords = repository.queryWithPredicates(pageInfo, sortInfo, withBuildConfigurationId(configId)); } if (buildRecords.isEmpty()) { return null; } return toRESTModel().apply(buildRecords.get(0)); } public CollectionInfo<BuildRecordRest> getRunningAndCompletedBuildRecords(Integer pageIndex, Integer pageSize, String sort, String orFindByBuildConfigurationName, String andFindByBuildConfigurationName, String search) { return getBuilds(pageIndex, pageSize, sort, orFindByBuildConfigurationName, andFindByBuildConfigurationName, search); } public CollectionInfo<BuildRecordRest> getRunningAndCompletedBuildRecordsByUserId(Integer pageIndex, Integer pageSize, String sort, String search, Integer userId) { return getBuilds(pageIndex, pageSize, sort, null, null, search, String.format(QUERY_BY_USER, userId)); } public CollectionInfo<BuildRecordRest> getRunningAndCompletedBuildRecordsByBuildConfigurationId( Integer pageIndex, Integer pageSize, String sort, String search, Integer buildConfigurationId) { return getBuilds(pageIndex, pageSize, sort, null, null, search, String.format(QUERY_BY_BUILD_CONFIGURATION_ID, buildConfigurationId)); } /* * Abstracts away the implementation detail that BuildRecords are not persisted to the database until the build is * complete. This abstraction allows clients to query for a list of all builds whether running or completed. */ private CollectionInfo<BuildRecordRest> getBuilds(Integer pageIndex, Integer pageSize, String sort, String orFindByBuildConfigurationName, String andFindByBuildConfigurationName, String... rsqlQueries) { List<Predicate<BuildRecord>> dbAndPredicatesList = Arrays.stream(rsqlQueries) .filter(rsqlString -> rsqlString != null && !rsqlString.isEmpty()) .map(p -> rsqlPredicateProducer.getPredicate(BuildRecord.class, p)).collect(Collectors.toList()); List<Predicate<BuildRecord>> dbOrPredicateList = new ArrayList<>(); String combinedQueries = combineRsqlQueriesMatchAll(rsqlQueries); if (!StringUtils.isEmpty(orFindByBuildConfigurationName)) { //add steam condition if (StringUtils.isEmpty(combinedQueries)) { combinedQueries = "(buildConfigurationName=like=" + orFindByBuildConfigurationName + ")"; } else { combinedQueries = "(" + combinedQueries + "),(buildConfigurationName=like=" + orFindByBuildConfigurationName + ")"; } //add DB predicate List<BuildConfigurationAudited> buildConfigurationAuditeds = buildConfigurationAuditedRepository .searchForBuildConfigurationName(orFindByBuildConfigurationName); if (!buildConfigurationAuditeds.isEmpty()) { dbOrPredicateList.add(BuildRecordPredicates.withBuildConfigurationIdRev(buildConfigurationAuditeds .stream().map(bca -> bca.getIdRev()).collect(Collectors.toList()))); } } if (!StringUtils.isEmpty(andFindByBuildConfigurationName)) { //add steam condition if (StringUtils.isEmpty(combinedQueries)) { combinedQueries = "(buildConfigurationName==" + andFindByBuildConfigurationName + ")"; } else { combinedQueries = "(" + combinedQueries + ");(buildConfigurationName==" + andFindByBuildConfigurationName + ")"; } //add DB predicate List<BuildConfigurationAudited> buildConfigurationAuditeds = buildConfigurationAuditedRepository .searchForBuildConfigurationName(andFindByBuildConfigurationName); if (!buildConfigurationAuditeds.isEmpty()) { dbAndPredicatesList.add(BuildRecordPredicates.withBuildConfigurationIdRev(buildConfigurationAuditeds .stream().map(bca -> bca.getIdRev()).collect(Collectors.toList()))); } else { dbAndPredicatesList.add(Predicate.nonMatching()); } } Set<BuildRecordRest> running = nullableStreamOf(buildCoordinator.getSubmittedBuildTasks()) .map(this::createNewBuildRecordRest) .filter(rsqlPredicateProducer.getStreamPredicate(BuildRecordRest.class, combinedQueries)) .sorted(sortInfoProducer.getSortInfo(sort).getComparator()).collect(Collectors.toSet()); final int totalRunning = running.size(); CollectionInfo<BuildRecordRest> page = null; for (int i = 0; i <= pageIndex; i++) { final int offset = totalRunning - running.size(); if (offset == totalRunning) { page = createInterleavedPage(pageIndex, pageSize, offset, totalRunning, sort, running, dbAndPredicatesList, dbOrPredicateList); break; } page = createInterleavedPage(i, pageSize, offset, totalRunning, sort, running, dbAndPredicatesList, dbOrPredicateList); running.removeAll(page.getContent()); } return page; } private final CollectionInfo<BuildRecordRest> createInterleavedPage(int pageIndex, int pageSize, int offset, int totalRunning, String sort, Set<BuildRecordRest> running, List<Predicate<BuildRecord>> dbAndPredicates, List<Predicate<BuildRecord>> dbOrPredicates) { PageInfo pageInfo = new DefaultPageInfo(pageIndex * pageSize - offset, pageSize); SortInfo sortInfo = sortInfoProducer.getSortInfo(sort); List<BuildRecordRest> content = nullableStreamOf(((BuildRecordRepository) repository) .queryWithPredicatesUsingCursor(pageInfo, sortInfo, dbAndPredicates, dbOrPredicates)) .map(toRESTModel()).collect(Collectors.toList()); content.addAll(running); content = content.stream().sorted(sortInfoProducer.getSortInfo(sort).getComparator()).limit(pageSize) .collect(Collectors.toList()); int totalPages = calculateInterleavedPageCount(totalRunning, repository.count(dbAndPredicates, dbOrPredicates), pageSize); return new CollectionInfo<>(pageIndex, pageSize, totalPages, content); } private String combineRsqlQueriesMatchAll(String... rsqlQueries) { return nullableStreamOf(Arrays.asList(rsqlQueries)).filter(x -> !StringUtils.isEmpty(x)) .collect(Collectors.joining(";")); } private int calculateInterleavedPageCount(int totalRunningBuilds, int totalDbBuilds, int pageSize) { return (int) Math.ceil((totalRunningBuilds + totalDbBuilds) / (double) pageSize); } public Map<String, String> putAttribute(Integer id, String name, String value) { BuildRecord buildRecord = repository.queryById(id); buildRecord.putAttribute(name, value); return buildRecord.getAttributes(); } public void removeAttribute(Integer id, String name) { BuildRecord buildRecord = repository.queryById(id); buildRecord.removeAttribute(name); } public Map<String, String> getAttributes(Integer id) { BuildRecord buildRecord = repository.queryById(id); return buildRecord.getAttributes(); } public Collection<BuildRecordRest> getByAttribute(String key, String value) { List<BuildRecord> buildRecords = repository.queryWithPredicates(withAttribute(key, value)); return buildRecords.stream().map(BuildRecordRest::new).collect(Collectors.toList()); } public CollectionInfo<BuildRecordRest> getByAttribute(int pageIndex, int pageSize, String sortingRsql, String rsql, String key, String value) { return queryForCollection(pageIndex, pageSize, sortingRsql, rsql, withAttribute(key, value)); } public SshCredentials getSshCredentialsForUser(Integer id, User currentUser) { BuildRecord buildRecord = repository.queryById(id); if (buildRecord != null && currentUser != null) { User buildRequester = buildRecord.getUser(); if (buildRequester != null && currentUser.getId().equals(buildRequester.getId()) && buildRecord.getSshCommand() != null) { return new SshCredentials(buildRecord.getSshCommand(), buildRecord.getSshPassword()); } } return null; } public Response createResultSet(BuildConfigurationSetTriggerResult result, UriInfo uriInfo) { UriBuilder uriBuilder = UriBuilder.fromUri(uriInfo.getBaseUri()).path("/build-config-set-records/{id}"); URI uri = uriBuilder.build(result.getBuildRecordSetId()); Page<BuildRecordRest> resultsToBeReturned = new Page<>( new CollectionInfo<>(0, result.getBuildTasks().size(), 1, result.getBuildTasks().stream().map(this::createBuildRecordForTask).filter(Objects::nonNull) .collect(Collectors.toList()))); return Response.ok(uri).header("location", uri).entity(resultsToBeReturned).build(); } }