1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.gridservice.server;
30
31 import java.io.File;
32 import java.net.URL;
33 import java.net.MalformedURLException;
34
35 import org.apache.mina.common.ByteBuffer;
36
37 import com.martiansoftware.jsap.JSAP;
38 import com.martiansoftware.jsap.Parameter;
39 import com.martiansoftware.jsap.Switch;
40 import com.martiansoftware.jsap.Option;
41 import com.martiansoftware.jsap.FlaggedOption;
42 import com.martiansoftware.jsap.UnflaggedOption;
43
44 import uk.ac.rdg.resc.jstyx.gridservice.config.SGSParam;
45
46 import uk.ac.rdg.resc.jstyx.server.AsyncStyxFile;
47 import uk.ac.rdg.resc.jstyx.server.InMemoryFile;
48 import uk.ac.rdg.resc.jstyx.server.StyxFileClient;
49 import uk.ac.rdg.resc.jstyx.StyxException;
50 import uk.ac.rdg.resc.jstyx.StyxUtils;
51
52 /***
53 * A StyxFile interface to a parameter that is passed to an SGS instance as
54 * part of the command line of the underlying executable. This is an AsyncStyxFile
55 * so clients can be automatically notified of changes to the value of the
56 * parameter.
57 *
58 * @author Jon Blower
59 * $Revision: 609 $
60 * $Date: 2006-03-31 18:09:42 +0100 (Fri, 31 Mar 2006) $
61 * $Log$
62 * Revision 1.21 2006/02/17 09:24:55 jonblower
63 * Change to comments
64 *
65 * Revision 1.20 2005/12/07 17:47:58 jonblower
66 * Changed "commandline" file to "args" - now just contains arguments, not program name
67 *
68 * Revision 1.19 2005/11/14 21:31:54 jonblower
69 * Got SGSRun working for SC2005 demo
70 *
71 * Revision 1.18 2005/11/11 21:57:21 jonblower
72 * Implemented passing of URLs to input files
73 *
74 * Revision 1.17 2005/11/07 21:06:42 jonblower
75 * Now allows setting of empty values for non-required parameters
76 *
77 * Revision 1.16 2005/11/04 19:31:16 jonblower
78 * Added code to disallow parameter setting while service is running
79 *
80 * Revision 1.15 2005/11/04 09:11:23 jonblower
81 * Made SGSParamFile inherit from AsyncStyxFile instead of InMemoryFile
82 *
83 * Revision 1.14 2005/11/03 07:42:47 jonblower
84 * Implemented JSAP-based parameter parsing
85 *
86 * Revision 1.10 2005/09/08 07:08:59 jonblower
87 * Removed "String user" from list of parameters to StyxFile.write()
88 *
89 * Revision 1.9 2005/08/01 16:38:05 jonblower
90 * Implemented simple parameter handling
91 *
92 * Revision 1.8 2005/07/29 16:56:07 jonblower
93 * Implementing reading command line asynchronously
94 *
95 * Revision 1.7 2005/06/20 07:17:34 jonblower
96 * Wrapped SGSParamFile as AsyncStyxFile
97 *
98 * Revision 1.6 2005/04/27 16:11:43 jonblower
99 * Added capability to add documentation files to SGS namespace
100 *
101 * Revision 1.5 2005/04/26 07:46:11 jonblower
102 * Continuing to improve setting of parameters in Styx Grid Services
103 *
104 * Revision 1.2 2005/03/26 14:30:17 jonblower
105 * Modified to use SGSConfigException
106 *
107 * Revision 1.1 2005/03/24 17:34:58 jonblower
108 * Initial import
109 *
110 */
111 public class SGSParamFile extends AsyncStyxFile
112 {
113 private static final String URL_PREFIX = "readfrom:";
114
115 private SGSParam param;
116 private StyxGridServiceInstance instance;
117 private boolean valueSet;
118
119 public SGSParamFile(SGSParam param, StyxGridServiceInstance instance) throws StyxException
120 {
121
122 super(new InMemoryFile(param.getName()));
123 this.param = param;
124 this.instance = instance;
125 if (this.getJSAPParameter().getDefault() != null)
126 {
127
128 this.setParameterValue(this.getJSAPParameter().getDefault()[0]);
129 this.valueSet = true;
130 }
131 }
132
133 /***
134 * @return the JSAP Parameter object that is associated with this file
135 */
136 public Parameter getJSAPParameter()
137 {
138 return this.param.getParameter();
139 }
140
141 /***
142 * The new value for the parameter must come in a single message (i.e.
143 * the offset must be zero and the incoming ByteBuffer must contain the
144 * entire parameter value). Must also write with truncation.
145 */
146 public synchronized void write(StyxFileClient client, long offset,
147 int count, ByteBuffer data, boolean truncate, int tag)
148 throws StyxException
149 {
150 if (instance.getStatus() == StatusCode.RUNNING)
151 {
152 throw new StyxException("Cannot set new parameter values while service is running");
153 }
154 if (!truncate)
155 {
156 throw new StyxException("Must write to the parameter file with truncation");
157 }
158 if (offset != 0 && count != 0)
159 {
160
161 throw new StyxException("Must write data to the start of the parameter file");
162 }
163 if (count == 0)
164 {
165
166 if (offset != this.getLength().asLong())
167 {
168
169 throw new StyxException("Can only write EOF to the end of this file");
170 }
171 this.replyWrite(client, 0, tag);
172 }
173 else
174 {
175
176
177 data.limit(data.position() + count);
178 String newValue = StyxUtils.dataToString(data);
179
180 this.setParameterValue(newValue);
181
182
183 super.write(client, offset, count, data, truncate, tag);
184
185 this.instance.argumentsChanged();
186 }
187 }
188
189 /***
190 * @return the parameter as it will appear on the command line, including
191 * the flag, if present (e.g. "-p 12"). Returns an empty string if no
192 * value has yet been set
193 */
194 public synchronized String getCommandLineFragment()
195 {
196 if (!this.valueSet)
197 {
198 return "";
199 }
200 if (this.getJSAPParameter() instanceof Switch)
201 {
202 Switch sw = (Switch)this.getJSAPParameter();
203 if (this.getParameterValue().equalsIgnoreCase("true"))
204 {
205 if (sw.getLongFlag() == JSAP.NO_LONGFLAG)
206 {
207 return "-" + sw.getShortFlag();
208 }
209 else
210 {
211 return "--" + sw.getLongFlag();
212 }
213 }
214 else
215 {
216 return "";
217 }
218 }
219 else if (this.getJSAPParameter() instanceof FlaggedOption)
220 {
221 FlaggedOption fo = (FlaggedOption)this.getJSAPParameter();
222
223 if (fo.getLongFlag() == JSAP.NO_LONGFLAG)
224 {
225 return "-" + fo.getShortFlag() + " " + this.getParameterValue();
226 }
227 else
228 {
229 return "--" + fo.getLongFlag() + "=" + this.getParameterValue();
230 }
231 }
232 else if (this.getJSAPParameter() instanceof UnflaggedOption)
233 {
234 return this.getParameterValue();
235 }
236 else
237 {
238
239 return "";
240 }
241 }
242
243 /***
244 * @return the current value of this parameter
245 */
246 public String getParameterValue()
247 {
248 return ((InMemoryFile)this.baseFile).getContents();
249 }
250
251 /***
252 * Sets the parameter value, checking that the value is OK.
253 * @throws StyxException if the parameter is not valid
254 */
255 public void setParameterValue(String newValue) throws StyxException
256 {
257
258
259 if (this.getJSAPParameter() instanceof Switch)
260 {
261 if (!newValue.equalsIgnoreCase("true") &&
262 !newValue.equalsIgnoreCase("false"))
263 {
264 throw new StyxException("Parameter " + this.getName() +
265 " can only be \"true\" or \"false\"");
266 }
267 }
268 else
269 {
270 Option op = (Option)this.getJSAPParameter();
271
272
273 if (newValue.trim().equals(""))
274 {
275 if (op.required())
276 {
277 throw new StyxException("Parameter " + this.getName() +
278 " must have a non-empty value");
279 }
280 else
281 {
282
283 ((InMemoryFile)this.baseFile).setContents("");
284 this.valueSet = false;
285 return;
286 }
287 }
288 else if (this.param.getInputFile() != null)
289 {
290
291
292
293
294 String[] files = newValue.split(" ");
295
296
297 this.instance.removeInputFiles(files);
298 for (int i = 0; i < files.length; i++)
299 {
300 if (!files[i].startsWith(URL_PREFIX))
301 {
302
303 this.instance.addInputFile(files[i]);
304 }
305 }
306 }
307
308 }
309
310 ((InMemoryFile)this.baseFile).setContents(newValue);
311 this.valueSet = true;
312 }
313
314 /***
315 * Checks to see if the contents of this file are valid. At the moment, this
316 * just checks to see if a value has been set for a required parameter.
317 * @throws StyxException if the file contents are not valid for some reason.
318 */
319 public void checkValid() throws StyxException
320 {
321 if (this.getJSAPParameter() instanceof Option)
322 {
323 Option op = (Option)this.getJSAPParameter();
324 if (this.valueSet)
325 {
326 if (this.param.getInputFile() != null)
327 {
328
329
330
331 String str = this.getParameterValue();
332 if (str.startsWith(URL_PREFIX))
333 {
334
335 String urlStr = str.substring(URL_PREFIX.length());
336 try
337 {
338 URL url = new URL(urlStr);
339 File urlPath = new File(url.getPath());
340
341
342 String name = urlPath.getName().equals("") ? "random.dat" : urlPath.getName();
343 this.instance.downloadFrom(url, name);
344
345 this.setParameterValue(name);
346 }
347 catch(MalformedURLException mue)
348 {
349 throw new StyxException(urlStr + " is not a valid URL");
350 }
351 }
352 }
353 }
354 else
355 {
356
357 if (op.required())
358 {
359 throw new StyxException(this.name + " is a required parameter:" +
360 " a value must be set");
361 }
362 }
363 }
364 }
365
366 }