JAL-633, JAL-591 - refactored ArgumentI.getValue from jabaws .getDefaultValue
[jalview.git] / src / jalview / ws / rest / InputType.java
1 package jalview.ws.rest;
2
3 import jalview.ws.rest.params.SeqGroupIndexVector;
4
5 import java.io.IOException;
6 import java.io.OutputStream;
7 import java.io.OutputStreamWriter;
8 import java.io.PrintWriter;
9 import java.io.StringWriter;
10 import java.io.UnsupportedEncodingException;
11 import java.nio.charset.Charset;
12 import java.util.ArrayList;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.regex.Matcher;
16 import java.util.regex.Pattern;
17
18 import org.apache.http.entity.mime.content.ContentBody;
19 import org.apache.http.entity.mime.content.StringBody;
20
21 import sun.io.CharacterEncoding;
22 import sun.misc.CharacterEncoder;
23
24 /***
25  * InputType is the abstract model of each input parameter that a rest service might take.
26  * It enables the engine to validate input by providing 
27  * { formatter for type, parser for type }
28  *  
29  */
30 public abstract class InputType {
31   /**
32    * not used yet
33    */
34   boolean replaceids;
35   public enum molType { NUC, PROT, MIX}
36   public String token;
37   public int min=1;
38   public int max=0; // unbounded
39   protected ArrayList<Class> inputData=new ArrayList<Class>();
40   /**
41    * initialise the InputType with a list of jalview data classes that the RestJob needs to be able to provide to it. 
42    * @param types
43    */
44   protected InputType(Class[] types)
45   {
46     if(types!=null)
47       {for (Class t:types)
48     {
49       inputData.add(t);
50     }
51       }
52   }
53   /**
54    * 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 
55    * @param restJob
56    * @return
57    */
58   public boolean validFor(RestJob restJob)
59   {
60     if (!validFor(restJob.rsd))
61       return false;
62     for (Class cl:inputData)
63     {
64       if (!restJob.hasDataOfType(cl))
65       {
66         return false;
67       }
68     }
69     return true;
70   }
71   
72   public boolean validFor(RestServiceDescription restServiceDescription)
73   {
74     if (!restServiceDescription.inputParams.values().contains(this))
75       return false;
76     
77     return true;
78   }
79   protected ContentBody utf8StringBody(String content, String type)
80   {
81     Charset utf8 = Charset.forName("UTF-8");
82     try {
83     if (type==null ) {
84       return new StringBody(utf8.encode(content).asCharBuffer().toString());
85     } else {
86       return new StringBody(utf8.encode(content).asCharBuffer().toString(), type, utf8);
87     }
88     } catch (Exception ex)
89     {
90       System.err.println("Couldn't transform string\n"+content+"\nException was :");
91       ex.printStackTrace(System.err);
92     }
93     return null;
94   }
95   /**
96    * 
97    * @param rj data from which input is to be extracted and formatted
98    * @return StringBody or FileBody ready for posting
99    */
100   abstract public ContentBody formatForInput(RestJob rj) throws UnsupportedEncodingException,NoValidInputDataException;
101   /**
102    * 
103    * @return true if no input data needs to be provided for this parameter
104    */
105   public boolean isConstant()
106   {
107     return (inputData==null || inputData.size()==0);
108   }
109   /**
110    * return a url encoded version of this parameter's value, or an empty string if the parameter has no ='value' content.
111    * @return
112    */
113   public abstract List<String> getURLEncodedParameter();
114   
115   /**
116    * set the property known as tok, possibly by assigning it with a given val
117    * @param tok
118    * @param val (may be empty or null)
119    * @param warnings place where parse warnings are reported
120    * @return true if property was set
121    */
122   public abstract boolean configureProperty(String tok, String val, StringBuffer warnings);
123   
124   /**
125    * Get unique key for this type of parameter in a URL encoding.
126    * @return the string that prefixes an input parameter of InputType<T> type in the string returned from getURLEncodedParameter
127    */
128   public abstract String getURLtokenPrefix();
129   /**
130    * parse the given token String and set InputParameter properties appropriately
131    * @param tokenstring - urlencoded parameter string as returned from getURLEncodedParameter
132    * @param warnings - place where any warning messages about bad property values are written
133    * @return true if configuration succeeded, false otherwise.
134    */
135   public boolean configureFromURLtokenString(List<String> tokenstring, StringBuffer warnings) {
136       boolean valid=true;
137       for (String tok:tokenstring)
138       {
139         Matcher mtch = Pattern.compile("^([^=]+)=?'?([^']*)?'?").matcher(tok);
140         if (mtch.find()) {
141           try {
142             if (mtch.group(1).equals("min"))
143             {
144               min = Integer.parseInt(mtch.group(2));
145               continue;
146               
147             } else 
148             if (mtch.group(1).equals("max"))
149             {
150                 max = Integer.parseInt(mtch.group(2));
151                 continue;
152               }
153             }
154           catch (NumberFormatException x)
155               {
156                 valid=false;
157                 warnings.append("Invalid value for parameter "+mtch.group(1).toLowerCase()+" '"+mtch.group(2)+"' (expected an integer)\n");
158             }
159           
160           valid = valid && configureProperty(mtch.group(1), mtch.group(2), warnings);
161         }
162         }
163       return valid;
164   }
165   public void addBaseParams(ArrayList<String> prms)
166   {
167     // todo : check if replaceids should be a global for the service, rather than for a specific parameter.
168     if (min!=1) {
169       prms.add("min='"+min+"'");
170     }
171     if (max!=0) {
172       prms.add("min='"+max+"'");
173     }
174   }
175 }