JAL-3851 merged to develop 2022-03-22
[jalview.git] / src / jalview / rest / AbstractEndpoint.java
1 package jalview.rest;
2
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.PrintWriter;
6
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9
10 import jalview.bin.Console;
11 import jalview.gui.AlignFrame;
12 import jalview.gui.Desktop;
13 import jalview.rest.RestHandler.EndpointI;
14
15 public abstract class AbstractEndpoint implements EndpointI
16 {
17   private final String path;
18
19   private API api;
20
21   private final String name;
22
23   private final String parameters;
24
25   private final String description;
26
27   public AbstractEndpoint(API api, String path, String name,
28           String parameters, String description)
29   {
30     this.api = api;
31     this.path = path;
32     this.name = name;
33     this.parameters = parameters;
34     this.description = description;
35   }
36
37   public String getPath()
38   {
39     return this.path;
40   }
41
42   protected API getAPI()
43   {
44     return this.api;
45   }
46
47   public String getName()
48   {
49     return this.name;
50   }
51
52   public String getParameters()
53   {
54     return this.parameters;
55   }
56
57   public String getDescription()
58   {
59     return this.description;
60   }
61
62   public abstract void processEndpoint(HttpServletRequest request,
63           HttpServletResponse response);
64
65   /*
66    * Shared methods below here
67    */
68
69   protected String[] getEndpointPathParameters(HttpServletRequest request)
70   {
71     String pathInfo = request.getPathInfo();
72     int slashpos = pathInfo.indexOf('/', 1);
73     return slashpos < 1 ? null
74             : pathInfo.substring(slashpos + 1).split("/");
75   }
76
77   protected void returnError(HttpServletRequest request,
78           HttpServletResponse response, String message)
79   {
80     String okString = request.getParameter("ok");
81     boolean ok = (okString != null && okString.equalsIgnoreCase("true"));
82     /*
83      * Annoyingly jetty is not adding content to anything other than a few
84      * 20x status codes. Possibly it is closing the PrintWriter.
85      * Find a fix for this!
86      ****************************************************/
87     response.setStatus(ok ? HttpServletResponse.SC_OK : //
88     // HttpServletResponse.SC_BAD_REQUEST //
89             HttpServletResponse.SC_PARTIAL_CONTENT //
90     );
91
92     String endpointName = getPath();
93     Console.error(getAPI().getName() + " error: endpoint " + endpointName
94             + " failed: '" + message + "'");
95     try
96     {
97       PrintWriter writer = response.getWriter();
98       writer.write("message=Endpoint " + endpointName + ": " + message);
99     } catch (IOException e)
100     {
101       Console.info("Exception writing to REST response", e);
102     }
103   }
104
105   protected String getRequestBody(HttpServletRequest request)
106           throws IOException
107   {
108     StringBuilder sb = new StringBuilder();
109     BufferedReader reader = request.getReader();
110     try
111     {
112       String line;
113       while ((line = reader.readLine()) != null)
114       {
115         sb.append(line).append('\n');
116       }
117     } finally
118     {
119       reader.close();
120     }
121     return sb.toString();
122   }
123
124   protected boolean checkParameters(HttpServletRequest request,
125           HttpServletResponse response, int i)
126   {
127     String[] parameters = getEndpointPathParameters(request);
128
129     // check we can run fetchsequence
130     if (parameters.length < i)
131     {
132       returnError(request, response,
133               "requires parameters:" + getParameters() + "\n" + getName()
134                       + ": " + getDescription());
135       return false;
136     }
137     return true;
138   }
139
140   public int[][] parseIntRanges(String rangesString)
141   {
142     if (rangesString.equals("*"))
143     {
144       return new int[][] { { -1 }, { -1 } };
145     }
146     String[] rangeStrings = rangesString.split(",");
147     int[][] ranges = new int[2][rangeStrings.length];
148     for (int i = 0; i < rangeStrings.length; i++)
149     {
150       String range = rangeStrings[i];
151       try
152       {
153         int hyphenpos = range.indexOf('-');
154         if (hyphenpos < 0)
155         {
156           ranges[0][i] = Integer.parseInt(range);
157           ranges[1][i] = ranges[0][i];
158         }
159         else
160         {
161           ranges[0][i] = Integer.parseInt(range.substring(0, hyphenpos));
162           ranges[1][i] = Integer.parseInt(range.substring(hyphenpos + 1));
163         }
164       } catch (NumberFormatException nfe)
165       {
166         return null;
167       }
168     }
169     return ranges;
170   }
171
172   /*
173    * Get all AlignFrames or just one if requested to work on a specific window (fromId query string parameter)
174    */
175   protected AlignFrame[] getAlignFrames(HttpServletRequest request,
176           boolean all)
177   {
178     return getAlignFrames(request, "fromId", all);
179   }
180
181   protected AlignFrame[] getAlignFrames(HttpServletRequest request,
182           String idParam, boolean all)
183   {
184     String fromIdString = request.getParameter(idParam);
185
186     if (fromIdString != null)
187     {
188       AlignFrame af = AlignFrame.getAlignFrameFromRestId(fromIdString);
189       return af == null ? null : new AlignFrame[] { af };
190     }
191     else if (all)
192     {
193       return Desktop.getAlignFrames();
194     }
195     else
196     {
197       return null;
198     }
199   }
200
201   protected AlignFrame getAlignFrameFromId(HttpServletRequest request)
202   {
203     return getAlignFrameFromId(request, "fromId");
204   }
205
206   protected AlignFrame getAlignFrameFromId(HttpServletRequest request,
207           String idParam)
208   {
209     AlignFrame[] afs = getAlignFrames(request, idParam, false);
210     return (afs == null || afs.length < 1 || afs[0] == null) ? null
211             : afs[0];
212   }
213
214   protected boolean deleteFromCache()
215   {
216     return false;
217   }
218
219 }