Skip to content
This repository was archived by the owner on May 14, 2025. It is now read-only.

Commit f80369f

Browse files
onobcCorneil du Plessis
and
Corneil du Plessis
committed
Add boot version to 'app register' flow (#5240)
- Introduces the `AppBootSchemaVersion` enum - Add bootVersion param to 'app register' shell - Add bootVersion param to AppRegistryController See #5239 Co-authored-by: Corneil du Plessis <[email protected]>
1 parent c802b68 commit f80369f

File tree

9 files changed

+257
-26
lines changed

9 files changed

+257
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.dataflow.core;
18+
19+
import java.util.Arrays;
20+
21+
/**
22+
* Defines the possible schema versions that currently map to Spring {@code "Boot"}. A registered application can only support one schema version.
23+
*
24+
* <p>Each value defines the supported Spring Boot version that represents the changes in the schemas or Spring Batch and Task.</p>
25+
*
26+
* @author Chris Bono
27+
* @author Corneil du Plessis
28+
*/
29+
public enum AppBootSchemaVersion {
30+
31+
BOOT2("2"),
32+
BOOT3("3");
33+
34+
private String bootVersion;
35+
36+
AppBootSchemaVersion(String bootVersion) {
37+
this.bootVersion = bootVersion;
38+
}
39+
40+
public static AppBootSchemaVersion defaultVersion() {
41+
return BOOT2;
42+
}
43+
44+
public static AppBootSchemaVersion fromBootVersion(String bootVersion) {
45+
return Arrays.stream(AppBootSchemaVersion.values())
46+
.filter((bv) -> bv.bootVersion.equals(bootVersion))
47+
.findFirst().orElseThrow(() -> new IllegalArgumentException("Invalid AppBootSchemaVersion: " + bootVersion));
48+
}
49+
50+
public String getBootVersion() {
51+
return this.bootVersion;
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "AppBootVersion{bootVersion='" + this.bootVersion + "'}";
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.dataflow.core;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.params.ParameterizedTest;
21+
import org.junit.jupiter.params.provider.NullAndEmptySource;
22+
import org.junit.jupiter.params.provider.ValueSource;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
26+
27+
/**
28+
* Unit tests for {@link AppBootSchemaVersion}.
29+
*
30+
* @author Chris Bono
31+
* @author Corneil du Plessis
32+
*/
33+
public class AppBootSchemaVersionTests {
34+
35+
@Test
36+
void bootVersion2() {
37+
assertThat(AppBootSchemaVersion.BOOT2.getBootVersion()).isEqualTo("2");
38+
}
39+
40+
@Test
41+
void bootVersion3() {
42+
assertThat(AppBootSchemaVersion.BOOT3.getBootVersion()).isEqualTo("3");
43+
}
44+
45+
@Test
46+
void fromBootVersionWithValidValues() {
47+
assertThat(AppBootSchemaVersion.fromBootVersion("2")).isEqualTo(AppBootSchemaVersion.BOOT2);
48+
assertThat(AppBootSchemaVersion.fromBootVersion("3")).isEqualTo(AppBootSchemaVersion.BOOT3);
49+
}
50+
51+
@ParameterizedTest
52+
@NullAndEmptySource
53+
@ValueSource(strings = { "Boot2", "boot2", "BOOT2", "foo", "Boot3", "boot3", "BOOT3" })
54+
void fromBootVersionWithInvalidValues(String invalidBootVersion) {
55+
assertThatIllegalArgumentException()
56+
.isThrownBy(() -> AppBootSchemaVersion.fromBootVersion(invalidBootVersion))
57+
.withMessage("Invalid AppBootSchemaVersion: %s", invalidBootVersion);
58+
}
59+
}

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/AppRegistryOperations.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2019 the original author or authors.
2+
* Copyright 2015-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.Properties;
2020

21+
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
2122
import org.springframework.cloud.dataflow.core.ApplicationType;
2223
import org.springframework.cloud.dataflow.rest.resource.AppRegistrationResource;
2324
import org.springframework.cloud.dataflow.rest.resource.DetailedAppRegistrationResource;
@@ -32,6 +33,7 @@
3233
* @author Patrick Peralta
3334
* @author Mark Fisher
3435
* @author Chris Schaefer
36+
* @author Chris Bono
3537
*/
3638
public interface AppRegistryOperations {
3739

@@ -81,9 +83,24 @@ public interface AppRegistryOperations {
8183
* @param metadataUri URI for the application metadata artifact
8284
* @param force if {@code true}, overwrites a pre-existing registration
8385
* @return the new app registration
86+
* @deprecated in favor of {@link #register(String, ApplicationType, AppBootSchemaVersion, String, String, boolean)}
8487
*/
88+
@Deprecated
8589
AppRegistrationResource register(String name, ApplicationType type, String uri, String metadataUri, boolean force);
8690

91+
/**
92+
* Register an application name, type, and boot version with its Maven coordinates.
93+
*
94+
* @param name application name
95+
* @param type application type
96+
* @param bootVersion application boot version
97+
* @param uri URI for the application artifact
98+
* @param metadataUri URI for the application metadata artifact
99+
* @param force if {@code true}, overwrites a pre-existing registration
100+
* @return the new app registration
101+
*/
102+
AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion, String uri, String metadataUri, boolean force);
103+
87104
/**
88105
* Register an application name, type and version with its Maven coordinates.
89106
*
@@ -94,10 +111,27 @@ public interface AppRegistryOperations {
94111
* @param metadataUri URI for the application metadata artifact
95112
* @param force if {@code true}, overwrites a pre-existing registration
96113
* @return the new app registration
114+
* @deprecated in favor of {@link #register(String, ApplicationType, AppBootSchemaVersion, String, String, String, boolean)}
97115
*/
116+
@Deprecated
98117
AppRegistrationResource register(String name, ApplicationType type, String version, String uri,
99118
String metadataUri, boolean force);
100119

120+
/**
121+
* Register an application name, type, boot version, and version with its Maven coordinates.
122+
*
123+
* @param name application name
124+
* @param type application type
125+
* @param bootVersion application boot version
126+
* @param version application version
127+
* @param uri URI for the application artifact
128+
* @param metadataUri URI for the application metadata artifact
129+
* @param force if {@code true}, overwrites a pre-existing registration
130+
* @return the new app registration
131+
*/
132+
AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion, String version, String uri,
133+
String metadataUri, boolean force);
134+
101135
/**
102136
* Unregister an application name and type.
103137
*

spring-cloud-dataflow-rest-client/src/main/java/org/springframework/cloud/dataflow/rest/client/AppRegistryTemplate.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2019 the original author or authors.
2+
* Copyright 2015-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.Properties;
2020

21+
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
2122
import org.springframework.cloud.dataflow.core.ApplicationType;
2223
import org.springframework.cloud.dataflow.rest.resource.AppRegistrationResource;
2324
import org.springframework.cloud.dataflow.rest.resource.DetailedAppRegistrationResource;
@@ -40,6 +41,7 @@
4041
* @author Patrick Peralta
4142
* @author Christian Tzolov
4243
* @author Chris Schaefer
44+
* @author Chris Bono
4345
*/
4446
public class AppRegistryTemplate implements AppRegistryOperations {
4547
/**
@@ -112,31 +114,44 @@ public DetailedAppRegistrationResource info(String name, ApplicationType type, S
112114
}
113115

114116
@Override
115-
public AppRegistrationResource register(String name, ApplicationType type, String uri, String metadataUri,
116-
boolean force) {
117-
MultiValueMap<String, Object> values = new LinkedMultiValueMap<String, Object>();
118-
values.add("uri", uri);
119-
if (metadataUri != null) {
120-
values.add("metadata-uri", metadataUri);
121-
}
122-
values.add("force", Boolean.toString(force));
117+
public AppRegistrationResource register(String name, ApplicationType type, String uri, String metadataUri, boolean force) {
118+
return register(name, type, (AppBootSchemaVersion) null, uri, metadataUri, force);
119+
}
123120

121+
@Override
122+
public AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion,
123+
String uri, String metadataUri, boolean force) {
124+
MultiValueMap<String, Object> values = valuesForRegisterPost(bootVersion, uri, metadataUri, force);
124125
return restTemplate.postForObject(appsLink.getHref() + "/{type}/{name}", values,
125126
AppRegistrationResource.class, type, name);
126127
}
127128

128129
@Override
129130
public AppRegistrationResource register(String name, ApplicationType type, String version, String uri,
130131
String metadataUri, boolean force) {
132+
return this.register(name, type, null, version, uri, metadataUri, force);
133+
}
134+
135+
@Override
136+
public AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion,
137+
String version, String uri, String metadataUri, boolean force) {
138+
MultiValueMap<String, Object> values = valuesForRegisterPost(bootVersion, uri, metadataUri, force);
139+
return restTemplate.postForObject(appsLink.getHref() + "/{type}/{name}/{version}", values,
140+
AppRegistrationResource.class, type, name, version);
141+
}
142+
143+
private MultiValueMap<String, Object> valuesForRegisterPost(AppBootSchemaVersion bootVersion, String uri,
144+
String metadataUri, boolean force) {
131145
MultiValueMap<String, Object> values = new LinkedMultiValueMap<>();
132146
values.add("uri", uri);
133147
if (metadataUri != null) {
134148
values.add("metadata-uri", metadataUri);
135149
}
150+
if (bootVersion != null) {
151+
values.add("bootVersion", bootVersion.getBootVersion());
152+
}
136153
values.add("force", Boolean.toString(force));
137-
138-
return restTemplate.postForObject(appsLink.getHref() + "/{type}/{name}/{version}", values,
139-
AppRegistrationResource.class, type, name, version);
154+
return values;
140155
}
141156

142157
@Override

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/config/web/WebConfiguration.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2022 the original author or authors.
2+
* Copyright 2015-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,12 +34,15 @@
3434
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
3535
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
3636
import org.springframework.boot.web.servlet.ServletContextInitializer;
37+
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
3738
import org.springframework.cloud.dataflow.rest.support.jackson.ISO8601DateFormatWithMilliSeconds;
3839
import org.springframework.cloud.dataflow.rest.support.jackson.Jackson2DataflowModule;
3940
import org.springframework.context.ApplicationListener;
4041
import org.springframework.context.annotation.Bean;
4142
import org.springframework.context.annotation.Configuration;
4243
import org.springframework.context.event.ContextClosedEvent;
44+
import org.springframework.core.convert.converter.Converter;
45+
import org.springframework.format.FormatterRegistry;
4346
import org.springframework.hateoas.server.core.DefaultLinkRelationProvider;
4447
import org.springframework.http.converter.HttpMessageConverter;
4548
import org.springframework.http.converter.ResourceHttpMessageConverter;
@@ -58,6 +61,8 @@
5861
* @author Christian Tzolov
5962
* @author David Turanski
6063
* @author Michael Wirth
64+
* @author Chris Bono
65+
* @author Corneil du Plessis
6166
*/
6267
@Configuration(proxyBeanMethods = false)
6368
@ConditionalOnWebApplication
@@ -92,6 +97,11 @@ public WebMvcConfigurer configurer() {
9297
public void configurePathMatch(PathMatchConfigurer configurer) {
9398
configurer.setUseSuffixPatternMatch(false);
9499
}
100+
101+
@Override
102+
public void addFormatters(FormatterRegistry registry) {
103+
registry.addConverter(new AppBootVersionConverter());
104+
}
95105
};
96106
}
97107

@@ -133,4 +143,13 @@ public void onApplicationEvent(ContextClosedEvent event) {
133143
this.longTaskSample = null;
134144
}
135145
}
146+
147+
static class AppBootVersionConverter implements Converter<String, AppBootSchemaVersion> {
148+
149+
@Override
150+
public AppBootSchemaVersion convert(String value) {
151+
return value != null ? AppBootSchemaVersion.fromBootVersion(value) : null;
152+
}
153+
}
154+
136155
}

spring-cloud-dataflow-server-core/src/main/java/org/springframework/cloud/dataflow/server/controller/AppRegistryController.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
3737
import org.springframework.cloud.dataflow.configuration.metadata.ApplicationConfigurationMetadataResolver;
38+
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
3839
import org.springframework.cloud.dataflow.core.AppRegistration;
3940
import org.springframework.cloud.dataflow.core.ApplicationType;
4041
import org.springframework.cloud.dataflow.core.StreamAppDefinition;
@@ -221,17 +222,21 @@ else if (entry.getKey().equals("outbound")) {
221222
* @param type module type
222223
* @param name module name
223224
* @param version module version
225+
* @param bootVersion module boot version or {@code null} to use the default
224226
* @param uri URI for the module artifact (e.g. {@literal maven://group:artifact:version})
225227
* @param metadataUri URI for the metadata artifact
226228
* @param force if {@code true}, overwrites a pre-existing registration
227229
*/
228230
@RequestMapping(value = "/{type}/{name}/{version:.+}", method = RequestMethod.POST)
229231
@ResponseStatus(HttpStatus.CREATED)
230-
public void register(@PathVariable("type") ApplicationType type, @PathVariable("name") String name,
232+
public void register(
233+
@PathVariable("type") ApplicationType type,
234+
@PathVariable("name") String name,
231235
@PathVariable("version") String version,
232-
@RequestParam("uri") String uri, @RequestParam(name = "metadata-uri", required = false) String metadataUri,
236+
@RequestParam(name = "bootVersion", required = false) AppBootSchemaVersion bootVersion,
237+
@RequestParam("uri") String uri,
238+
@RequestParam(name = "metadata-uri", required = false) String metadataUri,
233239
@RequestParam(value = "force", defaultValue = "false") boolean force) {
234-
235240
validateApplicationName(name);
236241
appRegistryService.validate(appRegistryService.getDefaultApp(name, type), uri, version);
237242
AppRegistration previous = appRegistryService.find(name, type, version);
@@ -251,11 +256,15 @@ public void register(@PathVariable("type") ApplicationType type, @PathVariable("
251256
@Deprecated
252257
@RequestMapping(value = "/{type}/{name}", method = RequestMethod.POST)
253258
@ResponseStatus(HttpStatus.CREATED)
254-
public void register(@PathVariable("type") ApplicationType type, @PathVariable("name") String name,
255-
@RequestParam("uri") String uri, @RequestParam(name = "metadata-uri", required = false) String metadataUri,
259+
public void register(
260+
@PathVariable("type") ApplicationType type,
261+
@PathVariable("name") String name,
262+
@RequestParam(name = "bootVersion", required = false) AppBootSchemaVersion bootVersion,
263+
@RequestParam("uri") String uri,
264+
@RequestParam(name = "metadata-uri", required = false) String metadataUri,
256265
@RequestParam(value = "force", defaultValue = "false") boolean force) {
257266
String version = this.appRegistryService.getResourceVersion(uri);
258-
this.register(type, name, version, uri, metadataUri, force);
267+
this.register(type, name, version, bootVersion, uri, metadataUri, force);
259268
}
260269

261270
/**

0 commit comments

Comments
 (0)