Merge branch 'develop' into update_212_Dec_merge_with_21125_chamges
[jalview.git] / src / jalview / ws / rest / HttpResultSet.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
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
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ws.rest;
22
23 import jalview.bin.Console;
24 import jalview.io.FileParse;
25 import jalview.io.packed.DataProvider;
26 import jalview.io.packed.DataProvider.JvDataType;
27 import jalview.io.packed.ParsePackedSet;
28 import jalview.io.packed.SimpleDataProvider;
29 import jalview.util.MessageManager;
30 import jalview.ws.io.mime.JalviewMimeContentHandler;
31
32 import java.io.BufferedReader;
33 import java.io.IOException;
34 import java.io.InputStreamReader;
35 import java.io.UnsupportedEncodingException;
36 import java.util.ArrayList;
37 import java.util.List;
38
39 import org.apache.http.HttpEntity;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.client.methods.HttpRequestBase;
42 import org.apache.http.entity.mime.MultipartEntity;
43 import org.apache.http.util.EntityUtils;
44 import org.apache.james.mime4j.MimeException;
45 import org.apache.james.mime4j.parser.MimeStreamParser;
46
47 /**
48  * data source instantiated from the response of an httpclient request.
49  * 
50  * @author JimP
51  * 
52  */
53
54 public class HttpResultSet extends FileParse implements AutoCloseable
55 {
56
57   private HttpRequestBase cachedRequest;
58
59   /**
60    * when set, indicates that en can be recreated by repeating the HttpRequest
61    * in cachedRequest
62    */
63   boolean repeatable = false;
64
65   /**
66    * response that is to be parsed as jalview input data
67    */
68   private HttpEntity en = null;
69
70   /**
71    * (sub)job that produced this result set.
72    */
73   private RestJob restJob;
74
75   public HttpResultSet(RestJob rj, HttpResponse con, HttpRequestBase req)
76           throws IOException
77   {
78     super();
79     setDataName(rj.getJobId() + " Part " + rj.getJobnum());
80     restJob = rj;
81     cachedRequest = req;
82     initDataSource(con);
83   }
84
85   /**
86    * construct a set of dataproviders to parse a result set from this service
87    * 
88    * @param resSet
89    * @return
90    */
91   public List<DataProvider> createResultDataProviders()
92   {
93     List<DataProvider> dp = new ArrayList<>();
94     for (JvDataType type : restJob.rsd.getResultDataTypes())
95     {
96       dp.add(new SimpleDataProvider(type, this, null));
97     }
98     return dp;
99   }
100
101   /**
102    * parses the results of the service output.
103    * 
104    * @return the result of ParsePackedSet.getAlignment()
105    * @throws Exception
106    * @throws Error
107    */
108   public Object[] parseResultSet() throws Exception, Error
109   {
110     List<DataProvider> dp = new ArrayList<>();
111     Object[] results = null;
112
113     if (en == null)
114     {
115       throw new Error(MessageManager.getString(
116               "error.implementation_error_need_to_have_httpresponse"));
117     }
118     jalview.io.packed.JalviewDataset ds = restJob.newJalviewDataset();
119     // Decide how we deal with content.
120     // TODO : verify we are detecting a multipart response correctly
121     if (en.getContentType().getValue().startsWith("multipart/form-data"))
122     {
123       // Multipart messages should be properly typed, so we parse them as we go.
124       JalviewMimeContentHandler handler = new JalviewMimeContentHandler(ds);
125       MimeStreamParser parser = new MimeStreamParser();
126       parser.setContentHandler(handler);
127       try
128       {
129         parser.parse(en.getContent());
130       } catch (MimeException me)
131       {
132         error = true;
133         errormessage = "Couldn't parse message from web service.";
134         Console.warn("Failed to parse MIME multipart content", me);
135         EntityUtils.consume(en);
136       }
137       return new ParsePackedSet().getAlignment(ds,
138               handler.getJalviewDataProviders());
139     }
140     else
141     {
142       // Need to use hints from rest service description.
143       dp = createResultDataProviders();
144       ParsePackedSet pps = new ParsePackedSet();
145       return pps.getAlignment(ds, dp);
146     }
147   }
148
149   private void initDataSource(HttpResponse con) throws IOException
150   {
151     en = con.getEntity();
152     repeatable = en.isRepeatable();
153
154     if (!(en instanceof MultipartEntity))
155     {
156       // assume content is simple text stream that can be read from
157       String enc = (en.getContentEncoding() == null) ? null
158               : en.getContentEncoding().getValue();
159       if (en.getContentType() != null)
160       {
161         Console.debug("Result Type: " + en.getContentType().toString());
162       }
163       else
164       {
165         Console.debug("No Result Type Specified.");
166       }
167       if (enc == null || enc.length() < 1)
168       {
169         Console.debug("Assuming 'Default' Result Encoding.");
170       }
171       else
172       {
173         Console.debug("Result Encoded as : " + enc);
174       }
175       // attempt to identify file and construct an appropriate DataSource
176       // identifier for it.
177       // try to parse
178       // Mime-Multipart or single content type will be expected.
179       // if (enc.equals(org.apache.http.client.utils.)))
180       InputStreamReader br = null;
181       try
182       {
183         br = (enc != null) ? new InputStreamReader(en.getContent(), enc)
184                 : new InputStreamReader(en.getContent());
185       } catch (UnsupportedEncodingException e)
186       {
187         Console.error("Can't handle encoding '" + enc
188                 + "' for response from webservice.", e);
189         EntityUtils.consume(en);
190         error = true;
191         errormessage = "Can't handle encoding for response from webservice";
192         return;
193       }
194       if (br != null)
195       {
196         dataIn = new BufferedReader(br);
197         error = false;
198       }
199     }
200   }
201
202   @Override
203   public void close()
204   {
205     dataIn = null;
206     cachedRequest = null;
207     try
208     {
209       if (en != null)
210       {
211         en.consumeContent();
212       }
213     } catch (Exception e)
214     {
215     } catch (Error ex)
216     {
217     }
218     // no finalize for FileParse
219     // super.close();
220   }
221
222   /**
223    * 
224    * @return the URL that this result set read data from.
225    */
226   public String getUrl()
227   {
228     try
229     {
230       return cachedRequest.getURI().toURL().toString();
231     } catch (Exception x)
232     {
233       x.printStackTrace();
234       return null;
235     }
236   }
237
238 }