| 94 | |
| 95 | === Input/output === |
| 96 | |
| 97 | The philosophy of MUSCLE is that I/O should be done by the runtime system, and not directly coded, unless done with Terminals. Therefor, rather than writing to a file or reading from a file directly, we advise to use a {{{FileSource}}} or {{{FileSink}}} and attach that to a conduit from which you read. In this way, if you decide that the input should not come from a file but from another submodel, the code in the submodel does not have to change. |
| 98 | |
| 99 | Each submodel and terminal has its own temporary directory, which can be accessed with |
| 100 | {{{ |
| 101 | File tmpPath = getTmpPath(); |
| 102 | }}} |
| 103 | after which the path can be used to write files, for instance, {{{fileOut.dat}}}. |
| 104 | {{{ |
| 105 | FileWriter fw = new FileWriter(new File(tmpPath, "fileOut.dat")); |
| 106 | }}} |
| 107 | |
| 108 | In this path it is safe to write output in this directory, since this will only be associated to the current submodel in the current run. The path is always printed at the beginning and ending of the execution, and can be specified on the command line with the {{{--tmp-path}}} flag. Additional to the given temporary path, it will create the directory {{{hostname_date_time_pid}}} in which the results of the current run are stored. This way, a script can always contain the same temporary path but MUSCLE will use a new unique directory for each run. |
| 109 | |
| 110 | Reading files depends on what type of execution method is chosen for. Middleware such as QCG can usually stage in and out files for a single job. If files are staged in this fashion ({{{fileIn.dat}}} for example), and the {{{--tmp-path}}} points to the directory which contains the staged files, you can use |
| 111 | {{{ |
| 112 | FileReader fr = new FileReader(new File(getTmpPath(), "../../fileIn.dat")); |
| 113 | }}} |
| 114 | as this will point to the {{{--tmp-path}}}. |
| 115 | |
| 116 | === Printing and logging === |
| 117 | |
| 118 | To keep track of what the different submodels are doing a logging facility is available. Simply call |
| 119 | {{{ |
| 120 | log("some message"); |
| 121 | }}} |
| 122 | and the message will be printed with timestamp and kernel name, and written to a log file {{{"kernelName.log"}}}, in the temporary path of the kernel. For more control over the log levels, a [[http://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html|Java log Level]] can be used: |
| 123 | {{{ |
| 124 | log("some message", Level.SEVERE); |
| 125 | }}} |
| 126 | Finally, for full control over the logger and for error handling the logger can also be accessed directly. |
| 127 | {{{ |
| 128 | try { |
| 129 | doSomethingDangerous(); |
| 130 | } |
| 131 | catch (Exception ex) { |
| 132 | getLogger().log(Level.SEVERE, "error message", ex); |
| 133 | } |
| 134 | }}} |