diff --git a/src/main/java/rife/bld/extension/AbstractBootOperation.java b/src/main/java/rife/bld/extension/AbstractBootOperation.java index f0ecfe9..187a4b7 100644 --- a/src/main/java/rife/bld/extension/AbstractBootOperation.java +++ b/src/main/java/rife/bld/extension/AbstractBootOperation.java @@ -42,13 +42,15 @@ import java.util.spi.ToolProvider; * @since 1.0 */ public abstract class AbstractBootOperation extends AbstractOperation { + private final List infLibs_ = new ArrayList<>(); + private final List launcherJars_ = new ArrayList<>(); private final List manifestAttributes_ = new ArrayList<>(); private final List sourceDirectories_ = new ArrayList<>(); - protected - Project project_; private String destinationArchiveFileName; private File destinationDirectory_; private String launcherClass_; + private String mainClass_; + private Project project_; public void deleteDirectories(File... directory) throws FileUtilsErrorException { for (var d : directory) { @@ -92,7 +94,6 @@ public abstract class AbstractBootOperation extends AbstractOperation jars) { + infLibs_.addAll(jars); + return this; } /** - * Part of the {@link #execute} operation, configure the JAR launcher class. + * Provides library JARs that will be used for the archive creation. + * + * @param jar Java archive file + * @return this operation instance */ - protected AbstractBootOperation launcherClass(String className) { + public AbstractBootOperation infLibs(File... jar) { + infLibs_.addAll(List.of(jar)); + return this; + } + + /** + * Retrieves the library JARs in {@code BOOT-INF} or {@code WEB-INF}. + */ + public List infLibs() { + return infLibs_; + } + + /** + * Part of the {@link #execute} operation, configure the JAR launcher ({@code spring-boot-loader}) class name. + */ + public AbstractBootOperation launcherClass(String className) { launcherClass_ = className; return this; } /** - * Retrieves the JAR launcher class fully-qualified name. + * Retrieves the JAR launcher ({@code spring-boot-loader}) class fully-qualified name. */ protected String launcherClass() { if (launcherClass_ == null) { - throw new IllegalArgumentException("ERROR: Spring boot launcher class required."); + throw new IllegalArgumentException("ERROR: Spring boot launcher (spring-boot-loader) class " + + "required."); } return launcherClass_; } + /** + * Retrieves the launcher ({@code spring-boot-loader}) JARs. + */ + public List launcherJars() { + return launcherJars_; + } + + /** + * Part of the {@link #execute} operation, configure the launcher ({@code spring-boot-loader}) JAR location. + */ + public AbstractBootOperation launcherJars(List jars) throws IOException { + if (!jars.isEmpty()) { + for (var j : jars) { + if (!j.exists()) { + throw new IOException("ERROR: launcher (spring-boot-loader) JAR(s) not found: " + j); + } + } + launcherJars_.addAll(jars); + } + return this; + } + + /** + * Provides the fully-qualified main class name. + */ + protected AbstractBootOperation mainClass(String className) { + mainClass_ = className; + return this; + } + + /** + * Retrieves the main class name. + */ + public String mainClass() { + return mainClass_; + } + /** * Provides an attribute to put in the JAR manifest. * @@ -242,7 +313,6 @@ public abstract class AbstractBootOperation extends AbstractOperation attributes) { manifestAttributes_.addAll(attributes); @@ -258,6 +328,21 @@ public abstract class AbstractBootOperation extends AbstractOperation sourceDirectories() { + return sourceDirectories_; + } + + /** + * Verifies that all the elements required to create the archived have been provided, throws an + * {@link IllegalArgumentException} otherwise. + */ + protected boolean verifyExecute() throws IllegalArgumentException { + if (mainClass() == null) { + throw new IllegalArgumentException("ERROR: project mainClass required."); + } else if (launcherClass().isEmpty()) { + throw new IllegalArgumentException(("ERROR: launcher (spring-boot-loader) class required")); + } else if (launcherJars().isEmpty()) { + throw new IllegalArgumentException(("ERROR: launcher (spring-boot-loader) JAR(s) required")); + } + return true; + } } diff --git a/src/main/java/rife/bld/extension/BootJarOperation.java b/src/main/java/rife/bld/extension/BootJarOperation.java index 9033016..76ed2a6 100644 --- a/src/main/java/rife/bld/extension/BootJarOperation.java +++ b/src/main/java/rife/bld/extension/BootJarOperation.java @@ -22,81 +22,40 @@ import rife.tools.FileUtils; import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; /** - * Builds and creates a Sprint Boot executable java archive (JAR). + * Builds and creates a Spring Boot executable Java archive (JAR). * * @author Erik C. Thauvin * @since 1.0 */ public class BootJarOperation extends AbstractBootOperation { private static final Logger LOGGER = Logger.getLogger(BootJarOperation.class.getName()); - private final List libJars_ = new ArrayList<>(); /** - * Performs the BootJar operation. + * Provides the destination file name that will be used for the archive creation. + * + * @param name the war archive destination file name + * @return this operation instance */ @Override - public void execute() throws Exception { - if (project_ == null) { - throw new IllegalArgumentException("ERROR: project required."); - } else if (project_.mainClass() == null) { - throw new IllegalArgumentException("ERROR: project mainClass required."); - } - - var staging_dir = Files.createTempDirectory("bootjar").toFile(); - - try { - var boot_inf_dir = executeCreateWebInfDirectory(staging_dir); - executeCopyBootInfClassesFiles(boot_inf_dir); - executeCopyBootInfLibs(boot_inf_dir); - executeCopyBootLoader(staging_dir); - - executeCreateArchive(staging_dir, LOGGER); - - if (!silent()) { - System.out.printf("The executable JAR (%s) was created in: %s%n", destinationArchiveFileName(), - destinationDirectory()); - } - - } finally { - FileUtils.deleteDirectory(staging_dir); - } + public BootJarOperation destinationArchiveFileName(String name) { + return (BootJarOperation) super.destinationArchiveFileName(name); } /** - * Part of the {@link #execute} operation, copy the {@code BOOT-INF} libs. + * Provides the destination directory in which the archive will be created. + * + * @param directory the war destination directory + * @return this operation instance */ - protected void executeCopyBootInfLibs(File stagingBootInfDirectory) throws IOException { - var boot_inf_lib_dir = new File(stagingBootInfDirectory, "lib"); - mkDirs(boot_inf_lib_dir); - - for (var jar : libJars_) { - Files.copy(jar.toPath(), boot_inf_lib_dir.toPath().resolve(jar.getName())); - } - } - - /** - * Configures the operation from a {@link Project}. - */ - public AbstractBootOperation fromProject(Project project) throws IOException { - project_ = project; - return bootInfLibs(project_.compileClasspathJars()) - .bootInfLibs(project_.runtimeClasspathJars()) - .launcherClass("org.springframework.boot.loader.JarLauncher") - .manifestAttributes( - List.of( - new BootManifestAttribute("Manifest-Version", "1.0"), - new BootManifestAttribute("Main-Class", launcherClass()), - new BootManifestAttribute("Start-Class", project_.mainClass())) - ) - .destinationDirectory(project.buildDistDirectory()) - .destinationArchiveFileName(project_.archiveBaseName() + "-" + project_.version() + "-boot.jar") - .sourceDirectories(project_.buildMainDirectory(), project_.srcMainResourcesDirectory()); + @Override + public BootJarOperation destinationDirectory(File directory) throws IOException { + return (BootJarOperation) super.destinationDirectory(directory); } /** @@ -105,9 +64,9 @@ public class BootJarOperation extends AbstractBootOperation { * @param jars Java archive files * @return this operation instance */ - public BootJarOperation bootInfLibs(Collection jars) { - libJars_.addAll(jars); - return this; + @Override + public BootJarOperation infLibs(List jars) { + return (BootJarOperation) super.infLibs(jars); } /** @@ -116,8 +75,132 @@ public class BootJarOperation extends AbstractBootOperation { * @param jar Java archive file * @return this operation instance */ - public BootJarOperation bootInfLibs(File... jar) { - libJars_.addAll(List.of(jar)); - return this; + @Override + public AbstractBootOperation infLibs(File... jar) { + return super.infLibs(jar); + } + + /** + * Part of the {@link #execute} operation, configure the JAR launcher ({@code spring-boot-loader}) class. + */ + @Override + public BootJarOperation launcherClass(String className) { + return (BootJarOperation) super.launcherClass(className); + } + + /** + * Part of the {@link #execute} operation, configure the launcher ({@code spring-boot-loader}) JAR(s). + */ + public BootJarOperation launcherJars(List jars) throws IOException { + return (BootJarOperation) super.launcherJars(jars); + } + + /** + * Provides the fully-qualified main class name. + */ + public BootJarOperation mainClass(String className) { + return (BootJarOperation) super.mainClass(className); + } + + /** + * Provides an attribute to put in the JAR manifest. + * + * @param name the attribute name to put in the manifest + * @param value the attribute value to put in the manifest + * @return this operation instance + */ + @Override + public BootJarOperation manifestAttribute(String name, String value) { + return (BootJarOperation) super.manifestAttribute(name, value); + } + + /** + * Provides a map of attributes to put in the jar manifest. + *

+ * A copy will be created to allow this map to be independently modifiable. + * + * @param attributes the attributes to put in the manifest + * @return this operation instance + */ + @Override + public BootJarOperation manifestAttributes(Collection attributes) { + return (BootJarOperation) super.manifestAttributes(attributes); + } + + /** + * Provides the bld project. + */ + @Override + public BootJarOperation project(Project project) { + return (BootJarOperation) super.project(project); + } + + /** + * Provides source directories that will be used for the jar archive creation. + * + * @param directories source directories + * @return this operation instance + */ + @Override + public BootJarOperation sourceDirectories(File... directories) { + return (BootJarOperation) super.sourceDirectories(directories); + } + + /** + * Performs the BootJar operation. + */ + @Override + public void execute() throws Exception { + verifyExecute(); + + var staging_dir = Files.createTempDirectory("bootjar").toFile(); + + try { + var boot_inf_dir = executeCreateBootInfDirectory(staging_dir); + executeCopyInfClassesFiles(boot_inf_dir); + executeCopyInfLibs(boot_inf_dir); + executeCopyBootLoader(staging_dir); + + executeCreateArchive(staging_dir, LOGGER); + + if (!silent() && LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(String.format("The executable JAR (%s) was created in: %s%n", destinationArchiveFileName(), + destinationDirectory())); + } + } finally { + FileUtils.deleteDirectory(staging_dir); + } + } + + + /** + * Part of the {@link #execute} operation, creates the {@code BOOT-INF} staging directory. + */ + protected File executeCreateBootInfDirectory(File stagingDirectory) throws IOException { + var boot_inf = new File(stagingDirectory, "BOOT-INF"); + mkDirs(boot_inf); + return boot_inf; + } + + /** + * Configures the operation from a {@link Project}. + */ + public BootJarOperation fromProject(Project project) throws IOException { + project(project); + mainClass(project.mainClass()); + + return destinationDirectory(project.buildDistDirectory()) + .destinationArchiveFileName(project.archiveBaseName() + "-" + project.version() + "-boot.jar") + .infLibs(project.compileClasspathJars()) + .infLibs(project.runtimeClasspathJars()) + .launcherClass("org.springframework.boot.loader.JarLauncher") + .launcherJars(project.standaloneClasspathJars()) + .manifestAttributes( + List.of( + new BootManifestAttribute("Manifest-Version", "1.0"), + new BootManifestAttribute("Main-Class", launcherClass()), + new BootManifestAttribute("Start-Class", mainClass())) + ) + .sourceDirectories(project.buildMainDirectory(), project.srcMainResourcesDirectory()); } } \ No newline at end of file diff --git a/src/main/java/rife/bld/extension/BootWarOperation.java b/src/main/java/rife/bld/extension/BootWarOperation.java index 3926c58..d3f76a3 100644 --- a/src/main/java/rife/bld/extension/BootWarOperation.java +++ b/src/main/java/rife/bld/extension/BootWarOperation.java @@ -25,63 +25,156 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; /** - * Builds and creates a Sprint Boot web archive (WAR). + * Builds and creates a Spring Boot web archive (WAR). * * @author Erik C. Thauvin * @since 1.0 */ public class BootWarOperation extends AbstractBootOperation { private static final Logger LOGGER = Logger.getLogger(BootWarOperation.class.getName()); - private final List webInfLibs_ = new ArrayList<>(); private final List webInfProvidedLibs_ = new ArrayList<>(); + /** + * Provides the destination file name that will be used for the archive creation. + * + * @param name the war archive destination file name + * @return this operation instance + */ + @Override + public BootWarOperation destinationArchiveFileName(String name) { + return (BootWarOperation) super.destinationArchiveFileName(name); + } + + /** + * Provides the destination directory in which the archive will be created. + * + * @param directory the war destination directory + * @return this operation instance + */ + @Override + public BootWarOperation destinationDirectory(File directory) throws IOException { + return (BootWarOperation) super.destinationDirectory(directory); + } + + /** + * Provides library JARs that will be used for the WAR creation. + * + * @param jars Java archive files + * @return this operation instance + */ + @Override + public BootWarOperation infLibs(List jars) { + return (BootWarOperation) super.infLibs(jars); + } + + /** + * Provides library JARs that will be used for the WAR creation. + * + * @param jar Java archive file + * @return this operation instance + */ + @Override + public BootWarOperation infLibs(File... jar) { + return (BootWarOperation) super.infLibs(jar); + } + + /** + * Part of the {@link #execute} operation, configure the JAR launcher ({@code spring-boot-loader}) class. + */ + @Override + public BootWarOperation launcherClass(String className) { + return (BootWarOperation) super.launcherClass(className); + } + + /** + * Part of the {@link #execute} operation, configure the launcher ({@code spring-boot-loader}) JAR(s). + */ + public BootWarOperation launcherJars(List jars) throws IOException { + return (BootWarOperation) super.launcherJars(jars); + } + + /** + * Provides the fully-qualified main class name. + */ + public BootWarOperation mainClass(String className) { + return (BootWarOperation) super.mainClass(className); + } + + /** + * Provides an attribute to put in the JAR manifest. + * + * @param name the attribute name to put in the manifest + * @param value the attribute value to put in the manifest + * @return this operation instance + */ + @Override + public BootWarOperation manifestAttribute(String name, String value) { + return (BootWarOperation) super.manifestAttribute(name, value); + } + + /** + * Provides a map of attributes to put in the jar manifest. + *

+ * A copy will be created to allow this map to be independently modifiable. + * + * @param attributes the attributes to put in the manifest + * @return this operation instance + */ + @Override + public BootWarOperation manifestAttributes(Collection attributes) { + return (BootWarOperation) super.manifestAttributes(attributes); + } + + /** + * Provides the bld project. + */ + @Override + public BootWarOperation project(Project project) { + return (BootWarOperation) super.project(project); + } + + /** + * Provides source directories that will be used for the jar archive creation. + * + * @param directories source directories + * @return this operation instance + */ + @Override + public BootWarOperation sourceDirectories(File... directories) { + return (BootWarOperation) super.sourceDirectories(directories); + } + /** * Performs the BootJar operation. */ @Override public void execute() throws Exception { - if (project_ == null) { - throw new IllegalArgumentException("ERROR: project required."); - } else if (project_.mainClass() == null) { - throw new IllegalArgumentException("ERROR: project mainClass required."); - } + verifyExecute(); var staging_dir = Files.createTempDirectory("bootwar").toFile(); try { - var boot_web_inf_dir = executeCreateWebInfDirectory(staging_dir); - executeCopyBootInfClassesFiles(boot_web_inf_dir); - executeCopyWebInfLib(boot_web_inf_dir); - executeCopyWebInfProvidedLib(boot_web_inf_dir); + var web_inf_dir = executeCreateWebInfDirectory(staging_dir); + executeCopyInfClassesFiles(web_inf_dir); + executeCopyInfLibs(web_inf_dir); + executeCopyWebInfProvidedLib(web_inf_dir); executeCopyBootLoader(staging_dir); executeCreateArchive(staging_dir, LOGGER); - if (!silent()) { - System.out.printf("The WAR (%s) was created in: %s%n", destinationArchiveFileName(), - destinationDirectory()); + if (!silent() && LOGGER.isLoggable(Level.INFO)) { + LOGGER.info(String.format("The executable WAR (%s) was created in: %s%n", destinationArchiveFileName(), + destinationDirectory())); } - } finally { FileUtils.deleteDirectory(staging_dir); } } - /** - * Part of the {@link #execute} operation, copy the {@code BOOT-INF} libs. - */ - protected void executeCopyWebInfLib(File stagingBootInfDirectory) throws IOException { - var boot_inf_lib_dir = new File(stagingBootInfDirectory, "lib"); - mkDirs(boot_inf_lib_dir); - - for (var jar : webInfLibs_) { - Files.copy(jar.toPath(), boot_inf_lib_dir.toPath().resolve(jar.getName())); - } - } - /** * Part of the {@link #execute} operation, copy the {@code BOOT-INF} libs. */ @@ -94,50 +187,41 @@ public class BootWarOperation extends AbstractBootOperation { } } + /** + * Part of the {@link #execute} operation, creates the {@code WEB-INF} staging directory. + */ + protected File executeCreateWebInfDirectory(File stagingDirectory) throws IOException { + var boot_inf = new File(stagingDirectory, "WEB-INF"); + mkDirs(boot_inf); + return boot_inf; + } + /** * Configures the operation from a {@link Project}. * * @param project the project to configure the operation from */ - public AbstractBootOperation fromProject(Project project) throws IOException { - project_ = project; - return webInfLibs(project.compileClasspathJars()) - .webInfLibs(project.runtimeClasspathJars()) - .webInfLibs(project.buildDistDirectory()) + public BootWarOperation fromProject(Project project) throws IOException { + project(project); + mainClass(project.mainClass()); + + return destinationDirectory(project.buildDistDirectory()) + .destinationArchiveFileName(project.archiveBaseName() + "-" + project.version() + "-boot.war") + .infLibs(project.compileClasspathJars()) + .infLibs(project.runtimeClasspathJars()) + .infLibs(project.buildDistDirectory()) // TODO add provided libs .launcherClass("org.springframework.boot.loader.WarLauncher") + .launcherJars(project.standaloneClasspathJars()) .manifestAttributes( List.of( new BootManifestAttribute("Manifest-Version", "1.0"), new BootManifestAttribute("Main-Class", launcherClass()), - new BootManifestAttribute("Start-Class", project.mainClass()) + new BootManifestAttribute("Start-Class", mainClass()) )) - .destinationDirectory(project.buildDistDirectory()) - .destinationArchiveFileName(project.archiveBaseName() + "-" + project.version() + "-boot.war") .sourceDirectories(project.buildMainDirectory(), project.srcMainResourcesDirectory()); } - /** - * Provides library JARs that will be used for the WAR creation. - * - * @param jars Java archive files - * @return this operation instance - */ - public BootWarOperation webInfLibs(Collection jars) { - webInfLibs_.addAll(jars); - return this; - } - - /** - * Provides library JARs that will be used for the WAR creation. - * - * @param jar Java archive file - * @return this operation instance - */ - public BootWarOperation webInfLibs(File... jar) { - webInfLibs_.addAll(List.of(jar)); - return this; - } /** * Provides library JARs that will be used for the WAR creation in {@code /WEB-INF/lib-provided}.