keskiviikko 10. huhtikuuta 2013

Tutorial 1. part 17. Create Java Web Services taking variable number of arguments

Shell Script wrapper

Next we will create a service that wraps shell scripts. We do this in Java with Jax-WS annotations.

First create a new application

File > New > General > Applications



And a new project and name it. I added Web Services to the selected project technologies. This added Java as well.



Create a new java class that will launch scripts






Note: We checked the “Main Method” checkbox because we want to also run the application from command line (or from IDE actually) during testing and development phase.

This is the class that the wizard generated:
package com.blogger.soanen;
public class ScriptWrapper {
    public ScriptWrapper() {
        super();
    }
    public static void main(String[] args) {
        ScriptWrapper scriptWrapper = new ScriptWrapper();
    }
}
Add java code to the newly created Java class
Next we’ll add an execute method that wraps an existing class “ProcessBuilder” that can be used to execute shell scripts.  We also add a few return values to the class. The end result is as this:
package com.blogger.soanen;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class ScriptWrapper {
        public final int IO_ERROR = -1;
        public final int SCRIPT_INTERRUPTED = -2;
        public final int NULL_COMMAND_ELEMENT = -3;
        public final int EMPTY_COMMAND = -4;
        public final int NOT_ALLOWED = -5;
        public final int UNKNOWN_SCRIPT = -6;        
    public ScriptWrapper() {
        super();
    }
    public int executeScript( String script, String scriptDir,
                              String... args) {

        List<String> command = new ArrayList<String>(1+args.length);
     command.add(script);
     for(String arg : args)
          command.add(arg);
        ProcessBuilder pb = new ProcessBuilder(command);
        Process p;
        pb.directory(new File(scriptDir));
        try {
          p = pb.start();
          return p.waitFor();
        } catch (IOException e) {
          e.printStackTrace();
          return IO_ERROR;
        } catch (InterruptedException e) {
          return SCRIPT_INTERRUPTED;
        } catch (NullPointerException e) {
          return NULL_COMMAND_ELEMENT;
        } catch (IndexOutOfBoundsException e) {
          return EMPTY_COMMAND;
        } catch (SecurityException e) {
          return NOT_ALLOWED;
        }
      }
   
    public static void main(String[] args) {
            try {
        ScriptWrapper scriptWrapper = new ScriptWrapper();

            int ret;
            ret = scriptWrapper.executeScript("cmd.exe", "c:\\temp", "/c", "a.bat");
            System.out.println("return value = " + ret);
        } catch (Exception e1) {
            System.out.println(e1);
        }
}
You can try out this program like this by selecting the Run option from the pop-up menu:



The same run icon is visible on the top tool bar as well.
Let’s improve the program a little bit so that execute does not take the program name but a symbolic name instead. This improves security as only applications embedded in the wrapper class can be executed.
First create a helper class Script. Remember not to check the main method this time.



Add fields to it. Fields can be added either by directly editing the java class or via a wizard. Use the right button on top of the Java class in structure pane and select “New Field…” from pop-up menu.


I added
·         scriptPath – The real file name this script has
·         scriptDir – directory where the script is executed (so a name like execDir might have been more descriptive…)
Potentially you might also want to add other fields like
·         userName
·         password



Here is the helper class:
package com.blogger.soanen;
public class Script {
    private String scriptPath;
    private String scriptDir;
    public Script() {
        super();
    }
     public Script(String scriptPath,String scriptDir) {
    super();
    this.scriptPath = scriptPath;
    this.scriptDir = scriptDir;
  }
 public String getScriptPath() {
        return scriptPath;
    }
    public void setScriptPath(String scriptPath) {
        this.scriptPath = scriptPath;
    }
    public String getScriptDir() {
        return scriptDir;
    }
    public void setScriptDir(String scriptDir) {
        this.scriptDir = scriptDir;
    }
}
Let’s add some code to the ShellScriptWrapper to have a Map to store the relationship between the name of the script and the Script class that contains the actual script file and directory to use as home dir when the script is executed.
  private Map<String,Script> scripts = new HashMap<String,Script>();

We’ll also change the execute method slightly to read the script name and directly from a Script class instead from the call parameters; we can also remove the scriptDir parameter from the call.

The final program is like this:
package com.blogger.soanen;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ScriptWrapper {
    public final int IO_ERROR = -1;
    public final int SCRIPT_INTERRUPTED = -2;
    public final int NULL_COMMAND_ELEMENT = -3;
    public final int EMPTY_COMMAND = -4;
    public final int NOT_ALLOWED = -5;
    public final int UNKNOWN_SCRIPT = -6;
    private Map<String, Script> scripts = new HashMap<String, Script>();

    public ScriptWrapper() {
        super();
        scripts.put("a.bat", new Script("C:\\TEMP\\a.bat", "C:\\TEMP"));
    }

    public int executeScript(String script, String... args) {
        Script s = scripts.get(script);
        if (s != null) {

            List<String> command = new ArrayList<String>(1 + args.length);
            command.add(s.getScriptPath());
            for (String arg : args)
                command.add(arg);
            ProcessBuilder pb = new ProcessBuilder(command);
            Process p;
            pb.directory(new File(s.getScriptDir()));
            try {
                p = pb.start();
                return p.waitFor();
            } catch (IOException e) {
                e.printStackTrace();
                return IO_ERROR;
            } catch (InterruptedException e) {
                return SCRIPT_INTERRUPTED;
            } catch (NullPointerException e) {
                return NULL_COMMAND_ELEMENT;
            } catch (IndexOutOfBoundsException e) {
                return EMPTY_COMMAND;
            } catch (SecurityException e) {
                return NOT_ALLOWED;
            }
        } else
            return UNKNOWN_SCRIPT;

    }

    public static void main(String[] args) {
        try {
            ScriptWrapper scriptWrapper = new ScriptWrapper();

            int ret;
            //ret = scriptWrapper.executeScript("cmd.exe", "c:\\temp", "/c", "a.bat");
            ret = scriptWrapper.executeScript("a.bat", "");
            System.out.println("return value = " + ret);
        } catch (Exception e1) {
            System.out.println(e1);
        }

    }
}

3 kommenttia:

  1. Hi there martti ylikoski,

    First let me congratulate you for the great job doing this tutorials. It's helping me a lot.
    I want to ask you if you have any idea how I can execute this script on Linux Gnome?

    Thank you,
    João

    VastaaPoista
  2. It is 2 years to late, but if one uses a LINUX all one needs to do is this:
    1. create at some locatin .sh file
    touch test.sh
    chmod +x test.sh
    2. open the newly created file and add some SHELL script:

    -------like this example------
    #!/bin/sh

    echo "TEST.......some file content" > /home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen/created_new_file.txt

    echo "TEST2.... some file content" | tee second_created_new_file.txt

    3. In the script provided by Martti edit the name of the script, the path to script and the path to directory where script is:

    public ScriptWrapper() {
    super();
    scripts.put("test.sh", new Script("/home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen/test.sh", "/home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen"));
    }

    4. In the main methode edit the folowing line:

    ret = scriptWrapper.executeScript("test.sh", "");


    I hope it helped someone

    VastaaPoista
  3. It is 2 years to late, but if one uses a LINUX all one needs to do is this:
    1. create at some locatin .sh file
    touch test.sh
    chmod +x test.sh
    2. open the newly created file and add some SHELL script:

    -------like this example------
    #!/bin/sh

    echo "TEST.......some file content" > /home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen/created_new_file.txt

    echo "TEST2.... some file content" | tee second_created_new_file.txt

    3. In the script provided by Martti edit the name of the script, the path to script and the path to directory where script is:

    public ScriptWrapper() {
    super();
    scripts.put("test.sh", new Script("/home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen/test.sh", "/home/oracle/jdeveloper/mywork/ScriptWrapper/ScriptWraPPER/src/com/blogger/soanen"));
    }

    4. In the main methode edit the folowing line:

    ret = scriptWrapper.executeScript("test.sh", "");


    I hope it helped someone

    VastaaPoista