root/trunk/corelib/src/org/bridgedb/webservice/bridgerest/BridgeRest.java @ 307

Revision 307, 13.9 KB (checked in by jgao, 7 months ago)

Add isFreeAttributeSearchSupported() to AttributeMapper?

Line 
1// BridgeDb,
2// An abstraction layer for identifer mapping services, both local and online.
3// Copyright 2006-2009 BridgeDb developers
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17package org.bridgedb.webservice.bridgerest;
18
19import java.io.BufferedReader;
20import java.io.IOException;
21import java.io.InputStreamReader;
22import java.net.HttpURLConnection;
23import java.net.URL;
24import java.net.URLEncoder;
25import java.util.Arrays;
26import java.util.Collection;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.Map;
30import java.util.Set;
31
32import org.bridgedb.AttributeMapper;
33import org.bridgedb.BridgeDb;
34import org.bridgedb.DataSource;
35import org.bridgedb.IDMapper;
36import org.bridgedb.IDMapperCapabilities;
37import org.bridgedb.IDMapperException;
38import org.bridgedb.Xref;
39import org.bridgedb.impl.InternalUtils;
40import org.bridgedb.webservice.IDMapperWebservice;
41
42/**
43 * IDMapper implementation for BridgeRest, the REST interface of BridgeDb itself.
44 */
45public class BridgeRest extends IDMapperWebservice implements AttributeMapper
46{
47        static {
48                BridgeDb.register ("idmapper-bridgerest", new Driver());
49        }
50
51        private final static class Driver implements org.bridgedb.Driver {
52                /** private constructor to prevent outside instantiation. */
53                private Driver() { }
54
55                /** {@inheritDoc} */
56                public IDMapper connect(String location) throws IDMapperException  {
57                        // replace all spaces by "%20" to access organisms such as "Arabidopsis theliana"
58                        return new BridgeRest(location.replaceAll(" ", "%20"));
59                }
60        }
61
62        private final class RestCapabilities implements IDMapperCapabilities {
63                private Map<String, String> properties = new HashMap<String, String>();
64                private boolean freeSearchSupported;
65
66                /**
67                 * Capabilities for the BridgeRest IDMapper.
68                 * @throws IDMapperException when the webservice was not available.
69                 */
70                public RestCapabilities() throws IDMapperException {
71                        try {
72                                loadProperties();
73                                loadFreeSearchSupported();
74                        } catch(IOException e) {
75                                throw new IDMapperException(e);
76                        }
77                }
78
79                /**
80                 * Helper method, reads a list of supported datasources from the webservice.
81                 * @param cmd can be sourceDataSources or targetDataSources
82                 * @return Set of DataSources
83                 * @throws IDMapperException when service is unavailable.
84                 */
85                private Set<DataSource> loadDataSources(String cmd) throws IDMapperException
86                {
87                        try
88                        {
89                                Set<DataSource> results = new HashSet<DataSource>();
90       
91                                BufferedReader in = new UrlBuilder (cmd).openReader();
92                                String line = null;
93                                while((line = in.readLine()) != null) {
94                                        results.add(DataSource.getByFullName(line));
95                                }
96                                in.close();
97                                return results;
98                        }
99                        catch (IOException ex)
100                        {
101                                throw new IDMapperException (ex);
102                        }
103                }
104
105                /**
106                 * Helper method, checks if free search is supported by the webservice.
107                 * @throws IOException when service is unavailable.
108                 */
109                private void loadFreeSearchSupported() throws IOException {
110                        BufferedReader in = new UrlBuilder ("isFreeSearchSupported").openReader();
111                        String line = null;
112                        while((line = in.readLine()) != null) {
113                                freeSearchSupported = Boolean.parseBoolean(line);
114                        }
115                        in.close();
116                }
117
118                /**
119                 * Helper method, reads properties from the webservice.
120                 * @throws IOException when service is unavailable.
121                 */
122                private void loadProperties() throws IOException {
123                        BufferedReader in = new UrlBuilder ("properties").openReader();
124                        String line = null;
125                        while((line = in.readLine()) != null) {
126                                String[] cols = line.split("\t");
127                                properties.put(cols[0], cols[1]);
128                        }
129                        in.close();
130                }
131
132                /** {@inheritDoc} */
133                public Set<String> getKeys() {
134                        return properties.keySet();
135                }
136
137                /** {@inheritDoc} */
138                public String getProperty(String key) {
139                        return properties.get(key);
140                }
141
142                /** {@inheritDoc} */
143                public Set<DataSource> getSupportedSrcDataSources()
144                        throws IDMapperException
145                {
146                        if (supportedSrcDataSources==null) {
147                                supportedSrcDataSources = loadDataSources("sourceDataSources");
148                        }
149                        return supportedSrcDataSources;
150                }
151
152                /** {@inheritDoc} */
153                public Set<DataSource> getSupportedTgtDataSources()
154                        throws IDMapperException
155                {
156                        if (supportedTgtDataSources==null) {
157                                supportedTgtDataSources = loadDataSources("targetDataSources");
158                        }
159                        return supportedTgtDataSources;
160                }
161
162                /** {@inheritDoc} */
163                public boolean isFreeSearchSupported() {
164                        return freeSearchSupported;
165                }
166
167                /** {@inheritDoc} */
168                public boolean isMappingSupported(DataSource src, DataSource tgt)
169                throws IDMapperException {
170                        try {
171                                boolean supported = false;                             
172                                BufferedReader in = new UrlBuilder("isMappingSupported")
173                                        .ordered(src.getSystemCode(), tgt.getSystemCode()).openReader();
174                                String line = null;
175                                while((line = in.readLine()) != null) {
176                                        supported = Boolean.parseBoolean(line);
177                                }
178                                in.close();
179                                return supported;
180                        } catch(IOException e) {
181                                throw new IDMapperException(e);
182                        }
183                }
184        }
185
186        private final String baseUrl;
187
188        private final IDMapperCapabilities capabilities;
189
190        private Set<DataSource> supportedSrcDataSources = null;
191        private Set<DataSource> supportedTgtDataSources = null;
192        private Set<String> attributeSet = null;
193
194        /**
195         * Helper class for constructing URL of a BridgeRest webservice command.
196         */
197        private final class UrlBuilder
198        {
199                private StringBuilder builder = new StringBuilder(baseUrl);
200               
201                /**
202                 * Start building a new Url for the BridgeRest webservice.
203                 * @param cmd the command, or the first parameter after the base Url. For example "properties".
204                 *      This param will be added after the baseUrl, separated by a "/"
205                 */
206                private UrlBuilder(String cmd)
207                {
208                        builder.append ("/");
209                        builder.append (cmd);
210                }
211               
212                /**
213                 * Ordered, unnamed arguments.
214                 * @param args Optional arguments, these will be URLencoded and separated by "/"
215                 * @return this, for chaining purposes
216                 * @throws IOException in case there is an encoding problem (really unlikely)
217                 */
218                UrlBuilder ordered (String... args) throws IOException
219                {
220                        for (String arg : args)
221                        {
222                                builder.append ("/");
223                                builder.append (URLEncoder.encode (arg, "UTF-8"));
224                        }
225                        return this;
226                }
227
228                private boolean hasQMark = false;
229               
230                /**
231                 * Named parameters, these will be appended after ? and formatted as key=val pairs,
232                 * separated by &
233                 * @param key name of parameter
234                 * @param val value of parameter
235                 * @throws IOException in case there is an encoding problem (really unlikely)
236                 * @return this, for chaining purposes
237                 */
238                UrlBuilder named (String key, String val) throws IOException
239                {
240                        if (!hasQMark)
241                        {
242                                builder.append ("?");
243                                hasQMark = true;
244                        }
245                        else
246                        {
247                                builder.append ("&");
248                        }
249                        builder.append (URLEncoder.encode (key, "UTF-8"));
250                        builder.append ("=");
251                        builder.append (URLEncoder.encode (val, "UTF-8"));
252                        return this;
253                }
254
255                /**
256                 * Open an InputStream to a given URL. For certain requests, when there are 0 results, the
257                 * BridgeWebservice helpfully redirects to an error page instead of simply returning
258                 * an empty list. Here we detect that situation and throw IOException.
259                 * @return inputstream to given url.
260                 * @throws IOException when there is a timeout, or when the http response code is not 200 - OK
261                 */
262                private BufferedReader openReader() throws IOException
263                {
264                        URL url = new URL (builder.toString());
265                        HttpURLConnection con = (HttpURLConnection) url.openConnection();
266                        con.setInstanceFollowRedirects(false);
267                        int response = con.getResponseCode();
268                        if (response < HttpURLConnection.HTTP_OK || response >= HttpURLConnection.HTTP_MULT_CHOICE )
269                                throw new IOException("HTTP response: " + con.getResponseCode() + " - " + con.getResponseMessage());
270                        return new BufferedReader(new InputStreamReader(con.getInputStream()));
271                }
272        }
273       
274        /**
275         * @param baseUrl base Url, e.g. http://webservice.bridgedb.org/Human or
276         *      http://localhost:8182
277         * @throws IDMapperException when service is unavailable
278         */
279        BridgeRest (String baseUrl) throws IDMapperException
280        {
281                this.baseUrl = baseUrl;
282
283                //Get the capabilities
284                capabilities = new RestCapabilities();
285        }
286
287        private boolean isConnected = true;
288
289        /** {@inheritDoc} */
290        public void close() throws IDMapperException { isConnected = false; }
291
292        /** {@inheritDoc} */
293        public Set<Xref> freeSearch(String text, int limit)
294        throws IDMapperException
295        {
296                try
297                {
298                        BufferedReader r = new UrlBuilder ("search").ordered(text).openReader();
299                        Set<Xref> result = new HashSet<Xref>();
300
301                        {
302                                Xref dest;
303                                while ((dest = parseLine(r)) != null) result.add (dest);
304                        }
305                       
306                        return result;
307                }
308                catch (IOException ex) {
309                        throw new IDMapperException (ex);
310                }
311        }
312
313        /** {@inheritDoc} */
314        public IDMapperCapabilities getCapabilities() {
315                return capabilities;
316        }
317
318        /** {@inheritDoc} */
319        public boolean isConnected() {
320                return isConnected;
321        }
322
323        /** {@inheritDoc} */
324        public Map<Xref, Set<Xref>> mapID(Collection<Xref> srcXrefs,
325                        DataSource... tgtDataSources) throws IDMapperException
326        {
327                return InternalUtils.mapMultiFromSingle(this, srcXrefs, tgtDataSources);
328        }
329
330        /** {@inheritDoc} */
331        public Set<Xref> mapID(Xref src,
332                        DataSource... tgtDataSources) throws IDMapperException
333                        {
334                Set<DataSource> dsFilter = new HashSet<DataSource>();
335                if(tgtDataSources != null) dsFilter.addAll(Arrays.asList(tgtDataSources));
336
337                try
338                {
339                        UrlBuilder builder = new UrlBuilder ("xrefs")
340                                .ordered(src.getDataSource().getSystemCode(), src.getId());
341                        if (tgtDataSources.length == 1)
342                                builder = builder.named("dataSource", tgtDataSources[0].getSystemCode());
343                        BufferedReader r = builder.openReader();
344                        Set<Xref> result = new HashSet<Xref>();
345                        {
346                                Xref dest;
347                                while ((dest = parseLine(r)) != null)
348                                {
349                                        if (dsFilter.size() == 0 || dsFilter.contains(dest.getDataSource()))
350                                        {
351                                                result.add (dest);
352                                        }
353                                }               
354                        }
355                        return result;
356                }
357                catch (IOException ex)
358                {
359                        throw new IDMapperException(ex);
360                }
361        }
362
363        /**
364         * parse a single line of input.
365         * @param reader reader to read line from
366         * @return Xref or null if end of stream was reached
367         * @throws IOException if there was an error while reading (not EOF!) */
368        private Xref parseLine(BufferedReader reader) throws IOException
369        {
370                StringBuilder builder = new StringBuilder();
371                String id = null;
372                int c;
373                while (true)
374                {
375                        // read char by char and use switch statement
376                        // for efficiency
377                        c = reader.read();
378                        switch (c)
379                        {
380                        case -1:
381                                return null; // end of the stream
382                        case '\n':
383                                DataSource ds = DataSource.getByFullName(builder.toString());
384                                return new Xref(id, ds);
385                        case '\t':
386                                id = builder.toString();
387                                builder = new StringBuilder();
388                                break;
389                        default:
390                                builder.append((char)c);
391                        }
392                }
393        }
394
395        /** {@inheritDoc} */
396        public boolean xrefExists(Xref xref) throws IDMapperException {
397                try {
398                        boolean exists = false;
399                        BufferedReader in = new UrlBuilder ("xrefExists")
400                                .ordered(xref.getDataSource().getSystemCode(), xref.getId())
401                                .openReader();
402                        String line = in.readLine();
403                        exists = Boolean.parseBoolean(line);
404                        in.close();
405                        return exists;
406                } catch(IOException e) {
407                        throw new IDMapperException(e);
408                }
409        }
410
411        /**
412         *
413         * @return true
414         */
415        public boolean isFreeAttributeSearchSupported()
416        {
417                return true;
418        }
419
420        /** {@inheritDoc} */
421        public Map<Xref, String> freeAttributeSearch(String query, String attrType,
422                        int limit) throws IDMapperException {
423                try {
424                        Map<Xref, String> result = new HashMap<Xref, String>();
425                       
426                        BufferedReader in = new UrlBuilder("attributeSearch")
427                                .ordered (query).named("limit", "" + limit)
428                                .named ("attrName", attrType)
429                                .openReader();
430                        String line;
431                        while ((line = in.readLine()) != null) {
432                                String[] cols = line.split("\t", -1);
433                                Xref x = new Xref (cols[0], DataSource.getByFullName(cols[1]));
434                                String value = cols[2];
435                                result.put(x, value);
436                        }
437                        in.close();
438                        return result;
439                } catch (IOException ex) {
440                        throw new IDMapperException (ex);
441                }
442        }
443
444        /** {@inheritDoc} */
445        public Set<String> getAttributes(Xref ref, String attrType)
446        throws IDMapperException {
447                try {
448                        Set<String> results = new HashSet<String>();
449
450                        BufferedReader in = new UrlBuilder ("attributes")
451                                .ordered(ref.getDataSource().getSystemCode(), ref.getId())
452                                .named ("attrName", attrType)
453                                .openReader();
454
455                        String line;
456                        while ((line = in.readLine()) != null) {
457                                results.add(line);
458                        }
459                        in.close();
460                        return results;
461                } catch (IOException ex) {
462                        throw new IDMapperException (ex);
463                }
464        }
465
466        /** {@inheritDoc} */
467        public Set<String> getAttributeSet() throws IDMapperException {
468                if (attributeSet==null) {
469                        try {
470                                Set<String> results = new HashSet<String>();
471
472                                BufferedReader in = new UrlBuilder ("attributeSet")
473                                        .openReader();
474                                String line;
475                                while ((line = in.readLine()) != null) {
476                                        results.add(line);
477                                }
478                                in.close();
479                                attributeSet = results;
480                        } catch (IOException ex) {
481                                throw new IDMapperException (ex);
482                        }
483                }
484
485                return attributeSet;
486        }
487
488        /** {@inheritDoc} */
489        public Map<String, Set<String>> getAttributes(Xref ref)
490        throws IDMapperException {
491                try {
492                        Map<String, Set<String>> results = new HashMap<String, Set<String>>();
493
494                        BufferedReader in = new UrlBuilder ("attributes")
495                                .ordered(ref.getDataSource().getSystemCode(), ref.getId())
496                                .openReader();
497                       
498                        String line;
499                        while ((line = in.readLine()) != null) {
500                                String[] cols = line.split("\t", -1);
501                                Set<String> rs = results.get(cols[0]);
502                                if(rs == null) results.put(cols[0], rs = new HashSet<String>());
503                                rs.add(cols[1]);
504                        }
505                        in.close();
506                        return results;
507                } catch (IOException ex) {
508                        throw new IDMapperException (ex);
509                }
510        }
511       
512}
Note: See TracBrowser for help on using the browser.