commit
e394cadc48
|
|
@ -43,7 +43,7 @@ import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
import org.springframework.boot.jarmode.tools.JarStructure.Entry;
|
import org.springframework.boot.jarmode.tools.JarStructure.Entry;
|
||||||
import org.springframework.boot.jarmode.tools.JarStructure.Entry.Type;
|
import org.springframework.boot.jarmode.tools.JarStructure.Entry.Type;
|
||||||
import org.springframework.boot.jarmode.tools.Layers.LayersNotEnabledException;
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
@ -118,12 +118,6 @@ class ExtractCommand extends Command {
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
throw new UncheckedIOException(ex);
|
throw new UncheckedIOException(ex);
|
||||||
}
|
}
|
||||||
catch (LayersNotEnabledException ex) {
|
|
||||||
printError(out, "Layers are not enabled");
|
|
||||||
}
|
|
||||||
catch (AbortException ex) {
|
|
||||||
printError(out, ex.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void checkDirectoryIsEmpty(Map<Option, String> options, File destination) {
|
private static void checkDirectoryIsEmpty(Map<Option, String> options, File destination) {
|
||||||
|
|
@ -134,11 +128,11 @@ class ExtractCommand extends Command {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!destination.isDirectory()) {
|
if (!destination.isDirectory()) {
|
||||||
throw new AbortException(destination.getAbsoluteFile() + " already exists and is not a directory");
|
throw new JarModeErrorException(destination.getAbsoluteFile() + " already exists and is not a directory");
|
||||||
}
|
}
|
||||||
File[] files = destination.listFiles();
|
File[] files = destination.listFiles();
|
||||||
if (files != null && files.length > 0) {
|
if (files != null && files.length > 0) {
|
||||||
throw new AbortException(destination.getAbsoluteFile() + " already exists and is not empty");
|
throw new JarModeErrorException(destination.getAbsoluteFile() + " already exists and is not empty");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,18 +141,13 @@ class ExtractCommand extends Command {
|
||||||
try (ZipInputStream stream = new ZipInputStream(new FileInputStream(file))) {
|
try (ZipInputStream stream = new ZipInputStream(new FileInputStream(file))) {
|
||||||
ZipEntry entry = stream.getNextEntry();
|
ZipEntry entry = stream.getNextEntry();
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new AbortException(
|
throw new JarModeErrorException(
|
||||||
"File '%s' is not compatible; ensure jar file is valid and launch script is not enabled"
|
"File '%s' is not compatible; ensure jar file is valid and launch script is not enabled"
|
||||||
.formatted(file));
|
.formatted(file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printError(PrintStream out, String message) {
|
|
||||||
out.println("Error: " + message);
|
|
||||||
out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void extractLibraries(FileResolver fileResolver, JarStructure jarStructure, Map<Option, String> options)
|
private void extractLibraries(FileResolver fileResolver, JarStructure jarStructure, Map<Option, String> options)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String librariesDirectory = getLibrariesDirectory(options);
|
String librariesDirectory = getLibrariesDirectory(options);
|
||||||
|
|
@ -494,12 +483,4 @@ class ExtractCommand extends Command {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class AbortException extends RuntimeException {
|
|
||||||
|
|
||||||
AbortException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ package org.springframework.boot.jarmode.tools;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides information about the jar layers.
|
* Provides information about the jar layers.
|
||||||
*
|
*
|
||||||
|
|
@ -62,22 +64,13 @@ interface Layers extends Iterable<String> {
|
||||||
* Return a {@link Layers} instance for the currently running application.
|
* Return a {@link Layers} instance for the currently running application.
|
||||||
* @param context the command context
|
* @param context the command context
|
||||||
* @return a new layers instance
|
* @return a new layers instance
|
||||||
* @throws LayersNotEnabledException if layers are not enabled
|
|
||||||
*/
|
*/
|
||||||
static Layers get(Context context) {
|
static Layers get(Context context) {
|
||||||
IndexedLayers indexedLayers = IndexedLayers.get(context);
|
IndexedLayers indexedLayers = IndexedLayers.get(context);
|
||||||
if (indexedLayers == null) {
|
if (indexedLayers == null) {
|
||||||
throw new LayersNotEnabledException();
|
throw new JarModeErrorException("Layers are not enabled");
|
||||||
}
|
}
|
||||||
return indexedLayers;
|
return indexedLayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
final class LayersNotEnabledException extends RuntimeException {
|
|
||||||
|
|
||||||
LayersNotEnabledException() {
|
|
||||||
super("Layers not enabled: Failed to load layer index file");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ import java.io.PrintStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.boot.jarmode.tools.Layers.LayersNotEnabledException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@code 'list-layers'} tools command.
|
* The {@code 'list-layers'} tools command.
|
||||||
*
|
*
|
||||||
|
|
@ -38,22 +36,12 @@ class ListLayersCommand extends Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void run(PrintStream out, Map<Option, String> options, List<String> parameters) {
|
void run(PrintStream out, Map<Option, String> options, List<String> parameters) {
|
||||||
try {
|
Layers layers = Layers.get(this.context);
|
||||||
Layers layers = Layers.get(this.context);
|
printLayers(out, layers);
|
||||||
printLayers(out, layers);
|
|
||||||
}
|
|
||||||
catch (LayersNotEnabledException ex) {
|
|
||||||
printError(out, "Layers are not enabled");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printLayers(PrintStream out, Layers layers) {
|
void printLayers(PrintStream out, Layers layers) {
|
||||||
layers.forEach(out::println);
|
layers.forEach(out::println);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printError(PrintStream out, String message) {
|
|
||||||
out.println("Error: " + message);
|
|
||||||
out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -172,8 +175,8 @@ class ExtractCommandTests extends AbstractJarModeTests {
|
||||||
try (FileWriter writer = new FileWriter(file)) {
|
try (FileWriter writer = new FileWriter(file)) {
|
||||||
writer.write("text");
|
writer.write("text");
|
||||||
}
|
}
|
||||||
TestPrintStream out = run(file);
|
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(file))
|
||||||
assertThat(out).contains("is not compatible; ensure jar file is valid and launch script is not enabled");
|
.withMessageContaining("is not compatible; ensure jar file is valid and launch script is not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -181,8 +184,9 @@ class ExtractCommandTests extends AbstractJarModeTests {
|
||||||
File destination = file("out");
|
File destination = file("out");
|
||||||
Files.createDirectories(destination.toPath());
|
Files.createDirectories(destination.toPath());
|
||||||
Files.createFile(new File(destination, "file.txt").toPath());
|
Files.createFile(new File(destination, "file.txt").toPath());
|
||||||
TestPrintStream out = run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath());
|
assertThatExceptionOfType(JarModeErrorException.class)
|
||||||
assertThat(out).contains("already exists and is not empty");
|
.isThrownBy(() -> run(ExtractCommandTests.this.archive, "--destination", destination.getAbsolutePath()))
|
||||||
|
.withMessageContaining("already exists and is not empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -266,10 +270,10 @@ class ExtractCommandTests extends AbstractJarModeTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void printErrorIfLayersAreNotEnabled() throws IOException {
|
void failsIfLayersAreNotEnabled() throws IOException {
|
||||||
File archive = createArchive();
|
File archive = createArchive();
|
||||||
TestPrintStream out = run(archive, "--layers");
|
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(archive, "--layers"))
|
||||||
assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt");
|
.withMessage("Layers are not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -318,10 +322,11 @@ class ExtractCommandTests extends AbstractJarModeTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void printErrorIfLayersAreNotEnabled() throws IOException {
|
void failsIfLayersAreNotEnabled() throws IOException {
|
||||||
File archive = createArchive();
|
File archive = createArchive();
|
||||||
TestPrintStream out = run(archive, "--launcher", "--layers");
|
assertThatExceptionOfType(JarModeErrorException.class)
|
||||||
assertThat(out).hasSameContentAsResource("ExtractCommand-printErrorIfLayersAreNotEnabled.txt");
|
.isThrownBy(() -> run(archive, "--launcher", "--layers"))
|
||||||
|
.withMessage("Layers are not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,12 @@ import org.junit.jupiter.api.io.TempDir;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
|
|
||||||
|
|
@ -146,8 +148,9 @@ class ExtractLayersCommandTests {
|
||||||
}
|
}
|
||||||
given(this.context.getArchiveFile()).willReturn(file);
|
given(this.context.getArchiveFile()).willReturn(file);
|
||||||
try (TestPrintStream out = new TestPrintStream(this)) {
|
try (TestPrintStream out = new TestPrintStream(this)) {
|
||||||
this.command.run(out, Collections.emptyMap(), Collections.emptyList());
|
assertThatExceptionOfType(JarModeErrorException.class)
|
||||||
assertThat(out).contains("is not compatible");
|
.isThrownBy(() -> this.command.run(out, Collections.emptyMap(), Collections.emptyList()))
|
||||||
|
.withMessageContaining("is not compatible");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ import java.util.jar.Manifest;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ListLayersCommand}.
|
* Tests for {@link ListLayersCommand}.
|
||||||
|
|
@ -39,9 +42,9 @@ class ListLayersCommandTests extends AbstractJarModeTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldPrintErrorWhenLayersAreNotEnabled() throws IOException {
|
void shouldFailWhenLayersAreNotEnabled() {
|
||||||
TestPrintStream out = run(createArchive());
|
assertThatExceptionOfType(JarModeErrorException.class).isThrownBy(() -> run(createArchive()))
|
||||||
assertThat(out).hasSameContentAsResource("list-layers-output-layers-disabled.txt");
|
.withMessage("Layers are not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestPrintStream run(File archive) {
|
private TestPrintStream run(File archive) {
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
Error: Layers are not enabled
|
|
||||||
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
Error: Layers are not enabled
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -36,7 +36,8 @@ public interface JarMode {
|
||||||
* Run the jar in the given mode.
|
* Run the jar in the given mode.
|
||||||
* @param mode the mode to use
|
* @param mode the mode to use
|
||||||
* @param args any program arguments
|
* @param args any program arguments
|
||||||
|
* @throws JarModeErrorException on an error that should print a simple error message
|
||||||
*/
|
*/
|
||||||
void run(String mode, String[] args);
|
void run(String mode, String[] args) throws JarModeErrorException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.loader.jarmode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple {@link RuntimeException} used to fail the jar mode with a simple printed error
|
||||||
|
* message.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 3.3.7
|
||||||
|
*/
|
||||||
|
public class JarModeErrorException extends RuntimeException {
|
||||||
|
|
||||||
|
public JarModeErrorException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarModeErrorException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -31,11 +31,31 @@ public final class JarModeLauncher {
|
||||||
|
|
||||||
static final String DISABLE_SYSTEM_EXIT = JarModeLauncher.class.getName() + ".DISABLE_SYSTEM_EXIT";
|
static final String DISABLE_SYSTEM_EXIT = JarModeLauncher.class.getName() + ".DISABLE_SYSTEM_EXIT";
|
||||||
|
|
||||||
|
static final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeLauncher.class.getName() + ".SUPPRESSED_SYSTEM_EXIT_CODE";
|
||||||
|
|
||||||
private JarModeLauncher() {
|
private JarModeLauncher() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
String mode = System.getProperty("jarmode");
|
String mode = System.getProperty("jarmode");
|
||||||
|
boolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT);
|
||||||
|
try {
|
||||||
|
runJarMode(mode, args);
|
||||||
|
if (disableSystemExit) {
|
||||||
|
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
printError(ex);
|
||||||
|
if (disableSystemExit) {
|
||||||
|
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runJarMode(String mode, String[] args) {
|
||||||
List<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,
|
List<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,
|
||||||
ClassUtils.getDefaultClassLoader());
|
ClassUtils.getDefaultClassLoader());
|
||||||
for (JarMode candidate : candidates) {
|
for (JarMode candidate : candidates) {
|
||||||
|
|
@ -44,10 +64,17 @@ public final class JarModeLauncher {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.err.println("Unsupported jarmode '" + mode + "'");
|
throw new JarModeErrorException("Unsupported jarmode '" + mode + "'");
|
||||||
if (!Boolean.getBoolean(DISABLE_SYSTEM_EXIT)) {
|
}
|
||||||
System.exit(1);
|
|
||||||
|
private static void printError(Throwable ex) {
|
||||||
|
if (ex instanceof JarModeErrorException) {
|
||||||
|
String message = ex.getMessage();
|
||||||
|
System.err.println("Error: " + message);
|
||||||
|
System.err.println();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -33,6 +33,12 @@ class TestJarMode implements JarMode {
|
||||||
@Override
|
@Override
|
||||||
public void run(String mode, String[] args) {
|
public void run(String mode, String[] args) {
|
||||||
System.out.println("running in " + mode + " jar mode " + Arrays.asList(args));
|
System.out.println("running in " + mode + " jar mode " + Arrays.asList(args));
|
||||||
|
if (args.length > 0 && "error".equals(args[0])) {
|
||||||
|
throw new JarModeErrorException("error message");
|
||||||
|
}
|
||||||
|
if (args.length > 0 && "fail".equals(args[0])) {
|
||||||
|
throw new IllegalStateException("bad");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ class LauncherJarModeTests {
|
||||||
System.setProperty("jarmode", "test");
|
System.setProperty("jarmode", "test");
|
||||||
new TestLauncher().launch(new String[] { "boot" });
|
new TestLauncher().launch(new String[] { "boot" });
|
||||||
assertThat(out).contains("running in test jar mode [boot]");
|
assertThat(out).contains("running in test jar mode [boot]");
|
||||||
|
assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -62,6 +63,25 @@ class LauncherJarModeTests {
|
||||||
System.setProperty("jarmode", "idontexist");
|
System.setProperty("jarmode", "idontexist");
|
||||||
new TestLauncher().launch(new String[] { "boot" });
|
new TestLauncher().launch(new String[] { "boot" });
|
||||||
assertThat(out).contains("Unsupported jarmode 'idontexist'");
|
assertThat(out).contains("Unsupported jarmode 'idontexist'");
|
||||||
|
assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void launchWhenJarModeRunFailsWithErrorExceptionPrintsSimpleMessage(CapturedOutput out) throws Exception {
|
||||||
|
System.setProperty("jarmode", "test");
|
||||||
|
new TestLauncher().launch(new String[] { "error" });
|
||||||
|
assertThat(out).contains("running in test jar mode [error]");
|
||||||
|
assertThat(out).contains("Error: error message");
|
||||||
|
assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void launchWhenJarModeRunFailsWithErrorExceptionPrintsStackTrace(CapturedOutput out) throws Exception {
|
||||||
|
System.setProperty("jarmode", "test");
|
||||||
|
new TestLauncher().launch(new String[] { "fail" });
|
||||||
|
assertThat(out).contains("running in test jar mode [fail]");
|
||||||
|
assertThat(out).contains("java.lang.IllegalStateException: bad");
|
||||||
|
assertThat(System.getProperty(JarModeLauncher.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class TestLauncher extends Launcher {
|
private static final class TestLauncher extends Launcher {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -36,7 +36,8 @@ public interface JarMode {
|
||||||
* Run the jar in the given mode.
|
* Run the jar in the given mode.
|
||||||
* @param mode the mode to use
|
* @param mode the mode to use
|
||||||
* @param args any program arguments
|
* @param args any program arguments
|
||||||
|
* @throws JarModeErrorException on an error that should print a simple error message
|
||||||
*/
|
*/
|
||||||
void run(String mode, String[] args);
|
void run(String mode, String[] args) throws JarModeErrorException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.loader.jarmode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple {@link RuntimeException} used to fail the jar mode with a simple printed error
|
||||||
|
* message.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 3.3.7
|
||||||
|
*/
|
||||||
|
public class JarModeErrorException extends RuntimeException {
|
||||||
|
|
||||||
|
public JarModeErrorException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarModeErrorException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,6 +19,7 @@ package org.springframework.boot.loader.launch;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.boot.loader.jarmode.JarMode;
|
import org.springframework.boot.loader.jarmode.JarMode;
|
||||||
|
import org.springframework.boot.loader.jarmode.JarModeErrorException;
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
|
@ -31,11 +32,31 @@ final class JarModeRunner {
|
||||||
|
|
||||||
static final String DISABLE_SYSTEM_EXIT = JarModeRunner.class.getName() + ".DISABLE_SYSTEM_EXIT";
|
static final String DISABLE_SYSTEM_EXIT = JarModeRunner.class.getName() + ".DISABLE_SYSTEM_EXIT";
|
||||||
|
|
||||||
|
static final String SUPPRESSED_SYSTEM_EXIT_CODE = JarModeRunner.class.getName() + ".SUPPRESSED_SYSTEM_EXIT_CODE";
|
||||||
|
|
||||||
private JarModeRunner() {
|
private JarModeRunner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void main(String[] args) {
|
static void main(String[] args) {
|
||||||
String mode = System.getProperty("jarmode");
|
String mode = System.getProperty("jarmode");
|
||||||
|
boolean disableSystemExit = Boolean.getBoolean(DISABLE_SYSTEM_EXIT);
|
||||||
|
try {
|
||||||
|
runJarMode(mode, args);
|
||||||
|
if (disableSystemExit) {
|
||||||
|
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
printError(ex);
|
||||||
|
if (disableSystemExit) {
|
||||||
|
System.setProperty(SUPPRESSED_SYSTEM_EXIT_CODE, "1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void runJarMode(String mode, String[] args) {
|
||||||
List<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,
|
List<JarMode> candidates = SpringFactoriesLoader.loadFactories(JarMode.class,
|
||||||
ClassUtils.getDefaultClassLoader());
|
ClassUtils.getDefaultClassLoader());
|
||||||
for (JarMode candidate : candidates) {
|
for (JarMode candidate : candidates) {
|
||||||
|
|
@ -44,10 +65,17 @@ final class JarModeRunner {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
System.err.println("Unsupported jarmode '" + mode + "'");
|
throw new JarModeErrorException("Unsupported jarmode '" + mode + "'");
|
||||||
if (!Boolean.getBoolean(DISABLE_SYSTEM_EXIT)) {
|
}
|
||||||
System.exit(1);
|
|
||||||
|
private static void printError(Throwable ex) {
|
||||||
|
if (ex instanceof JarModeErrorException) {
|
||||||
|
String message = ex.getMessage();
|
||||||
|
System.err.println("Error: " + message);
|
||||||
|
System.err.println();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2023 the original author or authors.
|
* Copyright 2012-2024 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -33,6 +33,12 @@ class TestJarMode implements JarMode {
|
||||||
@Override
|
@Override
|
||||||
public void run(String mode, String[] args) {
|
public void run(String mode, String[] args) {
|
||||||
System.out.println("running in " + mode + " jar mode " + Arrays.asList(args));
|
System.out.println("running in " + mode + " jar mode " + Arrays.asList(args));
|
||||||
|
if (args.length > 0 && "error".equals(args[0])) {
|
||||||
|
throw new JarModeErrorException("error message");
|
||||||
|
}
|
||||||
|
if (args.length > 0 && "fail".equals(args[0])) {
|
||||||
|
throw new IllegalStateException("bad");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ class LauncherTests {
|
||||||
System.setProperty("jarmode", "test");
|
System.setProperty("jarmode", "test");
|
||||||
new TestLauncher().launch(new String[] { "boot" });
|
new TestLauncher().launch(new String[] { "boot" });
|
||||||
assertThat(out).contains("running in test jar mode [boot]");
|
assertThat(out).contains("running in test jar mode [boot]");
|
||||||
|
assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -70,6 +71,25 @@ class LauncherTests {
|
||||||
System.setProperty("jarmode", "idontexist");
|
System.setProperty("jarmode", "idontexist");
|
||||||
new TestLauncher().launch(new String[] { "boot" });
|
new TestLauncher().launch(new String[] { "boot" });
|
||||||
assertThat(out).contains("Unsupported jarmode 'idontexist'");
|
assertThat(out).contains("Unsupported jarmode 'idontexist'");
|
||||||
|
assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void launchWhenJarModeRunFailsWithErrorExceptionPrintsSimpleMessage(CapturedOutput out) throws Exception {
|
||||||
|
System.setProperty("jarmode", "test");
|
||||||
|
new TestLauncher().launch(new String[] { "error" });
|
||||||
|
assertThat(out).contains("running in test jar mode [error]");
|
||||||
|
assertThat(out).contains("Error: error message");
|
||||||
|
assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void launchWhenJarModeRunFailsWithErrorExceptionPrintsStackTrace(CapturedOutput out) throws Exception {
|
||||||
|
System.setProperty("jarmode", "test");
|
||||||
|
new TestLauncher().launch(new String[] { "fail" });
|
||||||
|
assertThat(out).contains("running in test jar mode [fail]");
|
||||||
|
assertThat(out).contains("java.lang.IllegalStateException: bad");
|
||||||
|
assertThat(System.getProperty(JarModeRunner.SUPPRESSED_SYSTEM_EXIT_CODE)).isEqualTo("1");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue