How to detect presence and location of JVM on Windows? - java

I'm trying to detect if there is a JVM installed and where it is located so I can run java.exe.
All I've managed to find is HKCU\Software\JavaSoft\Java Runtime Environment\<ver>. Is it safe to assume that it is installed in %PROGRAMFILES%\Java\jre<ver>?
I'm trying to do this in C#, but I assume the answer is pretty language agnostic, so any answer is appreciated.
EDIT: Ok silly me, I found How to detect whether java runtime is installed or not on a computer using c# which pointed me at HKLM\Software\JavaSoft\Java Runtime Environment\CurrentVersion which works with HKLM\Software\JavaSoft\Java Runtime Environment\<ver>\JavaHome. I managed to find these instead underneath HKLM\Software\Wow6432Node\JavaSoft\Java Runtime Environment. Is there some way to detect which of these I should be checking without trying to sniff at the CPU type?

I'm going to throw my hat in the ring with the code I've ended up using:
string javaDirectory = null;
// Native registry key - 32b on 32b or 64b on 64b
// Fall back on 32b Java on Win64 if available
RegistryKey javaKey =
Registry.LocalMachine.OpenSubKey("SOFTWARE\\Javasoft\\Java Runtime Environment") ??
Registry.LocalMachine.OpenSubKey("SOFTWARE\\Wow6432Node\\Javasoft\\Java Runtime Environment");
if (javaKey != null)
{
string javaVersion = javaKey.GetValue("CurrentVersion").ToString();
try
{
javaDirectory = javaKey.OpenSubKey(javaVersion).GetValue("JavaHome").ToString();
} catch(NullReferenceException)
{ /* Ignore null deref, means we can't get a directory */ }
}
if (javaDirectory == null)
{
// deal with a lack of Java here.
}

A properly installed JVM on a windows system will (most likely..) respond to the command shell command:
java -version
This does not return the path, but try
java -verbose -version
(At least) one of the lines will contains the substring rt.jar and this line contains the path of the "active" java virtual machine.

Doesn't the JRE install a java.exe in c:\windows?

You can try to get "*JAVA_HOME*" environment variable.
It's could be helpful.
EDIT:
Better idea look por "CLASSPATH" variable.
------- start --------
C:\Documents and Settings\david>set
ALLUSERSPROFILE=...
APPDATA=...
CLASSPATH=.;C:\Archivos de programa\Java\jre6\lib\ext\QTJava.zip
CommonProgramFiles=...
...
----- end ----

Related

Java code - Best way to list java processes in localhost JVM (for Linux & Windows]

I'm writing a console app that will run in Linux and Windows systems. This app will mainly run on JRE 1.8 environments.
In my code, it needs to get a list of Java processes that run on the host running my application. I have read the posts about jps, which come as a part of JDK, but not JRE, and also it's a separate executable.
My question is, is there any java library that I can use, to list (and ideally also kill some of) the running Java processes? Preferably, I would not want to hassle of calling jps executable with sth like Runtime.exec().
Thanks in advance, for any suggestions.
Oops: I just spotted that you need solutions for JRE1.8, this will only help for JRE9+.
A simple way to scan processes within JRE is to use ProcessHandle.allProcesses(). This will read all processes and you can add filter on simple name match with "java" or "java.exe":
Path java = Path.of("bin", "java.exe"); // use "java" if not on Windows
ProcessHandle.allProcesses()
.filter(ph -> ph.info().command().isPresent())
.filter(ph -> Path.of(ph.info().command().get()).endsWith(java))
.forEach(ph -> {
System.out.println("PID "+ph.pid()+" "+ph.info().command());
})
This approach won't spot Java VMs embedded in EXE - such as from jpackage - so is not as reliable as using JDK jps which does recognise jpackage EXEs and JDK tools like jshell.exe.
I finally found the 3rd party library named Oshi, which apparently does not need JDK and is compatible with Java 1.8: https://github.com/oshi/oshi
For future reference, here is a sample method:
public static List<OSProcess> getOSProcesses() {
SystemInfo si = new SystemInfo();
OperatingSystem os = si.getOperatingSystem();
return os.getProcesses();
}

Get JRE version from application

I need to get the java version from my application that the user has currently installed on their machine. However, the application that I have is installed with a self-contained JRE and when I do a System.getProperty("java.version"), it only returns the version of that self-contained JRE. Is there anyway that I can get the version that is installed on the machine?
The JRE installation are listed in the registry in the key only for Windows, Linux do not have central registry.
HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
You can make a simple program to test :
public class ShowVersion {
public static void main(String args[]) {
System.out.println(System.getProperty("java.version"));
}
}
Or you can try command prompt
Type java -version
For more you can refer sister site of SO :
https://superuser.com/questions/1221096/how-do-i-check-what-version-of-java-i-have-installed
if you're bundling a JRE (did you check the distribution license for it? Make sure you are allowed to do so) and it's running under that, you get that version back.
If the user were to run it under another JRE, you'd get the version of that JRE. That's just how things work.
In fact if you're using a self-contained JRE the user doesn't even have to have another JRE installed on his system at all, that's the entire point of bundling one in the first place.
Apart from a full file system scan it's impossible to know what other JVMs might be installed, and if you do that you'd have to account for all the different names the Java runtime executables may have depending on the files system you're running on. And after finding all those executables you still have no real way of knowing what version of Java they belong to unless you either do a binary analysis of the executables or somehow detect the information from other files in the directories where those executables are installed, files that may or may not be present depending on the system in question, how it was set up, what JVM is in use, and whether the installation has been manually altered or not.
For example, in the root directory of a JDK installation there is a file called "release" which contains the JVM version, but AFAIK that file isn't required to be there for the JVM to work properly. And your application may not have the rights to the file system to read that file.
You can try looking in known paths e.g. C:\Program Files\Java but unless you scan the entire file system for java or java.exe you will never be sure.
This might not work as expected as in the user that runs your application shouldn't have access to system directories. You can force you application to be started with administrator level access but that would be a security risk.
You requirement seems a bit pointless if you are already bundling a JRE with your application.
You can run cmd command using java (java -version) and use that output to get version.
List<String> cmdArgs = new ArrayList<>();
cmdArgs.add("cmd.exe");
cmdArgs.add("/C");
cmdArgs.add("java -version");
ProcessBuilder processBuilderObj = new ProcessBuilder();
processBuilderObj.command(cmdArgs);
Process process = processBuilderObj.start();
//get inputStream
BufferedReader data = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line1;
while ((line = data.readLine()) != null){
System.out.println(line);
}
While System.getProperty("java.version") returns the version of the Java that your app is running on, calling "java -version" as a system command from your Java app will return the version of the default(installed) Java in your system.
Here are the generic steps to find it programmatically:
Using ProcessBuilder in Java, execute the system command "java -version". This is certainly platform-independent.
Read the output from executed process. The version is usually on the 1st line of the output (smth like java version "1.8.0_191"), so reading the 1st line is enough.
Check using regular expression, if the output matches a string containing a java version, you just parse the version and that will be what you are looking for.
Otherwise, it means the output is an error message (smth like -bash: java: command not found), and there is no Java installed in your system.
control panel
java
Java tab
view
you can see exact version of java used and it's location.

Java in Linux - different look and feel classes for root and non-root

I noticed that Java proposes different look and feel classes for root and non-root users. I am trying to understand how to make LAF consistent. Moreover, it's inconsistent even within a user/root: depends on how user/root logged in:
Sample code (compiled and packaged in laf.jar):
import javax.swing.UIManager;
public class laf {
public static void main(java.lang.String[] args) {
try {
System.out.print(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
}
}
}
Scenario 1 Logs in to machine (in GUI mode) as a regular user
Sample output (as user)
[xxx#yyy Downloads]$ java -classpath laf.jar laf
com.sun.java.swing.plaf.gtk.GTKLookAndFeel
Sample output (switch to root via su)
[root#yyy Downloads]# java -classpath ./laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel
Scenario 2 Logs in to machine (in GUI mode) as root
Sample output (as root)
[root#yyy Downloads]# java -classpath ./laf.jar laf
com.sun.java.swing.plaf.gtk.GTKLookAndFeel
Scenario 3 Logs in to machine via SSH as a regular user (similar as scenario #1 above, but in this case - same LAF)
Sample output (as user)
[xxx#yyy Downloads]$ java -classpath laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel
Sample output (switch to root)
[root#yyy Downloads]# java -classpath ./laf.jar laf
javax.swing.plaf.metal.MetalLookAndFeel
Software versions:
[root#yyy Downloads]# java -version
java version "1.7.0"
Java(TM) SE Runtime Environment (build pxa6470sr9fp10-20150708_01(SR9 FP10))
IBM J9 VM (build 2.6, JRE 1.7.0 Linux amd64-64 Compressed References 20150701_255667 (JIT enabled, AOT enabled)
J9VM - R26_Java726_SR9_20150701_0050_B255667
JIT - tr.r11_20150626_95120.01
GC - R26_Java726_SR9_20150701_0050_B255667_CMPRSS
J9CL - 20150701_255667)
JCL - 20150628_01 based on Oracle jdk7u85-b15
[root#yyy Downloads]# cat /etc/redhat-release
Red Hat Enterprise Linux Workstation release 6.7 (Santiago)
This is less about root, and more about environment variables.
Basically, the UIManager.getSystemLookAndFeelClassName method works like this:
Check the swing.systemlaf system property. This allows the user to override whatever the system wants to choose. If it is not null, it's used.
Otherwise, if the operating system is Windows, it returns the WindowsLookAndFeel.
Otherwise, it checks the sun.desktop property. If sun.desktop is set to gnome, and GTK is available natively, it returs the GTKLookAndFeel
Otherwise, checks for Mac OS X and Solaris and returns appropriate values for these operating systems.
If all other checks failed, it returns the "cross platform" L&F, which is MetalLookAndFeel.
So, the part that is relevant to Linux/Unix is the part that checks sun.desktop. This property is set when the JVM starts up. It is set to gnome if the environment variable GNOME_DESKTOP_SESSION_ID exists, ignoring its contents, and it is set to null otherwise. I believe this is the pertinent native source code that does this.
So, on Linux, if that environment variable is set (and GTK is available), your L&F will be set to GTKLookAndFeel. If not, it will be set to MetalLookAndFeel.
When you log in to a Gnome-based Linux using the desktop manager, your environment will have that variable set. But the su command does not propagate environment variables by default. Thus, when you su to any user, not necessarily root, you lose the GNOME_DESKTOP_SESSION_ID environment variable, and Java will default to MetalLookAndFeel.
You can cause your environment to be passed through su by using su -p, or if you are using sudo, using sudo -E.
The ssh command, like su and sudo, does not propagate environment variables. This can also be worked around using ~/.ssh/environment.
However, as already stated - you can easily force a specific L&F by passing the -Dswing.systemlaf=... switch to the java command.
The first line of getSystemLookAndFeelClassName is:
public static String getSystemLookAndFeelClassName() {
String systemLAF = AccessController.doPrivileged(
new GetPropertyAction("swing.systemlaf"));
So you can use the JAVA_OPTS of the user to set
-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel
As default.
add this to the .rc-File of the user:
set JAVA_OPTS=-Dswing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel
export JAVA_OPTS
Regards

check java is installed on windows system

How to check, java is installed on windows system and get fullpath from jvm.dll on client folder?
I used this code, but i dont know how to retrive the current version
TRegistry* reg = new TRegistry(KEY_READ);
reg->RootKey = HKEY_CURRENT_USER;
reg->Access = KEY_ALL_ACCESS;
bool openResult = reg->OpenKey("SOFTWARE\\JavaSoft\\Java Runtime Environment", true);
if(!openResult) // cannot create registry keys, use default values
return;
if(!reg->ValueExists("CurrentVersion")) //it's not exist CuurentVersion
return;
I don't think writing some code or anything like that is needed to see if java is installed.
To see if its installed on windows just go to C:\Program Files\Java if that directory exists then you have java, if its installed on a different directory look in windows programs and it should show if java is installed, if not then you most likely don't have java.
Use this link to see what version you have, but it is recommended to always get the latest version.
Hope this helps, Luke
Edit:
If you want to see if java is installed on another computer programmatically try using a .bat file to see, this link should help.
or use jsmooth to build the jar into an .exe, with this, if java is not installed it will prompt the user to install java.
You can execute a system "Java -version" command from your code. Here is an example for C++. To find the version you just need to parse the result you get, if you get. The String result would provide the information you required.
Meanwhile, to find the path i believe you can do it by iterating through environmental variables and look for JAVA_HOME.

An easy bulletproof technique to check if the system has jre (windows)

Sorry my newbie question :P If I promp "java -version" in the cmd on a windows system, am I guaranteed that the system will be able to run .jar files if I don't get any error?
From the command line you should be able to invoke "java --version" which will return an error if java is not installed or the currently installed version information.
I guess the only guaranteed way to check for a JRE is to try to run a small Java program.
Or maybe not even that - I suppose conceivably a system could have only part of the Java standard library installed, in which case a small test JAR might work fine but a full program might not. Although I can't imagine why anyone would go to the trouble of setting a system up that way.
Why not run a small class file, which write a value to a file which you then check? If it fails, it doesn't work.
A good value might be the value of the java.version system property.
On Windows, you can check the registry at HKLM\SOFTWARE\JavaSoft\Java Plug-in. From there, each subkey is an installed JRE.
edit Here is C# code that will return an array of strings with the installed JRE's
public string[] GetInstalledJavas() {
// hold the registry subkeys that list the installed JRE's
string[] jres = null;
try {
RegistryKey myKey = Registry.LocalMachine;
myKey = myKey.OpenSubKey(#"SOFTWARE\JavaSoft\Java Plug-in"); // read-only
jres = myKey.GetSubKeyNames();
} catch (Exception myException) {
Console.Writeline(myException.ToString());
}
return jres;
}
Well, obviously not. You can put an empty file called java.bat anywhare in PATH, like C:\Windows\System32. Invoking "java" will not yield any errors but it doesn't mean there's a JRE installed.
I'd actually suggest, if you're only concerned about checking on windows machines, checking the registry for a handler for JNLP... that should guarantee the presence of a relatively recent JRE.

Categories