Tuesday, June 27, 2017

Run a command with ProcessBuilder in Java

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Jceks {
    public static void main(String[] args) {
        System.out.println("Hello jceks...");
        System.out.println(Arrays.toString(args));
        try {
            run(args);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void run(String[] command) throws Exception {
        System.out.println(String.join(" ", command));

        int exitCode = 0;
        StringBuilder output = new StringBuilder();
        ProcessBuilder pb = new ProcessBuilder(command);
        pb.redirectErrorStream(true);

        Process p = pb.start();
        exitCode = p.waitFor();

        BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while ((line = reader.readLine())!= null) {
            output.append(line + "\n");
        }

        System.out.println(output);
    }
}

Thursday, June 22, 2017

RCA: /usr/java/jre1.8.0_112/bin/bin/java: No such file or directory

QA reported one issue observed in their environment:
Searching for java...
        1. /usr/java/jdk1.6.0_31/bin/java
        2. /usr/java/jdk1.6.0_31/jre/bin/java
        3. /usr/java/jdk1.7.0_67-cloudera/bin/java
        4. /usr/java/jdk1.7.0_67-cloudera/jre/bin/java
        5. /usr/java/jre1.8.0_112/bin/java
        6. Specify location of java to use.
Type the number for the required java from this list: [1] 5

/opt/cloudera/parcels/CDH-5.4.4-1.cdh5.4.4.p0.4/bin/../lib/hadoop/bin/hadoop: line 144: /usr/java/jre1.8.0_112/bin/bin/java: No such file or directory

/opt/cloudera/parcels/CDH-5.4.4-1.cdh5.4.4.p0.4/bin/../lib/hadoop/bin/hadoop: line 144: exec: /usr/java/jre1.8.0_112/bin/bin/java: cannot execute: No such file or directory
Note that the choice in the list is correct, but the script then invokes a “bin/bin/java” – where did it get that from?


Well, well, at the beginning I thought there was something wrong in our script using the specified Java directory(JAVA_HOME, PATH). While digging deeper, the error comes from:
-bash-3.2# /usr/bin/hadoop classpath --glob
/opt/cloudera/parcels/CDH-5.4.4-1.cdh5.4.4.p0.4/bin/../lib/hadoop/bin/hadoop: line 144: /usr/java/jre1.8.0_112/bin/bin/java: No such file or directory

/opt/cloudera/parcels/CDH-5.4.4-1.cdh5.4.4.p0.4/bin/../lib/hadoop/bin/hadoop: line 144: exec: /usr/java/jre1.8.0_112/bin/bin/java: cannot execute: No such file or directory

Check JAVA_HOME:
-bash-3.2# echo $JAVA_HOME
/usr/java/jre1.8.0_112/bin
-bash-3.2#

OMG, The above $JAVA_HOME is incorrect.

THE JAVA_HOME/JRE_HOME should be the installation directory, not the bin directory under it.

Correct it with

-bash-3.2# export JAVA_HOME=/usr/java/jre1.8.0_112

Documentation from Oracle:
https://docs.oracle.com/cd/E19182-01/820-7851/inst_cli_jdk_javahome_t/


RCA: boost::filesystem::permissions: Operation not permitted

There is a configuration file, say /our/product/config.json, in our product.  It was designed with permission 644 which means only the owner of this configuration can update its content. This makes it impossible to support multiple users since each user should be able to update this configuration file by design.

A fix was submitted to address this issue with:
    pt::write_json(...)
    changePermission(666)

The first line will create the configuration file if it does not exist or update it if it has already been created. Note that the 2nd line will set permission as 666 every time this file is created/updated -- a new problem arises:
    boost::filesystem::permissions: Operation not permitted: "/our/product/config.json"
A non-root user is not allowed to change the permission of a file owned by another user, not mention that this configuration file is created by root and owned by root.

A workaround for this is: set the permission to 666 only when it's created. Something like this:
    bool flag = isConfigFileExist(...)  
    pt::write_json(...)
    if (!flag) {
        changePermission(666)
    }

Monday, June 5, 2017

indent with 4 spaces in Emacs json-mode

1. install json-mode with
M-x package-install RET json-mode RET

2. set indent with:
M-x customize-group RET json-mode RET
Then change the default number from '2' to '4'.