Related
Is it just my setup or is anyone else having this problem?
Using AdoptOpenJDK 1.8.0_275 installed at:
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre
API docs of System.getProperties() do not specify any details.
Can confirm this is still happening on adoptopenjdk14, as well as openjdk early access build for j16.
You can file a bug if you want, but I bet it'll be denied. At this point, the name Mac OS X is not so much 'the name of the OS' as a 'globally agreed upon keyword identifying that unix-based mac operating system', where I mean globally literally (as in, 'around the planet', not 'across your source base/VM'). Changing it would just break stuff needlessly. The same applies, to a lesser degree, to version 10.16: The thing before the dot is not so much 'this is how the OS identifies itself' and more a 'globally agreed upon versioning scheme for Mac OS, identifying a wide and ill defined set of capabilities'.
There is no meaningful difference between the transition between big sur and catalina, other than the fact that apple made a marketing decision. If you want to point at an OS transition that might warrant the entirely nebulous choice to consider it a 'major change', surely it was the one to catalina, as that made by far the largest changes (including removing support for 32-bit entirely) in the last bunch of releases.
This leaves you with the challenge of: Okay, great, I can use System.getProperty("os.name") to get the globally agreed upon keyword that means unix-like Mac OS, and os.version for a string I can break into bits to figure out some nebulous batch of capabilities, but what if I need the actual name of the OS to e.g. show to a user?
Then you have three major options:
The easy one is to just write mapping code. Acknowledge that os.name and os.version give you (rather arguably) useful intent and not so much official names, and therefore, write some mappings. These would map name/version pairs to rendering strings, falling back to just printing the name string and the version string, concatenated, verbatim. You could add a mapping: Mac OS X/10.16 → Mac OS Big Sur in this table.
The hard way: Figure out you're on a mac (which is now easier; os.name returns Mac OS X, or just check for the existence: Files.isExecutable(Paths.get("/usr/bin/sw_vers"))), and then use ProcessBuilder to execute /usr/bin/sw_vers, picking up all output into a big string, and then parse it. Its output looks like:
ProductName: macOS
ProductVersion: 11.1
BuildVersion: 20C69
which, crucially, doesn't even include the words Big Sur, but does give you 11.1. I don't know how to run a command line tool that actually gives you Big Sur. Maybe system_profiler, but note that this takes many minutes to run, I really doubt you want to run that.
NB: you can also run .command("/usr/bin/sw_vers", "-productVersion") which gives you just 11.1, this may be a lot simpler to parse. -productName also works, gives you just macOS.
If you need this information to scan for OS capabilities, then stop doing this. It doesn't work with browsers, and it's not a good plan for OS releases either. What capability are you scanning for? Imagine, for example, if it is 'Can I run /usr/bin/sw_vers to figure stuff out', as a hypothetical example. The right strategy is NOT to check os.name/os.version, conclude that the command must exist, and then run it, failing catastrophically if it is not there. The right move is to check if /usr/bin/sw_vers exists, and then execute it, falling back to some non-mac based solution (perhaps /usr/bin/uname) in other cases. Scan for the capability, don't scan for the OS/version.
Java code to call native tool sw_vers
Regarding Option # 2 in the Answer by rzwitserloot, here is a complete code example to run from Java a command-line tool sw_vers that describes the version of macOS software running on the host computer.
If on the command-line (console) such as in Terminal.app, you run:
sw_vers
…in Big Sur on an Intel Mac we get:
ProductName: macOS
ProductVersion: 11.2
BuildVersion: 20D64
We only need the middle piece. So running:
sw_vers -productVersion
…shows simply 11.2, the value we need for your purpose.
Here is complete example app with a method to return this string into Java.
ProcessBuilder class creates operating system processes. Each new process is represented by the Process class.
We use try-with-resources syntax to automatically close the InputStream and Scanner objects.
Once you have the 11.2 string in hand, split on the FULL STOP, pull the first number 11, and you know you are running on Big Sur.
package org.example;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* Example code showing how to get current version of macOS from Java
* by running a native command-line tool `sw_vers`.
*/
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
String version = this.getMacOsVersionNumber();
System.out.println( "version = " + version );
}
public String getMacOsVersionNumber ( )
{
String result = "";
List < String > command = List.of( "sw_vers" , " -productVersion" );
try (
InputStream inputStream = new ProcessBuilder( command ).start().getInputStream() ;
Scanner s = new Scanner( inputStream ).useDelimiter( "\\A" ) ;
)
{
result = s.hasNext() ? s.next() : "";
}
catch ( IOException e )
{
e.printStackTrace();
}
return Objects.requireNonNull( result );
}
}
In Java, we can see the property value of os.name to know the name of the underlying operating system: System.getProperty("os.name").
For each edition of Windows, it used to return always the exact name of the OS: Windows XP for XP, Windows Vista for Vista, Windows 7 for Seven, Windows 8.1 for 8.1, and so on...
The problem is: I just updated my Windows 8.1 to Windows 10 using the released Microsoft updater, and it seems like this property still remains Windows 8.1:
public class OSTest {
public static void main(String[] args) {
System.out.println(System.getProperty("os.name"));
}
}
How can I create a workaround for this? And, does anyone know if this problem persists if installing a fresh Windows 10 copy - that is, this bug is caused by the Microsoft auto-updater -?
This is a known problem JDK-8066504 that has been fixed in upcoming Java 8 update 60.
The reason is GetVersionEx function has changed its behavior since Windows 8.1.
There are multiple possible workarounds, see MSDN article.
The trivial one is to exec cmd.exe /c ver.
The other is to look at the version information of one of the system files, e.g. kernel32.dll.
This is definitely a known bug. It occurs because the os.name property gets its value from the GetVersionEx in the source code of the Windows API. GetVersionEx however,
may be altered or unavailable for releases after Windows 8.1
As per Microsoft's official website. Instead, we will need to use the IsWindows10OrGreater found in the Version Helper API functions in the versionhelpers.h file. As you probably guessed though, this file is not a Java file, it is written in C. As a result we need to include it in a somewhat roundabout way. It does take quite a bit of work (you need to program in JNI :/) but this tutorial will help you do it. Another solution is shown in this bug log, and does require less effort.
I faced the same issue, used the following workaround:
The cmd command "systeminfo" returns "OS Name:" which is the right name for the OS, wrote the following function for this:
private boolean os2k10Check()
{
try{
Process p = Runtime.getRuntime().exec("systeminfo"); /*Execute cmd command "systeminfo"*/
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true)
{
line = r.readLine();
if (line == null) { break; }
if(line.contains("OS Name:")) /*If output contains OS Name and 2010*/
{
if(line.contains("2010"))
return true;
else
return false;
}
}
}
catch(Exception e)
{System.out.println("Platform Type: os2010check: exception"+e);}
return false;
}
Hm... I don't know if it is a fix of Windows 10(10.0.17134.590) or of Java 8(1.8.0_171-b11 for me), but it is correct now: os.name gives me Windows 10.
Besides, if you don't trust it, you can check os.version. I have 10.0.
(By the way, I see os.arch:amd64. This is of JVM, not of OS. )
You could also use the .contains() method and just check for the "windows"
string maybe along the lines of
if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains(windows version here [xp, 7, 8, etc]))){}
If you need the windows version you could check for all versions and then assume 8.1 or 10 to move around the bug.
if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("xp")){
//code for windows xp }
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("vista")){
//code for windows vista
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("7")){
//code for windows 7}
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("8")){
//code for windows 8}
else if (System.getProperty("os.name").toLowerCase().contains("windows") && System.getProperty("os.name").toLowerCase().contains("8.1")){
//code for both windows 8.1 and 10
}
Now to explain what is going on here:
the if statement is just a conditional to determine the version of windows
The System.getProperty("os.name") returns the name of the os as a string
The .toLowerCase() method makes that returned String lower case
The .contains(String) method checks if the given input string is contained in the String it is being called on
The last statement allows for different code for each os except 8.1 & 10 which would need to be handled as one block :(
I'd like to get an id unique to a computer with Java, on Windows, MacOS and, if possible, Linux. It could be a disk UUID, motherboard S/N...
Runtime.getRuntime().exec can be used (it is not an applet).
Ideas?
The problem with MAC address is that there can be many network adapters connected to the computer. Most of the newest ones have two by default (wi-fi + cable). In such situation one would have to know which adapter's MAC address should be used. I tested MAC solution on my system, but I have 4 adapters (cable, WiFi, TAP adapter for Virtual Box and one for Bluetooth) and I was not able to decide which MAC I should take... If one would decide to use adapter which is currently in use (has addresses assigned) then new problem appears since someone can take his/her laptop and switch from cable adapter to wi-fi. With such condition MAC stored when laptop was connected through cable will now be invalid.
For example those are adapters I found in my system:
lo MS TCP Loopback interface
eth0 Intel(R) Centrino(R) Advanced-N 6205
eth1 Intel(R) 82579LM Gigabit Network Connection
eth2 VirtualBox Host-Only Ethernet Adapter
eth3 Sterownik serwera dostepu do sieci LAN Bluetooth
Code I've used to list them:
Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
while (nis.hasMoreElements()) {
NetworkInterface ni = nis.nextElement();
System.out.println(ni.getName() + " " + ni.getDisplayName());
}
From the options listen on this page, the most acceptable for me, and the one I've used in my solution is the one by #Ozhan Duz, the other one, similar to #finnw answer where he used JACOB, and worth mentioning is com4j - sample which makes use of WMI is available here:
ISWbemLocator wbemLocator = ClassFactory.createSWbemLocator();
ISWbemServices wbemServices = wbemLocator.connectServer("localhost","Root\\CIMv2","","","","",0,null);
ISWbemObjectSet result = wbemServices.execQuery("Select * from Win32_SystemEnclosure","WQL",16,null);
for(Com4jObject obj : result) {
ISWbemObject wo = obj.queryInterface(ISWbemObject.class);
System.out.println(wo.getObjectText_(0));
}
This will print some computer information together with computer Serial Number. Please note that all classes required by this example has to be generated by maven-com4j-plugin. Example configuration for maven-com4j-plugin:
<plugin>
<groupId>org.jvnet.com4j</groupId>
<artifactId>maven-com4j-plugin</artifactId>
<version>1.0</version>
<configuration>
<libId>565783C6-CB41-11D1-8B02-00600806D9B6</libId>
<package>win.wmi</package>
<outputDirectory>${project.build.directory}/generated-sources/com4j</outputDirectory>
</configuration>
<executions>
<execution>
<id>generate-wmi-bridge</id>
<goals>
<goal>gen</goal>
</goals>
</execution>
</executions>
</plugin>
Above's configuration will tell plugin to generate classes in target/generated-sources/com4j directory in the project folder.
For those who would like to see ready-to-use solution, I'm including links to the three classes I wrote to get machine SN on Windows, Linux and Mac OS:
Java code to get computer SN on Windows
Java code to get computer SN on Linux
Java code to get computer SN on Mac OS
The OSHI project provides platform-independent hardware utilities.
Maven dependency:
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>LATEST</version>
</dependency>
For instance, you could use something like the following code to identify a machine uniquely:
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.ComputerSystem;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.OperatingSystem;
class ComputerIdentifier
{
static String generateLicenseKey()
{
SystemInfo systemInfo = new SystemInfo();
OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
HardwareAbstractionLayer hardwareAbstractionLayer = systemInfo.getHardware();
CentralProcessor centralProcessor = hardwareAbstractionLayer.getProcessor();
ComputerSystem computerSystem = hardwareAbstractionLayer.getComputerSystem();
String vendor = operatingSystem.getManufacturer();
String processorSerialNumber = computerSystem.getSerialNumber();
String processorIdentifier = centralProcessor.getIdentifier();
int processors = centralProcessor.getLogicalProcessorCount();
String delimiter = "#";
return vendor +
delimiter +
processorSerialNumber +
delimiter +
processorIdentifier +
delimiter +
processors;
}
public static void main(String[] arguments)
{
String identifier = generateLicenseKey();
System.out.println(identifier);
}
}
Output for my machine:
Microsoft#57YRD12#Intel64 Family 6 Model 60 Stepping 3#8
Your output will be different since at least the processor serial number will differ.
It is common to use the MAC address is associated with the network card.
The address is available in Java 6 through through the following API:
Java 6 Docs for Hardware Address
I haven't used it in Java, but for other network identification applications it has been helpful.
What do you want to do with this unique ID? Maybe you can do what you want without this ID.
The MAC address maybe is one option but this is not an trusted unique ID because the user can change the MAC address of a computer.
To get the motherboard or processor ID check on this link.
On Windows only, you can get the motherboard ID using WMI, through a COM bridge such as JACOB.
Example:
import java.util.Enumeration;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.EnumVariant;
import com.jacob.com.Variant;
public class Test {
public static void main(String[] args) {
ComThread.InitMTA();
try {
ActiveXComponent wmi = new ActiveXComponent("winmgmts:\\\\.");
Variant instances = wmi.invoke("InstancesOf", "Win32_BaseBoard");
Enumeration<Variant> en = new EnumVariant(instances.getDispatch());
while (en.hasMoreElements())
{
ActiveXComponent bb = new ActiveXComponent(en.nextElement().getDispatch());
System.out.println(bb.getPropertyAsString("SerialNumber"));
break;
}
} finally {
ComThread.Release();
}
}
}
And if you choose to use the MAC address to identify the machine, you can use WMI to determine whether an interface is connected via USB (if you want to exclude USB adapters.)
It's also possible to get a hard drive ID via WMI but this is unreliable.
Not Knowing all of your requirements. For example, are you trying to uniquely identify a computer from all of the computers in the world, or are you just trying to uniquely identify a computer from a set of users of your application. Also, can you create files on the system?
If you are able to create a file. You could create a file and use the creation time of the file as your unique id. If you create it in user space then it would uniquely identify a user of your application on a particular machine. If you created it somewhere global then it could uniquely identify the machine.
Again, as most things, How fast is fast enough.. or in this case, how unique is unique enough.
Be careful when using the MAC address as an identifier. I've experienced several gotchas:
On OS X, ethernet ports that are not active/up do not show up in the NetworkInterface.getNetworkInterfaces() Enumeration.
It's insanely easy to change a MAC address on cards if you've got appropriate OS privileges.
Java has a habit of not correctly identifying "virtual" interfaces. Even using the NetworkInterface.isVirtual() won't always tell you the truth.
Even with the above issues, I still think it's the best pure Java approach to hardware locking a license.
I think you should look at this link ... you can make a mixed key using several
identifiers such as mac+os+hostname+cpu id+motherboard serial number.
The usage of MAC id is most easier way if the task is about logging the unique id a system.
the change of mac id is though possible, even the change of other ids of a system are also possible is that respective device is replaced.
so, unless what for a unique id is required is not known, we may not be able to find an appropriate solution.
However, the below link is helpful extracting mac addresses.
http://www.stratos.me/2008/07/find-mac-address-using-java/
For identifying a windows machine uniquely.
Make sure when you use wmic to have a strategy of alternative methods. Since "wmic bios get serialnumber" might not work on all machines, you might need to have additional methods:
# Get serial number from bios
wmic bios get serialnumber
# If previous fails, get UUID
wmic csproduct get UUID
# If previous fails, get diskdrive serialnumber
wmic DISKDRIVE get SerialNumber
Resources:
The Best Way To Uniquely Identify A Windows Machine
http://www.nextofwindows.com/the-best-way-to-uniquely-identify-a-windows-machine/
In the java programs I have written for release I used the motherboard serial number (which is what I beleive windows use); however, this only works on windows as my function creates a temporary VB script which uses the WMI to retrieve the value.
public static String getMotherboardSerial() {
String result = "";
try {
File file = File.createTempFile("GetMBSerial",".vbs");
file.deleteOnExit();
FileWriter fw = new FileWriter(file);
String vbs =
"Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n"
+ "Set colItems = objWMIService.ExecQuery _ \n"
+ " (\"Select * from Win32_ComputerSystemProduct\") \n"
+ "For Each objItem in colItems \n"
+ " Wscript.Echo objItem.IdentifyingNumber \n"
+ "Next \n";
fw.write(vbs);
fw.close();
Process gWMI = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
BufferedReader input = new BufferedReader(new InputStreamReader(gWMI.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
result += line;
System.out.println(line);
}
input.close();
}
catch(Exception e){
e.printStackTrace();
}
result = result.trim();
return result;
}
This sounds like something that should have been asked before, and it has sort of, but I'm looking to get the local hostname and IP addresses of a machine even when it is not resolvable through DNS (in Java).
I can get the local IP addresses without resolution by iterating through NetworkInterfaces.getNetworkInterfaces().
Any answers to this question I've found indicate to use getLocalHost()
InetAddress localhost = java.net.InetAddress.getLocalHost();
hostName = localhost.getHostName();
but this throws an UnknownHostException if the hostname isn't resolvable through DNS.
Is there no way to get the local hostname without a DNS lookup happening behind the scenes?
edit: the IP address retrieved is 10.4.168.23
The exception is java.net.UnknownHostException: cms1.companyname.com: cms1.companyname.com (hostname changed for pseudo-anonymity), and the hosts file does not contain the hostname. But it does know its hostname, so I'm not sure why I can't get it without an exception being thrown.
Yes, there should be a way in Java to get the hostname without resorting to name service lookups but unfortunately there isn't.
However, you can do something like this:
if (System.getProperty("os.name").startsWith("Windows")) {
// Windows will always set the 'COMPUTERNAME' variable
return System.getenv("COMPUTERNAME");
} else {
// If it is not Windows then it is most likely a Unix-like operating system
// such as Solaris, AIX, HP-UX, Linux or MacOS.
// Most modern shells (such as Bash or derivatives) sets the
// HOSTNAME variable so lets try that first.
String hostname = System.getenv("HOSTNAME");
if (hostname != null) {
return hostname;
} else {
// If the above returns null *and* the OS is Unix-like
// then you can try an exec() and read the output from the
// 'hostname' command which exist on all types of Unix/Linux.
// If you are an OS other than Unix/Linux then you would have
// to do something else. For example on OpenVMS you would find
// it like this from the shell: F$GETSYI("NODENAME")
// which you would probably also have to find from within Java
// via an exec() call.
// If you are on zOS then who knows ??
// etc, etc
}
}
and that will get you 100% what you want on the traditional Sun JDK platforms (Windows, Solaris, Linux) but becomes less easy if your OS is more excotic (from a Java perspective). See the comments in the code example.
I wish there was a better way.
This question is old, but unfortunately still relevant since it's still not trivial to get a machine's host name in Java. Here's my solution with some test runs on different systems:
public static void main(String[] args) throws IOException {
String OS = System.getProperty("os.name").toLowerCase();
if (OS.indexOf("win") >= 0) {
System.out.println("Windows computer name throguh env:\"" + System.getenv("COMPUTERNAME") + "\"");
System.out.println("Windows computer name through exec:\"" + execReadToString("hostname") + "\"");
} else {
if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) {
System.out.println("Linux computer name throguh env:\"" + System.getenv("HOSTNAME") + "\"");
System.out.println("Linux computer name through exec:\"" + execReadToString("hostname") + "\"");
System.out.println("Linux computer name through /etc/hostname:\"" + execReadToString("cat /etc/hostname") + "\"");
}
}
}
public static String execReadToString(String execCommand) throws IOException {
Process proc = Runtime.getRuntime().exec(execCommand);
try (InputStream stream = proc.getInputStream()) {
try (Scanner s = new Scanner(stream).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
}
}
Results for different operating systems:
OpenSuse 13.1
Linux computer name throguh env:"machinename"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:""
Ubuntu 14.04 LTS
This one is kinda strange since echo $HOSTNAME returns the correct hostname, but System.getenv("HOSTNAME") does not (this however might be an issue with my environment only):
Linux computer name throguh env:"null"
Linux computer name through exec:"machinename
"
Linux computer name through /etc/hostname:"machinename
"
Windows 7
Windows computer name throguh env:"MACHINENAME"
Windows computer name through exec:"machinename
"
The machine names have been replaced for (some) anonymization, but I've kept the capitalization and structure. Note the extra newline when executing hostname, you might have to take it into account in some cases.
Alternatively, use JNA to call the gethostname function on unixes, avoiding the reverse DNS lookup.
Some notes: on Linux, I believe gethostname simply calls uname and parses the output. On OS X the situation is more complex, as your hostname can be affected by DNS, but those side-effects aside, it's definitely what I get from hostname.
import com.sun.jna.LastErrorException
import com.sun.jna.Library
import com.sun.jna.Native
...
private static final C c = (C) Native.loadLibrary("c", C.class);
private static interface C extends Library {
public int gethostname(byte[] name, int size_t) throws LastErrorException;
}
public String getHostName() {
byte[] hostname = new byte[256];
c.gethostname(hostname, hostname.length)
return Native.toString(hostname)
}
jna-platform.jar includes Win32 functions, so there it's as simple as a call to Kernel32Util.getComputerName().
If you are getting 127.0.0.1 as the IP address then you may need to locate your Operating System specific hosts file and add a mapping to your hostname in it.
This is a bit of a hack. But you could launch a new Process from Java and run the hostname command. Reading the outputstream of the child process would give you the name of the localhost.
Java will read the /etc/hosts file if there is no DNS configured, or rather the corresponding C functions will.
on Linux read
/proc/sys/kernel/hostname
If you're not against using an external dependency from maven central, I wrote gethostname4j to solve this problem for myself. It just uses JNA to call libc's gethostname function (or gets the ComputerName on Windows) and returns it to you as a string.
https://github.com/mattsheppard/gethostname4j
(I think it's almost exactly what #danny-thomas proposed, but maybe more convenient if you're already using Maven ;)
I have an application which is running on tomcat, one of the methods is, creating a simple thumbnail from an jpeg image. The functions works fine offline and a week ago also on tomcat. But now i get the following error:
java.lang.NoClassDefFoundError
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:164)
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141)
eval.impl.ImageEval.getThumbnail(ImageEval.java:155)
eval.impl.ImageServlet.doGet(ImageServlet.java:79)
javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
I don't think that i have change anything what should influence this (actually i didn't change the function at all according to the svn repository), so it must be a library problem. But i can't figure out what is missing.
Here are the actual lines from the getThumbnail function, where the error occures:
BufferedImage thumbImage = new BufferedImage(thumbWidth,
thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(simage, 0, 0, thumbWidth, thumbHeight, null);
[edit] I decided to update the problem description a little.
Yes it seems that he can not find some class from java.awt or one related to that. But they do exist on the server in the jvm. Java headless mode doesn't solve the problem.
In another project the exact same code, but inside an axis2 webservice on this server is working fine.
[/edit]
It seems like you've change the configuration of Tomcat.
Either you've changed to a l{0,1}[iu]n[iu]x box or installed on a virtual machine with different security control than the one where you test it.
Apparently the
GraphicsEnvironment.getLocalGraphicsEnvironment()
Is trying to access the property: java.awt.graphicsenv
Which may return null or some non existing class name which is then loaded and throws the ClassNotFoundException. 1
The solution seems to be specifying the "java.awt.headless" property.
This is a similar question: java.awt.Color error
Try this search , it shows similar situations as your.
I remember there was something in the sun bugs database too.
Post the solution when you find it!
1.GraphicsEnvironment.java
EDIT
It is not eclipse!!
In my original post there is a link to the source code of the class which is throwing the exception.
Since I looks like you miss it, I'll post it here for you:
public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() {
if (localEnv == null) {
// Y O U R E R R O R O R I G I N A T E S H E R E !!!
String nm = (String) java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction
("java.awt.graphicsenv", null));
try {
// long t0 = System.currentTimeMillis();
localEnv =
(GraphicsEnvironment) Class.forName(nm).newInstance();
// long t1 = System.currentTimeMillis();
// System.out.println("GE creation took " + (t1-t0)+ "ms.");
if (isHeadless()) {
localEnv = new HeadlessGraphicsEnvironment(localEnv);
}
} catch (ClassNotFoundException e) {
throw new Error("Could not find class: "+nm);
} catch (InstantiationException e) {
throw new Error("Could not instantiate Graphics Environment: "
+ nm);
} catch (IllegalAccessException e) {
throw new Error ("Could not access Graphics Environment: "
+ nm);
}
}
return localEnv;
}
That's what gets executed.
And in the original post which you don't seem to have read, I said the code is accessing the property "java.awt.graphicsenv"
If that other project using axis doesn't have the same problem it may be because it may be running in a different tomcat configuration or the axis library allowed the access to that property. But we cannot be sure. That's pure speculation. So why don't you test the following and see what gets printed:
String nm = (String) java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction
("java.awt.graphicsenv", null));
System.out.println("java.awt.graphicsenv = " + nm );
It it prints null then you now what the problem is. You don't have that property in your system, or the security forbids you do use it.
It is very hard to tell you from here: "Go and edit file xyz and add : fail = false" So you have to do your work and try to figure out what's the real reason.
Start by researching what's the code being executed is ( which I have just posted ) and follow by understand what it does and how does all that "AccessController.doPrivileged" works. (You may use Google + StackOverflow for that).
We had a similar issue and after much trouble shooting it was identified to be related to the java.awt.headless property. The issue was resolved by explicitly setting the JVM option to
-Djava.awt.headless=true
It was running a week ago, and now it is not.
THEREFORE, YOU CHANGED SOMETHING BETWEEN "working" and "not working".
Go back to the working config (if you can), and rigorously track what you changed. If you don't have a backup of the working config, then meticulously go back through what you've done between working and non-working until you find what you changed.
It may not be code - it could be a config file, etc.
Best of luck,
-R
Is this server running java in server mode - I hear that doesn't load in the AWT classes.
If you are deploying this on *nix, and you don't have an X window system running anymore, that could explain it. Even if you do, if you aren't exporting the DISPLAY system variable to the process that starts the JVM, or if you are but it is not actually valid, it could cause such an issue.
That would at least explain why you didn't change any configuration in tomcat, but still have a problem.
If your NoClassDefFoundError has no message at all, then this means two things:
The JVM has already tried and failed to load a class. Usually, this means the JVM was unable to complete static initialization for that class, i.e. assign values to any static fields and run any static { } blocks. Often, this is because the classes necessary to do this static initialization are missing.
You're using Java 5, not Java 6. (In Java 6, you get a 'Could not initialize class xyz' message instead.)
The problem class appears to be the one whose name is the value of the system property java.awt.graphicsenv. I would start by finding out the value of this property. What happens when you try to instantiate this class?
Since you're getting NoClassDefFoundError from inside the AWT code, it looks like Java is failing to load the X Windows libraries. Note that even if you're running in headless mode ($DISPLAY not pointing to an X Windows server), AWT still needs some subset of the X11 libraries in order to render images. See, for example, this reference:
http://javatechniques.com/blog/linux-x11-libraries-for-headless-mode
If something stopped working and your Java code didn't change, it's possible that the X11 libraries got moved or uninstalled on your machine, or that for some other reason your LD_LIBRARY_PATH environment variable doesn't point to them anymore.