root/grails-app/controllers/RestController.groovy @ 123

Revision 123, 11.4 KB (checked in by vinlud, 4 years ago)

Fixed bug, negative array let SAM crash

Line 
1import data.*
2import grails.converters.*
3import java.io.PrintWriter
4import java.io.StringWriter
5import org.codehaus.groovy.grails.web.json.*
6import org.compass.core.engine.SearchEngineQueryParseException
7import org.compass.core.impl.*
8
9
10class RestController {
11
12    def searchableService
13
14    def simpleAssayList = []
15    def measurementDataList = []
16
17
18
19    /** Expose the list of features within a certain assay
20     *
21     * @author Adem and Jahn
22     * @since 20100525
23     *
24     * $Rev$
25     *
26     * This class provides a REST-full service for getting and setting the data
27     * in the Simple Assay Module (SAM). The service consists of several
28     * resources listed below. So far, all resources are GET resoruces, i.e. we
29     * do not use PUT, POST or DELETE. Because we are using Grails' web libaries,
30     * each resource corresponds to exactly one action of this controller.
31     *
32     *
33     *
34     * The REST resources implemented in this controller are:
35     *
36     * SAM-host:port/sam/rest/getMeasurements
37     * SAM-host:port/sam/rest/getMeasurementsForValue
38     * SAM-host:port/sam/rest/getMeasurementsForRange
39     * SAM-host:port/sam/rest/getMeasurementsForSample
40     * SAM-host:port/sam/rest/getDataSimple
41     * SAM-host:port/sam/rest/getAvailableBiomarkers
42     *
43     * Where 'SAM-host-url' is the url of the SAM server's host with port number 'port'.
44     *
45     *
46     *
47     * Some of the resources use additional parameters such, e.g. because they Grails'
48     * Searchable plugin. For instance, the getMeasurement resource is addressed as follows:
49     *
50     * SAM-host:port/sam/rest/getMeasurements?submit=Query&ump;q=ldl
51     *
52     * In this example the first paramter is 'submit' with value 'Query' and the second
53     * parameter is 'q' with value 'ldl'. The parameter 'submit' is neccessary to exploit
54     * automatic parsing functionality of the the Searchable plugin. The parameter 'q'
55     * is the keyword requested by the same plugin.
56     */
57
58
59
60
61      /****************************************************************/
62     /* REST resources for providing basic data to the GSCF          */
63    /****************************************************************/
64
65
66
67    /**
68     * Return a list of simple assay measurements matching the querying text.
69     * Uses Searchable plugin.
70     *
71     * @param measurement name
72     * @return list of measurements
73     */
74    def getMeasurements = {
75        if (!params.q?.trim()) {
76            return [:]
77        }
78        try {
79            render params
80            render searchableService.search(params.q, params).results
81            return [searchResult: searchableService.search(params.q, params)]
82        } catch (SearchEngineQueryParseException ex) {
83            return [parseException: true]
84        }
85    }
86
87
88
89
90
91
92
93
94
95      /***************************************************/
96     /* REST resources related to the querying in GSCF  */
97    /***************************************************/
98
99
100    /**
101     * Run searchable on query string for finding hits in SimpleAssays and SimpleAssayMeasurementTypes.
102     *
103     * @param  string: Query string
104     * @return map.    The map contains two keys "studyIds" and "assays". studyIds represent the studies for 
105     *                 which MeasurementTypes were found containing the query string. assayIds are the
106     *                 externalAssayIDs of the SimpleAssays for which a match was found.
107     *                     Example of a returned map:  [ assays:[data.SimpleAssay : 1], studyIds:[PPSH] ].
108     */
109    def getQueryResult = {
110                def query = params['query']
111                def searchResult = querySearchable( query )
112                def results = getResultingObjects( searchResult )       // get assays and studies
113                render results as JSON 
114    }
115
116
117
118    /**
119     * Run searchable on query string and values for finding hits in SimpleAssayMeasurement and
120     * SimpleAssayMeasurementType. (This rest resource is called by the SimpleQuery of GSCF.)
121     *
122     * @param  string: Query string
123     * @return map. The map contains enriched information on SimpleAssayMeasurements.   
124     *                 
125     * Example return value (contained in JSON):                 
126         *              [[externalAssayId:1, externalSampleId:A10_B, type:Glucose, unit:Insulin, value:202.0],
127         *               [externalAssayId:1, externalSampleId:A1_B, type:Insulin, unit:g, value:101.0]]
128     */
129    def getQueryResultWithOperator = {
130                def userQuery = params['query']
131                def operator  = params['operator']
132                def value     = params['value']
133                def dValue = value.toDouble()
134                def searchResult = querySearchable( userQuery )
135
136                def query = "from SimpleAssayMeasurement as m where m.type =:type AND m.value "
137                if( operator=="<" )      { query += " <:value " }
138                else if( operator==">" ) { query += " >:value " }
139                else                                 { query += " = :value " }
140
141                def measurements = []
142                searchResult.each{ result ->
143                        if( result.class == SimpleAssayMeasurementType ) {
144
145                                SimpleAssayMeasurement.findAll( query, [type:result,value:dValue] ).each {
146                                        measurements.add( it.getRestRepresentation() )
147                                }
148                        }
149                }
150
151                render measurements as JSON 
152    }
153
154
155
156
157
158
159
160    /**
161     * Gets measurement for value, return a list of Measurement value matching the querying keyword and value
162     * Uses Searchable plugin.
163     *
164     * @param measurement name
165     * @param value
166     * @return list of measurement values
167     */
168    def getMeasurementsForValue = {
169        try {
170                        render params
171            def measurementName = params.q.getAt(0)
172            def measurementValue = params.q.getAt(1)
173
174            for ( i in SimpleAssayMeasurement.list()){
175                if ( (i.assay.name.equals(measurementName))&&(i.value.equals(measurementValue.toFloat()))){
176                    measurementDataList.add(i)
177                }
178            }
179            render measurementDataList
180        } catch (SearchEngineQueryParseException ex) {
181            return [parseException: true]
182        }
183    }
184
185
186    /**
187     * Return a list of Measurement corresponding to the searched
188     * Measurement with the searched min and max values
189     * Uses Searchable plugin.
190     *
191     * @params measurement name
192     * @params min value
193     * @params max value
194     */
195    def getMeasurementsForRange = {
196        try {
197            def measurementName = params.q.getAt(0)
198            def measurementMinValue = params.q.getAt(1)
199            def measurementMaxValue = params.q.getAt(2)
200
201            for ( i in SimpleAssayMeasurement.list()){
202                if ( (i.assay.name.equals(measurementName))&&(i.value > measurementMinValue.toFloat() )
203                &&(i.value < measurementMaxValue.toFloat() )){
204                    measurementDataList.add(i)
205                }
206            }
207            render measurementDataList
208        } catch (SearchEngineQueryParseException ex) {
209            return [parseException: true]
210        }
211    }
212
213
214
215    /**
216     * Get a measurement for a given sample, return a list of all measurements
217     * that reference the given sample in the study.
218     *
219     * @param sample ID
220     * @return list of Measurements linked to the param
221     */
222
223    def getMeasurementsForSample = {
224    try {
225            def paramId = params.q
226            for ( i in SimpleAssay.list()){
227                if ( i.sampleID.equals(paramId) ){
228                    simpleAssayList.add(i)
229                }
230            }
231            render simpleAssayList
232        } catch (SearchEngineQueryParseException ex) {
233            return [parseException: true]
234        }
235    }
236
237
238    /**
239     * Return measurement value referencing a given measurement.
240     *
241     * @param measurement name
242     * @return list of measurement values
243     */
244    def getDataSimple = {
245         try {
246            def measurementName = params.q
247
248            for ( i in SimpleAssayMeasurement.list()){
249               if ( i.assay.name.equals(measurementName)){
250                   measurementDataList.add(i)
251               }
252            }
253            render measurementDataList
254        } catch (SearchEngineQueryParseException ex) {
255            return [parseException: true]
256        }
257    }
258
259    /**
260     * getDataForSample return the data relatives to a sample
261     * @param sample ID
262     * @return list of Measurements
263     */
264    def getDataForSample = {
265        try {
266            //change this value depending on the GET method
267            def sampleId = params.q
268                   
269            for ( i in SimpleAssay.list()){         
270               if ( i.sampleID.equals(sampleId)){
271                   measurementDataList.add(i.measurements)
272                 render i.measurements
273               }
274            }
275            render measurementDataList
276           
277        } catch (SearchEngineQueryParseException ex) {
278            return [parseException: true]
279        }
280    }
281
282
283    def getAvailableBiomarkers = {
284
285         try {
286            def measurementName = params.q
287            render measurementsList
288        } catch (SearchEngineQueryParseException ex) {
289            return [parseException: true]
290        }
291    }
292
293
294
295
296
297
298    /**  Launch a Searchable query and return its result object
299     *
300     *   @param  searchable query string, e.g. "Insulin"
301     *   @return Resulting searchable object
302     */
303    private Object querySearchable( query ) {
304                def searchResult = []
305                try {
306                        searchResult = searchableService.search( query )
307                        searchResult = searchResult['results']
308                }
309                catch( SearchEngineQueryParseException e) { println "SEQPE: " + e }
310                catch( Exception ex) {
311                        StringWriter sw = new StringWriter();
312                        ex.printStackTrace(new PrintWriter(sw));
313                        String stacktrace = sw.toString();
314                        System.out.println("stacktrace = " + stacktrace);
315                }
316                return searchResult
317    }
318
319
320
321    /**  For SimpleAssayMeasurement objects, collect their correpsonding externalAssayIDs
322     *   in a set (i.e., collection without double entries).
323     *   
324     *   @param  SimpleAssayMeasurement object
325     *   @return List of externalAssayIds corresponding to studies, which contain samples, which
326     *           use the given type.
327     */
328    private Object getAssaysForMeasurementType( type ) {
329                // unfortunately there seems to be no easy way to get the table name for a domain class?
330                // a method via the metaclass is mentioned here: http://taapps-javalibs.blogspot.com/2009/03/grailshow-to-get-database-table-and.html
331                // but if the names are changed, this has to be refactored inside this query
332                // Use 'select distinct a' to get a list of SimpleAssay objects instead of a list of ids
333                def assayQuery  = "select distinct a.externalAssayID from SimpleAssayMeasurement m, SimpleAssay a "
334                        assayQuery += "where m.type.id = ${type.id} and m.assay.id=a.id"
335                def assays = SimpleAssay.executeQuery(assayQuery)
336                return assays
337    }
338
339   
340
341    /** Collect studyIds and SimpleAssay domain objects related to the result of a
342     *  Searchable query.
343     *   
344     *   @param  queryResult: Searchable result (Map).
345     *   @return Map with one key that has a list as value. The key is 'assays'.
346     *           The list contains externalAssayIds of the assays that match the given query string.
347     *           Example of a returned map:  [ assays:[2,3] ].
348     */
349    private Map getResultingObjects( queryResult ) {
350                def results = [assays:[]]
351                queryResult.each { result ->
352                        switch( result ) {
353                                case { it instanceof data.SimpleAssayMeasurementType }:
354                                        def assays = getAssaysForMeasurementType(result)
355                                        results['assays'] = results['assays'].plus(assays)
356                                                break
357                                case { it instanceof data.SimpleAssay }:
358                                        results['assays'] = results['assays'].plus(result.id)
359                                        break
360                        }
361                }
362                return results
363    }
364
365
366
367}
368
Note: See TracBrowser for help on using the browser.