Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.core.DefaultStreamDefinitionService;
import org.springframework.cloud.dataflow.core.StreamDefinitionService;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -128,7 +129,7 @@ public AppRegistryService appRegistry() {

return new DefaultAppRegistryService(mock(AppRegistrationRepository.class),
new AppResourceCommon(new MavenProperties(), new FileSystemResourceLoader()),
mock(DefaultAuditRecordService.class)) {
mock(DefaultAuditRecordService.class), mock(AppRegistrationDao.class)) {

@Override
public boolean appExist(String name, ApplicationType type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.core.DefaultStreamDefinitionService;
import org.springframework.cloud.dataflow.core.StreamDefinitionService;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -74,7 +75,7 @@ public AppRegistryService appRegistry() {

return new DefaultAppRegistryService(mock(AppRegistrationRepository.class),
new AppResourceCommon(new MavenProperties(), new FileSystemResourceLoader()),
mock(DefaultAuditRecordService.class)) {
mock(DefaultAuditRecordService.class), mock(AppRegistrationDao.class)) {

@Override
public boolean appExist(String name, ApplicationType type) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2021 the original author or authors.
*
* 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
*
* https://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.springframework.cloud.dataflow.registry.repository;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.cloud.dataflow.core.AppRegistration;
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

@Component
public class AppRegistrationDao {

private final EntityManager entityManager;
private final AppRegistrationRepository appRegistrationRepository;

public AppRegistrationDao(EntityManager entityManager, AppRegistrationRepository appRegistrationRepository) {
Assert.notNull(entityManager, "Entity manager cannot be null");
Assert.notNull(appRegistrationRepository, "AppRegistrationRepository cannot be null");
this.entityManager = entityManager;
this.appRegistrationRepository = appRegistrationRepository;
}

public Page<AppRegistration> findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type,
String name, String version, boolean defaultVersion, Pageable pageable) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<AppRegistration> cq = cb.createQuery(AppRegistration.class);
Root<AppRegistration> appRegistrationRoot = cq.from(AppRegistration.class);
final List<Predicate> predicates = new ArrayList<>();
if (type != null) {
predicates.add(cb.equal(appRegistrationRoot.get("type"), type));
}
if (StringUtils.hasText(name)) {
predicates.add(cb.like(cb.lower(appRegistrationRoot.get("name")), "%" + name.toLowerCase() + "%"));
}
if (StringUtils.hasText(version)) {
predicates.add(cb.equal(cb.lower(appRegistrationRoot.get("version")), version.toLowerCase()));
}
if (defaultVersion) {
predicates.add(cb.isTrue(appRegistrationRoot.get("defaultVersion")));
}
cq.where(predicates.toArray(new Predicate[0]));
cq.orderBy(QueryUtils.toOrders(pageable.getSort(), appRegistrationRoot, cb));
TypedQuery<AppRegistration> query = entityManager.createQuery(cq);
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize());
final List<AppRegistration> resultList = query.getResultList();
if (defaultVersion) {
resultList.forEach(appRegistration -> {
HashSet<String> versions =
appRegistrationRepository.findAllByName(appRegistration.getName()).stream()
.map(AppRegistration::getVersion).collect(Collectors.toCollection(HashSet::new));
appRegistration.setVersions(versions);
});
}
return new PageImpl<>(resultList, pageable, getTotalCount(cb, predicates.toArray(new Predicate[0])));
}

private Long getTotalCount(CriteriaBuilder criteriaBuilder, Predicate[] predicateArray) {
CriteriaQuery<Long> criteriaQuery = criteriaBuilder.createQuery(Long.class);
Root<AppRegistration> root = criteriaQuery.from(AppRegistration.class);

criteriaQuery.select(criteriaBuilder.count(root));
criteriaQuery.where(predicateArray);

return entityManager.createQuery(criteriaQuery).getSingleResult();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ public interface AppRegistrationRepository extends KeyValueRepository<AppRegistr

Page<AppRegistration> findAllByNameContainingIgnoreCaseAndDefaultVersionIsTrue(String name, Pageable pageable);

List<AppRegistration> findAllByName(String name);

@Override
<S extends AppRegistration> S save(S s);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,26 @@ public interface AppRegistryService {
Page<AppRegistration> findAll(Pageable pageable);

/**
* @param type appliation type
* @param type application type
* @param name application name
* @param pageable Pagination information
* @return returns all {@link AppRegistration} versions for given name and type. Uses the
* pagination.
*/
Page<AppRegistration> findAllByTypeAndNameIsLike(ApplicationType type, String name, Pageable pageable);

/**
* @param type application type
* @param name application name
* @param version application version
* @param defaultVersion application default version
* @param pageable Pagination information
* @return returns all {@link AppRegistration} versions for given name and type. Uses the
* pagination.
*/
Page<AppRegistration> findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type,
String name, String version, boolean defaultVersion, Pageable pageable);


/**
* @param type appliation type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.core.AuditActionType;
import org.springframework.cloud.dataflow.core.AuditOperationType;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.support.AppResourceCommon;
import org.springframework.cloud.dataflow.registry.support.NoSuchAppRegistrationException;
Expand Down Expand Up @@ -87,15 +88,20 @@ public class DefaultAppRegistryService implements AppRegistryService {

protected final AuditServiceUtils auditServiceUtils;

private final AppRegistrationDao appRegistrationDao;

public DefaultAppRegistryService(AppRegistrationRepository appRegistrationRepository,
AppResourceCommon appResourceCommon, AuditRecordService auditRecordService) {
AppResourceCommon appResourceCommon, AuditRecordService auditRecordService,
AppRegistrationDao appRegistrationDao) {
Assert.notNull(appResourceCommon, "'appResourceCommon' must not be null");
Assert.notNull(appRegistrationRepository, "'appRegistrationRepository' must not be null");
Assert.notNull(auditRecordService, "'auditRecordService' must not be null");
Assert.notNull(appRegistrationDao, "'appRegistrationDao' must not be null");
this.appResourceCommon = appResourceCommon;
this.appRegistrationRepository = appRegistrationRepository;
this.auditRecordService = auditRecordService;
this.auditServiceUtils = new AuditServiceUtils();
this.appRegistrationDao = appRegistrationDao;
}

@Override
Expand Down Expand Up @@ -182,6 +188,13 @@ else if (StringUtils.hasText(name)) {
return result;
}

@Override
public Page<AppRegistration> findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type,
String name, String version, boolean defaultVersion, Pageable pageable) {
return appRegistrationDao.findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(type, name, version,
defaultVersion, pageable);
}

@Override
public Page<AppRegistration> findAllByTypeAndNameIsLikeAndDefaultVersionIsTrue(ApplicationType type, String name, Pageable pageable) {
Page<AppRegistration> result = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.springframework.cloud.dataflow.audit.service.DefaultAuditRecordService;
import org.springframework.cloud.dataflow.core.AppRegistration;
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.support.AppResourceCommon;
import org.springframework.cloud.deployer.resource.maven.MavenProperties;
Expand Down Expand Up @@ -72,7 +73,8 @@ public class DefaultAppRegistryServiceTests {
private ResourceLoader resourceLoader = new DefaultResourceLoader();

private AppRegistryService appRegistryService = new DefaultAppRegistryService(appRegistrationRepository,
new AppResourceCommon(new MavenProperties(), resourceLoader), mock(DefaultAuditRecordService.class));
new AppResourceCommon(new MavenProperties(), resourceLoader), mock(DefaultAuditRecordService.class),
mock(AppRegistrationDao.class));

@Test
public void testNotFound() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.springframework.cloud.dataflow.completion.TaskCompletionProvider;
import org.springframework.cloud.dataflow.configuration.metadata.ApplicationConfigurationMetadataResolver;
import org.springframework.cloud.dataflow.core.StreamDefinitionService;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -227,8 +228,10 @@ public AppResourceCommon appResourceCommon(@Nullable MavenProperties mavenProper

@Bean
public AppRegistryService appRegistryService(AppRegistrationRepository appRegistrationRepository,
AppResourceCommon appResourceCommon, AuditRecordService auditRecordService) {
return new DefaultAppRegistryService(appRegistrationRepository, appResourceCommon, auditRecordService);
AppResourceCommon appResourceCommon, AuditRecordService auditRecordService,
AppRegistrationDao appRegistrationDao) {
return new DefaultAppRegistryService(appRegistrationRepository, appResourceCommon, auditRecordService,
appRegistrationDao);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.springframework.hateoas.server.RepresentationModelAssembler;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
Expand Down Expand Up @@ -129,21 +130,21 @@ public AppRegistryController(Optional<StreamDefinitionRepository> streamDefiniti
* @param pagedResourcesAssembler the resource assembler for app registrations
* @param type the application type: source, sink, processor, task
* @param search optional findByTaskNameContains parameter
* @param version optional findByTaskVersionEquals parameter
* @return the list of registered applications
*/
@RequestMapping(method = RequestMethod.GET)
@GetMapping
@ResponseStatus(HttpStatus.OK)
public PagedModel<? extends AppRegistrationResource> list(
Pageable pageable,
PagedResourcesAssembler<AppRegistration> pagedResourcesAssembler,
@RequestParam(value = "type", required = false) ApplicationType type,
@RequestParam(required = false) String search,
@RequestParam(required = false) String version,
@RequestParam(required = false) boolean defaultVersion) {

Page<AppRegistration> pagedRegistrations = (defaultVersion) ?
this.appRegistryService.findAllByTypeAndNameIsLikeAndDefaultVersionIsTrue(type, search, pageable)
: this.appRegistryService.findAllByTypeAndNameIsLike(type, search,
pageable);
Page<AppRegistration> pagedRegistrations = this.appRegistryService
.findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(type, search, version, defaultVersion, pageable);

return pagedResourcesAssembler.toModel(pagedRegistrations, this.appRegistryAssembler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.core.StreamDefinition;
import org.springframework.cloud.dataflow.core.StreamDefinitionService;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -134,7 +135,7 @@ public AppRegistryService appRegistry() {

return new DefaultAppRegistryService(mock(AppRegistrationRepository.class),
new AppResourceCommon(new MavenProperties(), new FileSystemResourceLoader()),
mock(DefaultAuditRecordService.class)) {
mock(DefaultAuditRecordService.class), mock(AppRegistrationDao.class)) {

@Override
public boolean appExist(String name, ApplicationType type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import org.springframework.cloud.dataflow.configuration.metadata.container.ContainerImageMetadataResolver;
import org.springframework.cloud.dataflow.core.Launcher;
import org.springframework.cloud.dataflow.core.TaskPlatform;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -382,7 +383,8 @@ public RestControllerAdvice restControllerAdvice() {
public AppRegistryService appRegistryService(AppRegistrationRepository appRegistrationRepository,
AuditRecordService auditRecordService) {
return new DefaultAppRegistryService(appRegistrationRepository,
new AppResourceCommon(new MavenProperties(), new DefaultResourceLoader()), auditRecordService);
new AppResourceCommon(new MavenProperties(), new DefaultResourceLoader()), auditRecordService,
mock(AppRegistrationDao.class));
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Optional;
import java.util.concurrent.ForkJoinPool;

import javax.persistence.EntityManager;
import javax.sql.DataSource;

import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
Expand All @@ -34,6 +35,7 @@
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScan;
Expand All @@ -58,6 +60,7 @@
import org.springframework.cloud.dataflow.core.Launcher;
import org.springframework.cloud.dataflow.core.StreamDefinitionService;
import org.springframework.cloud.dataflow.core.TaskPlatform;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao;
import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository;
import org.springframework.cloud.dataflow.registry.service.AppRegistryService;
import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService;
Expand Down Expand Up @@ -217,6 +220,9 @@
@EnableTransactionManagement
public class TestDependencies extends WebMvcConfigurationSupport {

@Autowired
EntityManager entityManager;

@Bean
public RestControllerAdvice restControllerAdvice() {
return new RestControllerAdvice();
Expand Down Expand Up @@ -411,7 +417,8 @@ public ToolsController toolsController() {
@Bean
public AppRegistryService appRegistryService(AppRegistrationRepository appRegistrationRepository,
AppResourceCommon appResourceService, AuditRecordService auditRecordService) {
return new DefaultAppRegistryService(appRegistrationRepository, appResourceService, auditRecordService);
return new DefaultAppRegistryService(appRegistrationRepository, appResourceService, auditRecordService,
new AppRegistrationDao(entityManager, appRegistrationRepository));
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,23 @@ public void testListApplicationsBySearch() throws Exception {
.andExpect(jsonPath("content", hasSize(2)));
}

@Test
public void testListApplicationsByVersion() throws Exception {
mockMvc.perform(get("/apps?version=1.0.0.BUILD-SNAPSHOT").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("content", hasSize(4)));
}

@Test
public void testListApplicationsByVersionAndSearch() throws Exception {
mockMvc.perform(get("/apps?version=1.0.0.BUILD-SNAPSHOT&search=time").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("content", hasSize(2)));
mockMvc.perform(get("/apps?version=1.0.0.BUILD-SNAPSHOT&search=timestamp").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("content", hasSize(1)));
}

@Test
public void testListApplicationsByTypeAndSearch() throws Exception {
mockMvc.perform(get("/apps?type=task&search=time").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
Expand Down
Loading