I'd like to start a JavaFX application, if it isn't already running.
The JavaFX application is packaged in a JAR container, which is in the classpath of the calling application. The calling application should execute the JavaFX app.
The JavaFX application should not terminate if the calling application gets terminated. (therefore it needs to be in a separate process)
I tried the following approach, but even though uiProcess.isAlive() returns true, the JavaFX application is never visible.
// caller main thread
String[] startOptions = new String[]{"java", "-jar", "javafx-ui.jar"};
Process uiProcess = new ProcessBuilder(startOptions).start();
+++++++++++++++++++++++++++++++++++++++
UPDATE:
I created a helper class which takes the JAR name and tries to execute it. Unfortunately this doesn't work. But if I copy the the logged CLI command and execute the command in a terminal, the app is started as expected. If I print System.getProperty("java.class.path") property, I see that my javafx-ui.jar is on the classpath.
Usage:
ProcessExecutor processExecutor = new ProcessExecutor();
processExecutor.executeJarByName("javafx-ui.jar");
Executor:
public class ProcessExecutor {
private List<Process> processes;
private static Logger logger = LoggerFactory.getLogger(ProcessExecutor.class);
/**
* Default constructor
*/
public ProcessExecutor() {
processes = new ArrayList<>();
}
/**
* Executes jar in a standalone process
*
* #param jarName
*/
public Process executeJarByName(String jarName) throws IOException {
String[] command = new String[]{"java", "-jar", jarName};
ProcessBuilder builder = createProcessBuilder(command);
Process process = builder.start();
processes.add(process);
if (process.isAlive()) {
Optional<ProcessHandle> processHandle = ProcessHandle.of(process.pid());
if (processHandle.isPresent()) {
ProcessHandle.Info processInfo = processHandle.get().info();
logger.info("COMMAND: {}", processInfo.command().orElse(""));
logger.info("CLI: {}", processInfo.commandLine().orElse(""));
logger.info("USER: {}", processInfo.user().orElse(""));
logger.info("START TIME: {}", processInfo.startInstant().orElse(null));
logger.info("TOTAL CPU: {}", processInfo.totalCpuDuration().orElse(null));
}
}
return process;
}
private ProcessBuilder createProcessBuilder(String[] command) {
return new ProcessBuilder(command);
}
/**
* Kills all executed processes
*/
public void killAll() {
processes.forEach(p -> p.destroy());
}
}
I got it working, if I execute the following command, using the Java ProcessBuilder. The mainClassName needs to be the fully qualified class name of the class, containing the main() method. (including the package name)
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String javaHome = System.getProperty("java.home");
String java = javaHome + separator + "bin" + separator + "java";
String[] command = {java, "-cp", classpath, mainClassName};
ProcessBuilder builder = createProcessBuilder(command);
Related
I'm writing a program that includes a feature where the user can type in Java code into a text box and be able to compile and run it. The error I get is:
The two directories shown at the top are correct, and the command works when I do it manually through command prompt from the same working directory. I'm using Windows 10, and also here's the code:
public Process compile() throws IOException {
save(); //saves changes to source file
System.out.println(file.getCanonicalPath());
ProcessBuilder processBuilder = new ProcessBuilder("javac", file.getCanonicalPath());
processBuilder.directory(new File(settingsFile.getJdkPath()));
System.out.println(processBuilder.directory());
Process process = processBuilder.start(); //Throws exception
this.compiledFile = new File(file.getParentFile(), file.getName().replace(".java", ".class"));
return process;
}
File to compile:
Working directory:
Using this code, I was able to compile a Test.java file into a Test.class file on my Desktop.
import java.io.IOException;
public class App {
public static Process compile() throws IOException {
String myFilePath = "C:\\Users\\redacted\\Desktop\\Test.java";
String javacPath = "C:\\Program Files\\Java\\jdk1.8.0_171\\bin\\javac.exe";
ProcessBuilder processBuilder = new ProcessBuilder(javacPath, myFilePath);
return processBuilder.start();
}
public static void main(String[] args) throws IOException {
Process process = compile();
}
}
Using String javacPath = "javac.exe"; also worked, but that could be because my JDK bin is on my PATH variable.
There is something wrong with your paths or permissions in the ProcessBuilder constructor call.
I am a fresher and I have created a java swing application, which is running perfectly.
I want to add a functionality in this application that when user exit or close this application from anywhere like close from task manager, or force stop or by some other methods. Application will restart automatically after some time.
Is it possible to do so?
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
final File currentJar = new File(MyClassInTheJar.class.getProtectionDomain().getCodeSource().getLocation().toURI());
/* is it a jar file? */
if(!currentJar.getName().endsWith(".jar"))
return;
/* Build command: java -jar application.jar */
final ArrayList<String> command = new ArrayList<String>();
command.add(javaBin);
command.add("-jar");
command.add(currentJar.getPath());
final ProcessBuilder builder = new ProcessBuilder(command);
builder.start();
System.exit(0);
}
},
5000);
read https://docs.oracle.com/javase/6/docs/api/java/util/Timer.html
I am working on developing a plugin for teamcity . The requirement is to run a jar file from the code which does some custom operation. I tried with the below code, but its not working for me.Any ideas on how to run the jar, links to documentation or sample code will help me a lot to progress further
public class CustomBuildProcess extends BuildProcessAdapter
{
private static final String jarDir = "\\plugins\\teamcity-custom-plugin-agent\\lib\\metrics-17.6.4.4.jar";
#Override
public void start()
{
buildStatus = startProcess();
}
private BuildFinishedStatus startProcess() throws IOException
{
final GeneralCommandLine cmd = new GeneralCommandLine();
cmd.setExePath("java -jar C:\\BuildAgent"+jarDir);
final ExecResult result = SimpleCommandLineProcessRunner.runCommand(cmd, new byte[0]);
}
The following code worked for me.
final Runtime rTime = Runtime.getRuntime();
final Process process = rTime.exec("java -jar
C:\\TeamCity\\BuildAgent\\plugins\\teamcity-cutom-plugin-agent\\lib\\metrics-17.6.4.4.jar");
logger.progressMessage(new String(IOUtils.toByteArray(process.getInputStream())));
PrintStream printStream = new PrintStream(process.getOutputStream());
logger.progressMessage(new String(IOUtils.toByteArray(process.getErrorStream())));
i'd like to run a command that executes a shell script with the java class "DefaultExecutor", but i get this error:
Cannot run program "get_encrypted_password.sh" (in directory "C:\Temp\scripts"): CreateProcess error=2 specified file not found".
the script works well with git bash.
can someone tell me where i'm doing wrong?
public Entity updateWithEncryptedPassword(Entity entity) throws IOException {
String password = entity.getPwd();
String security_key = "00000000000000000000000000000000";
String path = "C:/Temp/scripts";
CommandLine commandLine = CommandLine.parse("get_encrypted_password.sh");
commandLine.addArgument(password);
commandLine.addArgument(security_key);
String encrypted_password = Utils.runCommandAndGetOutput(commandLine, path);
entity.setNewPwd(encrypted_password);
return super.update(entity);
}
public static String runCommandAndGetOutput(CommandLine commandLine, String path) throws IOException {
DefaultExecutor defaultExecutor = new DefaultExecutor();
defaultExecutor.setExitValue(0);
defaultExecutor.setWorkingDirectory(new File(path));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
defaultExecutor.setStreamHandler(streamHandler);
defaultExecutor.execute(commandLine);
return outputStream.toString();
}
Instead of executing "get_encrypted_password.sh", which cannot be ran under Windows, execute "bash", (probably git bash,) and pass "get_encrypted_password.sh" as a parameter to it, so that bash will execute your script.
Along the lines of "This tape will self-destruct in five seconds. Good luck, Jim"...
Would it be possible for an application to delete itself (or it's executable wrapper form) once a preset time of use or other condition has been reached?
Alternatively, what other approaches could be used to make the application useless?
The aim here is to have a beta expire, inviting users to get a more up-to-date version.
It is possible. To get around the lock on the JAR file, your application may need to spawn a background process that waits until the JVM has exited before deleting stuff.
However, this isn't bomb-proof. Someone could install the application and then make the installed files and directories read-only so that your application can't delete itself. The user (or their administrator) via the OS'es access control system has the final say on what files are created and deleted.
If you control where testers download your application, you could use an automated build system (e.g. Jenkins) that you could create a new beta versions every night that has a hard-coded expiry date:
private static final Date EXPIRY_DATE = <90 days in the future from build date>;
the above date is automatically inserted by the build process
if (EXPIRY_DATE.before(new Date()) {
System.out.println("Get a new beta version, please");
System.exit(1);
}
Mix that with signed and sealed jars, to put obstacles in the way of decompiling the bytecode and providing an alternative implementation that doesn't include that code, you can hand out a time-expiring beta of the code.
The automated build system could be configured to automatically upload the beta version to the server hosting the download version.
Since Windows locks the JAR file while it is running, you cannot delete it from your own Java code hence you need a Batch file:
private static void selfDestructWindowsJARFile() throws Exception
{
String resourceName = "self-destruct.bat";
File scriptFile = File.createTempFile(FilenameUtils.getBaseName(resourceName), "." + FilenameUtils.getExtension(resourceName));
try (FileWriter fileWriter = new FileWriter(scriptFile);
PrintWriter printWriter = new PrintWriter(fileWriter))
{
printWriter.println("taskkill /F /IM \"java.exe\"");
printWriter.println("DEL /F \"" + ProgramDirectoryUtilities.getCurrentJARFilePath() + "\"");
printWriter.println("start /b \"\" cmd /c del \"%~f0\"&exit /b");
}
Desktop.getDesktop().open(scriptFile);
}
public static void selfDestructJARFile() throws Exception
{
if (SystemUtils.IS_OS_WINDOWS)
{
selfDestructWindowsJARFile();
} else
{
// Unix does not lock the JAR file so we can just delete it
File directoryFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath();
Files.delete(directoryFilePath.toPath());
}
System.exit(0);
}
ProgramDirectoryUtilities class:
public class ProgramDirectoryUtilities
{
private static String getJarName()
{
return new File(ProgramDirectoryUtilities.class.getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath())
.getName();
}
public static boolean isRunningFromJAR()
{
String jarName = getJarName();
return jarName.contains(".jar");
}
public static String getProgramDirectory()
{
if (isRunningFromJAR())
{
return getCurrentJARDirectory();
} else
{
return getCurrentProjectDirectory();
}
}
private static String getCurrentProjectDirectory()
{
return new File("").getAbsolutePath();
}
public static String getCurrentJARDirectory()
{
try
{
return getCurrentJARFilePath().getParent();
} catch (URISyntaxException exception)
{
exception.printStackTrace();
}
throw new IllegalStateException("Unexpected null JAR path");
}
public static File getCurrentJARFilePath() throws URISyntaxException
{
return new File(ProgramDirectoryUtilities.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
}
}
Solution inspired by this question.
Here is a better method for Windows:
private static void selfDestructWindowsJARFile() throws Exception
{
String currentJARFilePath = ProgramDirectoryUtilities.getCurrentJARFilePath().toString();
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd /c ping localhost -n 2 > nul && del \"" + currentJARFilePath + "\"");
}
Here is the original answer.
it is pretty possible i guess. maybe you can delete the jar like this and make sure the application vanishes given that you have the rights.
File jar = new File(".\\app.jar");
jar.deleteOnExit();
System.exit(0);
also using something like Nullsoft Scriptable Install System which enables you to write your own installed/uninstaller should help.