/*
* Copyright (c) 2014 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.werval.test.util;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.function.Predicate;
import io.werval.util.Couple;
import static io.werval.util.IllegalArguments.ensureNotEmpty;
/**
* Processes utilities.
*/
public final class Processes
{
/**
* Current Process PID.
*
* @param fallback Fallback in case detection fail
*
* @return Current Process PID or {@literal fallback} if unable to detect
*/
public static String currentPID( String fallback )
{
final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
final int index = jvmName.indexOf( '@' );
if( index < 1 )
{
// part before '@' empty (index = 0) / '@' not found (index = -1)
return fallback;
}
try
{
return Long.toString( Long.parseLong( jvmName.substring( 0, index ) ) );
}
catch( NumberFormatException e )
{
// ignore
}
return fallback;
}
/**
* List locally running JVM processes.
*
* @return List of Couple, with PID as left and textual info as right.
*/
public static List<Couple<String, String>> jvmList()
{
return jvmList( null );
}
/**
* List locally running JVM processes.
*
* @param filter Filter the JVM processes
*
* @return List of Couple, with PID as left and textual info as right.
*/
public static List<Couple<String, String>> jvmList( Predicate<String> filter )
{
List<Couple<String, String>> list = new ArrayList<>();
try
{
Process jps = new ProcessBuilder( "jps", "-mlv" ).start();
Scanner scanner = new Scanner( jps.getInputStream() );
while( scanner.hasNext() )
{
String line = scanner.nextLine();
if( filter == null || filter.test( line ) )
{
list.add(
Couple.of(
line.substring( 0, line.indexOf( ' ' ) ),
line.substring( line.indexOf( ' ' ) + 1 )
)
);
}
}
if( jps.waitFor() != 0 )
{
throw new RuntimeException( "Unable to list jvm processes" );
}
return list;
}
catch( InterruptedException ex )
{
Thread.currentThread().interrupt();
throw new RuntimeException( "Unable to list jvm processes", ex );
}
catch( IOException ex )
{
throw new UncheckedIOException( ex );
}
}
/**
* Kill all JVM Processes that match a given filter.
*
* @param filter Filter JVM Processes
*/
public static void killJvms( Predicate<String> filter )
{
jvmList( filter ).stream().forEach( z -> kill( z.left() ) );
}
/**
* Kill a Process.
*
* Use {@literal kill -9} on Unices, {@literal TASKKILL /PID} on Windows.
*
* @param pid PID of the Process to kill
*/
public static void kill( String pid )
{
ensureNotEmpty( "pid", pid );
ProcessBuilder kill;
if( System.getProperty( "os.name" ).toLowerCase().contains( "win" ) )
{
kill = new ProcessBuilder( "TASKKILL", "/PID", pid );
}
else
{
kill = new ProcessBuilder( "kill", "-9", pid );
}
try
{
if( kill.start().waitFor() != 0 )
{
throw new RuntimeException( "Unable to kill process: " + pid );
}
}
catch( InterruptedException ex )
{
Thread.currentThread().interrupt();
throw new RuntimeException( "Unable to kill process: " + pid, ex );
}
catch( IOException ex )
{
throw new UncheckedIOException( ex );
}
}
private Processes()
{
}
}