How to display JAVA logger print out to C# console - java

I am trying to display the information that is printed out in the command prompt from JAVA console to C#. It works fine when a System.out.println is issued in JAVA however it does not work with logger.info print out.
Note: When i run it through windows command prompt (CMD > java -jar testbed.jar) the logger info is printed out in the command prompt.
Appreciate inputs and help from anyone on this. A test code that i'm working is as follow:
JAVA to do a simple increment and decrement number and print out through a logger when a button is pressed to increment or decrement. (THIS CODE CANNOT BE CHANGED)
private static int ValueInteger = 0 ;
static Logger l;
public TestBed() {
initComponents();
try{
l = Logger.getLogger("");
FileHandler fh = new FileHandler("main.log", false);
l.addHandler(fh);
l.setLevel(Level.ALL);
l.fine("Logger Created - JTSRunner.main()");
}catch(Exception ex){}
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
ValueInteger--;
// System.out.println(Integer.toString(ValueInteger));
l.info(Integer.toString(ValueInteger));
}
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
ValueInteger++;
// System.out.println(Integer.toString(ValueInteger));
l.info(Integer.toString(ValueInteger));
}
C# code to handle and print out onto a textbox (CODE THAT I'M WORKING ON):
private void Button_Click(object sender, RoutedEventArgs e)
{
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/k java -jar Testbed.jar ")
{
WorkingDirectory = "C:\\Testbed",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process process = Process.Start(startInfo);
process.OutputDataReceived += writeCommandInfo;
process.BeginOutputReadLine();
//process.WaitForExit();
}
private void writeCommandInfo(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
{
this.Text.Dispatcher.Invoke(new Action(() => this.Text.Text = e.Data.ToString()), DispatcherPriority.Normal, null);
}
}

The default java.util.logging properties file configures ConsoleHandler which logs messages to System.err (source), and that's why the messages appear in the command prompt. But since your C# code only redirects standard out and not the standard error (RedirectStandardError), the process isn't able to capture the messages.
Try setting the RedirectStandardError property to true.

Related

How do I make a new main class? There is already one made but its not its own .java file and currently does not work

I am using Lobo Browser in NetBeans 11.2 and I cant run the program because NetBeans cannot read which file has the Main class which is in the main browser file (main class of main browser code below)
I would like to get this working because I need some code that I want to steal but I would like to see how the browser runs first.
public static void main(final String[] args) {
// Detect if we are running on mac
if (isMac()) {
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("dock.name", "LoboBrowser");
}
// Checking for stack allows us to call AccessController.doPrivileged()
// which in turn allows us to reduce the permissions on Uno codesource
final int stackDepth = Thread.currentThread().getStackTrace().length;
if (stackDepth > 11) {
System.err.println("Stack depth (" + stackDepth + ") is too deep! Quitting as a safety precaution");
Thread.dumpStack();
System.exit(1);
} else {
privilegedLaunch(args);
}
}
private static void launch(final String[] args) {
try {
final SSLSocketFactory socketFactory = TrustManager.makeSSLSocketFactory(ReuseManager.class.getResourceAsStream("/trustStore.certs"));
ReuseManager.getInstance().launch(args, socketFactory);
} catch (final Exception err) {
final StringWriter swriter = new StringWriter();
final PrintWriter writer = new PrintWriter(swriter);
err.printStackTrace(writer);
writer.flush();
JOptionPane.showMessageDialog(new JFrame(),
"An unexpected error occurred during application startup:\r\n" + swriter.toString(),
"ERROR", JOptionPane.ERROR_MESSAGE);
System.err.println(swriter.toString());
System.exit(1);
}
}
I believe you have to put the main method with in a class as described here http://tutorials.jenkov.com/java/main-method.html. I know in net beans you can tell it what class to try to run by I think right clicking the run then selecting what file to run and if its set up correctly it will run the file.

Why can I not close my JAR executable in this way?

I have written a piece of software that requires me to open and close an executable jar file.
At the moment I have the code able to open the jar with specific arguments
(I have used notepad in the code example as I do not have the Jar file or my original code on me, and needed to test what I had written for this example worked)
The issue I have is when I open and close notepad I get the correct behaviour, however when I try to close my JAR file I am not getting a response.
I have tried killing by the process name under task manager - go to details, the app name, and variants of java, java.exe, javaw etc.
Is it something to do with having launched the jar through CMD?
in which case I have another issue because I have several processes with the exact same name and am not sure how to get the ID when the name is the same.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
// Click on the link below to continue learning how to build a desktop app using WinForms!
System.Diagnostics.Process.Start("http://aka.ms/dotnet-get-started-desktop");
}
//string jarFile = "/JarLocation";
//string jsonlocation = "/jsonlocation";
//string command = $"java - jar {jarfile} -qsArgs {jsonLocation}";
string command = "Notepad";
string processName = "Notepad";
List<int> processIDs = new List<int>();
int[] processID;
Thread testThread;
ThreadStart ts;
private void RunButton_Click(object sender, EventArgs e)
{
MessageBox.Show("Running!");
// METHOD 1 // Launch through CMD directly (in a new thread and try to terminate by process name)
/*
new Thread(() =>
{
LaunchClient();
}).Start();
*/
// METHOD 2 // Generate
/*
foreach (int ID in processIDs)
{
Console.WriteLine($"Process {ID} Created");
}
*/
//Method 3
/*
testThread = new Thread(new ThreadStart(LaunchClient()));
//testThread.Start();
*/
// Method 4
ts = delegate { LaunchClient(); };
}
private void KillButton_Click(object sender, EventArgs e)
{
MessageBox.Show("Killing!");
try
{
// Method 1
Process[] ProcList = Process.GetProcessesByName(processName);
foreach (Process targetProc in ProcList)
{
targetProc.CloseMainWindow();
}
// Method 2
/*
foreach (int ID in processIDs)
{
Process killMe = Process.GetProcessById(ID);
killMe.CloseMainWindow();
}
*/
// Method 3
//testThread.Abort();
//Method 4
//ts.EndInvoke();
}
catch (Exception f)
{
Console.WriteLine("f.StackTrace");
}
}
public void LaunchClient()
{
Thread.CurrentThread.IsBackground = false;
Process proc = new Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardInput = true;
//proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.StandardInput.WriteLine(command);
proc.StandardInput.Flush();
Console.WriteLine($"PROCESS ID: {proc.Id}");
processIDs.Add(proc.Id);
//proc.StandardInput.Close();
proc.WaitForExit();
}
}
Sorry to dump a large swathe of code but I thought seeing my implementation of the opening as well as the close would help.
EDIT:
Updated the code sample given to show the 4 different ways I have tried to handle this.
Method 1:
Closing process by name (works for notepad, but not my jar)
2: Trying to pass the process ID back and use that to close the process
(Cant see the ID outside of the thread running the cmd window)
3: using new threadstart (launchclient says 'method name expected')
4: Doesn't open Notepad at all.
If your JAR file is opened with your code, an useful technique is to listen for windowClosing, which happens when the user clicks the X button on Windows (and the equivalent on other systems):
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

Combine commons-cli and password prompt in Java

I'm currently using import org.apache.commons.cli
Let's say I have a command line parser like:
private static commandLineParser(Options options, String[] strings) throws ParseException {
options.addOption("u", "username", true, "Login Username");
options.addOption("p", "password", true, "Login Password");
// Some other options
CommandLineParser parser = new DefaultParser();
return parser.parse(options, strings);
}
and my main function:
public static void main(String args[]) {
Options options = new Options();
CommandLine cmd = null;
try {
cmd = commandLineParser(options, args);
//some helpFormatter stuff to make the options human-readable
} catch (ParseException e) {
e.printStackTrace();
System.exit(2);
}
//calling my main program
doSomething(cmd)
}
For obvious reasons I want to omit the password from the command line, since it would be visible in both the history and the process list. However my main program expects an object of type CommandLine. Is there any way to parse a password with a similar behaviour as console.readPassword() or even call this function and add it to the CommandLine object?
I've already tried to search for a combination of commons-cli and password parsing but was not successful.
While there doesn't seem to be a way in commons-cli to add an option value to the CommandLine object, you can (hopefully) modify your doSomething(cmd) program to read from stdin.
If the password was provided on the commandline, accept it. If not, read from stdin on the fly.
For example:
private void doSomething(CommandLine cmd) {
String username = cmd.getOptionValue("username");
char[] password = (cmd.hasOption("password"))
? cmd.getOptionValue("password").toCharArray()
: System.console().readPassword("Enter password for %s user: ", username);
}

Spark submit in java(SparkLauncher)

I made spark+hadoop yarn enviroment and spark-submit command works well. So I made SparkLauncher java code to do this in my application jar, BUT somehow it doesn't work (actually computer fan is spinning at first but not as long as i did with spark-submit.)
It seems not work well (no application log in hadoop web ui, unlike spark-submit). I cannot see any error log when I do with 'SparkLauncher'. without log message, I can do nothing with it.
Here is how I made it so far.
public class Main {
public static void main(String[] args) {
Process spark = null;
try
{
spark = new SparkLauncher()
.setAppResource("/usr/local/spark/examples/jars/spark-examples*.jar")
.setMainClass("org.apache.spark.examples.SparkPi")
.setMaster("yarn")
.setDeployMode( "cluster")
.launch();
}
catch( IOException e)
{
e.printStackTrace();
}
}
}
executed it with ( java -jar example.jar)
I had the same problem at first. I think the main issue is that you forgot about the waitFor().
Also, it's really helpfull to extract your errorMessage and deal with it (e.g. log it or checking it while debuging ) within your java code. To allow this, you should create a streamReader thread as follows:
InputStreamReaderRunnable errorStreamReaderRunnable = new InputStreamReaderRunnable(spark.getErrorStream(), "error");
Thread errorThread = new Thread(errorStreamReaderRunnable, "LogStreamReader error");
errorThread.start();
int result= spark.waitFor();
if(result!=0) {
String errorMessage = extractExceptionMessage(errorStreamReaderRunnable.getMessage());
LOGGER.error(errorMessage);
}
This should be after your launch() command and inside your try block. Hope it helps

Prevent launching multiple instances of a java application

I want to prevent the user from running my java application multiple times in parallel.
To prevent this, I have created a lock file when am opening the application, and delete the lock file when closing the application.
When the application is running, you can not open an another instance of jar. However, if you kill the application through task manager, the window closing event in the application is not triggered and the lock file is not deleted.
How can I make sure the lock file method works or what other mechanism could I use?
You could use a FileLock, this also works in environments where multiple users share ports:
String userHome = System.getProperty("user.home");
File file = new File(userHome, "my.lock");
try {
FileChannel fc = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
FileLock lock = fc.tryLock();
if (lock == null) {
System.out.println("another instance is running");
}
} catch (IOException e) {
throw new Error(e);
}
Also survives Garbage Collection.
The lock is released once your process ends, doesn't matter if regular exit or crash or whatever.
Similar discussion is at
http://www.daniweb.com/software-development/java/threads/83331
Bind a ServerSocket. If it fails to bind then abort the startup. Since a ServerSocket can be bound only once, only single instsances of the program will be able to run.
And before you ask, no. Just because you bind a ServerSocket, does not mean you are open to network traffic. That only comes into effect once the program starts "listening" to the port with accept().
I see two options you can try:
Use a Java shutdown hook
Have your lock file hold the main process number. The process should exist when you lanuch another instance. If it's not found in your system, you can assume that the lock can be dismissed and overwritten.
Creating a server socket, bounds to a specific port with a ServerSocket instance as the application starts is a straight way.
Note that ServerSocket.accept() blocks, so running it in its own thread makes sense to not block the main Thread.
Here is an example with a exception thrown as detected :
public static void main(String[] args) {
assertNoOtherInstanceRunning();
... // application code then
}
public static void assertNoOtherInstanceRunning() {
new Thread(() -> {
try {
new ServerSocket(9000).accept();
} catch (IOException e) {
throw new RuntimeException("the application is probably already started", e);
}
}).start();
}
You could write the process id of the process that created the lock file into the file.
When you encounter an existing lock file, you do not just quit, but you check if the process with that id is still alive. If not, you can go ahead.
You can create a Server socket like
new ServerSocket(65535, 1, InetAddress.getLocalHost());
at very beginning of your code. Then if AddressAlreadyInUse exception caught in main block you can display the appropriate message.
There are already available java methods in File class to achieve the same. The method is deleteOnExit() which ensure the file is automatically deleted when the JVM exits. However, it does not cater to forcible terminations. One should use FileLock in case of forcible termination.
For more details check, https://docs.oracle.com/javase/7/docs/api/java/io/File.html
Thus code snippet which could be used in the main method can be like :
public static void main(String args[]) throws Exception {
File f = new File("checkFile");
if (!f.exists()) {
f.createNewFile();
} else {
System.out.println("App already running" );
return;
}
f.deleteOnExit();
// whatever your app is supposed to do
System.out.println("Blah Blah")
}
..what other mechanism could I use?
If the app. has a GUI it can be launched using Java Web Start. The JNLP API provided to web-start offers the SingleInstanceService. Here is my demo. of the SingleInstanceService.
You can write something like this.
If file exists try to delete it. if it is not able to delete. We can say that application is already running.
Now create the same file again and redirect the sysout and syserr.
This works for me
Simple lock and advanced lock
I developed 2 solutions for this problem. I was also looking for an easy way of doing this without using any libraries and a lot of code.
My solutions are based on: https://stackoverflow.com/a/46705579/10686802 which I have improved upon. Therefore I would like to thank #akshaya pandey and #rbento
Simple file lock
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.IOException;
/**
* Minimal reproducible example (MRE) - Example of a simple lock file.
* #author Remzi Cavdar - ict#remzi.info - #Remzi1993
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
try {
if (FILE.createNewFile()) {
System.out.println("Starting application");
} else {
System.err.println("The application is already running!");
return;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
Advanced lock
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
/**
* Minimal reproducible example (MRE) - Example of a more advanced lock system.
* #author Remzi Cavdar - ict#remzi.info - #Remzi1993
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
if (FILE.exists()) {
System.err.println("The application is already running!");
return;
}
try (
FileOutputStream fileOutputStream = new FileOutputStream(FILE);
FileChannel channel = fileOutputStream.getChannel();
FileLock lock = channel.lock()
) {
System.out.println("Starting application");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
Testing
Tested on: 31-10-2022
Tested OS: Windows 11 - Version 21H2 (OS Build 22000.1098)
Tested with: OpenJDK 19 - Eclipse Temurin JDK with Hotspot 19+36(x64)
I closed the application and also forcefully closed the application with task manager on Windows both times the lock file seems to be deleted upon (force) close.
I struggled with this same problem for a while... none of the ideas presented here worked for me. In all cases, the lock (file, socket or otherwise) did not persist into the 2nd process instance, so the 2nd instance still ran.
So I decided to try an old school approach to simply crate a .pid file with the process id of the first process. Then any 2nd process would quit if it finds the .pid file, and also the process number specified in the file is confirmed to be still running. This approach worked for me.
There is a fair bit of code, which I provide here in full for your use... a complete solution.
package common.environment;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.nio.charset.Charset;
public class SingleAppInstance
{
private static final #Nonnull Logger log = LogManager.getLogger(SingleAppInstance.class.getName());
/**
* Enforces that only a single instance of the given component is running. This
* is resilient to crashes, unexpected reboots and other forceful termination
* scenarios.
*
* #param componentName = Name of this component, for disambiguation with other
* components that may run simultaneously with this one.
* #return = true if the program is the only instance and is allowed to run.
*/
public static boolean isOnlyInstanceOf(#Nonnull String componentName)
{
boolean result = false;
// Make sure the directory exists
String dirPath = getHomePath();
try
{
FileUtil.createDirectories(dirPath);
}
catch (IOException e)
{
throw new RuntimeException(String.format("Unable to create directory: [%s]", dirPath));
}
File pidFile = new File(dirPath, componentName + ".pid");
// Try to read a prior, existing pid from the pid file. Returns null if the file doesn't exist.
String oldPid = FileUtil.readFile(pidFile);
// See if such a process is running.
if (oldPid != null && ProcessChecker.isStillAllive(oldPid))
{
log.error(String.format("An instance of %s is already running", componentName));
}
// If that process isn't running, create a new lock file for the current process.
else
{
// Write current pid to the file.
long thisPid = ProcessHandle.current().pid();
FileUtil.createFile(pidFile.getAbsolutePath(), String.valueOf(thisPid));
// Try to be tidy. Note: This won't happen on exit if forcibly terminated, so we don't depend on it.
pidFile.deleteOnExit();
result = true;
}
return result;
}
public static #Nonnull String getHomePath()
{
// Returns a path like C:/Users/Person/
return System.getProperty("user.home") + "/";
}
}
class ProcessChecker
{
private static final #Nonnull Logger log = LogManager.getLogger(io.cpucoin.core.platform.ProcessChecker.class.getName());
static boolean isStillAllive(#Nonnull String pidStr)
{
String OS = System.getProperty("os.name").toLowerCase();
String command;
if (OS.contains("win"))
{
log.debug("Check alive Windows mode. Pid: [{}]", pidStr);
command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";
}
else if (OS.contains("nix") || OS.contains("nux"))
{
log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr);
command = "ps -p " + pidStr;
}
else
{
log.warn("Unsupported OS: Check alive for Pid: [{}] return false", pidStr);
return false;
}
return isProcessIdRunning(pidStr, command); // call generic implementation
}
private static boolean isProcessIdRunning(#Nonnull String pid, #Nonnull String command)
{
log.debug("Command [{}]", command);
try
{
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
InputStreamReader isReader = new InputStreamReader(pr.getInputStream());
BufferedReader bReader = new BufferedReader(isReader);
String strLine;
while ((strLine = bReader.readLine()) != null)
{
if (strLine.contains(" " + pid + " "))
{
return true;
}
}
return false;
}
catch (Exception ex)
{
log.warn("Got exception using system command [{}].", command, ex);
return true;
}
}
}
class FileUtil
{
static void createDirectories(#Nonnull String dirPath) throws IOException
{
File dir = new File(dirPath);
if (dir.mkdirs()) /* If false, directories already exist so nothing to do. */
{
if (!dir.exists())
{
throw new IOException(String.format("Failed to create directory (access permissions problem?): [%s]", dirPath));
}
}
}
static void createFile(#Nonnull String fullPathToFile, #Nonnull String contents)
{
try (PrintWriter writer = new PrintWriter(fullPathToFile, Charset.defaultCharset()))
{
writer.print(contents);
}
catch (IOException e)
{
throw new RuntimeException(String.format("Unable to create file at %s! %s", fullPathToFile, e.getMessage()), e);
}
}
static #Nullable String readFile(#Nonnull File file)
{
try
{
try (BufferedReader fileReader = new BufferedReader(new FileReader(file)))
{
StringBuilder result = new StringBuilder();
String line;
while ((line = fileReader.readLine()) != null)
{
result.append(line);
if (fileReader.ready())
result.append("\n");
}
return result.toString();
}
}
catch (IOException e)
{
return null;
}
}
}
To use it, simply invoke it like this:
if (!SingleAppInstance.isOnlyInstanceOf("my-component"))
{
// quit
}
I hope you find this helpful.
Finally I found really simple library to achieve this. You can you use JUniqe.
The JUnique library can be used to prevent a user to run at the same
time more instances of the same Java application.
This is an example how to use it from the documentation
public static void main(String[] args) {
String appId = "myapplicationid";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (!alreadyRunning) {
// Start sequence here
}
}
here is a pretty rudimental approach.
If your application is launched from a script, check the running java/javaw processes and their command line before launch
In windows
REM check if there is a javaw process running your.main.class
REM if found, go to the end of the script and skip the launch of a new instance
WMIC path win32_process WHERE "Name='javaw.exe'" get CommandLine 2>nul | findstr your.main.class >nul 2>&1
if %ERRORLEVEL% EQU 0 goto:eof
javaw your.main.class

Categories