Skip to content

Use JAVA_HOME or java.exe in PATH like the Linux scripts do #18685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 3, 2016
Merged

Use JAVA_HOME or java.exe in PATH like the Linux scripts do #18685

merged 7 commits into from
Jun 3, 2016

Conversation

StefanScherer
Copy link
Contributor

I've enhanced the Windows batch scripts to retrieve the JAVA_HOME environment from the symlink installed by Oracle's Java. See also the PR elastic/logstash#4913 in logstash repo.

@clintongormley clintongormley added review :Delivery/Packaging RPM and deb packaging, tar and zip archives, shell and batch scripts labels Jun 1, 2016
@clintongormley
Copy link
Contributor

@gmarz could you take a look at this please?

@jasontedor
Copy link
Member

Sorry, I don't think this change should be made. JAVA_EXE is a non-standard environment variable, and we already have a standard environment variable in JAVA_HOME for pointing to Java. We are moving strongly in the direction of having one way to do things, and not multiple ways to do things and I don't see the benefit of multiple ways to point to Java when we already have the fairly standard way of respecting JAVA_HOME.

@StefanScherer
Copy link
Contributor Author

The JAVA_EXE is a temporary variable to fetch the target of the symlink. I can update the PR and unset the variable again.

Having one way to do things is ok, but in my opinion using JAVA_HOME is hard to maintain (one admin updates Java for security reasons and forgets about updating JAVA_HOME...). Oracle's Java MSI does not set JAVA_HOME, but provides this symbolic link.

So that's why I try to give you an updated code. At our work we have put ELK into MSI packages and our testers and later users struggle about their forgotten JAVA_HOME variable. If Elasticsearch finds the current Java installed would be much more convenient as no manual set environment is involved.

@jasontedor
Copy link
Member

jasontedor commented Jun 2, 2016

Sorry, I realize my comment was a little confusing, but here's what I mean. Currently we have exactly one way to specify the location of Java: JAVA_HOME. This is consistent across all of our packaging. This introduces a second way, namely a symbolic link that gets set into JAVA_EXE. Except this is only available on Windows, and only if you install from an MSI which sets this symbolic link (which, I think is only possible if you have a commercial license?). This means we now sometimes (but not always) have two ways of specifying the location of Java: JAVA_HOME on all systems, and this symbolic link on Windows if it's available. These would be the multiple ways and it complicates rather than simplifies the situation. Then we have to add testing for it to make sure that it's maintained properly. But rather than introduce this into our scripts, I think it should just be handled outside the scripts exactly like we do on all other systems.

(one admin updates Java for security reasons and forgets about updating JAVA_HOME...)

That's exactly why changes like this should be automated. It shouldn't the case that one admin updates Java and another must remember to update JAVA_HOME, but rather that JAVA_HOME is automatically updated as part of updating Java.

In particular, can't you just point JAVA_HOME to this same symbolic link on your systems?

@StefanScherer
Copy link
Contributor Author

StefanScherer commented Jun 2, 2016

AFAIK there is only Oracle Java for Windows and not openjdk. So this PR exists to simplify that only Java installation way for Windows: Downloading and installing the EXE (sorry, no MSI, but still the only standard package from Oracle).

This PR doesn't change the behaviour if someone still insists to set JAVA_HOME on a Windows machine. It then uses the value of JAVA_HOME. But if you just install the standard java through its installer you just don't have to do this extra step.

There is no second way to do it, just do the right way simpler.

Why do I want to set JAVA_HOME when there is a standard way from the makers of Java that add a symlink for me? I just don't understand why I should do this extra step, it's just not necessary. Sorry, I'm only a parttime user of Java, and never understood that. I think that if Oracle expected that JAVA_HOME must be set, then I would expect that their installer would do that for me.

This PR just reads the target of the symlink (which directs to the java.exe and not the value needed for JAVA_HOME) and calculates the right value for JAVA_HOME automatically.

@jasontedor
Copy link
Member

jasontedor commented Jun 2, 2016

I think that if Oracle expected that JAVA_HOME must be set, then I would expect that their installer would do that for me.

Their docs even explain that it needs to be set and how to set it for some of their own applications.

A change that I would very much welcome is setting JAVA_HOME if java.exe is found in the path and JAVA_HOME is not set. I welcome this change because it would bring the Windows script to feature-parity with the Unix-based script, it's a simple change to make and maintain, and it's very common for scripts to do this.

I think that would satisfy your need, do you agree?

@gmarz
Copy link
Contributor

gmarz commented Jun 2, 2016

Windows is a different beast than Linux, and while I agree that it can be painful/confusing for Windows users to have to set JAVA_HOME manually, I think @jasontedor is right in that we should stick to the hard rule that JAVA_HOME should be set outside of the scripts.

There are too many things that can go wrong by assuming the correct location of Java. What if there are multiple versions installed? JRE vs JDK? 32 vs 64-bit? Does the Oracle MSI update the symlink when these things change? Maybe it does the right thing, but I think it's best not to assume and leave it to the user.

IMO, it's a task better suited for the Elasticsearch MSI (which we're currently working on) where we can bake in more complex logic (checking the registry) and invoke user interaction if needed.

@gmarz
Copy link
Contributor

gmarz commented Jun 2, 2016

A change that I would very much welcome is setting JAVA_HOME if java.exe is found in the path and JAVA_HOME is not set.

+1

@StefanScherer
Copy link
Contributor Author

This is how it looks like after Java 8 installation.

bildschirmfoto 2016-06-02 um 21 42 00

Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.

C:\Users\vagrant>where java
C:\ProgramData\Oracle\Java\javapath\java.exe

C:\Users\vagrant>set java
Environment variable java not defined

C:\Users\vagrant>java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b15, mixed mode)

C:\Users\vagrant>dir C:\ProgramData\Oracle\Java\javapath
 Volume in drive C is Windows 10
 Volume Serial Number is 9C9F-63C7

 Directory of C:\ProgramData\Oracle\Java\javapath

06/02/2016  09:39 PM    <DIR>          .
06/02/2016  09:39 PM    <DIR>          ..
06/02/2016  09:39 PM    <SYMLINK>      java.exe [C:\Program Files\Java\jre1.8.0_91\bin\java.exe]
06/02/2016  09:39 PM    <SYMLINK>      javaw.exe [C:\Program Files\Java\jre1.8.0_91\bin\javaw.exe]
06/02/2016  09:39 PM    <SYMLINK>      javaws.exe [C:\Program Files\Java\jre1.8.0_91\bin\javaws.exe]
               3 File(s)              0 bytes
               2 Dir(s)  49,184,186,368 bytes free

C:\Users\vagrant>

So java.exe is in PATH, but you have to read the symlink to know where JAVA_HOME should be.
That's why this PR was born.

@StefanScherer
Copy link
Contributor Author

@gmarz Cool that your are working on a MSI, so I can drop ours soon :-) For Kibana and Logstash as well?

That you can install the wrong CPU type and different versions of Java on one machine is the heritage of the lack of a proper package management in the first place. But yes this it is how we have to work with it now. That way may go back to Sun...

Just found out that the Server JRE is only deployed as a tar.gz and Oracle does not give any hint how to extract this on a Windows machine: http://docs.oracle.com/javase/8/docs/technotes/guides/install/windows_server_jre.html#CFHGHHFJ
So yes your are on your own and then you are willing to set JAVA_HOME as well, I think.

My focus for this PR was for the EXE installer that I normally use and that would make it easy to make Elasticsearch run out-of-the-box.

@StefanScherer
Copy link
Contributor Author

One other thing. As you can see I'm testing this in Vagrant boxes. I just found the Vagrantfile in your repo with lots of platforms. Great! Does it make sense to add one or more Windows platforms as well?
Don't know which tests are running in the Vagrant boxes.

@jasontedor
Copy link
Member

jasontedor commented Jun 2, 2016

Does it make sense to add one or more Windows platforms as well?

We are working on that, it is badly needed exactly so we can feel confident when making packaging changes. See #18475.

Don't know which tests are running in the Vagrant boxes.

We basically run a full suite of packaging tests. Does Elasticsearch start? Can it install a plugin? Does it work if there is a path with a space in the name? Does it work with a custom config? All sorts of fun things like that.

@jasontedor
Copy link
Member

jasontedor commented Jun 2, 2016

So java.exe is in PATH, but you have to read the symlink to know where JAVA_HOME should be.
That's why this PR was born.

No, because we can just do something very simple like this:

if defined JAVA_HOME goto cont

set JAVA=java.exe
%JAVA% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto start

@rem print some error message here
goto fail

:cont
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA=%JAVA_HOME%/bin/java.exe

if exist %JAVA% goto start

@rem print some error message here
goto fail

:start

and then replace the launch command from %JAVA_HOME%\bin\java% to %JAVA%.

This is completely off the cuff, completely untested, but gives the idea.

@StefanScherer
Copy link
Contributor Author

Ah, so the JAVA_HOME environment is only needed for the path to java.exe? I didn't know the details and thought that a lib/etc. also needs this to find files in the installation tree.

@jasontedor
Copy link
Member

jasontedor commented Jun 2, 2016

Ah, so the JAVA_HOME environment is only needed for the path to java.exe?

Exactly. And that's why I'm comfortable saying, hey, if java.exe is already on the path we can just use that.

@StefanScherer
Copy link
Contributor Author

OK, I'll update the PR. But I prefer to use where java.exe instead of calling java.exe -version to avoid running the Java binary only to check if it's in the PATH. The Linux version looks good to me:

if [ -x "$JAVA_HOME/bin/java" ]; then
    JAVA="$JAVA_HOME/bin/java"
else
    JAVA=`which java`
fi

if [ ! -x "$JAVA" ]; then
    echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
    exit 1
fi

I will keep the Windows version in about that order.

@jasontedor
Copy link
Member

jasontedor commented Jun 3, 2016

But I prefer to use where java.exe instead of calling java.exe -version to avoid running the Java binary only to check if it's in the PATH.

Can you double-check if where is available on all of the Windows platforms that we support and that might be in use by developers? That's the reason I didn't use it, I know it's a new addition to Windows but I didn't look up the exact history. As long as it's available in the places that matter, it's fine to use.

@StefanScherer
Copy link
Contributor Author

I've worked with where.exe since XP. Found this at stack overflow http://stackoverflow.com/questions/304319/is-there-an-equivalent-of-which-on-the-windows-command-line

The old variant

C:\Users\vagrant>for %i in (java.exe) do set JAVA=%~$PATH:i

C:\Users\vagrant>set JAVA=C:\ProgramData\Oracle\Java\javapath\java.exe

works still with Windows 10. I probably use this.

@jasontedor
Copy link
Member

I probably use this.

I prefer this option too.

@StefanScherer
Copy link
Contributor Author

I've come up with this batch solution

IF DEFINED JAVA_HOME (
  set JAVA=%JAVA_HOME%\bin\java.exe
) ELSE (
  FOR %%I IN (java.exe) DO set JAVA=%%~$PATH:I
)
IF EXIST "%JAVA%" GOTO cont

:err
ECHO Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME 1>&2
EXIT /B 1

:cont

which looks pretty similar to the bash solution.

I've commited that for the elasticsearch*.bat scripts. Still working on service.bat as this needs some more care as it uses JAVA_HOME to specify the jvm dll...

But you can have a look at the elasticsearch*.bat scripts.

@StefanScherer
Copy link
Contributor Author

I've updated service.bat as well. But this script has to calculate JAVA_HOME

  • Tested with java.exe in PATH:
    1. Path=C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows with the symlink to C:\Program Files\Java\jre1.8.0_91\bin\java.exe -> sets JAVA + JAVA_HOME correctly
    2. Path=C:\Program Files\Java\jre1.8.0_91\bin;C:\Windows\system32;C:\Windows with the exe in bin folder -> sets JAVA + JAVA_HOME correctly
  • Tested with JAVA_HOME set regardless if java.exe is in PATH:
    1. JAVA_HOME=C:\Program Files\Java\jre1.8.0_91 -> sets JAVA correctly

PTAL

@jasontedor
Copy link
Member

Thanks @StefanScherer, it looks great. Can you update the title of the PR?

@jasontedor jasontedor self-assigned this Jun 3, 2016
@StefanScherer StefanScherer changed the title Retrieve JAVA_HOME from symlink Use JAVA_HOME or java.exe in PATH like the Linux scripts do Jun 3, 2016
@StefanScherer
Copy link
Contributor Author

@jasontedor better?

@jasontedor
Copy link
Member

jasontedor commented Jun 3, 2016

@StefanScherer Thanks! I will merge soon.

@jasontedor jasontedor merged commit 92c6d78 into elastic:master Jun 3, 2016
@jasontedor jasontedor removed the review label Jun 3, 2016
@StefanScherer StefanScherer deleted the retrieve-java-home-from-symlink branch June 3, 2016 19:32
@jasontedor
Copy link
Member

Thanks for working through this one @StefanScherer, your contribution is greatly appreciated.

@StefanScherer
Copy link
Contributor Author

Thanks for merging @jasontedor. That's what open source and PR's are for. To review and to understand the intention behind the code both of the maintainer's view and the contributor's view. I've learned a lot :-)

@mark-vieira mark-vieira added the Team:Delivery Meta label for Delivery team label Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Delivery/Packaging RPM and deb packaging, tar and zip archives, shell and batch scripts >enhancement Team:Delivery Meta label for Delivery team v5.0.0-alpha4
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants