dae669602c9171395d70b79570547e9533c4b314
[jabaws.git] / engine / compbio / engine / client / CommandBuilder.java
1 /* Copyright (c) 2009 Peter Troshin\r
2  *  \r
3  *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 1.0     \r
4  * \r
5  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
6  *  Apache License version 2 as published by the Apache Software Foundation\r
7  * \r
8  *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without\r
9  *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache \r
10  *  License for more details.\r
11  * \r
12  *  A copy of the license is in apache_license.txt. It is also available here:\r
13  * @see: http://www.apache.org/licenses/LICENSE-2.0.txt\r
14  * \r
15  * Any republication or derived work distributed in source code form\r
16  * must include this copyright and license notice.\r
17  */\r
18 \r
19 package compbio.engine.client;\r
20 \r
21 import java.util.ArrayList;\r
22 import java.util.LinkedHashMap;\r
23 import java.util.List;\r
24 import java.util.Map;\r
25 \r
26 import javax.xml.bind.annotation.XmlAccessType;\r
27 import javax.xml.bind.annotation.XmlAccessorType;\r
28 import javax.xml.bind.annotation.XmlTransient;\r
29 \r
30 import org.apache.log4j.Logger;\r
31 \r
32 import compbio.metadata.Option;\r
33 \r
34 /*\r
35  * Class to replace List<String> params in the SkeletalExecutable\r
36  * So this must be included into executable \r
37  * \r
38  * List<String> Executable.getParameter() - is OK, but \r
39  * when RunConfiguration is loaded CommandBuilder must be recreated from the saved list!\r
40  * It is safer to return CommandBuilder from getParameters and persist it but needs more work.\r
41  * Benefits of doing it: delimiter is saved, key value pairs are explicitly known, no reliance on the order for \r
42  * space delimited key value pairs, fully functional object    \r
43  * \r
44  * TODO complete and use \r
45  */\r
46 @XmlAccessorType(XmlAccessType.FIELD)\r
47 public class CommandBuilder<T> {\r
48 \r
49         private static final Logger log = Logger.getLogger(CommandBuilder.class);\r
50 \r
51         Map<String, Parameter> paramList;\r
52         String nameValueSeparator;\r
53 \r
54         // Optionally accept order template with keys in order\r
55         // List<String> orderTemplate\r
56         // String keyPrefix;\r
57 \r
58         private CommandBuilder() {\r
59                 // JAXB default constructor\r
60         }\r
61 \r
62         public CommandBuilder(String nameValueSeparator) {\r
63                 this.paramList = new LinkedHashMap<String, Parameter>();\r
64                 this.nameValueSeparator = nameValueSeparator;\r
65         }\r
66 \r
67         public void addParams(List<String> params) {\r
68                 for (String param : params) {\r
69                         setParam(param);\r
70                 }\r
71         }\r
72 \r
73         public void setParams(List<String> params) {\r
74                 paramList.clear();\r
75                 addParams(params);\r
76         }\r
77 \r
78         Parameter newParameter(String param) {\r
79                 if (compbio.util.Util.isEmpty(param)) {\r
80                         throw new NullPointerException("Param must be provided!");\r
81                 }\r
82                 if (isCombinedValue(param)) {\r
83                         return new Parameter(getName(param), getValue(param));\r
84                 }\r
85                 return new Parameter(param);\r
86         }\r
87 \r
88         boolean isCombinedValue(String param) {\r
89                 return param.contains(nameValueSeparator);\r
90         }\r
91 \r
92         public boolean hasParam(String paramName) {\r
93                 return paramList.containsKey(paramName);\r
94         }\r
95 \r
96         String getName(String param) {\r
97                 assert param.indexOf(nameValueSeparator) >= 0 : "The value does not look like a combined value (key+value). Value:"\r
98                                 + param;\r
99                 return param.substring(0, param.indexOf(nameValueSeparator));\r
100         }\r
101 \r
102         String getValue(String param) {\r
103                 assert param.indexOf(nameValueSeparator) >= 0 : "The value does not look like a combined value (key+value). Value:"\r
104                                 + param;\r
105                 return param.substring(param.indexOf(nameValueSeparator) + 1);\r
106         }\r
107 \r
108         public boolean setFirst(String param) {\r
109                 Parameter p = newParameter(param);\r
110                 p.setFirst();\r
111                 return setParam(p);\r
112         }\r
113 \r
114         public boolean setParam(String param) {\r
115                 return setParam(newParameter(param));\r
116         }\r
117 \r
118         boolean setParam(Parameter param) {\r
119                 boolean overriden= paramList.put(param.name, param) != null;\r
120                 if(overriden) {\r
121                         log.warn("Key " + param.name + " in the command list has been overriden! ");\r
122                 }\r
123                 return overriden;\r
124         }\r
125 \r
126         public boolean setLast(String paramName) {\r
127                 Parameter p = newParameter(paramName);\r
128                 p.setLast();\r
129                 return setParam(p);\r
130         }\r
131 \r
132         public boolean setLast(String paramName, String paramValue) {\r
133                 if (compbio.util.Util.isEmpty(paramName)) {\r
134                         throw new NullPointerException("ParamName must be provided!");\r
135                 }\r
136                 // paramName could contain separator character as long as there is no\r
137                 // paramValue!\r
138                 // e.g. paramName could be a path to the file with spaces\r
139                 if (paramValue != null && paramName.contains(nameValueSeparator)) {\r
140                         log\r
141                                         .warn("WARN: paramName "\r
142                                                         + paramName\r
143                                                         + " contains nameValue separator. Removing the separator...");\r
144                         paramName = paramName.trim().substring(0, paramName.length() - 1);\r
145                 }\r
146                 if (paramValue != null && paramName.contains(nameValueSeparator)) {\r
147                         throw new IllegalArgumentException("Parameter name '" + paramName\r
148                                         + "' contains name value separator character '"\r
149                                         + nameValueSeparator + "'!");\r
150                 }\r
151                 Parameter p = new Parameter(paramName, paramValue);\r
152                 p.setLast();\r
153                 return setParam(p);\r
154         }\r
155 \r
156         public String getParamValue(String paramName) {\r
157                 Parameter p = paramList.get(paramName);\r
158                 return p == null ? null : p.value;\r
159         }\r
160 \r
161         public boolean removeParam(String paramName) {\r
162                 return paramList.remove(paramName) != null;\r
163         }\r
164 \r
165         public boolean setParam(String paramName, String paramValue) {\r
166                 return setParam( new Parameter(paramName, paramValue));\r
167         }\r
168 \r
169         public List<String> getCommands() {\r
170                 return parameterToString(getCommandList());\r
171         }\r
172 \r
173         public String getCommandString() {\r
174                 String command = "";\r
175                 for (Parameter p : getCommandList()) {\r
176                         command += p.toCommand(this.nameValueSeparator) + " ";\r
177                 }\r
178                 return command;\r
179         }\r
180 \r
181         List<String> parameterToString(List<Parameter> parameters) {\r
182                 List<String> commands = new ArrayList<String>();\r
183                 for (Parameter p : parameters) {\r
184                         if (isWhiteSpaceSeparator()) {\r
185                                 commands.add(p.name);\r
186                                 if (p.value != null) {\r
187                                         commands.add(p.value);\r
188                                 }\r
189                         } else {\r
190                                 commands.add(p.toCommand(this.nameValueSeparator));\r
191                         }\r
192                 }\r
193                 return commands;\r
194         }\r
195 \r
196         /**\r
197          * This produces the same result as getCommands method. The only difference\r
198          * is that it accepts a List of Options as an input\r
199          * \r
200          * @param arguments\r
201          * @return\r
202          */\r
203         public static <T> CommandBuilder<T> newCommandBuilder(\r
204                         List<? extends Option<T>> arguments, String nameValueSeparator) {\r
205                 CommandBuilder<T> cbuilder = new CommandBuilder<T>(nameValueSeparator);\r
206                 for (Option<T> option : arguments) {\r
207                         String comm = option.toCommand(nameValueSeparator);\r
208                         log.trace("Setting parameter " + comm);\r
209                         cbuilder.setParam(comm);\r
210                 }\r
211                 return cbuilder;\r
212         }\r
213 \r
214         public int size() {\r
215                 return paramList.size();\r
216         }\r
217 \r
218         boolean isWhiteSpaceSeparator() {\r
219                 return nameValueSeparator.trim().length()==0;\r
220         }\r
221 \r
222         List<Parameter> getCommandList() {\r
223                 List<Parameter> commands = new ArrayList<Parameter>();\r
224                 Parameter first = null;\r
225                 Parameter last = null;\r
226                 for (Parameter param : paramList.values()) {\r
227                         if (param.isFirst()) {\r
228                                 assert first == null : "Attempting to set more the one parameter as FIRST! "\r
229                                                 + "Parameter which has been set is: "\r
230                                                 + first\r
231                                                 + "\n Parameters to be set is " + param;\r
232                                 first = param;\r
233                                 commands.add(0, first);\r
234                                 continue;\r
235                         }\r
236                         if (param.isLast()) {\r
237                                 assert last == null : "Attempting to set more the one parameter as LAST! "\r
238                                                 + "Parameter which has been set is: "\r
239                                                 + last\r
240                                                 + "\n Parameters to be set is " + param;\r
241                                 last = param;\r
242                                 continue;\r
243                         }\r
244                         commands.add(param);\r
245                 }\r
246                 if (last != null) {\r
247                         commands.add(last);\r
248                 }\r
249                 return commands;\r
250         }\r
251 \r
252         @Override\r
253         public int hashCode() {\r
254                 final int prime = 31;\r
255                 int result = 1;\r
256                 result = prime\r
257                                 * result\r
258                                 + ((nameValueSeparator == null) ? 0 : nameValueSeparator\r
259                                                 .hashCode());\r
260                 result = prime * result\r
261                                 + ((paramList == null) ? 0 : paramList.hashCode());\r
262                 return result;\r
263         }\r
264 \r
265         @Override\r
266         public boolean equals(Object obj) {\r
267                 if (this == obj)\r
268                         return true;\r
269                 if (obj == null)\r
270                         return false;\r
271                 if (getClass() != obj.getClass())\r
272                         return false;\r
273                 CommandBuilder<?> other = (CommandBuilder<?>) obj;\r
274                 if (nameValueSeparator == null) {\r
275                         if (other.nameValueSeparator != null)\r
276                                 return false;\r
277                 } else if (!nameValueSeparator.equals(other.nameValueSeparator))\r
278                         return false;\r
279                 if (paramList == null) {\r
280                         if (other.paramList != null)\r
281                                 return false;\r
282                 }\r
283                 if (other.paramList == null && paramList != null) {\r
284                         return false;\r
285                 }\r
286                 if (paramList.size() != other.paramList.size()) {\r
287                         return false;\r
288                 }\r
289                 /*\r
290                  * Order is important at runtime, but jaxb will not preserve the order\r
291                  * on marshalling This is to no concern here as the order is managed\r
292                  * internally using position\r
293                  */\r
294                 for (Map.Entry<String, Parameter> param : paramList.entrySet()) {\r
295                         String key = param.getKey();\r
296                         Parameter p = other.paramList.get(key);\r
297                         if (p == null) {\r
298                                 return false;\r
299                         }\r
300                         if (!p.equals(param.getValue())) {\r
301                                 return false;\r
302                         }\r
303                 }\r
304                 return true;\r
305         }\r
306 \r
307         @Override\r
308         public String toString() {\r
309                 String value = "NameValueSeparator: " + nameValueSeparator + "\n";\r
310                 for (Map.Entry<String, Parameter> entry : paramList.entrySet()) {\r
311                         value += "Key: " + entry.getKey() + "\n" + " Value: "\r
312                                         + entry.getValue() + "\n";\r
313                 }\r
314                 return value;\r
315         }\r
316 \r
317         @XmlAccessorType(XmlAccessType.FIELD)\r
318         static class Parameter {\r
319 \r
320                 @XmlTransient\r
321                 private static final int LAST = -100;\r
322                 @XmlTransient\r
323                 private static final int FIRST = -200;\r
324 \r
325                 // e.g. stick it at the beginning or the end or elsewhere\r
326                 private int position = -1;\r
327                 String name;\r
328                 // String alias;\r
329                 String value;\r
330 \r
331                 Parameter() {\r
332                         // JAXB default constructor\r
333                 }\r
334 \r
335                 Parameter(String name) {\r
336                         this.name = name;\r
337                 }\r
338 \r
339                 Parameter(String name, String value) {\r
340                         this(name);\r
341                         this.value = value;\r
342                 }\r
343 \r
344                 void setLast() {\r
345                         this.position = LAST;\r
346                 }\r
347 \r
348                 void setFirst() {\r
349                         this.position = FIRST;\r
350                 }\r
351 \r
352                 void setAtPosition(int position) {\r
353                         throw new UnsupportedOperationException();\r
354                         // this.position = position;\r
355                 }\r
356 \r
357                 boolean isLast() {\r
358                         return position == LAST;\r
359                 }\r
360 \r
361                 boolean isFirst() {\r
362                         return position == FIRST;\r
363                 }\r
364 \r
365                 String toCommand(String separator) {\r
366                         if (value == null) {\r
367                                 return name;\r
368                         }\r
369                         return name + separator + value;\r
370                 }\r
371 \r
372                 @Override\r
373                 public String toString() {\r
374                         String value = "Name: " + name + "\n";\r
375                         if (value != null) {\r
376                                 value += "Value: " + value + "\n";\r
377                         }\r
378                         if (position == LAST) {\r
379                                 value += "Position: LAST" + "\n";\r
380                         } else if (position == FIRST) {\r
381                                 value += "Position: FIRST" + "\n";\r
382                         } else if (position != -1) {\r
383                                 value += "Position:" + position + "\n";\r
384                         }\r
385                         return value;\r
386                 }\r
387 \r
388                 @Override\r
389                 public int hashCode() {\r
390                         final int prime = 7;\r
391                         int result = 1;\r
392                         result = prime * result + ((name == null) ? 0 : name.hashCode());\r
393                         result = prime * result + position;\r
394                         result = prime * result + ((value == null) ? 0 : value.hashCode());\r
395                         return result;\r
396                 }\r
397 \r
398                 @Override\r
399                 public boolean equals(Object obj) {\r
400                         if (this == obj)\r
401                                 return true;\r
402                         if (obj == null)\r
403                                 return false;\r
404                         if (getClass() != obj.getClass())\r
405                                 return false;\r
406                         Parameter other = (Parameter) obj;\r
407                         if (name == null) {\r
408                                 if (other.name != null)\r
409                                         return false;\r
410                         } else if (!name.equals(other.name))\r
411                                 return false;\r
412                         if (position != other.position)\r
413                                 return false;\r
414                         if (value == null) {\r
415                                 if (other.value != null)\r
416                                         return false;\r
417                         } else if (!value.equals(other.value))\r
418                                 return false;\r
419                         return true;\r
420                 }\r
421 \r
422         }\r
423 }\r