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