View Javadoc
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 }