Skip to content

Commit

Permalink
Optionally close context after command logic
Browse files Browse the repository at this point in the history
- spring.shell.context.close=true adds ApplicationListerner
  which attempts to close context with ApplicationReadyEvent.
- Relates #863
  • Loading branch information
jvalkeal committed Sep 12, 2023
1 parent 51c2506 commit 2e5264a
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 the original author or authors.
* Copyright 2021-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 @@ -19,7 +19,10 @@

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.shell.DefaultShellApplicationRunner;
import org.springframework.shell.ShellApplicationRunner;
Expand All @@ -34,4 +37,20 @@ public class ApplicationRunnerAutoConfiguration {
public DefaultShellApplicationRunner defaultShellApplicationRunner(List<ShellRunner> shellRunners) {
return new DefaultShellApplicationRunner(shellRunners);
}

@Bean
@ConditionalOnProperty(prefix = "spring.shell.context", name = "close", havingValue = "true")
public ApplicationReadyEventListener applicationReadyEventListener() {
return new ApplicationReadyEventListener();
}

static class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent>{

@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// request context close after application runners so that
// shell exits in case that context is kept alive
event.getApplicationContext().close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class SpringShellProperties {
private Command command = new Command();
private Help help = new Help();
private Option option = new Option();
private Context context = new Context();

public void setConfig(Config config) {
this.config = config;
Expand Down Expand Up @@ -107,6 +108,14 @@ public void setOption(Option option) {
this.option = option;
}

public Context getContext() {
return context;
}

public void setContext(Context context) {
this.context = context;
}

public static class Config {

private String env;
Expand Down Expand Up @@ -603,6 +612,19 @@ public void setCaseType(OptionNamingCase caseType) {
}
}

public static class Context {

private boolean close = false;

public boolean isClose() {
return close;
}

public void setClose(boolean close) {
this.close = close;
}
}

public static enum OptionNamingCase {
NOOP,
CAMEL,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* 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.shell.boot;

import org.junit.jupiter.api.Test;

import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;

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

public class ApplicationRunnerAutoConfigurationTests {

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ApplicationRunnerAutoConfiguration.class));

@Test
void contextCloseDisabledByDefault() {
contextRunner.run(context -> assertThat(context)
.doesNotHaveBean(ApplicationRunnerAutoConfiguration.ApplicationReadyEventListener.class));
}

@Test
void contextCloseEnabled() {
contextRunner.withPropertyValues("spring.shell.context.close:true")
.run(context -> assertThat(context)
.hasSingleBean(ApplicationRunnerAutoConfiguration.ApplicationReadyEventListener.class));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public void defaultNoPropertiesSet() {
assertThat(properties.getHelp().getLongNames()).containsExactly("help");
assertThat(properties.getHelp().getShortNames()).containsExactly('h');
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.NOOP);
assertThat(properties.getContext().isClose()).isFalse();
});
}

Expand Down Expand Up @@ -112,6 +113,7 @@ public void setProperties() {
.withPropertyValues("spring.shell.help.long-names=fake")
.withPropertyValues("spring.shell.help.short-names=f")
.withPropertyValues("spring.shell.option.naming.case-type=camel")
.withPropertyValues("spring.shell.context.close=true")
.withUserConfiguration(Config1.class)
.run((context) -> {
SpringShellProperties properties = context.getBean(SpringShellProperties.class);
Expand Down Expand Up @@ -151,6 +153,7 @@ public void setProperties() {
assertThat(properties.getHelp().getLongNames()).containsExactly("fake");
assertThat(properties.getHelp().getShortNames()).containsExactly('f');
assertThat(properties.getOption().getNaming().getCaseType()).isEqualTo(OptionNamingCase.CAMEL);
assertThat(properties.getContext().isClose()).isTrue();
});
}

Expand Down

0 comments on commit 2e5264a

Please sign in to comment.