001/* 002 * Copyright 2017-2023 original authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.micronaut.maven.testresources; 017 018import io.micronaut.testresources.buildtools.ServerFactory; 019import io.micronaut.testresources.buildtools.ServerUtils; 020import org.apache.maven.execution.MavenSession; 021import org.apache.maven.plugin.logging.Log; 022import org.apache.maven.toolchain.ToolchainManager; 023 024import java.io.File; 025import java.time.Duration; 026import java.util.ArrayList; 027import java.util.concurrent.TimeUnit; 028import java.util.concurrent.atomic.AtomicBoolean; 029import java.util.stream.Collectors; 030 031import static io.micronaut.maven.MojoUtils.findJavaExecutable; 032 033/** 034 * Default implementation for {@link ServerFactory}. 035 * 036 * @author Álvaro Sánchez-Mariscal 037 * @since 4.0.0 038 */ 039public class DefaultServerFactory implements ServerFactory { 040 041 private final Log log; 042 private final ToolchainManager toolchainManager; 043 private final MavenSession mavenSession; 044 private final AtomicBoolean serverStarted; 045 private final String testResourcesVersion; 046 private final boolean debugServer; 047 private final boolean foreground; 048 049 private Process process; 050 051 public DefaultServerFactory(Log log, 052 ToolchainManager toolchainManager, 053 MavenSession mavenSession, 054 AtomicBoolean serverStarted, 055 String testResourcesVersion, 056 boolean debugServer, 057 boolean foreground) { 058 this.log = log; 059 this.toolchainManager = toolchainManager; 060 this.mavenSession = mavenSession; 061 this.serverStarted = serverStarted; 062 this.testResourcesVersion = testResourcesVersion; 063 this.debugServer = debugServer; 064 this.foreground = foreground; 065 } 066 067 @Override 068 public void startServer(ServerUtils.ProcessParameters processParameters) { 069 log.info("Starting Micronaut Test Resources service, version " + testResourcesVersion); 070 var cli = new ArrayList<String>(); 071 072 String javaBin = findJavaExecutable(toolchainManager, mavenSession); 073 if (javaBin == null) { 074 throw new IllegalStateException("Java executable not found"); 075 } 076 cli.add(javaBin); 077 cli.addAll(processParameters.getJvmArguments()); 078 if (debugServer) { 079 cli.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000"); 080 } 081 processParameters.getSystemProperties().forEach((key, value) -> cli.add("-D" + key + "=" + value)); 082 cli.add("-cp"); 083 cli.add(processParameters.getClasspath().stream() 084 .map(File::getAbsolutePath) 085 .collect(Collectors.joining(File.pathSeparator))); 086 String mainClass = processParameters.getMainClass(); 087 if (mainClass == null) { 088 throw new IllegalStateException("Main class is not set"); 089 } 090 cli.add(mainClass); 091 cli.addAll(processParameters.getArguments()); 092 093 if (log.isDebugEnabled()) { 094 log.debug(String.format("Command parameters: %s", String.join(" ", cli))); 095 } 096 097 var builder = new ProcessBuilder(cli); 098 try { 099 process = builder.inheritIO().start(); 100 if (foreground) { 101 log.info("Test Resources Service started in foreground. Press Ctrl+C to stop."); 102 process.waitFor(); 103 } 104 } catch (InterruptedException e) { 105 log.error("Failed to start server", e); 106 Thread.currentThread().interrupt(); 107 } catch (Exception e) { 108 log.error("Failed to start server", e); 109 serverStarted.set(false); 110 if (process != null) { 111 process.destroyForcibly(); 112 } 113 } finally { 114 if (process != null) { 115 if (process.isAlive()) { 116 serverStarted.set(true); 117 } else { 118 process.destroyForcibly(); 119 } 120 } 121 } 122 } 123 124 @Override 125 public void waitFor(Duration duration) throws InterruptedException { 126 if (process != null) { 127 process.waitFor(duration.toMillis(), TimeUnit.MILLISECONDS); 128 } 129 } 130}