1 /*******************************************************************************
2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3 * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
11 * Jalview is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
17 *******************************************************************************/
18 package jalview.ws.rest;
20 import jalview.ws.params.ArgumentI;
21 import jalview.ws.params.InvalidArgumentException;
22 import jalview.ws.params.OptionI;
23 import jalview.ws.params.ParameterI;
24 import jalview.ws.params.simple.IntegerParameter;
25 import jalview.ws.params.simple.Option;
26 import jalview.ws.rest.params.SeqGroupIndexVector;
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.io.PrintWriter;
32 import java.io.StringWriter;
33 import java.io.UnsupportedEncodingException;
34 import java.nio.charset.Charset;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.List;
39 import java.util.regex.Matcher;
40 import java.util.regex.Pattern;
42 import org.apache.http.entity.mime.content.ContentBody;
43 import org.apache.http.entity.mime.content.StringBody;
45 import sun.io.CharacterEncoding;
46 import sun.misc.CharacterEncoder;
49 * InputType is the abstract model of each input parameter that a rest service might take.
50 * It enables the engine to validate input by providing
51 * { formatter for type, parser for type }
54 public abstract class InputType {
59 public enum molType { NUC, PROT, MIX;
61 public static Collection<String> toStringValues()
63 Collection<String> c = new ArrayList<String>();
64 for (molType type:values())
66 c.add(type.toString());
72 public int max=0; // unbounded
73 protected ArrayList<Class> inputData=new ArrayList<Class>();
75 * initialise the InputType with a list of jalview data classes that the RestJob needs to be able to provide to it.
78 protected InputType(Class[] types)
88 * do basic tests to ensure the job's service takes this parameter, and the job's input data can be used to generate the input data
92 public boolean validFor(RestJob restJob)
94 if (!validFor(restJob.rsd))
96 for (Class cl:inputData)
98 if (!restJob.hasDataOfType(cl))
106 public boolean validFor(RestServiceDescription restServiceDescription)
108 if (!restServiceDescription.inputParams.values().contains(this))
113 protected ContentBody utf8StringBody(String content, String type)
115 Charset utf8 = Charset.forName("UTF-8");
118 return new StringBody(utf8.encode(content).asCharBuffer().toString());
120 return new StringBody(utf8.encode(content).asCharBuffer().toString(), type, utf8);
122 } catch (Exception ex)
124 System.err.println("Couldn't transform string\n"+content+"\nException was :");
125 ex.printStackTrace(System.err);
131 * @param rj data from which input is to be extracted and formatted
132 * @return StringBody or FileBody ready for posting
134 abstract public ContentBody formatForInput(RestJob rj) throws UnsupportedEncodingException,NoValidInputDataException;
137 * @return true if no input data needs to be provided for this parameter
139 public boolean isConstant()
141 return (inputData==null || inputData.size()==0);
144 * return a url encoded version of this parameter's value, or an empty string if the parameter has no ='value' content.
147 public abstract List<String> getURLEncodedParameter();
150 * set the property known as tok, possibly by assigning it with a given val
152 * @param val (may be empty or null)
153 * @param warnings place where parse warnings are reported
154 * @return true if property was set
156 public abstract boolean configureProperty(String tok, String val, StringBuffer warnings);
159 * Get unique key for this type of parameter in a URL encoding.
160 * @return the string that prefixes an input parameter of InputType<T> type in the string returned from getURLEncodedParameter
162 public abstract String getURLtokenPrefix();
164 * parse the given token String and set InputParameter properties appropriately
165 * @param tokenstring - urlencoded parameter string as returned from getURLEncodedParameter
166 * @param warnings - place where any warning messages about bad property values are written
167 * @return true if configuration succeeded, false otherwise.
169 public boolean configureFromURLtokenString(List<String> tokenstring, StringBuffer warnings) {
171 for (String tok:tokenstring)
173 Matcher mtch = Pattern.compile("^([^=]+)=?'?([^']*)?'?").matcher(tok);
176 if (mtch.group(1).equals("min"))
178 min = Integer.parseInt(mtch.group(2));
182 if (mtch.group(1).equals("max"))
184 max = Integer.parseInt(mtch.group(2));
188 catch (NumberFormatException x)
191 warnings.append("Invalid value for parameter "+mtch.group(1).toLowerCase()+" '"+mtch.group(2)+"' (expected an integer)\n");
194 if (!configureProperty(mtch.group(1), mtch.group(2), warnings)) {
195 if (warnings.length()==0)
197 warnings.append("Failed to configure InputType :"+getURLtokenPrefix()+" with property string: '"+mtch.group(0)+"'\n (token is '"+mtch.group(1)+"' and value is '"+mtch.group(2)+"')\n");
205 public void addBaseParams(ArrayList<String> prms)
207 // todo : check if replaceids should be a global for the service, rather than for a specific parameter.
209 prms.add("min='"+min+"'");
212 prms.add("max='"+max+"'");
216 public abstract List<OptionI> getOptions();
217 public List<OptionI> getBaseOptions()
219 ArrayList<OptionI> opts = new ArrayList<OptionI>();
220 opts.add(new IntegerParameter("min","Minimum number of data of this type",true,1,min,0,-1));
221 opts.add(new IntegerParameter("max","Maximum number of data of this type",false,0,max,0,-1));
225 * make a copy of this InputType
228 public abstract InputType copy();
232 * parse a set of configuration options
233 * @param currentSettings - modified settings originally from getOptions
234 * @throws InvalidArgumentException thrown if currentSettings contains invalid options for this type.
236 public void configureFromArgumentI(List<ArgumentI> currentSettings) throws InvalidArgumentException
238 ArrayList<String> urltoks = new ArrayList<String>();
240 for (ArgumentI arg: currentSettings)
242 if (arg instanceof ParameterI)
244 rg=arg.getName()+"='"+arg.getValue()+"'";
246 // TODO: revise architecture - this is counter intuitive - options with different values to their names are actually parameters
247 rg=(arg.getValue().length()>0) ? (arg.getValue().equals(arg.getName()) ? arg.getName():arg.getName()+"='"+arg.getValue()+"'")
254 StringBuffer warnings;
255 if (!configureFromURLtokenString(urltoks, warnings=new StringBuffer()))
257 throw new InvalidArgumentException(warnings.toString());
260 protected OptionI createMolTypeOption(String name, String descr,
261 boolean req, molType curType, molType defType)
263 return new Option(name,descr, req, defType==null ? "" : defType.toString(), curType==null ? "" : curType.toString(),molType.toStringValues(),