1 /*
2 * Copyright 2008 Ange Optimization ApS
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 /**
17 * @author Kim Hansen
18 */
19 package eu.simuline.octave;
20
21 import java.io.File;
22 import java.io.OutputStreamWriter;
23 import java.io.Writer;
24
25 import java.util.Arrays;
26
27 /**
28 * Factory that creates OctaveEngines.
29 * First of all, create an OctaveEngineFactory
30 * using the default constructor {@link #OctaveEngineFactory()}
31 * then, optionally, change parameters
32 * and finally create an Octave Engine using {@link #getScriptEngine()}
33 * with the current parameters.
34 * To set a parameter, use the various setter methods.
35 * In the documentation of each setter method,
36 * also the default value is documented
37 * which is used to create an {@link OctaveEngine}
38 * if the setter method is not invoked.
39 *
40 */
41 public final class OctaveEngineFactory {
42
43 /**
44 * System property where the executable is found.
45 */
46 public static final String PROPERTY_EXECUTABLE =
47 "eu.simuline.octave.executable";
48
49 /**
50 * If this is not <code>null</code>, the octave engine created
51 * writes the output to that log writer also.
52 * By default, this is <code>null</code>.
53 * The according setter method is {@link #setOctaveInputLog(Writer)}.
54 */
55 private Writer octaveInputLog = null;
56
57 /**
58 * The error writer for the octave process.
59 * By default, this is just {@link System#err}.
60 * The according setter method is {@link #setErrorWriter(Writer)}.
61 */
62 private Writer errWriter = new OutputStreamWriter(System.err,
63 OctaveUtils.getUTF8());
64
65 /**
66 * The file containing the octave program or is <code>null</code>.
67 * In the latter case, the name of the octave program command
68 * is determined as described for {@link #octaveProgramCmd}.
69 * By default, this is <code>null</code>.
70 */
71 private File octaveProgramFile = null;
72
73 /**
74 * The command which determines the octave executable
75 * if {@link #octaveProgramFile} is <code>null</code>
76 * and if the property {@link #PROPERTY_EXECUTABLE} is not set.
77 * By default, this is "<code>octave</code>".
78 */
79 private String octaveProgramCmd = "octave";
80
81 /**
82 * The array of arguments of the octave engines created.
83 * For details, see octave user manual, version 3.4.0.+, Section 2.2.1.
84 * <p>
85 * Default value of this field is default value for octave engines created.
86 * The default value consists of the following components:
87 * <ul>
88 * <li>
89 * <code>--silent</code>:
90 * prevents octave from printing the usual greeting and version message
91 * at startup.
92 * <li>
93 * <code>--no-init-file</code>, <code>--no-site-file</code>
94 * prevents octave from reading the initialization files
95 * <code>~/.octaverc</code>, <code>.octaverc</code> and
96 * site-wide <code>octaverc</code>.
97 * <li>
98 * </ul>
99 *
100 * The only mandatory argument is <code>--silent</code>:
101 * If not set this, octave's greeting message causes an exception.
102 * Option <code>--no-init-file</code> makes the result independent
103 * of user input,
104 * whereas <code>--no-init-file</code> and <code>--no-site-file</code>
105 * makes it independent of initialization files.
106 * Since this is used to create scripting engines,
107 * line editing and history seem superfluous
108 * and so <code>--no-line-editing</code> and <code>--no-history</code>
109 * seem appropriate.
110 * Note that <code>--no-init-file</code> and <code>--no-site-file</code>
111 * may be appropriate or not.
112 * ***** why not needed --no-gui? --no-window-system
113 */
114 private String[] argsArray = {
115 "--silent", // greeting message causes exception ****
116 "--no-init-file", // makes result depend on init file
117 "--no-site-file", // see --no-init-file
118 "--no-line-editing", // make independent of user input
119 "--no-history" // superfluous, because commands come from scripts
120 };
121
122
123 /**
124 * An array of strings of the form <code>name=value</code>
125 * representing the environment, i.e. the set of environment variables
126 * or <code>null</code>.
127 * In the latter case,
128 * the environment is inherited from the current process.
129 * This field is initialized with <code>null</code>.
130 */
131 private String[] environment = null;
132
133 /**
134 * The file representing the working directory or <code>null</code>.
135 * In the latter case,
136 * the working directory is inherited from the current process.
137 * By default, this is <code>null</code>.
138 */
139 private File workingDir = null;
140
141 /**
142 * The number of threads to be reused or
143 * <code>-1</code> if there is no limit.
144 * By default, this is <code>2</code>.
145 */
146 private int numThreadsReuse = 2;
147
148 /**
149 * Default constructor creating a factory with default parameters.
150 */
151 public OctaveEngineFactory() {
152 // Empty constructor
153 }
154
155 /**
156 * Returns a script engine with the parameters set for this factory.
157 *
158 * @return
159 * a new OctaveEngine with the current parameters.
160 */
161 public OctaveEngine getScriptEngine() {
162 // determine the command/path of the octave program
163 String octaveProgramPathCmd = (this.octaveProgramFile == null)
164 ? System.getProperty(PROPERTY_EXECUTABLE, this.octaveProgramCmd)
165 : this.octaveProgramFile.getPath();
166
167 // determine the command array
168 final String[] cmdArray = new String[this.argsArray.length + 1];
169 cmdArray[0] = octaveProgramPathCmd;
170 System.arraycopy(this.argsArray, 0, cmdArray, 1, this.argsArray.length);
171
172 return new OctaveEngine(this,
173 this.numThreadsReuse,
174 this.octaveInputLog,
175 this.errWriter,
176 cmdArray,
177 this.environment,
178 this.workingDir);
179 }
180
181 /**
182 * Setter method for {@link #octaveInputLog}.
183 *
184 * @param octaveInputLog
185 * the octaveInputLog to set
186 */
187 public void setOctaveInputLog(final Writer octaveInputLog) {
188 this.octaveInputLog = octaveInputLog;
189 }
190
191 /**
192 * Setter method for {@link #errWriter}.
193 *
194 * @param errWriter
195 * the errWriter to set
196 */
197 public void setErrorWriter(final Writer errWriter) {
198 this.errWriter = errWriter;
199 }
200
201 /**
202 * Setter method for {@link #octaveProgramFile}.
203 *
204 * @param octaveProgramFile
205 * the octaveProgramFile to set or <code>null</code>.
206 */
207 public void setOctaveProgramFile(final File octaveProgramFile) {
208 this.octaveProgramFile = octaveProgramFile;
209 }
210
211 /**
212 * Setter method for {@link #octaveProgramCmd}.
213 * This takes effect only,
214 * if {@link #octaveProgramFile} is <code>null</code>
215 * and if the property {@link #PROPERTY_EXECUTABLE} is not set.
216 *
217 * @param octaveProgramCmd
218 * the octave program executable to set
219 */
220 public void setOctaveProgramCmd(final String octaveProgramCmd) {
221 this.octaveProgramCmd = octaveProgramCmd;
222 }
223
224 /**
225 * Sets an array of arguments <code>argsArray</code>
226 * used when creating an {@link OctaveEngine}.
227 * The validity of the argument string is not proved.
228 * Note that subsequent changes on the array <code>argsArray</code>
229 * do not have any influence on this factory.
230 * The default options
231 * and a discussion of necessary options are
232 * documented with {@link #argsArray}.
233 *
234 * @param argsArray
235 * the arguments as an array to set
236 */
237 public void setArgsArray(final String[] argsArray) {
238 this.argsArray = Arrays.copyOf(argsArray, argsArray.length);
239 }
240
241 /**
242 * Setter method for {@link #environment}.
243 * Note that subsequent changes on the array <code>environment</code>
244 * do not have any influence on this factory.
245 * The details are documented with {@link #environment}.
246 *
247 * @param environment
248 * the environment or <code>null</code>.
249 */
250 public void setEnvironment(final String[] environment) {
251 this.environment = environment == null
252 ? null
253 : Arrays.copyOf(environment, environment.length);
254 }
255
256 /**
257 * Setter method for {@link #workingDir}.
258 *
259 * @param workingDir
260 * the workingDir to set or <code>null</code>.
261 */
262 public void setWorkingDir(final File workingDir) {
263 this.workingDir = workingDir;
264 }
265
266 /**
267 * Sets the number of threads to be reused or <code>-1</code>
268 * which indicates no limit.
269 * The default value is 2 but this can be speed optimized
270 * depending on the hardware.
271 * The number of threads to be created shall be positive
272 * or <code>-1</code> otherwise throwing an exception.
273 */
274 // **** with -1 seems not to work: cached pool
275 public void setNumThreadsReuse(int numThreadsReuse) {
276 if (numThreadsReuse == 0 || numThreadsReuse < -1) {
277 throw new IllegalArgumentException();
278 }
279 this.numThreadsReuse = numThreadsReuse;
280 }
281 }