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

Add AppBootVersion to 'app register' shell/client #5240

Merged
merged 4 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
@@ -0,0 +1,58 @@
/*
* Copyright 2023 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.core;

import java.util.Arrays;

/**
* Defines the possible schema versions that currently map to Spring {@code "Boot"}. A registered application can only support one schema version.
*
* <p>Each value defines the supported Spring Boot version that represents the changes in the schemas or Spring Batch and Task.</p>
*
* @author Chris Bono
* @author Corneil du Plessis
*/
public enum AppBootSchemaVersion {

BOOT2("2"),
BOOT3("3");

private String bootVersion;

AppBootSchemaVersion(String bootVersion) {
this.bootVersion = bootVersion;
}

public static AppBootSchemaVersion defaultVersion() {
return BOOT2;
}

public static AppBootSchemaVersion fromBootVersion(String bootVersion) {
return Arrays.stream(AppBootSchemaVersion.values())
.filter((bv) -> bv.bootVersion.equals(bootVersion))
.findFirst().orElseThrow(() -> new IllegalArgumentException("Invalid AppBootSchemaVersion:" + bootVersion));
}

public String getBootVersion() {
return this.bootVersion;
}

@Override
public String toString() {
return "AppBootVersion{bootVersion='" + this.bootVersion + "'}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2023 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.core;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;

/**
* Unit tests for {@link AppBootSchemaVersion}.
*
* @author Chris Bono
*/
public class AppBootVersionTests {

@Test
void bootVersion2() {
assertThat(AppBootSchemaVersion.BOOT2.getBootVersion()).isEqualTo("2");
}

@Test
void bootVersion3() {
assertThat(AppBootSchemaVersion.BOOT3.getBootVersion()).isEqualTo("3");
}

@Test
void fromBootVersion() {
assertThat(AppBootSchemaVersion.fromBootVersion("2")).isEqualTo(AppBootSchemaVersion.BOOT2);
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("Boot2")).withMessage("Invalid AppBootSchemaVersion:Boot2");
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("boot2")).withMessage("Invalid AppBootSchemaVersion:boot2");
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("BOOT2")).withMessage("Invalid AppBootSchemaVersion:BOOT2");

assertThat(AppBootSchemaVersion.fromBootVersion("3")).isEqualTo(AppBootSchemaVersion.BOOT3);
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("Boot3")).withMessage("Invalid AppBootSchemaVersion:Boot3");
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("boot3")).withMessage("Invalid AppBootSchemaVersion:boot3");
assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion("BOOT3")).withMessage("Invalid AppBootSchemaVersion:BOOT3");

assertThatIllegalArgumentException().isThrownBy(() -> AppBootSchemaVersion.fromBootVersion(null)).withMessage("Invalid AppBootSchemaVersion:null");
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-2023 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.
Expand All @@ -18,6 +18,7 @@

import java.util.Properties;

import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.rest.resource.AppRegistrationResource;
import org.springframework.cloud.dataflow.rest.resource.DetailedAppRegistrationResource;
Expand All @@ -32,6 +33,7 @@
* @author Patrick Peralta
* @author Mark Fisher
* @author Chris Schaefer
* @author Chris Bono
*/
public interface AppRegistryOperations {

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

/**
* Register an application name, type, and boot version with its Maven coordinates.
*
* @param name application name
* @param type application type
* @param bootVersion application boot version
* @param uri URI for the application artifact
* @param metadataUri URI for the application metadata artifact
* @param force if {@code true}, overwrites a pre-existing registration
* @return the new app registration
*/
AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion, String uri, String metadataUri, boolean force);

/**
* Register an application name, type and version with its Maven coordinates.
*
Expand All @@ -94,10 +111,27 @@ public interface AppRegistryOperations {
* @param metadataUri URI for the application metadata artifact
* @param force if {@code true}, overwrites a pre-existing registration
* @return the new app registration
* @deprecated in favor of {@link #register(String, ApplicationType, AppBootSchemaVersion, String, String, String, boolean)}
*/
@Deprecated
AppRegistrationResource register(String name, ApplicationType type, String version, String uri,
String metadataUri, boolean force);

/**
* Register an application name, type, boot version, and version with its Maven coordinates.
*
* @param name application name
* @param type application type
* @param bootVersion application boot version
* @param version application version
* @param uri URI for the application artifact
* @param metadataUri URI for the application metadata artifact
* @param force if {@code true}, overwrites a pre-existing registration
* @return the new app registration
*/
AppRegistrationResource register(String name, ApplicationType type, AppBootSchemaVersion bootVersion, String version, String uri,
String metadataUri, boolean force);

/**
* Unregister an application name and type.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-2023 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.
Expand All @@ -18,6 +18,7 @@

import java.util.Properties;

import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.rest.resource.AppRegistrationResource;
import org.springframework.cloud.dataflow.rest.resource.DetailedAppRegistrationResource;
Expand All @@ -40,6 +41,7 @@
* @author Patrick Peralta
* @author Christian Tzolov
* @author Chris Schaefer
* @author Chris Bono
*/
public class AppRegistryTemplate implements AppRegistryOperations {
/**
Expand Down Expand Up @@ -112,31 +114,44 @@ public DetailedAppRegistrationResource info(String name, ApplicationType type, S
}

@Override
public AppRegistrationResource register(String name, ApplicationType type, String uri, String metadataUri,
boolean force) {
MultiValueMap<String, Object> values = new LinkedMultiValueMap<String, Object>();
values.add("uri", uri);
if (metadataUri != null) {
values.add("metadata-uri", metadataUri);
}
values.add("force", Boolean.toString(force));
public AppRegistrationResource register(String name, ApplicationType type, String uri, String metadataUri, boolean force) {
return register(name, type, (AppBootSchemaVersion) null, uri, metadataUri, force);
}

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

@Override
public AppRegistrationResource register(String name, ApplicationType type, String version, String uri,
String metadataUri, boolean force) {
return this.register(name, type, null, version, uri, metadataUri, force);
}

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

private MultiValueMap<String, Object> valuesForRegisterPost(AppBootSchemaVersion bootVersion, String uri,
String metadataUri, boolean force) {
MultiValueMap<String, Object> values = new LinkedMultiValueMap<>();
values.add("uri", uri);
if (metadataUri != null) {
values.add("metadata-uri", metadataUri);
}
if (bootVersion != null) {
values.add("bootVersion", bootVersion.getBootVersion());
}
values.add("force", Boolean.toString(force));

return restTemplate.postForObject(appsLink.getHref() + "/{type}/{name}/{version}", values,
AppRegistrationResource.class, type, name, version);
return values;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2022 the original author or authors.
* Copyright 2015-2023 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.
Expand Down Expand Up @@ -34,12 +34,15 @@
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
import org.springframework.cloud.dataflow.rest.support.jackson.ISO8601DateFormatWithMilliSeconds;
import org.springframework.cloud.dataflow.rest.support.jackson.Jackson2DataflowModule;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.hateoas.server.core.DefaultLinkRelationProvider;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
Expand All @@ -58,6 +61,8 @@
* @author Christian Tzolov
* @author David Turanski
* @author Michael Wirth
* @author Chris Bono
* @author Corneil du Plessis
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
Expand Down Expand Up @@ -92,6 +97,11 @@ public WebMvcConfigurer configurer() {
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new AppBootVersionConverter());
}
};
}

Expand Down Expand Up @@ -133,4 +143,13 @@ public void onApplicationEvent(ContextClosedEvent event) {
this.longTaskSample = null;
}
}

static class AppBootVersionConverter implements Converter<String, AppBootSchemaVersion> {

@Override
public AppBootSchemaVersion convert(String value) {
return value != null ? AppBootSchemaVersion.fromBootVersion(value) : null;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import org.springframework.boot.configurationmetadata.ConfigurationMetadataProperty;
import org.springframework.cloud.dataflow.configuration.metadata.ApplicationConfigurationMetadataResolver;
import org.springframework.cloud.dataflow.core.AppBootSchemaVersion;
import org.springframework.cloud.dataflow.core.AppRegistration;
import org.springframework.cloud.dataflow.core.ApplicationType;
import org.springframework.cloud.dataflow.core.StreamAppDefinition;
Expand Down Expand Up @@ -221,17 +222,21 @@ else if (entry.getKey().equals("outbound")) {
* @param type module type
* @param name module name
* @param version module version
* @param bootVersion module boot version or {@code null} to use the default
* @param uri URI for the module artifact (e.g. {@literal maven://group:artifact:version})
* @param metadataUri URI for the metadata artifact
* @param force if {@code true}, overwrites a pre-existing registration
*/
@RequestMapping(value = "/{type}/{name}/{version:.+}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void register(@PathVariable("type") ApplicationType type, @PathVariable("name") String name,
public void register(
@PathVariable("type") ApplicationType type,
@PathVariable("name") String name,
@PathVariable("version") String version,
@RequestParam("uri") String uri, @RequestParam(name = "metadata-uri", required = false) String metadataUri,
@RequestParam(name = "bootVersion", required = false) AppBootSchemaVersion bootVersion,
@RequestParam("uri") String uri,
@RequestParam(name = "metadata-uri", required = false) String metadataUri,
@RequestParam(value = "force", defaultValue = "false") boolean force) {

validateApplicationName(name);
appRegistryService.validate(appRegistryService.getDefaultApp(name, type), uri, version);
AppRegistration previous = appRegistryService.find(name, type, version);
Expand All @@ -251,11 +256,15 @@ public void register(@PathVariable("type") ApplicationType type, @PathVariable("
@Deprecated
@RequestMapping(value = "/{type}/{name}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void register(@PathVariable("type") ApplicationType type, @PathVariable("name") String name,
@RequestParam("uri") String uri, @RequestParam(name = "metadata-uri", required = false) String metadataUri,
public void register(
@PathVariable("type") ApplicationType type,
@PathVariable("name") String name,
@RequestParam(name = "bootVersion", required = false) AppBootSchemaVersion bootVersion,
@RequestParam("uri") String uri,
@RequestParam(name = "metadata-uri", required = false) String metadataUri,
@RequestParam(value = "force", defaultValue = "false") boolean force) {
String version = this.appRegistryService.getResourceVersion(uri);
this.register(type, name, version, uri, metadataUri, force);
this.register(type, name, version, bootVersion, uri, metadataUri, force);
}

/**
Expand Down
Loading