2

I have written a JavaFX program that runs a python script that uses google console search api to get data. It works fine before I deploy it as a standalone program (.exe). After I install the program it runs fine until I click the button that runs the script; it does nothing.

After the button is clicked it succesfully checks if the python is installed or not, after that the problem occurs when it tries the run the script. I have specified the path like this, "./src/com/fortunamaritime/" and I think this might be the problem.

private static final String ANALYTICS_PATH ="./src/com/fortunamaritime/";

inside the method

//set up the command and parameter
String[] cmd = new String[3];
cmd[0] = "python"; 
cmd[1] = "analytics.py";
cmd[2] = "https://fortunamaritime.com.tr";
String command = cmd[0] + " " + cmd[1] + " " + cmd[2] + " " + 
startDate + " " + endDate;
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "cd " + new 
File(ANALYTICS_PATH).getAbsolutePath() + " && " + command);
builder.redirectErrorStream(true);
Process p = builder.start();

I have redirected console output to a .txt file to see what was happening and there's only one line that said "system cannot find the path specified".


I have switched from absolute path to relative path and it produced this error: The filename, directory name, or volume label syntax is incorrect. I also printed this line to console

this.getClass().getResource("/com/fortunamaritime/analytics.py")

and the result is:

jar:file:/D:/IdeaProjects/FortunaWebTracker/out/artifacts/FortunaWebTracker/FortunaWebTracker.jar!/com/fortunamaritime/analytics.py

Is it possible to access the inside of the jar file and run the script from there via cmd through stripping parts of this URL?

Altuğ Ceylan
  • 93
  • 1
  • 10
  • 1
    That is indeed very likely the problem. Files from the source folder are seldom added to a deployed program and if they are, it's usually as resource, not as part of the file system. Is there a `./src/com/fortunamaritime/` in the working directory (usually the location of the `.exe`) when launching the program? – fabian Aug 24 '19 at 08:23
  • I would recommand you to check if python is installed and display an error message if not. – dan1st Aug 24 '19 at 12:36
  • 1
    I would use `String.join()` instead of `cmd[0]+" "+...` – dan1st Aug 24 '19 at 12:41
  • @dan1st I have already found a temporary solution in which I have to download jdk but I was thinking about your answer would be way practical than mine. If I can manage it; program will create a directory and print out 3 text files and fill them with the content of .dat .json and .py files then change their extensions. After I manage to make program run as I expected it to run, I will review and edit my code for readability and performance improvements. Thank you. – Altuğ Ceylan Aug 24 '19 at 13:02
  • Do you really mean text files? (Normally, a `.dat` file is everything but a text file) – dan1st Aug 24 '19 at 13:06
  • @dan1st Yes, I was thinking of keeping those 3 files with their extensions changed to .txt in my resource folder, make the program read & write then change extensions, or I can try storing all of them as Strings then make the program write them and change their extensions – Altuğ Ceylan Aug 24 '19 at 13:15
  • 1
    You can simply copy it from the jar using nio (or io) – dan1st Aug 24 '19 at 13:17
  • @dan1st I should get some sleep... Thanks! I found this https://stackoverflow.com/questions/10308221/how-to-copy-file-inside-jar-to-outside-the-jar just by copying and pasting your answer then searching... – Altuğ Ceylan Aug 24 '19 at 13:28
  • Use `java.nio.Files#copy` in combination with `getResourceAsStream`. I think this is easier. – dan1st Aug 24 '19 at 13:30
  • @dan1st I fiddled with nio, I could manage to copy files when I was running the program in Intellij but I couldn't when I deployed it in the end. On the other hand, the method in link I commented earlier worked for me. If it wasn't for your advice It would cost me hours. I really appreciate it. – Altuğ Ceylan Aug 24 '19 at 14:45
  • 1
    I've added a code example to my answer. – dan1st Aug 24 '19 at 18:35

2 Answers2

1

Copy the script to a (maybe temporary) file and run it from that file.

You can get the script as InputStream with Main.class.getResourceAsStream(String resc) (relative to main) or Main.class.getClassLoader().getResourceAsStream(String resc) (relative to root)

You may use java.nio.file.Files#createTempFile(String,String and delete that file on exit.

You can also copy the script into the user home or relative to the exe (and don't delete it).

For example, you could do this:

File dir=new File("./resc");
if(!dir.exists()) {
    dir.mkdirs();
}
File analyticsFile=new File(dir,"analytics.py");
if(!analyticsFile.exists()) {
    /*
     * alternative:
     * this.getClass().getResourceAsStream("com/fortunamaritime/analytics.py")
     */
    try(InputStream analyticsIn = this.getClass().getClassLoader().getResourceAsStream("analytics.py")){
        Files.copy(analyticsIn, analyticsFile.toPath());
    }
}
/*
 * alternative: String command=String.join(" ",new String[]{"python",analyticsFile.getAbsolutePath(),"https://fortunamaritime.com.tr"});
 */
String command="python "+analyticsFile.getAbsolutePath()+" https://fortunamaritime.com.tr";
/*
 * alternative (without error redirection): Process p=Runtime.getRuntime().exec(command);
 */
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process p=builder.start();
dan1st
  • 12,568
  • 8
  • 34
  • 67
0

I have solved my problem. Here's the code sample first, explanation will follow;

String path =  new 
File(Main.class.getProtectionDomain().getCodeSource().getLocation()
     .toURI()).getPath();
path=path.substring(0,path.length()-21);
// set up the command and parameter
String[] cmd = new String[3];
cmd[0] = "python";
cmd[1] = "analytics.py";
cmd[2] = "https://fortunamaritime.com.tr";
String command0="jar xf FortunaWebTracker.jar" +                   
"com/fortunamaritime/analytics.pycom/fortunamaritime/client_secrets.json" +
" com/fortunamaritime/webmasters.dat";
String command1 = cmd[0] + " " + cmd[1] + " " + cmd[2] + " " + startDate + " " + 
endDate;
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "cd " + path + " && " + 
command0+"&&"+"cd "+path+"\\com\\fortunamaritime"+" && "+command1);
builder.redirectErrorStream(true);
Process p = builder.start();

My first mistake was to use absolute path, and the second problem arose when I got the path I wanted via:

File(Main.class.getProtectionDomain().getCodeSource().getLocation()
     .toURI()).getPath();
//Jar's name is 21 characters long, minus that and I get the directory path
path=path.substring(0,path.length()-21);

The second problem was unpacking elements inside the jar so I used this command in cmd:

jar xf FortunaWebTracker.jar
com/fortunamaritime/analytics.py com/fortunamaritime/client_secrets.json com/fortunamaritime/webmasters.dat

then I could get it to work.

Altuğ Ceylan
  • 93
  • 1
  • 10