Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2012-2015 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
*
* http://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 io.joshworks.snappy.maven;
import io.joshworks.snappy.maven.tools.JavaExecutable;
import io.joshworks.snappy.maven.tools.RunProcess;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import javax.management.MBeanServerConnection;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.ConnectException;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
/**
* Start a application. Contrary to the {@code run} goal, this does not block and
* allows other goal to operate on the application. This goal is typically used in
* integration test scenario where the application is started before a test suite and
* stopped after.
*
* @author Stephane Nicoll
* @see StopMojo
* @since 1.3.0
*/
@Mojo(name = "start", requiresProject = true, defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST, requiresDependencyResolution = ResolutionScope.TEST)
public class StartMojo extends AbstractRunMojo {
private static final String ENABLE_MBEAN_PROPERTY = "--snappy.application.admin.enabled=true";
private static final String JMX_NAME_PROPERTY_PREFIX = "--snappy.application.admin.jmx-name=";
private final Object lock = new Object();
/**
* The JMX name of the automatically deployed MBean managing the lifecycle of the
* spring application.
*/
@Parameter
private String jmxName = SpringApplicationAdminClient.DEFAULT_OBJECT_NAME;
/**
* The port to use to expose the platform MBeanServer if the application needs to be
* forked.
*/
@Parameter
private int jmxPort = 9001;
/**
* The number of milli-seconds to wait between each attempt to check if the spring
* application is ready.
*/
@Parameter
private long wait = 500;
/**
* The maximum number of attempts to check if the spring application is ready.
* Combined with the "wait" argument, this gives a global timeout value (30 sec by
* default)
*/
@Parameter
private int maxAttempts = 60;
@Override
protected void runWithForkedJvm(List args)
throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = runProcess(args);
try {
waitForSpringApplication();
} catch (MojoExecutionException ex) {
runProcess.kill();
throw ex;
} catch (MojoFailureException ex) {
runProcess.kill();
throw ex;
}
}
private RunProcess runProcess(List args) throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(new JavaExecutable().toString());
runProcess.run(false, args.toArray(new String[args.size()]));
return runProcess;
} catch (Exception ex) {
throw new MojoExecutionException("Could not exec java", ex);
}
}
@Override
protected RunArguments resolveApplicationArguments() {
RunArguments applicationArguments = super.resolveApplicationArguments();
applicationArguments.getArgs().addLast(ENABLE_MBEAN_PROPERTY);
if (isFork()) {
applicationArguments.getArgs()
.addLast(JMX_NAME_PROPERTY_PREFIX + this.jmxName);
}
return applicationArguments;
}
@Override
protected RunArguments resolveJvmArguments() {
RunArguments jvmArguments = super.resolveJvmArguments();
if (isFork()) {
List remoteJmxArguments = new ArrayList();
remoteJmxArguments.add("-Dcom.sun.management.jmxremote");
remoteJmxArguments.add("-Dcom.sun.management.jmxremote.port=" + this.jmxPort);
remoteJmxArguments.add("-Dcom.sun.management.jmxremote.authenticate=false");
remoteJmxArguments.add("-Dcom.sun.management.jmxremote.ssl=false");
jvmArguments.getArgs().addAll(remoteJmxArguments);
}
return jvmArguments;
}
@Override
protected void runWithMavenJvm(String startClassName, String... arguments)
throws MojoExecutionException {
IsolatedThreadGroup threadGroup = new IsolatedThreadGroup(startClassName);
Thread launchThread = new Thread(threadGroup,
new LaunchRunner(startClassName, arguments), startClassName + ".main()");
launchThread.setContextClassLoader(new URLClassLoader(getClassPathUrls()));
launchThread.start();
waitForSpringApplication(this.wait, this.maxAttempts);
}
private void waitForSpringApplication(long wait, int maxAttempts)
throws MojoExecutionException {
SpringApplicationAdminClient client = new SpringApplicationAdminClient(
ManagementFactory.getPlatformMBeanServer(), this.jmxName);
getLog().debug("Waiting for spring application to start...");
for (int i = 0; i < maxAttempts; i++) {
if (client.isReady()) {
return;
}
String message = "Spring application is not ready yet, waiting " + wait
+ "ms (attempt " + (i + 1) + ")";
getLog().debug(message);
synchronized (this.lock) {
try {
this.lock.wait(wait);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException(
"Interrupted while waiting for Spring Boot app to start.");
}
}
}
throw new MojoExecutionException(
"Spring application did not start before the configured timeout ("
+ (wait * maxAttempts) + "ms");
}
private void waitForSpringApplication()
throws MojoFailureException, MojoExecutionException {
try {
if (isFork()) {
waitForForkedSpringApplication();
} else {
doWaitForSpringApplication(ManagementFactory.getPlatformMBeanServer());
}
} catch (IOException ex) {
throw new MojoFailureException("Could not contact Spring Boot application",
ex);
} catch (Exception ex) {
throw new MojoExecutionException(
"Could not figure out if the application has started", ex);
}
}
private void waitForForkedSpringApplication()
throws IOException, MojoFailureException, MojoExecutionException {
try {
getLog().debug("Connecting to local MBeanServer at port " + this.jmxPort);
JMXConnector connector = execute(this.wait, this.maxAttempts,
new CreateJmxConnector(this.jmxPort));
if (connector == null) {
throw new MojoExecutionException(
"JMX MBean server was not reachable before the configured "
+ "timeout (" + (this.wait * this.maxAttempts) + "ms");
}
getLog().debug("Connected to local MBeanServer at port " + this.jmxPort);
try {
MBeanServerConnection connection = connector.getMBeanServerConnection();
doWaitForSpringApplication(connection);
} finally {
connector.close();
}
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
throw new MojoExecutionException(
"Failed to connect to MBean server at port " + this.jmxPort, ex);
}
}
private void doWaitForSpringApplication(MBeanServerConnection connection)
throws IOException, MojoExecutionException, MojoFailureException {
final SpringApplicationAdminClient client = new SpringApplicationAdminClient(
connection, this.jmxName);
try {
execute(this.wait, this.maxAttempts, new Callable() {
@Override
public Boolean call() throws Exception {
return (client.isReady() ? true : null);
}
});
} catch (ReflectionException ex) {
throw new MojoExecutionException("Unable to retrieve 'ready' attribute",
ex.getCause());
} catch (Exception ex) {
throw new MojoFailureException("Could not invoke shutdown operation", ex);
}
}
/**
* Execute a task, retrying it on failure.
*
* @param the result type
* @param wait the wait time
* @param maxAttempts the maximum number of attempts
* @param callback the task to execute (possibly multiple times). The callback should
* return {@code null} to indicate that another attempt should be made
* @return the result
* @throws Exception in case of execution errors
*/
public T execute(long wait, int maxAttempts, Callable callback)
throws Exception {
getLog().debug("Waiting for spring application to start...");
for (int i = 0; i < maxAttempts; i++) {
T result = callback.call();
if (result != null) {
return result;
}
String message = "Spring application is not ready yet, waiting " + wait
+ "ms (attempt " + (i + 1) + ")";
getLog().debug(message);
synchronized (this.lock) {
try {
this.lock.wait(wait);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new IllegalStateException(
"Interrupted while waiting for Spring Boot app to start.");
}
}
}
throw new MojoExecutionException(
"Spring application did not start before the configured " + "timeout ("
+ (wait * maxAttempts) + "ms");
}
private class CreateJmxConnector implements Callable {
private final int port;
CreateJmxConnector(int port) {
this.port = port;
}
@Override
public JMXConnector call() throws Exception {
try {
return SpringApplicationAdminClient.connect(this.port);
} catch (IOException ex) {
if (hasCauseWithType(ex, ConnectException.class)) {
String message = "MBean server at port " + this.port
+ " is not up yet...";
getLog().debug(message);
return null;
}
throw ex;
}
}
private boolean hasCauseWithType(Throwable t, Class extends Exception> type) {
return type.isAssignableFrom(t.getClass())
|| t.getCause() != null && hasCauseWithType(t.getCause(), type);
}
}
}