JAL-3851 Some streamlining of caching/removing from cache. 'Highlighting' in InputAli...
[jalview.git] / src / jalview / rest / AbstractEndpoint.java
1 package jalview.rest;
2
3 import java.io.IOException;
4 import java.io.PrintWriter;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.Map.Entry;
8
9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11
12 import jalview.bin.Console;
13 import jalview.gui.AlignFrame;
14 import jalview.gui.Desktop;
15 import jalview.rest.RestHandler.EndpointI;
16
17 public abstract class AbstractEndpoint implements EndpointI
18 {
19   private final String path;
20
21   private API api;
22
23   private final String name;
24
25   private final String parameters;
26
27   private final String description;
28
29   private String[] pathParameters = null;
30
31   private Map<String, String[]> queryParameters = null;
32
33   private Map<String, String> options = null;
34
35   private String requestUrl = null;
36
37   private String id = null;
38
39   private String fromId = null;
40
41   public AbstractEndpoint(API api, String path, String name,
42           String parameters, String description)
43   {
44     this.api = api;
45     this.path = path;
46     this.name = name;
47     this.parameters = parameters;
48     this.description = description;
49   }
50
51   public String getPath()
52   {
53     return this.path;
54   }
55
56   protected API getAPI()
57   {
58     return this.api;
59   }
60
61   public String getName()
62   {
63     return this.name;
64   }
65
66   public String getParameters()
67   {
68     return this.parameters;
69   }
70
71   public String getDescription()
72   {
73     return this.description;
74   }
75
76   public abstract void processEndpoint(HttpServletRequest request,
77           HttpServletResponse response);
78
79   /*
80    * Shared methods below here
81    */
82
83   protected String getId(HttpServletRequest request)
84   {
85     if (id != null)
86       return id;
87     id = getQueryParameter(request, "id");
88     return id;
89   }
90
91   protected String getFromId(HttpServletRequest request)
92   {
93     if (fromId != null)
94       return fromId;
95     fromId = getQueryParameter(request, "fromId");
96     return fromId;
97   }
98
99   protected Map<String, String[]> getQueryParameters(
100           HttpServletRequest request)
101   {
102     if (queryParameters != null)
103       return queryParameters;
104     queryParameters = request.getParameterMap();
105     return queryParameters;
106   }
107
108   protected String getQueryParameter(HttpServletRequest request,
109           String param)
110   {
111     String[] vals = getQueryParameters(request).get(param);
112     return (vals == null || vals.length < 1) ? null : vals[0];
113   }
114
115   protected String[] getEndpointPathParameters(HttpServletRequest request)
116   {
117     if (pathParameters != null)
118       return pathParameters;
119     String pathInfo = request.getPathInfo();
120     int slashpos = pathInfo.indexOf('/', 1);
121     if (slashpos < 1)
122       return null;
123
124     pathParameters = pathInfo.substring(slashpos + 1).split("/");
125     return pathParameters;
126   }
127
128   protected Map<String, String> getOptions(HttpServletRequest request)
129   {
130     if (this.options != null)
131       return this.options;
132     Map<String, String> opts = new HashMap<>();
133     for (Entry<String, String[]> e : getQueryParameters(null).entrySet())
134     {
135       if (e.getKey().startsWith("option:"))
136       {
137         for (int i = 0; i < e.getValue().length; i++)
138         {
139           opts.put(e.getKey().substring(7), e.getValue()[i]);
140         }
141       }
142     }
143
144     String[] params = getEndpointPathParameters(request);
145     if (params != null)
146     {
147       for (int i = 0; i < params.length; i++)
148       {
149         String param = params[i];
150         if (param.startsWith("option:"))
151         {
152           int ePos = param.indexOf("=");
153           if (ePos == -1)
154           {
155             opts.put(param.substring(7), null);
156           }
157           else
158           {
159             opts.put(param.substring(7, ePos), param.substring(ePos + 1));
160           }
161         }
162       }
163     }
164     this.options = opts;
165     return opts;
166   }
167
168   protected String getRequestUrl(HttpServletRequest request)
169   {
170     if (requestUrl != null)
171       return requestUrl;
172     if (request != null)
173     {
174       StringBuilder sb = new StringBuilder(
175               request.getRequestURL().toString());
176       String query = request.getQueryString();
177       if (query != null || query.length() > 0)
178       {
179         sb.append("?").append(query);
180       }
181       requestUrl = sb.toString();
182     }
183     else
184     {
185       Console.debug("AbstractEndpoint: request is null");
186     }
187     return requestUrl;
188   }
189
190   protected void returnError(HttpServletRequest request,
191           HttpServletResponse response, String message)
192   {
193     String okString = request.getParameter("ok");
194     boolean ok = (okString != null && okString.equalsIgnoreCase("true"));
195     /*
196      * Annoyingly jetty is not adding content to anything other than a few
197      * 20x status codes. Possibly it is closing the PrintWriter.
198      * Find a fix for this!
199      ****************************************************/
200     response.setStatus(ok ? HttpServletResponse.SC_OK : //
201     // HttpServletResponse.SC_BAD_REQUEST //
202             HttpServletResponse.SC_PARTIAL_CONTENT //
203     );
204
205     String endpointName = getPath();
206     Console.error(getAPI().getName() + " error: endpoint " + endpointName
207             + " failed: '" + message + "'");
208     try
209     {
210       PrintWriter writer = response.getWriter();
211       writer.write("message=Endpoint " + endpointName + ": " + message);
212     } catch (IOException e)
213     {
214       Console.info("Exception writing to REST response", e);
215     }
216   }
217
218   protected boolean checkParameters(HttpServletRequest request,
219           HttpServletResponse response, int i)
220   {
221     String[] parameters = getEndpointPathParameters(request);
222
223     // check we can run fetchsequence
224     if (parameters.length < i)
225     {
226       returnError(request, response,
227               "requires parameters:" + getParameters() + "\n" + getName()
228                       + ": " + getDescription());
229       return false;
230     }
231     return true;
232   }
233
234   public int[][] parseIntRanges(String rangesString)
235   {
236     if (rangesString.equals("*"))
237     {
238       return new int[][] { { -1 }, { -1 } };
239     }
240     String[] rangeStrings = rangesString.split(",");
241     int[][] ranges = new int[2][rangeStrings.length];
242     for (int i = 0; i < rangeStrings.length; i++)
243     {
244       String range = rangeStrings[i];
245       try
246       {
247         int hyphenpos = range.indexOf('-');
248         if (hyphenpos < 0)
249         {
250           ranges[0][i] = Integer.parseInt(range);
251           ranges[1][i] = ranges[0][i];
252         }
253         else
254         {
255           ranges[0][i] = Integer.parseInt(range.substring(0, hyphenpos));
256           ranges[1][i] = Integer.parseInt(range.substring(hyphenpos + 1));
257         }
258       } catch (NumberFormatException nfe)
259       {
260         return null;
261       }
262     }
263     return ranges;
264   }
265
266   /*
267    * Get all AlignFrames or just one if requested to work on a specific window (fromId query string parameter)
268    */
269   protected AlignFrame[] getAlignFrames(HttpServletRequest request,
270           boolean all)
271   {
272     return getAlignFrames(request, "fromId", all);
273   }
274
275   protected AlignFrame[] getAlignFrames(HttpServletRequest request,
276           String idParam, boolean all)
277   {
278     String fromIdString = this.getQueryParameter(request, idParam);
279
280     if (fromIdString != null)
281     {
282       AlignFrame af = AlignFrame.getAlignFrameFromRestId(fromIdString);
283       return af == null ? null : new AlignFrame[] { af };
284     }
285     else if (all)
286     {
287       return Desktop.getAlignFrames();
288     }
289     else
290     {
291       return null;
292     }
293   }
294
295   protected AlignFrame getAlignFrameUsingId(HttpServletRequest request)
296   {
297     return getAlignFrameUsingFromId(request, getId(request));
298   }
299
300   protected AlignFrame getAlignFrameUsingFromId(HttpServletRequest request)
301   {
302     return getAlignFrameUsingFromId(request, "fromId");
303   }
304
305   protected AlignFrame getAlignFrameUsingFromId(HttpServletRequest request,
306           String idParam)
307   {
308     AlignFrame[] afs = getAlignFrames(request, idParam, false);
309     return (afs == null || afs.length < 1) ? null : afs[0];
310   }
311
312   protected boolean deleteFromCache()
313   {
314     return false;
315   }
316
317 }