Search code examples
javasql-serverexecsqlexception

SQL Exception only when program is run from Runtime.exec()


I am having some problems understanding the following issue. For reasons I will not (and cannot) tell here, I had to write an external JAR to be executed inside a Java web application, using a Process bound to a Runtime.exec() method call. This external JAR executes a query inside a database and prints its results inside an Excel file, using the Apache POI libraries. This is its code:

public static void main(String[] args) {

    //Initializing error variable
    boolean error = false;

    //Initializing rownum variable
    int rownum = 0;

    //Initializing db connection parameters
    String userName = args[0];
    String password = args[1];
    String dbUrl = args[2];

    //Initializing file path
    String filePath = args[3];

    //Initializing query string
    String query = args[4];
    if(!query.endsWith(";"))
        query += ";";

    //Keep 100 rows in memory, exceeding rows will be flushed to disk
    SXSSFWorkbook wb = new SXSSFWorkbook(SXSSFWorkbook.DEFAULT_WINDOW_SIZE);

    //Temp files will be gzipped
    wb.setCompressTempFiles(true);

    //Initializing xlsx sheet
    Sheet sh = wb.createSheet();
    wb.setSheetName(wb.getSheetIndex(sh), "DBExtraction");

    //Trying to connect to db and execute a query.
    //If the previous operation succeeded, parse query results
    //into an xlsx workbook
    try {
        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
        Connection conn = DriverManager.getConnection(dbUrl, userName, password);
        Statement stmt = conn.createStatement();
        ResultSet rs = stmt.executeQuery(query);
        ResultSetMetaData md = rs.getMetaData();
        int cols = md.getColumnCount();
        int cn = 0;

        Row header = sh.createRow(rownum++);
        for(int i = 0; i < cols; ++i) {
            header.createCell(cn++).setCellValue(md.getColumnLabel(i + 1));
        }

        while(rs.next()) {
            Row row = sh.createRow(rownum++);
            cn = 0;
            for (int cellnum = 0; cellnum < cols; cellnum++) {
                Cell cell = row.createCell(cellnum);
                cell.setCellValue(rs.getString(++cn));
            }
        }

        for(int j = 0; j < cols; ++j) {
            sh.setColumnWidth(j, 67*256);
        }

        FileOutputStream fos = new FileOutputStream(filePath);

        //Writing workbook to file
        wb.write(fos);

        //Closing file
        fos.flush();
        fos.close();

        //Dispose of temporary files backing this workbook on disk
        wb.dispose();
        wb.close();

        //Closing db connection objects
        rs.close();
        stmt.close();
        conn.close();

    } catch (Exception e) {
        error = true;
        e.printStackTrace();
    }

    if(error)
        System.exit(1);
    else
        System.exit(0);
}

Inside the archive are also packed the external libraries (Apache POI and the SQL Server Driver in jar format).

When I try to execute the program directly from the terminal (either cmd or bash), using the command java -jar executable.jar "param1" "param2" ... everything works fine.

The problem occurs when I try to launch the same command using the method mentioned above.

Following you will find the code responsible for the call:

Process p = null;
p = Runtime.getRuntime().exec("java -jar " +
    jarDir +
    File.separator +
    "executable.jar " +
    "\"" + param0 + "\" " +
    "\"" + param1 + "\" " +
    "\"" + param2 + "\" " +
    "\"" + param3 + "\" " +
    "\"" + param4 +"\"");

p.waitFor();
String line;

BufferedReader error = new BufferedReader(new 
    InputStreamReader(p.getErrorStream()));
while((line = error.readLine()) != null){
    System.out.println(line);
}
error.close();

BufferedReader input = new BufferedReader(new 
    InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
    System.out.println(line);
}
input.close();

System.out.println("EXIT VALUE: " + p.exitValue());

In this second case, I obtain the following Exception: java.sql.SQLException: No suitable driver found for "jdbc:sqlserver://remoteServer:1433;databaseName=dbName".

The web application is currently running on Wildfly 10.0.0-Final on CentOS7 server.

Thank you for your time.

EDIT: I thought it could be a good idea to add the JAR manifest, since it may contain some mistakes (the JAR file was generated by Eclipse export): MANIFEST.MF.

Also, this is the JAR internal structure: JAR Structure.


Solution

  • I finally managed to solve the issue, but in a very inefficient (and really ugly) way.

    I had to create a shell script to parse the external JAR arguments, because there were some problems converting the quote (") character from the web application method calling the JAR and the actual terminal. Once I did that, the JAR application worked like a charm.

    I do not intend to provide the shell script source (unless explicitly requested) because I am bit ashamed of myself. Not about the code itself, but about this "workaround".