-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Camel Spring Boot on Tomcat App/Product
- Loading branch information
Showing
7 changed files
with
409 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
fuse-products/src/main/java/software/tnb/product/csb/TomcatCamelSpringBoot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package software.tnb.product.csb; | ||
|
||
import software.tnb.product.LocalProduct; | ||
import software.tnb.product.Product; | ||
import software.tnb.product.application.App; | ||
import software.tnb.product.csb.application.TomcatSpringBootApp; | ||
import software.tnb.product.integration.builder.AbstractIntegrationBuilder; | ||
|
||
import com.google.auto.service.AutoService; | ||
|
||
@AutoService(Product.class) | ||
public class TomcatCamelSpringBoot extends LocalProduct { | ||
|
||
private TomcatSpringBootApp app; | ||
|
||
@Override | ||
public App createIntegrationApp(AbstractIntegrationBuilder<?> integrationBuilder) { | ||
app = new TomcatSpringBootApp(integrationBuilder); | ||
return app; | ||
} | ||
|
||
@Override | ||
public void setupProduct() { | ||
super.setupProduct(); | ||
} | ||
|
||
@Override | ||
public void teardownProduct() { | ||
app.stop(); | ||
} | ||
} |
233 changes: 233 additions & 0 deletions
233
fuse-products/src/main/java/software/tnb/product/csb/application/TomcatSpringBootApp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
package software.tnb.product.csb.application; | ||
|
||
import software.tnb.common.config.TestConfiguration; | ||
import software.tnb.product.application.App; | ||
import software.tnb.product.application.Phase; | ||
import software.tnb.product.csb.configuration.SpringBootConfiguration; | ||
import software.tnb.product.customizer.Customizer; | ||
import software.tnb.product.customizer.component.rest.RestCustomizer; | ||
import software.tnb.product.integration.builder.AbstractIntegrationBuilder; | ||
import software.tnb.product.log.FileLog; | ||
import software.tnb.product.log.Log; | ||
import software.tnb.product.log.stream.LogStream; | ||
import software.tnb.product.util.ZipUtils; | ||
import software.tnb.product.util.maven.BuildRequest; | ||
import software.tnb.product.util.maven.Maven; | ||
|
||
import org.apache.commons.io.FileUtils; | ||
import org.apache.maven.model.Dependency; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.net.URL; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
public class TomcatSpringBootApp extends App { | ||
private static final Logger LOG = LoggerFactory.getLogger(TomcatSpringBootApp.class); | ||
|
||
private AbstractIntegrationBuilder<?> integrationBuilder; | ||
private Path tomcatTmpDirectory; | ||
private Path tomcatHome = null; | ||
private Process tomcatProcess = null; | ||
private static final String TOMCAT_PARENT_DIRECTORY = "tomcat"; | ||
private static final String TOMCAT_ARCHIVE_NAME = "tomcat-archive.zip"; | ||
|
||
@Override | ||
public Log getLog() { | ||
return new FileLog(getLogPath()); | ||
} | ||
|
||
public TomcatSpringBootApp(AbstractIntegrationBuilder<?> integrationBuilder) { | ||
super(integrationBuilder.getIntegrationName()); | ||
|
||
downloadTomcat(); | ||
|
||
this.integrationBuilder = integrationBuilder; | ||
} | ||
|
||
private void startTomcat() { | ||
File[] file = tomcatTmpDirectory.resolve(TOMCAT_PARENT_DIRECTORY).toFile().listFiles(); | ||
for (File f : file) { | ||
if (f.isDirectory()) { | ||
if (f.getName().contains("apache-tomcat")) { | ||
tomcatHome = f.toPath(); | ||
} else if (f.getName().contains("jws")) { | ||
tomcatHome = f.toPath().resolve("tomcat"); // Case JWS | ||
} | ||
} | ||
} | ||
|
||
if (tomcatHome == null) { | ||
throw new RuntimeException("Could not find Tomcat home in " + tomcatTmpDirectory.resolve(TOMCAT_PARENT_DIRECTORY)); | ||
} | ||
|
||
Path logFile = getLogPath(); | ||
// startup.sh starts on another process, let's use catalina run so that we can control the lifecyle | ||
ProcessBuilder processBuilder = new ProcessBuilder(tomcatHome + File.separator + "bin" + File.separator + "catalina.sh", "run") | ||
.redirectError(logFile.toFile()) | ||
.redirectOutput(logFile.toFile()); | ||
|
||
try { | ||
tomcatProcess = processBuilder.start(); | ||
Runtime.getRuntime().addShutdownHook(new Thread(() -> { | ||
if (tomcatProcess != null) { | ||
tomcatProcess.destroyForcibly(); | ||
} | ||
})); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
LOG.info("Starting tomcat in {}", tomcatHome); | ||
} | ||
|
||
private void downloadTomcat() { | ||
try { | ||
tomcatTmpDirectory = Files.createTempDirectory("tnb-tomcat"); | ||
LOG.info("Downloading tomcat in {}", tomcatTmpDirectory); | ||
FileUtils.copyURLToFile(new URL(SpringBootConfiguration.tomcatZipUrl()), tomcatTmpDirectory.resolve(TOMCAT_ARCHIVE_NAME).toFile()); | ||
|
||
ZipUtils.unzip(tomcatTmpDirectory.resolve(TOMCAT_ARCHIVE_NAME), tomcatTmpDirectory.resolve(TOMCAT_PARENT_DIRECTORY)); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void start() { | ||
startTomcat(); | ||
|
||
// Let's remove restcustomizer, since it exclude tomcat | ||
List<Customizer> customizers = integrationBuilder.getCustomizers() | ||
.stream().filter(customizer -> customizer instanceof RestCustomizer) | ||
.collect(Collectors.toList()); | ||
integrationBuilder.getCustomizers().remove(customizers); | ||
|
||
// spring web is needed and tomcat is provided | ||
Dependency providedTomcatDependency = new Dependency(); | ||
providedTomcatDependency.setArtifactId("spring-boot-starter-tomcat"); | ||
providedTomcatDependency.setGroupId("org.springframework.boot"); | ||
providedTomcatDependency.setScope("provided"); | ||
|
||
integrationBuilder.dependencies( | ||
Maven.createDependency("org.springframework.boot:spring-boot-starter-web"), | ||
providedTomcatDependency); | ||
|
||
// Create the integration | ||
new SpringBootApp(integrationBuilder) { | ||
@Override | ||
public void start() { | ||
// We just need the application to be generated, not run | ||
} | ||
|
||
@Override | ||
public void stop() { | ||
// do nothing | ||
} | ||
|
||
@Override | ||
public boolean isReady() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isFailed() { | ||
return false; | ||
} | ||
}.start(); | ||
|
||
// replace packaging and extend SpringBootServletInitializer | ||
try { | ||
Path pomPath = TestConfiguration.appLocation().resolve(name).resolve("pom.xml"); | ||
String pom = Files.readString(pomPath); | ||
pom = pom.replace("<artifactId>" + name + "</artifactId>", | ||
"<artifactId>" + name + "</artifactId><packaging>war</packaging>"); | ||
Files.write(pomPath, pom.getBytes(StandardCharsets.UTF_8)); | ||
|
||
Path mainPath = TestConfiguration.appLocation().resolve(name) | ||
.resolve("src") | ||
.resolve("main") | ||
.resolve("java") | ||
.resolve("com") | ||
.resolve("test") | ||
.resolve("MySpringBootApplication.java"); | ||
String main = Files.readString(mainPath); | ||
|
||
main = main.replace("class MySpringBootApplication {", | ||
""" | ||
class MySpringBootApplication extends org.springframework.boot.web.servlet.support.SpringBootServletInitializer { | ||
@Override | ||
protected org.springframework.boot.builder.SpringApplicationBuilder | ||
configure(org.springframework.boot.builder.SpringApplicationBuilder application) { | ||
return application.sources(MySpringBootApplication.class); | ||
} | ||
"""); | ||
Files.write(mainPath, main.getBytes(StandardCharsets.UTF_8)); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
|
||
// package application | ||
BuildRequest.Builder requestBuilder = new BuildRequest.Builder() | ||
.withBaseDirectory(TestConfiguration.appLocation().resolve(name)) | ||
.withGoals("clean", "package") | ||
.withProperties(Map.of( | ||
"skipTests", "true" | ||
)) | ||
.withLogFile(getLogPath(Phase.BUILD)) | ||
.withLogMarker(LogStream.marker(name, Phase.BUILD)); | ||
|
||
LOG.info("Building {} application project for tomcat", name); | ||
Maven.invoke(requestBuilder.build()); | ||
|
||
// copy generated WAR in tomcat | ||
String warName = name + "-1.0.0-SNAPSHOT.war"; | ||
try { | ||
Files.copy(TestConfiguration.appLocation().resolve(name).resolve("target").resolve(warName), | ||
tomcatHome.resolve("webapps").resolve(warName)); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void stop() { | ||
if (logStream != null) { | ||
logStream.stop(); | ||
} | ||
|
||
if (log != null) { | ||
log.save(); | ||
} | ||
|
||
if (tomcatProcess != null) { | ||
try { | ||
Process shutdown = new ProcessBuilder(tomcatHome + File.separator + "bin" + File.separator + "shutdown.sh") | ||
.start(); | ||
shutdown.waitFor(); | ||
|
||
tomcatProcess.destroyForcibly(); | ||
} catch (IOException | InterruptedException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isReady() { | ||
return tomcatProcess != null && tomcatProcess.isAlive(); | ||
} | ||
|
||
@Override | ||
public boolean isFailed() { | ||
return tomcatProcess != null && !tomcatProcess.isAlive(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.