JAL-3821 ported to refactored FlatFile parser
[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.Cache;
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.james.mime4j.MimeException;
44 import org.apache.james.mime4j.parser.MimeStreamParser;
45
46 /**
47  * data source instantiated from the response of an httpclient request.
48  * 
49  * @author JimP
50  * 
51  */
52
53 public class HttpResultSet extends FileParse implements AutoCloseable
54 {
55
56   private HttpRequestBase cachedRequest;
57
58   /**
59    * when set, indicates that en can be recreated by repeating the HttpRequest
60    * in cachedRequest
61    */
62   boolean repeatable = false;
63
64   /**
65    * response that is to be parsed as jalview input data
66    */
67   private HttpEntity en = null;
68
69   /**
70    * (sub)job that produced this result set.
71    */
72   private RestJob restJob;
73
74   public HttpResultSet(RestJob rj, HttpResponse con, HttpRequestBase req)
75           throws IOException
76   {
77     super();
78     setDataName(rj.getJobId() + " Part " + rj.getJobnum());
79     restJob = rj;
80     cachedRequest = req;
81     initDataSource(con);
82   }
83
84   /**
85    * construct a set of dataproviders to parse a result set from this service
86    * 
87    * @param resSet
88    * @return
89    */
90   public List<DataProvider> createResultDataProviders()
91   {
92     List<DataProvider> dp = new ArrayList<>();
93     for (JvDataType type : restJob.rsd.getResultDataTypes())
94     {
95       dp.add(new SimpleDataProvider(type, this, null));
96     }
97     return dp;
98   }
99
100   /**
101    * parses the results of the service output.
102    * 
103    * @return the result of ParsePackedSet.getAlignment()
104    * @throws Exception
105    * @throws Error
106    */
107   public Object[] parseResultSet() throws Exception, Error
108   {
109     List<DataProvider> dp = new ArrayList<>();
110     Object[] results = null;
111
112     if (en == null)
113     {
114       throw new Error(MessageManager.getString(
115               "error.implementation_error_need_to_have_httpresponse"));
116     }
117     jalview.io.packed.JalviewDataset ds = restJob.newJalviewDataset();
118     // Decide how we deal with content.
119     if (en instanceof MultipartEntity)
120     {
121       // Multipart messages should be properly typed, so we parse them as we go.
122       MultipartEntity mpe = (MultipartEntity) en;
123       // multipart
124       JalviewMimeContentHandler handler = new JalviewMimeContentHandler(ds);
125       MimeStreamParser parser = new MimeStreamParser();
126       parser.setContentHandler(handler);
127       try
128       {
129         parser.parse(mpe.getContent());
130       } catch (MimeException me)
131       {
132         error = true;
133         errormessage = "Couldn't parse message from web service.";
134         Cache.log.warn("Failed to parse MIME multipart content", me);
135         en.consumeContent();
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         Cache.log.debug("Result Type: " + en.getContentType().toString());
162       }
163       else
164       {
165         Cache.log.debug("No Result Type Specified.");
166       }
167       if (enc == null || enc.length() < 1)
168       {
169         Cache.log.debug("Assuming 'Default' Result Encoding.");
170       }
171       else
172       {
173         Cache.log.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         Cache.log.error("Can't handle encoding '" + enc
188                 + "' for response from webservice.", e);
189         en.consumeContent();
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 }