From 918102deec35edc86e5ac1043dcff31a194f7b61 Mon Sep 17 00:00:00 2001 From: siddhantsorann Date: Tue, 16 Feb 2021 15:54:43 +0530 Subject: [PATCH 1/4] added dao for application registration to implement predicates for multiple filters --- .../BootVersionsCompletionProviderTests.java | 3 +- .../completion/CompletionTestsMocks.java | 3 +- .../repository/AppRegistrationDao.java | 29 ++++++ .../repository/AppRegistrationRepository.java | 2 + .../repository/JdbcAppRegistrationDao.java | 98 +++++++++++++++++++ .../registry/service/AppRegistryService.java | 12 +++ .../service/DefaultAppRegistryService.java | 34 +++++-- .../DefaultAppRegistryServiceTests.java | 4 +- .../DataFlowControllerAutoConfiguration.java | 7 +- .../config/DataFlowServerConfiguration.java | 10 ++ .../controller/AppRegistryController.java | 10 +- .../TabOnTapCompletionProviderTests.java | 3 +- .../server/configuration/JobDependencies.java | 6 +- .../configuration/TestDependencies.java | 16 ++- .../AppRegistryControllerTests.java | 17 ++++ 15 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java create mode 100644 spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java diff --git a/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/BootVersionsCompletionProviderTests.java b/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/BootVersionsCompletionProviderTests.java index 9a7a8bdfea..ba81e4889e 100644 --- a/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/BootVersionsCompletionProviderTests.java +++ b/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/BootVersionsCompletionProviderTests.java @@ -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; @@ -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) { diff --git a/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/CompletionTestsMocks.java b/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/CompletionTestsMocks.java index 5228350c25..d47d85428c 100644 --- a/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/CompletionTestsMocks.java +++ b/spring-cloud-dataflow-completion/src/test/java/org/springframework/cloud/dataflow/completion/CompletionTestsMocks.java @@ -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; @@ -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) { diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java new file mode 100644 index 0000000000..a4153ad05c --- /dev/null +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java @@ -0,0 +1,29 @@ +/* + * 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 org.springframework.cloud.dataflow.core.AppRegistration; +import org.springframework.cloud.dataflow.core.ApplicationType; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface AppRegistrationDao { + + Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion( + ApplicationType type, String name, String version, boolean defaultVersion, Pageable pageable); + +} diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationRepository.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationRepository.java index 8e09070d04..08c8a06e4c 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationRepository.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationRepository.java @@ -52,6 +52,8 @@ public interface AppRegistrationRepository extends KeyValueRepository findAllByNameContainingIgnoreCaseAndDefaultVersionIsTrue(String name, Pageable pageable); + List findAllByName(String name); + @Override S save(S s); diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java new file mode 100644 index 0000000000..0b619ad04b --- /dev/null +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java @@ -0,0 +1,98 @@ +/* + * 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.util.Assert; +import org.springframework.util.StringUtils; + +public class JdbcAppRegistrationDao implements AppRegistrationDao { + + private final EntityManager entityManager; + private final AppRegistrationRepository appRegistrationRepository; + + public JdbcAppRegistrationDao(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; + } + + @Override + public Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, + String name, String version, boolean defaultVersion, Pageable pageable) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(AppRegistration.class); + Root appRegistrationRoot = cq.from(AppRegistration.class); + final List 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 query = entityManager.createQuery(cq); + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + final List resultList = query.getResultList(); + if (defaultVersion) { + resultList.forEach(appRegistration -> { + HashSet 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 criteriaQuery = criteriaBuilder.createQuery(Long.class); + Root root = criteriaQuery.from(AppRegistration.class); + + criteriaQuery.select(criteriaBuilder.count(root)); + criteriaQuery.where(predicateArray); + + return entityManager.createQuery(criteriaQuery).getSingleResult(); + } + +} diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java index 19ea19a494..316339d315 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java @@ -206,4 +206,16 @@ default AppRegistration find(String name, ApplicationType type, String version) * @return the resource version */ String getResourceVersion(String uriString); + + /** + * @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 findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, + String name, String version, boolean defaultVersion, Pageable pageable); } diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryService.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryService.java index 4ff381dee8..5717e232e2 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryService.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryService.java @@ -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; @@ -81,6 +82,8 @@ public class DefaultAppRegistryService implements AppRegistryService { private final AppRegistrationRepository appRegistrationRepository; + private final AppRegistrationDao appRegistrationDao; + private AppResourceCommon appResourceCommon; protected final AuditRecordService auditRecordService; @@ -88,7 +91,8 @@ public class DefaultAppRegistryService implements AppRegistryService { protected final AuditServiceUtils auditServiceUtils; 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"); @@ -96,6 +100,7 @@ public DefaultAppRegistryService(AppRegistrationRepository appRegistrationReposi this.appRegistrationRepository = appRegistrationRepository; this.auditRecordService = auditRecordService; this.auditServiceUtils = new AuditServiceUtils(); + this.appRegistrationDao = appRegistrationDao; } @Override @@ -183,22 +188,25 @@ else if (StringUtils.hasText(name)) { } @Override - public Page findAllByTypeAndNameIsLikeAndDefaultVersionIsTrue(ApplicationType type, String name, Pageable pageable) { + public Page findAllByTypeAndNameIsLikeAndDefaultVersionIsTrue(ApplicationType type, String name, + Pageable pageable) { Page result = null; if (!StringUtils.hasText(name) && type == null) { result = this.appRegistrationRepository.findAllByDefaultVersionIsTrue(pageable); } else if (StringUtils.hasText(name) && type == null) { - result = this.appRegistrationRepository.findAllByNameContainingIgnoreCaseAndDefaultVersionIsTrue(name, pageable); + result = this.appRegistrationRepository.findAllByNameContainingIgnoreCaseAndDefaultVersionIsTrue(name, + pageable); } else if (StringUtils.hasText(name)) { - result = this.appRegistrationRepository.findAllByTypeAndNameContainingIgnoreCaseAndDefaultVersionIsTrue(type, name, pageable); + result = this.appRegistrationRepository + .findAllByTypeAndNameContainingIgnoreCaseAndDefaultVersionIsTrue(type, name, pageable); } else { result = this.appRegistrationRepository.findAllByTypeAndDefaultVersionIsTrue(type, pageable); } - for (AppRegistration pagedAppRegistration: result.getContent()) { - for (AppRegistration appRegistration: this.findAll()) { + for (AppRegistration pagedAppRegistration : result.getContent()) { + for (AppRegistration appRegistration : this.findAll()) { if (pagedAppRegistration.getName().equals(appRegistration.getName()) && pagedAppRegistration.getType().equals(appRegistration.getType())) { if (pagedAppRegistration.getVersions() == null) { @@ -272,7 +280,8 @@ private void populateAuditData(AuditActionType auditActionType, AppRegistration public void delete(String name, ApplicationType type, String version) { this.appRegistrationRepository.deleteAppRegistrationByNameAndTypeAndVersion(name, type, version); - populateAuditData(AuditActionType.DELETE, new AppRegistration(name, type, version, URI.create(""), URI.create(""))); + populateAuditData(AuditActionType.DELETE, + new AppRegistration(name, type, version, URI.create(""), URI.create(""))); } @Override @@ -326,6 +335,13 @@ public String getResourceVersion(String uriString) { return this.getResourceVersion(this.appResourceCommon.getResource(uriString)); } + @Override + public Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, + String name, String version, boolean defaultVersion, Pageable pageable) { + return appRegistrationDao.findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(type, name, version, + defaultVersion, pageable); + } + protected Properties loadProperties(Resource resource) { try { return PropertiesLoaderUtils.loadProperties(resource); @@ -383,9 +399,7 @@ public List importAll(boolean overwrite, Resource... resources) return registrations; } - private BiFunction, - ? super String[], - HashMap> reduceToAppRegistrations() { + private BiFunction, ? super String[], HashMap> reduceToAppRegistrations() { return (map, lineSplit) -> { String[] typeName = lineSplit[0].split("\\."); if (typeName.length < 2 || typeName.length > 3) { diff --git a/spring-cloud-dataflow-registry/src/test/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryServiceTests.java b/spring-cloud-dataflow-registry/src/test/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryServiceTests.java index f2bd076d42..9787589872 100644 --- a/spring-cloud-dataflow-registry/src/test/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryServiceTests.java +++ b/spring-cloud-dataflow-registry/src/test/java/org/springframework/cloud/dataflow/registry/service/DefaultAppRegistryServiceTests.java @@ -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; @@ -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() { diff --git a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java index 69493297ad..6e87393c12 100644 --- a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java +++ b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowControllerAutoConfiguration.java @@ -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; @@ -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 diff --git a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowServerConfiguration.java b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowServerConfiguration.java index bfb9782381..a8555a61a8 100644 --- a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowServerConfiguration.java +++ b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/DataFlowServerConfiguration.java @@ -16,6 +16,7 @@ package org.springframework.cloud.dataflow.server.config; +import javax.persistence.EntityManager; import javax.servlet.Filter; import javax.sql.DataSource; @@ -26,6 +27,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.dataflow.audit.service.AuditRecordService; import org.springframework.cloud.dataflow.completion.CompletionConfiguration; +import org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao; +import org.springframework.cloud.dataflow.registry.repository.AppRegistrationRepository; +import org.springframework.cloud.dataflow.registry.repository.JdbcAppRegistrationDao; import org.springframework.cloud.dataflow.server.config.apps.CommonApplicationProperties; import org.springframework.cloud.dataflow.server.config.features.FeaturesConfiguration; import org.springframework.cloud.dataflow.server.config.web.WebConfiguration; @@ -113,4 +117,10 @@ public AuthenticationSuccessEventListener authenticationSuccessEventListener( AuditRecordService auditRecordService) { return new AuthenticationSuccessEventListener(auditRecordService); } + + @Bean + AppRegistrationDao appRegistrationDao( + EntityManager entityManager, AppRegistrationRepository appRegistrationRepository) { + return new JdbcAppRegistrationDao(entityManager, appRegistrationRepository); + } } diff --git a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java index 5749e3662d..11eaffdbe5 100644 --- a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java +++ b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java @@ -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; @@ -131,19 +132,18 @@ public AppRegistryController(Optional streamDefiniti * @param search optional findByTaskNameContains parameter * @return the list of registered applications */ - @RequestMapping(method = RequestMethod.GET) + @GetMapping @ResponseStatus(HttpStatus.OK) public PagedModel list( Pageable pageable, PagedResourcesAssembler pagedResourcesAssembler, @RequestParam(value = "type", required = false) ApplicationType type, @RequestParam(required = false) String search, + @RequestParam(required = false) String version, @RequestParam(required = false) boolean defaultVersion) { - Page pagedRegistrations = (defaultVersion) ? - this.appRegistryService.findAllByTypeAndNameIsLikeAndDefaultVersionIsTrue(type, search, pageable) - : this.appRegistryService.findAllByTypeAndNameIsLike(type, search, - pageable); + Page pagedRegistrations = this.appRegistryService + .findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(type, search, version, defaultVersion, pageable); return pagedResourcesAssembler.toModel(pagedRegistrations, this.appRegistryAssembler); } diff --git a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/completion/TabOnTapCompletionProviderTests.java b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/completion/TabOnTapCompletionProviderTests.java index 1e36195858..99c0b425de 100644 --- a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/completion/TabOnTapCompletionProviderTests.java +++ b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/completion/TabOnTapCompletionProviderTests.java @@ -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; @@ -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) { diff --git a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java index ba1eee8fa7..17997054dc 100644 --- a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java +++ b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java @@ -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; @@ -380,9 +381,10 @@ public RestControllerAdvice restControllerAdvice() { @Bean @ConditionalOnMissingBean public AppRegistryService appRegistryService(AppRegistrationRepository appRegistrationRepository, - AuditRecordService auditRecordService) { + AuditRecordService auditRecordService, AppRegistrationDao appRegistrationDao) { return new DefaultAppRegistryService(appRegistrationRepository, - new AppResourceCommon(new MavenProperties(), new DefaultResourceLoader()), auditRecordService); + new AppResourceCommon(new MavenProperties(), new DefaultResourceLoader()), auditRecordService, + appRegistrationDao); } @Bean diff --git a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java index a1f8eba332..d66d8af2ec 100644 --- a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java +++ b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/TestDependencies.java @@ -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; @@ -58,7 +59,9 @@ 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.repository.JdbcAppRegistrationDao; import org.springframework.cloud.dataflow.registry.service.AppRegistryService; import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService; import org.springframework.cloud.dataflow.registry.support.AppResourceCommon; @@ -410,8 +413,10 @@ public ToolsController toolsController() { @Bean public AppRegistryService appRegistryService(AppRegistrationRepository appRegistrationRepository, - AppResourceCommon appResourceService, AuditRecordService auditRecordService) { - return new DefaultAppRegistryService(appRegistrationRepository, appResourceService, auditRecordService); + AppResourceCommon appResourceService, AuditRecordService auditRecordService, + AppRegistrationDao appRegistrationDao) { + return new DefaultAppRegistryService(appRegistrationRepository, appResourceService, auditRecordService, + appRegistrationDao); } @Bean @@ -714,4 +719,11 @@ public JobInstanceController jobInstanceController() { public OAuth2TokenUtilsService oauth2TokenUtilsService() { return mock(OAuth2TokenUtilsService.class); } + + @Bean + public AppRegistrationDao appRegistrationDao(EntityManager entityManager, + AppRegistrationRepository appRegistrationRepository) { + return new JdbcAppRegistrationDao(entityManager, appRegistrationRepository); + } + } diff --git a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/AppRegistryControllerTests.java b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/AppRegistryControllerTests.java index 5fdca8b33b..1b5ba193c4 100644 --- a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/AppRegistryControllerTests.java +++ b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/controller/AppRegistryControllerTests.java @@ -661,4 +661,21 @@ public void testPagination() throws Exception { .andExpect(jsonPath("page.number", is(5))); } + @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))); + } + } From f75e97f60122ead5446b52e476aac07aa7be83e6 Mon Sep 17 00:00:00 2001 From: siddhantsorann Date: Wed, 17 Feb 2021 15:42:33 +0530 Subject: [PATCH 2/4] fixing failing test cases --- .../dataflow/server/configuration/JobDependencies.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java index 17997054dc..32f740dd41 100644 --- a/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java +++ b/spring-cloud-dataflow-server-core/src/test/java/org/springframework/cloud/dataflow/server/configuration/JobDependencies.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Map; +import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; @@ -50,6 +51,7 @@ 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.repository.JdbcAppRegistrationDao; import org.springframework.cloud.dataflow.registry.service.AppRegistryService; import org.springframework.cloud.dataflow.registry.service.DefaultAppRegistryService; import org.springframework.cloud.dataflow.registry.support.AppResourceCommon; @@ -493,4 +495,10 @@ public ScheduleInfo getSchedule(String scheduleName) { public OAuth2TokenUtilsService oauth2TokenUtilsService() { return mock(OAuth2TokenUtilsService.class); } + + @Bean + public AppRegistrationDao appRegistrationDao(EntityManager entityManager, + AppRegistrationRepository appRegistrationRepository) { + return new JdbcAppRegistrationDao(entityManager, appRegistrationRepository); + } } From 47db7bde48354eb4a98cc29c41434cc54e9d2ecc Mon Sep 17 00:00:00 2001 From: siddhantsorann Date: Wed, 17 Feb 2021 16:41:44 +0530 Subject: [PATCH 3/4] added javadocs --- .../repository/AppRegistrationDao.java | 21 +++- .../repository/JdbcAppRegistrationDao.java | 108 ++++++++++-------- .../registry/service/AppRegistryService.java | 8 +- .../controller/AppRegistryController.java | 1 + 4 files changed, 85 insertions(+), 53 deletions(-) diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java index a4153ad05c..ab48678243 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/AppRegistrationDao.java @@ -20,10 +20,29 @@ import org.springframework.cloud.dataflow.core.ApplicationType; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; +/** + * DAO to access {@link org.springframework.cloud.dataflow.core.AppRegistration}. Contains + * predicate specific operations to make filtering based on optional parameters more + * efficient. + * + * @author Siddhant Sorann + */ public interface AppRegistrationDao { + /** + * Function to find all app registrations based on various optional parameters using + * predicates. + * @param type application type. + * @param name application name. + * @param version application version. + * @param defaultVersion default version. + * @param pageable enumerates the data to be returned. + * @return paginated list of filtered app registrations. + */ Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion( - ApplicationType type, String name, String version, boolean defaultVersion, Pageable pageable); + @Nullable ApplicationType type, @Nullable String name, @Nullable String version, boolean defaultVersion, + Pageable pageable); } diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java index 0b619ad04b..72a5d6aea2 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/repository/JdbcAppRegistrationDao.java @@ -37,62 +37,70 @@ import org.springframework.util.Assert; import org.springframework.util.StringUtils; +/** + * DAO to access {@link org.springframework.cloud.dataflow.core.AppRegistration}. Contains + * predicate specific operations to make filtering based on optional parameters more + * efficient. Implements + * {@link org.springframework.cloud.dataflow.registry.repository.AppRegistrationDao} + * + * @author Siddhant Sorann + */ public class JdbcAppRegistrationDao implements AppRegistrationDao { - private final EntityManager entityManager; - private final AppRegistrationRepository appRegistrationRepository; + private final EntityManager entityManager; + + private final AppRegistrationRepository appRegistrationRepository; - public JdbcAppRegistrationDao(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 JdbcAppRegistrationDao(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; + } - @Override - public Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, - String name, String version, boolean defaultVersion, Pageable pageable) { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery(AppRegistration.class); - Root appRegistrationRoot = cq.from(AppRegistration.class); - final List 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 query = entityManager.createQuery(cq); - query.setFirstResult((int) pageable.getOffset()); - query.setMaxResults(pageable.getPageSize()); - final List resultList = query.getResultList(); - if (defaultVersion) { - resultList.forEach(appRegistration -> { - HashSet 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]))); - } + @Override + public Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, + String name, String version, boolean defaultVersion, Pageable pageable) { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery(AppRegistration.class); + Root appRegistrationRoot = cq.from(AppRegistration.class); + final List 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 query = entityManager.createQuery(cq); + query.setFirstResult((int) pageable.getOffset()); + query.setMaxResults(pageable.getPageSize()); + final List resultList = query.getResultList(); + if (defaultVersion) { + resultList.forEach(appRegistration -> { + HashSet 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 criteriaQuery = criteriaBuilder.createQuery(Long.class); - Root root = criteriaQuery.from(AppRegistration.class); + private Long getTotalCount(CriteriaBuilder criteriaBuilder, Predicate[] predicateArray) { + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + Root root = criteriaQuery.from(AppRegistration.class); - criteriaQuery.select(criteriaBuilder.count(root)); - criteriaQuery.where(predicateArray); + criteriaQuery.select(criteriaBuilder.count(root)); + criteriaQuery.where(predicateArray); - return entityManager.createQuery(criteriaQuery).getSingleResult(); - } + return entityManager.createQuery(criteriaQuery).getSingleResult(); + } } diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java index 316339d315..83b8949e99 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java @@ -18,12 +18,15 @@ import java.net.URI; import java.util.List; +import javax.validation.constraints.Null; + import org.springframework.cloud.dataflow.core.AppRegistration; import org.springframework.cloud.dataflow.core.ApplicationType; import org.springframework.cloud.dataflow.registry.support.NoSuchAppRegistrationException; import org.springframework.core.io.Resource; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; /** * @author Christian Tzolov @@ -208,6 +211,7 @@ default AppRegistration find(String name, ApplicationType type, String version) String getResourceVersion(String uriString); /** + * Returns all app registrations based on various optional parameters. * @param type application type * @param name application name * @param version application version @@ -216,6 +220,6 @@ default AppRegistration find(String name, ApplicationType type, String version) * @return returns all {@link AppRegistration} versions for given name and type. Uses the * pagination. */ - Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(ApplicationType type, - String name, String version, boolean defaultVersion, Pageable pageable); + Page findAllByTypeAndNameIsLikeAndVersionAndDefaultVersion(@Nullable ApplicationType type, + @Nullable String name, @Nullable String version, boolean defaultVersion, Pageable pageable); } diff --git a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java index 11eaffdbe5..c97e25d769 100644 --- a/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java +++ b/spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java @@ -129,6 +129,7 @@ public AppRegistryController(Optional streamDefiniti * @param pageable Pagination information * @param pagedResourcesAssembler the resource assembler for app registrations * @param type the application type: source, sink, processor, task + * @param version optional application version * @param search optional findByTaskNameContains parameter * @return the list of registered applications */ From 68409265f6ed79581ecae32fcad6491e83cab5d0 Mon Sep 17 00:00:00 2001 From: siddhantsorann Date: Wed, 17 Feb 2021 17:09:06 +0530 Subject: [PATCH 4/4] added javadocs --- .../cloud/dataflow/registry/service/AppRegistryService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java index 83b8949e99..39d458bde0 100644 --- a/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java +++ b/spring-cloud-dataflow-registry/src/main/java/org/springframework/cloud/dataflow/registry/service/AppRegistryService.java @@ -18,8 +18,6 @@ import java.net.URI; import java.util.List; -import javax.validation.constraints.Null; - import org.springframework.cloud.dataflow.core.AppRegistration; import org.springframework.cloud.dataflow.core.ApplicationType; import org.springframework.cloud.dataflow.registry.support.NoSuchAppRegistrationException;