001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.align.client;
022
023import org.biojava.nbio.structure.Atom;
024import org.biojava.nbio.structure.StructureException;
025import org.biojava.nbio.structure.align.fatcat.FatCatRigid;
026import org.biojava.nbio.structure.align.model.AFPChain;
027import org.biojava.nbio.structure.align.util.AtomCache;
028import org.biojava.nbio.structure.align.util.HTTPConnectionTools;
029import org.biojava.nbio.structure.align.util.ResourceManager;
030import org.biojava.nbio.structure.align.xml.*;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034import java.io.BufferedReader;
035import java.io.IOException;
036import java.io.InputStream;
037import java.io.InputStreamReader;
038import java.net.URL;
039import java.net.URLEncoder;
040import java.util.Random;
041import java.util.SortedSet;
042import java.util.TreeSet;
043
044public class JFatCatClient {
045        private final static Logger logger = LoggerFactory.getLogger(JFatCatClient.class);
046
047        private static ResourceManager resourceManager = ResourceManager.getResourceManager("jfatcat");
048
049        private static final String serverAPPEND    = "show?name1=%s&name2=%s";
050
051        private static final String sendAPPEND      = "submit?name1=%s&name2=%s&version=%s";
052
053        private static final String multiSendAPPEND = "jobSubmit?username=%s&version=%s";
054
055        private static final String representAPPEND = "representatives?cluster=%s";
056
057        private static final String serverHasResult = "hasResult?method=%s&name1=%s&name2=%s";
058
059        private static final int DEFAULT_TIMEOUT = 5000;
060
061        private static final String serverPositionInQueue =  "queuePosition?method=%s&name1=%s&name2=%s";
062
063        private static Random generator;
064
065        private static String newline = System.getProperty("line.separator");
066
067        private static String KILL_JOB = "KILL_JOB";
068
069        private static String COME_BACK_LATER = "COME_BACK_LATER";
070
071        static {
072
073                generator = new Random();
074
075        }
076
077        public static void main(String[] args) throws Exception {
078                //System.out.println(hasPrecalculatedResult("http://source.rcsb.org/jfatcatserver/align/", "jCE Circular Permutation", "1CDG.A", "1TIM.A"));
079                AtomCache cache = new AtomCache();
080                String name1= "2W72.A";
081                String name2= "1D2Z.D";
082
083                Atom[] ca1 = cache.getAtoms(name1);
084                Atom[] ca2 = cache.getAtoms(name2);
085
086                int timeout = 10000;
087
088                String testServer = "http://source.rcsb.org/jfatcatserver/align/";
089
090                System.out.println(getAFPChainFromServer(testServer, FatCatRigid.algorithmName, name1, name2, ca1, ca2, timeout));
091
092                PdbPairsMessage msg = getPdbPairs(testServer, 1, "test");
093
094                System.out.println(msg);
095
096                System.out.println(getRepresentatives(FarmJobParameters.DEFAULT_SERVER_URL, 40));
097        }
098
099        public static boolean hasPrecalculatedResult(String serverLocation, String method, String name1, String name2 ){
100                return hasPrecalculatedResult(serverLocation, method, name1, name2, DEFAULT_TIMEOUT );
101        }
102
103        public static boolean hasPrecalculatedResult(String serverLocation, String method, String name1, String name2, int timeout){
104
105                String serverURL = serverLocation + serverHasResult;
106
107
108                boolean hasResults = false;
109                try {
110                        String u = String.format(serverURL,URLEncoder.encode(method,"UTF-8"),name1,name2) ;
111                        URL url = new URL(u);
112                        //System.out.println("has result ? ..."  + url);
113
114                        InputStream stream = HTTPConnectionTools.getInputStream(url,timeout);
115
116                        String xml = null;
117
118                        if ( stream != null) {
119
120                                xml = convertStreamToString(stream);
121                                logger.info(" has PrecalcResults got XML from server: " + xml);
122                                HasResultXMLConverter conv = new HasResultXMLConverter();
123                                hasResults = conv.fromXML(xml);
124                        }
125
126                } catch (IOException e){
127                        // log error and return false
128                        logger.error("error in JFatCatClient: getAFPChainFromServer",e);
129                }
130                return hasResults;
131        }
132
133
134        public int getPositionInQueue(String serverLocation, String method, String name1, String name2){
135                return getPositionInQueue(serverLocation, method, name1, name2, DEFAULT_TIMEOUT);
136        }
137
138        public int getPositionInQueue(String serverLocation, String method, String name1, String name2, int timeout){
139                String serverURL = serverLocation + serverPositionInQueue;
140
141
142                int position = Integer.MIN_VALUE;
143                try {
144                        String u = String.format(serverURL,URLEncoder.encode(method,"UTF-8"),name1,name2) ;
145                        URL url = new URL(u);
146
147                        InputStream stream = HTTPConnectionTools.getInputStream(url,timeout);
148
149                        String xml = null;
150
151                        if ( stream != null) {
152
153                                xml = convertStreamToString(stream);
154                                //System.out.println("got XML from server: " + xml);
155                                PositionInQueueXMLConverter conv = new PositionInQueueXMLConverter();
156                                position = conv.fromXML(xml);
157                        }
158
159                } catch (IOException e){
160                        logger.error("error in JFatCatClient: getAFPChainFromServer",e); // TODO dmyersturnbull: method should throw; we shouldn't catch here
161                }
162                return position;
163
164        }
165        public static AFPChain getAFPChainFromServer(String serverLocation ,  String name1, String name2, Atom[] ca1, Atom[] ca2) {
166                String method = FatCatRigid.algorithmName;
167                return getAFPChainFromServer(serverLocation, method, name1, name2, ca1, ca2,DEFAULT_TIMEOUT);
168        }
169
170        public static AFPChain getAFPChainFromServer(String serverLocation , String method, String name1, String name2, Atom[] ca1, Atom[] ca2, int timeout)
171        {
172
173                String serverURL = serverLocation + serverAPPEND;
174
175                try {
176                        String u = String.format(serverURL,name1,name2) ;
177
178                        if ( method != null)
179                                u+= "&method=" + URLEncoder.encode(method,"UTF-8");
180
181                        URL url = new URL(u);
182                        logger.info("requesting alignment from server..."  + url);
183                        // have a short timeout for this...
184                        // 5 sec
185                        InputStream stream = HTTPConnectionTools.getInputStream(url,timeout);
186
187                        String xml = null;
188
189                        if ( stream != null) {
190
191                                xml = convertStreamToString(stream);
192                        }
193                        if (xml != null) {
194
195                                return AFPChainXMLParser.fromXML (xml, name1, name2, ca1, ca2);
196
197                        } else {
198                                return null;
199                        }
200                        // TODO dmyersturnbull: method should throw; we shouldn't catch here
201                } catch (IOException e){
202                        logger.error("error in JFatCatClient: getAFPChainFromServer",e);
203                } catch (StructureException e) {
204                        logger.error("error in JFatCatClient: getAFPChainFromServer",e);
205                }
206                return null;
207        }
208
209
210        public static String convertStreamToString(InputStream stream){
211                BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
212                StringBuilder sb = new StringBuilder();
213
214                String line = null;
215                try {
216                        while ((line = reader.readLine()) != null) {
217                                sb.append(line).append(newline);
218                        }
219                } catch (IOException e) {
220                        logger.error("Couldn't convert stream to string", e); // TODO dmyersturnbull: method should throw; we shouldn't catch here
221                } finally {
222                        try {
223                                stream.close();
224                        } catch (IOException e) {
225                                logger.warn("Can't close stream", e);
226                        }
227                }
228
229                return sb.toString();
230        }
231
232        public static String sendMultiAFPChainToServer(String serverLocation, String multiXML, String username) throws JobKillException{
233                String version = resourceManager.getString("jfatcat.version");
234                return sendMultiAFPChainToServer(serverLocation, multiXML, username, version);
235        }
236
237        public static String sendMultiAFPChainToServer(String serverLocation, String multiXML, String username, String version) throws JobKillException{
238                String multiSendURL = serverLocation + multiSendAPPEND;
239
240                String responseS = "";
241
242                String u = String.format(multiSendURL,username,version);
243
244                int timeout = getTimeout();
245
246                boolean submitted = false;
247
248                while (! submitted ){
249                        try {
250                                URL url = new URL(u);
251                                InputStream response = HTTPConnectionTools.doPOST(url, multiXML,timeout);
252                                responseS = convertStreamToString(response);
253                                submitted = true;
254                                if (! responseS.contains("OK"))
255                                        logger.error("server returned " + responseS);
256
257                                // server is busy... wait a bit and try again
258                                if ( responseS.startsWith(COME_BACK_LATER)){
259                                        submitted = false;
260                                }
261
262                        } catch (Exception e){
263                                logger.error("Error in JFatCatClient: while sending results back to server",e);
264
265                                try {
266                                        int randomSleep = getRandomSleepTime();
267                                        logger.warn("sleeping " + (randomSleep/1000) + " sec.");
268                                        Thread.sleep(randomSleep);
269                                } catch (InterruptedException ex){
270                                        logger.warn("Interrupted while sleeping", ex);
271                                }
272                        }
273                }
274
275                if ( responseS.startsWith(KILL_JOB)){
276                        throw new JobKillException("Server responded with KILL message.");
277
278                }
279
280
281                return responseS;
282        }
283
284        public static int getRandomSleepTime() {
285
286                // now wait between 7 and 13 min.
287
288                int minTime = 560000;
289
290                int maxTime = 7800000 - minTime;
291
292                int nextId = generator.nextInt(maxTime);
293                return minTime + nextId;
294
295        }
296
297
298        public static final void sendAFPChainToServer(String serverLocation, AFPChain afpChain,Atom[] ca1, Atom[] ca2) throws JobKillException
299        {
300
301                String sendURL = serverLocation + sendAPPEND;
302
303                String version = resourceManager.getString("jfatcat.version");
304
305                int timeout = getTimeout();
306
307                try {
308
309                        // just to make sure that similarity has been calculated!
310                        afpChain.getSimilarity();
311
312                        String xml = AFPChainXMLConverter.toXML(afpChain, ca1, ca2);
313
314                        String u = String.format(sendURL,afpChain.getName1() , afpChain.getName2(),version);
315
316                        URL url = new URL(u);
317
318                        InputStream response = HTTPConnectionTools.doPOST(url, xml,timeout);
319
320                        logger.debug("got response: {}", convertStreamToString(response));
321
322                        if ( xml.startsWith("KILL_JOB")){
323                                throw new JobKillException("Server responded with KILL message.");
324                        }
325
326                } catch (IOException e){
327                        logger.error("error in JFatCatClient: sendAFPChainToServer",e);
328                }
329
330        }
331
332        public static final int getTimeout(){
333                String timeoutS = resourceManager.getString("connection.timeout");
334                int timeout = 60000;
335
336                try {
337                        timeout = Integer.parseInt(timeoutS);
338                } catch (NumberFormatException ex ){
339                        logger.error("Bad connection.timeout parameter",ex);
340                }
341                return timeout;
342        }
343
344
345        public static final PdbPairsMessage getPdbPairs(String url,int nrPair, String username) throws IOException, JobKillException {
346
347
348                String urlS= url + "getPairs?" + "nrPairs=" + nrPair + "&username=" + URLEncoder.encode(username, "UTF-8");
349                int timeout = getTimeout();
350
351                PdbPairsMessage msg = null;
352                logger.info("requesting {}", urlS);
353                URL serverUrl = new URL(urlS);
354                // we are very tolerant with requesting a set of pairs, since we probably depend on getting it to get work started...
355                // 1 min...
356                InputStream stream = HTTPConnectionTools.getInputStream(serverUrl,timeout);
357                String xml = null;
358
359                if ( stream != null) {
360
361                        xml = convertStreamToString(stream);
362                        if (xml != null) {
363                                if ( xml.startsWith("KILL_JOB")){
364                                        // we got the KILL signal from the server...
365                                        throw new JobKillException("Server responded with KILL message.");
366                                }
367                                msg = PdbPairXMLConverter.convertXMLtoPairs(xml);
368
369                        }
370                }
371
372                return msg;
373        }
374
375
376        public static final SortedSet<String> getRepresentatives(String serverLocation, int cutoff){
377                SortedSet<String> representatives = new TreeSet<String>();
378
379                String representURL = serverLocation + representAPPEND;
380
381                if ( cutoff < 20)
382                        cutoff = 40;
383                int timeout = getTimeout();
384                String u = String.format(representURL,cutoff);
385
386                logger.info("Fetching representatives from "+u);
387                try {
388                        URL url = new URL(u);
389
390                        InputStream stream = HTTPConnectionTools.getInputStream(url,timeout);
391
392                        String xml = null;
393
394                        if ( stream != null) {
395
396                                xml = convertStreamToString(stream);
397                        }
398                        if (xml != null) {
399                                representatives = RepresentativeXMLConverter.fromXML(xml);
400                        }
401                } catch (IOException e){ // TODO dmyersturnbull: method should throw; we shouldn't catch here
402                        logger.error("Error fetching representatives",e);
403                }
404                return representatives;
405        }
406
407
408
409}