3

I am trying to start a command line app through a GUI made in JavaFX. When I run the program in my IDE it all works fine, but when I try to run it by double clicking the compiled .jar file, it doesn't.

I've figured out that it's probably because the PATH or Classpath or working directory or something like that is different from when you run it from the Terminal.

public Button startButton;
public Button clearButton;
public Button minButton;
public Button plusButton;
public Button clearFieldButton;
public Button clearLogButton;
public TextField linkField;
public TextField qualField;
public TextArea errorField;
public ListView<String> historyField;

private String os;

public void initialize(){
    os = System.getProperty("os.name");
    linkField.setText(null);
    qualField.setText(null);
    getHistory();
    setButtonActions();
    Runnable run = new Runnable() {
        @Override
        public void run() {
            linkField.requestFocus();
        }
    };
    Platform.runLater(run);
}

private void setButtonActions(){
    historyField.setOnMouseClicked(new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent mouseEvent) {
            if(mouseEvent.getClickCount() == 2){
                String qual;
                if(qualField.getText() == null){
                    qual = "best";
                }
                else{
                    qual = qualField.getText();
                }
                startStream(historyField.getSelectionModel().getSelectedItem(), qual);
            }
        }
    });
    clearButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            clearHistory();
        }
    });
    minButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            delLast();
        }
    });
    plusButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            writeHistory(linkField.getText());
        }
    });
    startButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            startStream(linkField.getText(),qualField.getText());
        }
    });
    clearFieldButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            linkField.clear();
            qualField.clear();
        }
    });
    clearLogButton.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent actionEvent) {
            errorField.clear();
        }
    });
}

private void delLast(){
    LinkedList<String> temp = new LinkedList<>();
    try(BufferedReader br = new BufferedReader(new FileReader("history.txt"))){
        String line;
        while((line = br.readLine()) != null){
            temp.add(line);
        }
        temp.removeLast();
        clearHistory();
        for (String s : temp) {
            writeHistory(s);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void clearHistory(){
    try(BufferedWriter br = new BufferedWriter(new FileWriter("history.txt"))){
        br.write("");
        getHistory();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void getHistory(){
    if(!new File("history.txt").exists()){
        try(BufferedWriter wr = new BufferedWriter(new FileWriter("history.txt"))) {
            wr.write("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    else{
        historyField.getItems().clear();
        ArrayList<String> history = new ArrayList<>();
        try(BufferedReader br = new BufferedReader(new FileReader("history.txt"))){
            String line;
            while((line = br.readLine()) != null){
                history.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        historyField.getItems().addAll(history);
    }
}

private boolean checkIfInFile(String link){
    try(BufferedReader br = new BufferedReader(new FileReader("history.txt"))){
        String line;
        while ((line = br.readLine()) != null){
            if(line.equals(link)){
                return true;
            }
        }
        return false;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

private void writeHistory(String link){
    if(link != null){
        try(PrintWriter print = new PrintWriter(new FileWriter("history.txt", true))) {
            print.append(link).append("\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
        getHistory();
    }
}

private void startStream(String link, String quality){
    errorField.setText("");
    String command = "";
    if(!checkIfInFile(link)){
        writeHistory(link);
    }
    if(!os.contains("win")){
        ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "/usr/bin/which streamlink");
        Map<String, String> env = pb.environment();
        env.put("PATH",System.getenv("PATH"));
        errorField.appendText(env.get("PATH") + "\n");
        try(BufferedReader br = new BufferedReader(new InputStreamReader(pb.start().getInputStream()))) {
            command = br.readLine();
            errorField.appendText(command);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(quality == null){
            command = command + " " + link;
        }
        else if(link != null){
            command = command + " " + link + " " + quality;
        }
    }
    else{
        if(link == null){
            command = "streamlink";
        }
        else if(quality == null){
            command = "streamlink " + link;
        }
        else{
            command = "streamlink " + link + " " + quality;
        }
    }
    try {
        ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", command);
        Process proc = pb.start();
        final InputStream in = proc.getInputStream();
        Thread outputThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try(BufferedReader br = new BufferedReader(new InputStreamReader(in))){
                    String read;
                    while((read = br.readLine()) != null){
                        errorField.appendText(read + "\n");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        outputThread.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Any help will be greatly appreciated.

EDIT: Forgot to mention that double clicking on Windows works perfect.

EDIT 2: **I just found out what the "real" problem was. If you run through terminal or bash script, this is the outcome of echo $PATH: '/Users/Vermeulen/.jenv/shims:/opt/local/bin:/opt/local/sbin‌​:/Library/Frameworks‌​/Python.framework/Ve‌​rsions/3.5/bin:/usr/‌​local/bin:/usr/bin:/‌​bin:/usr/sbin:/sbin:‌​/usr/local/bin:/opt/‌​X11/bin:/usr/X11/bi' and when you double click the jar the outcome of echo $PATH is: '/usr/bin:/bin:/usr/sbin:/sbin' **

GijsV
  • 31
  • 5

2 Answers2

3

On my linux machine double clicking uses my home directory as the working directory. Thus, it will fail if you are trying to find some files relative to your jar file.

To work around this behaviour you cant start your jar with a shell-script containing

java -jar myjarfile.jar

You sould than be able to double click the shell script (depending on your linux-distribution)

If you want to work around by code, try this snippet:

CodeSource src = Main.class.getProtectionDomain().getCodeSource();
File pathToJar = new File(src.getLocation().toURI());
System.out.println(pathToJar.getAbsolutePath());

It returns either the directory of your Main-class file or the full path to your jar-file. Depending on how you have started your program. Use this information to find your files.

---------------- Update 1

You haven't described exactly what your are trying to do. If you want to set environment variables like PATH for external commands use the ProcessBuilder.

ProcessBuilder builder = new ProcessBuilder("myprogramm", "firstArg", "secondArg");
Map<String, String> environment = builder.environment();
environment.put("PATH", environment.get("PATH") + ":/my/path");
Process process = builder.start();
OutputStream outputStream = process.getOutputStream();
process.waitFor();

For more information read ProcessBuilder.

Zomono
  • 772
  • 6
  • 17
  • Thank you for the answer, but I don't really know how to use this info to solve my problem.. Sorry :/ – GijsV Sep 27 '16 at 21:10
  • I just found out what the "real" problem was. If you run through terminal or bash script, this is the outcome of echo $PATH: '/Users/Vermeulen/.jenv/shims:/opt/local/bin:/opt/local/sbin:/Library/Frameworks/Python.framework/Versions/3.5/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/X11/bi' and when you double click the jar the outcome of echo $PATH is: '/usr/bin:/bin:/usr/sbin:/sbin' – GijsV Sep 27 '16 at 23:31
  • Thank you for the extra info, but the thing is, I want to run a command line program that is installed on a different place on Linux and OS X. I want to execute the "which" command to find it, but the installation path is not inside the PATH variable when double clicking, it is however when running the jar trough console. I want to PATH variable when double clicking to be the same as when run through the console. I'll edit my post to show the whole code of the program. – GijsV Sep 28 '16 at 14:00
  • I'd like to think that _which_ does nothing else but searching in every directory from the PATH variable. If your system can't find a program because its dirctory is missing in PATH, _which_ coulnd find it either. May try some other shell instead of _/bin/bash_ to execute your program. _/bin/sh_ for example – Zomono Sep 28 '16 at 16:13
0

Can you please share Manifest.mf file in jar? There should be main-class correctly set in it. please check this

Secondly check this as well. I expect jdk is already set properly in properties tab.

Community
  • 1
  • 1