10

I need to execute an external program from Java (to convert a fodt file to pdf using libreoffice, it so happens) I know the precise command-line I need for the program:

/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir /home/develop/tomcat/mf/ROOT/private/docs/0/ /home/develop/tomcat/mf/ROOT/private/docs/0/35_invoice.fodt

and that works perfectly from the command line. But it does not work in Java using a ProcessBuilder:

java.io.IOException: Cannot run program "/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir /home/develop/tomcat/mf/ROOT/private/docs/0 /home/develop/tomcat/mf/ROOT/private/docs/0/35_invoice.fodt": java.io.IOException: error=2, No such file or directory

I tried some different approaches without success. Here is a sample of the last test

        List<String> command = new ArrayList<String>();
        command.add("/usr/bin/libreoffice");
        command.add("--headless");
        command.add("--convert-to pdf:'writer_pdf_Export' --outdir " + getDestinationDirectory(order) + " " + getInvoiceFilename() + ".fodt");
  
        ProcessBuilder builder = new ProcessBuilder(command);

        Process process = null;
        try {
            process = builder.start();
        } catch (IOException ex) {
            Logger.getLogger(Documents.class.getName()).log(Level.SEVERE, null, ex);
        }
        InputStream is = process.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String line;
        try {
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException ex) {
            Logger.getLogger(Documents.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("Program terminated!");
2
  • 1
    This error is typical when file or the directory you try to move ou do something doesn't exists. Your command, problably is correct, but, your file or path didn't arrive the other side (path, for example). Commented May 10, 2013 at 12:51
  • 1
    @ViniciusLima that is not the cause of the problem here. Commented Oct 12, 2020 at 13:53

4 Answers 4

6

The ProcessBuilder constructors require each argument of the external program to be separate (in the form of an array or List of Strings). The first exception message you got,

Cannot run program "/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir /home/develop/tomcat/mf/ROOT/private/docs/0 /home/develop/tomcat/mf/ROOT/private/docs/0/35_invoice.fodt"

is not complaining that it can find a program named /usr/bin/libreoffice. It is complaining that it can not find a program with the very long and peculiar name "/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir /home/develop/tomcat/mf/ROOT/private/docs/0 /home/develop/tomcat/mf/ROOT/private/docs/0/35_invoice.fodt", because you concatenated the arguments into one String.

Instead of

command.add("--convert-to pdf:'writer_pdf_Export' --outdir " + getDestinationDirectory(order) + " " + getInvoiceFilename() + ".fodt")

and such like, split each of the arguments into its own call to List.add

command.add("--convert-to");
command.add("pdf:writer_pdf_Export");

command.add("--outdir");
command.add(getDestinationDirectory(order).toString());

command.add(getInvoiceFilename() + ".fodt");

Note that there are no apostrophes around "writer_pdf_Export" since those are shell meta-characters and are not required when you're constructing an array to pass to exec without an intermediating shell.

Sign up to request clarification or add additional context in comments.

3 Comments

I do not have any filters/writer_pdf_Export.xcu on my system but if I type thath command directly into a shell it works
Splitting in two (command.add("--convert-to"); command.add("pdf:writer_pdf_Export");) results in *Unknown option: --outdir *
@Azathoth, It sounds like we're making progress since its complaining about a later parameter. Have you tried splitting every argument into its own add as I suggested above? Maybe updating your question with your current code would make diagnosis easier.
1

Try this (keep it simple) ...

Process p = Runtime.getRuntime().exec("/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir "+ getDestinationDirectory(order)+" "+getInvoiceFilename()+".fodt");

Fully ...

    Process process = null;
    try {
            process = Runtime.getRuntime().exec("/usr/bin/libreoffice --headless --convert-to pdf:'writer_pdf_Export' --outdir "+ getDestinationDirectory(order)+" "+getInvoiceFilename()+".fodt");
    } catch (IOException ex) {
        Logger.getLogger(Documents.class.getName()).log(Level.SEVERE, null, ex);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
    String line;
    try {
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException ex) {
        Logger.getLogger(Documents.class.getName()).log(Level.SEVERE, null, ex);
    }
    br.close();
    System.out.println("Program terminated!");

17 Comments

This is one of the first test made: no error, no outpu and most of all ... no pdf
It works from the command line? I found this bugs.freedesktop.org/show_bug.cgi?id=44486
Do you get the same error when you read both the process InputStream and the process ErrorStream? See getInputStream and getErrorStream.
Can you cd to here /home/develop/tomcat/mf/ROOT/private/docs/0? What are the permission on the directory? ... and the output file?
Yes, via shell works like a charm. Removed the underscores but nothing changes. My user has r/w permissions, yes. Actually this project runs locally with netbeans+tomcat and those belongs to the same user
|
1

I have tried every solution proposed in this thread and it does not work.

In my app (java webapp using TOMCAT in linux) it only works to create a shell script and execute the script. But you have to put the absolute path in the script, if not, it does not work ($HOME does not work). Besides, you can pass it arguments.

Example:

Runtime.getRuntime().exec("/home/user/myscript.sh param1");

Comments

0

ProcessBuilder can be erratic sometimes with long command (executable path with lot of arguments.). What you can do is,

Assume your command string is String cmdString = "executableFilePath -param1 -param2"

Convert this to map

List cmdMap = Arrays.asList(cmdString.split(" "));

Pass this cmdMap to ProcessBuilder.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.