What determines which version of Java Tomcat uses on Ubuntu? - java

I have two Ubuntu 20.04 servers, Alpha and Beta, both with Tomcat 9 installed from the standard repo. In principle, they should be virtually identical, but I've found a discrepancy in which version of Java each uses that I can't find the origin of.
On server Alpha, both the ps process listing for Tomcat and systemctl status tomcat9.service show that its Java binary is /usr/lib/jvm/java-8-openjdk-amd64/bin/java. On server Beta, the same commands show that Tomcat's Java binary is /usr/lib/jvm/default-java/bin/java, which is a symlink to /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java.
Thus, server Alpha uses Java 8, while server Beta uses Java 11. They should be identical, yet something is clearly different.
The obvious question at this point is, how does Tomcat determine which version of Java to use?
1) Documentation
I cannot find the answer to this question in the Tomcat configuration documentation, and there are no other top-level topics in the documentation that seem relevant to this question.
2) Stack Overflow
This Stack Overflow question is the best I can find on the site, and it doesn't have any useful answers for an Ubuntu system; /etc/sysconfig/tomcat{N} is mentioned in one answer, but it does not exist on either server, while /etc/default/tomcat{N} exists on both but does not contain any parameters relating to Java version.
3) Standard config files
I have also checked the main Tomcat config file /var/lib/tomcat9/conf/server.xml and the Tomcat systemd service file /lib/systemd/system/tomcat9.service, but neither contain any parameters relating to Java version. Both servers have a service file override /etc/systemd/system/tomcat9.service.d/override.conf, but since I wrote that myself, I'm certain it doesn't set the version of Java used.
4) setenv.sh
Tomcat's /usr/share/tomcat9/bin/catalina.sh file mentions a JAVA_HOME environment variable, which I have to assume is what I'm looking for. That file appears to expect this variable to be set when it sources one of two files, $CATALINA_BASE/bin/setenv.sh or $CATALINA_HOME/bin/setenv.sh. Neither of these files (or bin/ directories, even) exist on either server, so this can't explain the difference.
That's all I can figure out. The question is:
In the absence of explicit user configuration, what determines what Java version Tomcat uses? This information must be stored in one of the files in Tomcat's installation, but I have no way of knowing which one.
EDIT
As #Emerson Pardo suggested, the two instances of Ubuntu 20.04 did have different default Java versions. After changing Beta's to use Java 8 using the Debian/Ubuntu update-alternatives program and restarting Tomcat, however, the problem outlined above is unchanged. Tomcat continues to use
/usr/lib/jvm/default-java/bin/java -> /usr/lib/jvm/java-1.11.0-openjdk-amd64/bin/java
on Beta.

On derivatives of Debian 10, such as Ubuntu 20.04, Tomcat is started through a wrapper script located in /usr/libexec/tomcat9/tomcat-start.sh. If you don't set JAVA_HOME yourself a heuristic procedure is performed in /usr/libexec/tomcat9/tomcat-locate-java.sh:
# This function sets the variable JDK_DIRS
find_jdks()
{
for java_version in 11 10 9 8
do
for jvmdir in /usr/lib/jvm/java-${java_version}-openjdk-* \
/usr/lib/jvm/jdk-${java_version}-oracle-* \
/usr/lib/jvm/jre-${java_version}-oracle-* \
/usr/lib/jvm/java-${java_version}-oracle \
/usr/lib/jvm/oracle-java${java_version}-jdk-* \
/usr/lib/jvm/oracle-java${java_version}-jre-*
do
if [ -d "${jvmdir}" ]
then
JDK_DIRS="${JDK_DIRS} ${jvmdir}"
fi
done
done
}
# The first existing directory is used for JAVA_HOME
JDK_DIRS="/usr/lib/jvm/default-java"
find_jdks
# Look for the right JVM to use
for jdir in $JDK_DIRS; do
if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then
JAVA_HOME="$jdir"
fi
done
export JAVA_HOME
Therefore:
if /usr/lib/jvm/default-java exists it is chosen,
otherwise the highest (up to 11) version of Java is used.

Generally, Ubuntu chooses what Java it will be used by default. You can find it like this:
$ which java
/usr/bin/java
$/usr/bin/java --version
openjdk 11.0.11 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.18.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.18.04, mixed mode, sharing)
You can also check the alternatives available in your system using:
$ update-java-alternatives -l
which will list all java installed.
To choose a specific version you can use:
$ sudo update-alternatives --config java

Related

Not able to switch the Java version to Java 17

Posting again since someone moved my question a community where there is not much activity and the solution provided there in the comment did not work.
I have installed Amazon Corretto Java 17 from here.
However, I am not able to switch the Java version to Java 17.
Following are the steps I have already tried:
1.
export JAVA_HOME=$(`/usr/libexec/java_home -v17`)
export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
I have also check the highest version of Java using below command:
/usr/libexec/java_home and it shows correct Java 17 version:
/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
I have also checked all the versions of Java installed on my machine using command /usr/libexec/java_home -V and it correctly shows Java 8, 11, and 17:
17.0.1 (x86_64) "Amazon.com Inc." - "Amazon Corretto 17" /Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
11.0.9.1 (x86_64) "Amazon.com Inc." - "Amazon Corretto 11" /Users/harsh.pamnani/Library/Java/JavaVirtualMachines/corretto-11.0.9.1/Contents/Home
1.8.0_275 (x86_64) "Amazon" - "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home
I also added JAVA_HOME exports mentioned in step-1 and step-2 to .zshrc and .bash_profile as well.
I have followed multiple questions on StackOverflow and multiple
blogs as well. For example,
How to set or change the default Java (JDK) version on macOS?
switch java version on mac OS
https://java.tutorials24x7.com/blog/how-to-switch-java-version-on-mac
https://www.lotharschulz.info/2019/08/21/mac-change-default-java-version
https://akrabat.com/using-jenv-to-select-java-version-on-macos/
https://www.happycoders.eu/java/how-to-switch-multiple-java-versions-windows/
I am using jenv to switch between different java versions. Even jenv is not able to find Java 17. I used jenv versions and following is the output:
system
1.8
1.8.0.275
11
11.0
* 11.0.9.1 (set by /Users/harsh.pamnani/.jenv/version)
corretto64-1.8.0.275
corretto64-11.0.9.1
I have also checked that JAVA_HOME is pointing to Java 17. Here is the screenshot: Screenshot
Even after following all the steps above when I do java --version, it is still set to Java 11:
openjdk 11.0.9.1 2020-11-04 LTS
OpenJDK Runtime Environment Corretto-11.0.9.12.1 (build 11.0.9.1+12-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.9.12.1 (build 11.0.9.1+12-LTS, mixed mode)
I have also checked PATH variable, and nothing seems to be relatable to Java. Following is the output for path variables:
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
/Users/harsh.pamnani/Downloads/apache-maven-3.6.3/bin
Could someone please help me understand if I am missing anything here. Thank you.
which java is often used to find the exact executable you are calling when you type in java.
Keep in mind that when you type in the command java your JAVA_HOME setting is not used. Rather, the operating system PATH setting is used. If you have an older copy of java "before" the one you want to use on the path, then that's what the operating system will give you. To fix a problem like this, you need to alter your path such that the directory of your desired java version comes before any other java versions.
I do see that you checked your PATH setting, but I think you didn't know what to check, because you only listed directories. In those directories, a java executable exists. If the old executable comes in a directory earlier in the path, that's the version of java you will get when running it from the command line, regardless of any other settings.
Now, it is still important to have the JAVA_HOME set correctly, because when various Java tools want to discover items, thy might read JAVA_HOME (and if it is wrong, get directed to a non-matching JVM).

Why can I use javac & java without having JAVA_HOME set?

My Java version is :
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
I don't set JAVA_HOME in my ~/.bash_profile, but I can use both javac and java!
My .bash_profile looks like this:
export EDITOR="vim"
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
export MAVEN_HOME="$HOME/opt/maven"
export PATH="$PATH:$MAVEN_HOME/bin"
If I want to install other version of the JDK like 11,14,15...., how can I use that? Do I need to setJAVA_HOME?
And if I have multiple versions of JDK installed at the same time, how can I use them at different times as needed? What I see on the Internet is to configure Java_ Home, I don't know what to do at all, because I'm worried that after I install several other versions of JDK, they won't work.
I use MacOS Big Sur.
JAVA_HOME is widely misunderstood.
Java itself (i.e. the java, javac and related executables) doesn't actually care about JAVA_HOME.
When they are executed they know which JDK to use (the one they are associated with). The only relevant thing is that your shell (or other tool) finds the executables in the first place and for this PATH is used. Note that PATH is a general-purpose variable used by basically all widely used general purpose OS today to find executables. It's not a Java-specific thing.
In other words: when launching java directly from the shell, only PATH is relevant.
So why does JAVA_HOME come up so frequently?
Some third-party tools (such as Gradle, Maven, Tomcat and various others) will use JAVA_HOME to find the appropriate JDK/JRE to execute. Most of the ones that do will fall back to whatever is on the PATH if no JAVA_HOME is set.
So if you use such a tool and you want to specify a specific Java version then you can set JAVA_HOME as an additional hint.
It might be a good idea to set JAVA_HOME to point to your preferred Java runtime, but it's not necessary for many things.
One commonly used pattern is to define a JAVA_HOME to point to your preferred JDK and then use that to set up your PATH. This way the two will be aligned and if the preferred JDK changes, you only need to change it in one point:
export JAVA_HOME="/some/path/pointing/to/a/jdk"
export PATH="$JAVA_HOME/bin:$PATH"
I have had good experiences with sdkman. You can easily install different JDKs and switch between them. All required environment variables will be set by sdkman!
You can use Jenv which let you maintain different version of JDK and set JAVA_HOME dynamically.
You can also set specific Java version for different folder by having a file named .java-version and mention the java version.

What is the recommended approach to switch between java 7 and java 8 in Linux (Ubuntu)?

I have a linux box (Ubuntu server 14.04). I installed jdk7 via apt-get and Oracles Java 8 manually by extracting the tarball.
How can I switch between the Java versions from a bash session?
I suppose it should be done via "alternatives", but the details are not clear to me.
Switching java is more than calling one of the two java executables. There are other binaries (e.g. javac) and some tools refer to different files within the java installation directories (think of cacerts for example).
An optimal solution would simulate the effects of having only one of the two versions installed at any time.
Example: Using maven it is possible to set JAVA_HOME, but if some process started by maven calls java, JAVA_HOME is ignored.
I think Debian has Java 8 meanwhile. Does anybody know how they deal with this issue?
Is the alternatives mechanism only usable for individual binaries or can it be used for a complete "suite", too?
You can use this command to get a list of installed jdk's and easily choose one you would like to use:
sudo update-alternatives --config javac
I'm not sure that I fully understand the question, but you could either use an environment variable in your bash session that holds the path to your java executable or you could put a symbolic link somewhere for the same purpose.
For example
export JAVA_EXEC=/usr/lib/jvm/java-8-oracle/jre/bin/java
$JAVA_EXEC -version
$JAVA_EXEC -jar cooljar.jar
Or with symlink, like the "alternatives" you mentioned
ln -s /usr/lib/jvm/java-8-oracle/jre/bin/java /usr/local/bin/java
/usr/local/bin/java -version
ln -s "${SOME_JAVA_PATH}" /usr/local/bin/java
/usr/local/bin/java -version

Expanation for the inconsitency regarding java installtion paths in unix?

I installed java in my system around 6 months. I blindly followed this document's instruction here. I downloaded the jdk, unpacked it, set the paths Java_Home, Path according to the instructions in the doc.
Today I wanted to find out, which java is installed in my system and where. So, I looked it up online and ran this command
readlink -f $(which java)
It says
/usr/local/java/jre1.7.0_40/bin/java
But when I check Java_Home variable, it says
/usr/lib/jvm/jdk1.7.0_40
Here both paths refer to jdk 1.7, but they are different. One is in /usr/lib/jvm and other is in /user/local/java.
I think, due to some confusion, I set the java_home incorrectly. I must have unpakced jdk at couple of places. And, while setting up the java_home, I took incorrect path. Either that, or it is some linkage between two locations, which occurred due to some command I ran which I don't know of.
Anyway, I can run java programs correctly and run eclipse etc, so everything is fine and because of that I never noticed that.
But, I would like to know whether I need to fix the java_home variable to ensure that both of above commands return the same value. And, if it is not necessary, why is this set up working fine when 'readlink -f $(which java)' and java_home return different path.
readlink -f $(which java) just tells you which file is executed when you type java in your shell. JAVA_HOME is an environment variable used by some programs to locate java. Since both variables point to a 1.7 jre/jdk, it should not matter much that they differ. Programs using JAVA_HOME will use the JDK java and programs just using java command line will use the JRE version.
If you really need to change them to point to the same java, then you should NOT change your JAVA_HOME but instead your java symlink, because pointing to a JDK is usually better than pointing to a JRE, since some programs mandate that JAVA_HOME must point to a JDK (for example, because those programs need javac which is not included in the JRE).
Your JAVA_HOME should match your chosen version of Java. I set my JAVA_HOME with the following:
export JAVA_HOME=`readlink -f /usr/bin/javac | sed 's|/bin/javac||g'`
I use the Debain/Ubuntu update-java-alternatives command to choose which version of Java I use. It makes sure that it doesn't just update /usr/bin/java, but also all the other Java commands like javac and javadoc.
sudo update-java-alternatives --set java-7-oracle
You can get a list of the Java distributions installed on your system:
update-java-alternatives -l
Most programs don't rely on both JAVA_HOME and which java is in your path. Typically they rely on one or the other, but not both. So for any given application, it will probably run, but different applications may run using different versions of Java. In my experience, most installed java applications will use /usr/bin/java and most development environments will use JAVA_HOME.
Specifying both JAVA_HOME and setting /usr/bin/java correctly ensure that almost all Java application run with your preferred (and the latest) version of Java.
There are some notable exceptions to that rule, however. Some programs that use run under Java have their own configuration to choose which version of Java they are using.
For example I run the tomcat7 server, and I have to have the configuration file /usr/share/tomcat7/bin/setenv.sh that sets the JAVA_HOME directory for just that application:
JAVA_HOME=`readlink -f /usr/bin/javac | sed 's|/bin/javac||g'`
JAVA_OPTS="-Xms256m -Xmx2048m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512M -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n"
Other programs like Eclipse completely ignore JAVA_HOME. It has its own algorithm for figuring out which version of Java it will run under and has a -vm command line option that allows you to specify your preference.
It's two different things.
The first tells you where the JRE (Java Runtime Environment), the java binary is located. You need this to run JAR files.
JAVA_HOME tells you where the JDK (Java Development Kit), the javac binary is located. You need this to compile and package JAR files.

How to create compact profiles

I was googling to find a way to create a Compact profile in Java 1.8 .Is it possible to create a compact profile because Here is saying it is for embedded version only
Short answer
JEP 161 says that profiles must be in Java 8. They are. To create them, use make profiles
Slightly longer answerr
Your suspicion that profiles may exist on embedded platforms only and comment from #skiwi confused me a bit and I decided to check it myself.
Example with OpenJDK
To check profiles existence I took OpenJDK. I built it on my ubuntu x86 (I read this and this READMEs and process was simple). Instructions say finish with make all command. However, there were not compact profiles after that. Then I read Makefile help section and invoke make profiles. Success
$ hg clone http://hg.openjdk.java.net/jdk8/jdk8
$ cd jdk8
$ bash ./get_source.sh
$ bash ./configure
$ make all
$ make profiles
Then I found 'images' directory and went there
$ cd build/linux-x86-normal-server-release/images/
$ export PATH=j2re-compact1-image/bin/:$PATH
$ java -version
openjdk version "1.8.0-internal"
OpenJDK Runtime Environment (build 1.8.0-internal-fasdaq_2014_03_22_20_17-b00, profile compact1)
OpenJDK Server VM (build 25.0-b70, mixed mode)
As you can see from output:
It works
It's not embedded
It's compact1 profile
It's 1.8.0 version
About embedded and link you provided
There is a jrecreate tool that allows you to get jre with profile/vm/extensions you want (and do not include these you don't want).
so that applications that do not require the entire Platform can be deployed and run on small devices (c) jep161
There is no such tool in OpenJDK. Jrecreate is a part of embedded java as you can read from release notes.
It's hard question for me: what do you want to reach creating compact profile of non-embedded java. However, you're capable to do it :)

Categories

Resources