root/trunk/grails-app/controllers/api/ApiController.groovy @ 2233

Revision 2233, 14.0 KB (checked in by work@…, 2 years ago)

debug getMeasurementDataForAssay issue where data has no sampleToken?

Line 
1/**
2 * Api Controler
3 *
4 * API for third party applications to interact
5 * with GSCF
6 *
7 * @author  Jeroen Wesbeek <work@osx.eu>
8 * @since       20120328
9 * @package api
10 *
11 * Revision information:
12 * $Rev$
13 * $Author$
14 * $Date$
15 */
16package api
17
18import grails.plugins.springsecurity.Secured
19import grails.converters.JSON
20import dbnp.studycapturing.Study
21import dbnp.studycapturing.Assay
22
23class ApiController {
24    def authenticationService
25    def apiService
26
27        /**
28         * index closure
29         */
30    def index = {
31        render(view:'index')
32    }
33
34    /**
35     * authenticate with the api using HTTP_BASIC authentication
36     *
37     * This means
38     * 1. the client should send the HTTP_BASIC authentication header
39     *    which is an md5 hash of the username + password concatenated:
40     *
41     *    Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
42     *
43     * 2. the user used to authenticate with the API should have
44     *    the ROLE_CLIENT role
45     *
46     * @param string deviceID
47     */
48    @Secured(['ROLE_CLIENT', 'ROLE_ADMIN'])
49    def authenticate = {
50        println "api::authenticate: ${params}"
51
52        // see if we already have a token on file for this device id
53        String deviceID = (params.containsKey('deviceID')) ? params.deviceID : ''
54        def token = Token.findByDeviceID(deviceID)
55       
56        // generate a new token if we don't have a token on file
57        def result = [:]
58        try {
59            // TODO - check if token belongs to current user?
60            if (!token) {
61                // generate a token for this device
62                token = new Token(
63                        deviceID    : params.deviceID,
64                        deviceToken : UUID.randomUUID().toString(),
65                        user        : authenticationService.getLoggedInUser(),
66                        sequence    : 0
67                ).save(failOnError: true)
68            }
69           
70            result = ['token':token.deviceToken,'sequence':token.sequence]
71
72            // set output headers
73            response.status = 200
74        } catch (Exception e) {
75            // caught an error
76            response.status = 500
77            result = ['error':e.getMessage()]
78        }
79
80        response.contentType = 'application/json;charset=UTF-8'
81
82        if (params.containsKey('callback')) {
83            render "${params.callback}(${result as JSON})"
84        } else {
85            render result as JSON
86        }
87    }
88
89    /**
90     * get all readable studies
91     *
92     * @param string deviceID
93     * @param string validation md5 sum
94     */
95    def getStudies = {
96        println "api::getStudies: ${params}"
97
98        String deviceID = (params.containsKey('deviceID')) ? params.deviceID : ''
99        String validation = (params.containsKey('validation')) ? params.validation : ''
100
101        // check
102        if (!apiService.validateRequest(deviceID,validation)) {
103            response.sendError(401, 'Unauthorized')
104        } else {
105            def user = Token.findByDeviceID(deviceID)?.user
106            def readableStudies = Study.giveReadableStudies(user)
107            def studies = []
108           
109            // iterate through studies and define resultset
110            readableStudies.each { study ->
111                // get result data
112                studies[ studies.size() ] = [
113                        'token'                 : study.getToken(),
114                        'title'                 : study.title,
115                        'description'           : study.description,
116                        'subjects'              : study.subjects.size(),
117                        'species'               : study.subjects.species.collect { it.name }.unique(),
118                        'assays'                : study.assays.collect { it.name }.unique(),
119                        'modules'               : study.assays.collect { it.module.name }.unique(),
120                        'events'                : study.events.size(),
121                        'uniqueEvents'          : study.events.collect { it.toString() }.unique(),
122                        'samplingEvents'        : study.samplingEvents.size(),
123                        'uniqueSamplingEvents'  : study.samplingEvents.collect { it.toString() }.unique(),
124                        'eventGroups'           : study.eventGroups.size(),
125                        'uniqueEventGroups'     : study.eventGroups.collect { it.name }.unique(),
126                        'samples'               : study.samples.size()
127                ]
128            }
129
130            def result = [
131                    'count'     : studies.size(),
132                    'studies'   : studies
133            ]
134
135            // set output headers
136            response.status = 200
137            response.contentType = 'application/json;charset=UTF-8'
138
139            if (params.containsKey('callback')) {
140                render "${params.callback}(${result as JSON})"
141            } else {
142                render result as JSON
143            }
144        }
145    }
146
147    /**
148     * get all subjects for a study
149     *
150     * @param string deviceID
151     * @param string studyToken
152     * @param string validation md5 sum
153     */
154    def getSubjectsForStudy = {
155        println "api::getSubjectsForStudy: ${params}"
156
157        // fetch study
158        String studyToken   = (params.containsKey('studyToken')) ? params.studyToken : ''
159        def study           = Study.findByStudyUUID(studyToken)
160
161        // wrap result in api call validator
162        apiService.executeApiCall(params,response,'study',study,{
163            def subjects = apiService.flattenDomainData( study.subjects )
164
165            // define result
166            def result = [
167                    'count'     : subjects.size(),
168                    'subjects'  : subjects
169            ]
170
171            // set output headers
172            response.status = 200
173            response.contentType = 'application/json;charset=UTF-8'
174
175            if (params.containsKey('callback')) {
176                render "${params.callback}(${result as JSON})"
177            } else {
178                render result as JSON
179            }
180        })
181    }
182
183    /**
184     * get all assays for a study
185     *
186     * @param string deviceID
187     * @param string studyToken
188     * @param string validation md5 sum
189     */
190    def getAssaysForStudy = {
191        println "api::getAssaysForStudy: ${params}"
192
193        // fetch study
194        String studyToken   = (params.containsKey('studyToken')) ? params.studyToken : ''
195        def study           = Study.findByStudyUUID(studyToken)
196
197        // wrap result in api call validator
198        apiService.executeApiCall(params,response,'study',study,{
199            def assays = apiService.flattenDomainData( study.assays )
200
201            // define result
202            def result = [
203                    'count'     : assays.size(),
204                    'assays'    : assays
205            ]
206
207            // set output headers
208            response.status = 200
209            response.contentType = 'application/json;charset=UTF-8'
210
211            if (params.containsKey('callback')) {
212                render "${params.callback}(${result as JSON})"
213            } else {
214                render result as JSON
215            }
216        })
217    }
218
219    /**
220     * get all eventGroups for a study
221     *
222     * @param string deviceID
223     * @param string studyToken
224     * @param string validation md5 sum
225     */
226    def getEventGroupsForStudy = {
227        println "api::getEventGroupsForStudy: ${params}"
228
229        // fetch study
230        String studyToken   = (params.containsKey('studyToken')) ? params.studyToken : ''
231        def study           = Study.findByStudyUUID(studyToken)
232
233        // wrap result in api call validator
234        apiService.executeApiCall(params,response,'study',study,{
235            def eventGroups = apiService.flattenDomainData( study.eventGroups )
236
237            // define result
238            def result = [
239                'count'         : eventGroups.size(),
240                'eventGroups'   : eventGroups
241            ]
242
243            // set output headers
244            response.status = 200
245            response.contentType = 'application/json;charset=UTF-8'
246
247            if (params.containsKey('callback')) {
248                render "${params.callback}(${result as JSON})"
249            } else {
250                render result as JSON
251            }
252        })
253    }
254
255    /**
256     * get all events for a study
257     *
258     * @param string deviceID
259     * @param string studyToken
260     * @param string validation md5 sum
261     */
262    def getEventsForStudy = {
263        println "api::getEventsForStudy: ${params}"
264
265        // fetch study
266        String studyToken   = (params.containsKey('studyToken')) ? params.studyToken : ''
267        def study           = Study.findByStudyUUID(studyToken)
268
269        // wrap result in api call validator
270        apiService.executeApiCall(params,response,'study',study,{
271            def events = apiService.flattenDomainData( study.events )
272
273            // define result
274            def result = [
275                'count' : events.size(),
276                'events': events
277            ]
278
279            // set output headers
280            response.status = 200
281            response.contentType = 'application/json;charset=UTF-8'
282
283            if (params.containsKey('callback')) {
284                render "${params.callback}(${result as JSON})"
285            } else {
286                render result as JSON
287            }
288        })
289    }
290
291    /**
292     * get all samplingEvents for a study
293     *
294     * @param string deviceID
295     * @param string studyToken
296     * @param string validation md5 sum
297     */
298    def getSamplingEventsForStudy = {
299        println "api::getSamplingEventsForStudy: ${params}"
300
301        // fetch study
302        String studyToken   = (params.containsKey('studyToken')) ? params.studyToken : ''
303        def study           = Study.findByStudyUUID(studyToken)
304
305        // wrap result in api call validator
306        apiService.executeApiCall(params,response,'study',study,{
307            def samplingEvents = apiService.flattenDomainData( study.samplingEvents )
308            println study.samplingEvents.dump()
309
310            // define result
311            def result = [
312                    'count'         : samplingEvents.size(),
313                    'samplingEvents': samplingEvents
314            ]
315
316            // set output headers
317            response.status = 200
318            response.contentType = 'application/json;charset=UTF-8'
319
320            if (params.containsKey('callback')) {
321                render "${params.callback}(${result as JSON})"
322            } else {
323                render result as JSON
324            }
325        })
326    }
327
328    /**
329     * get all samples for an assay
330     *
331     * @param string deviceID
332     * @param string assayToken
333     * @param string validation md5 sum
334     */
335    def getSamplesForAssay = {
336        println "api::getSamplesForAssay: ${params}"
337
338        // fetch assay
339        String assayToken   = (params.containsKey('assayToken')) ? params.assayToken : ''
340        def assay           = Assay.findByAssayUUID(assayToken)
341
342        // wrap result in api call validator
343        apiService.executeApiCall(params,response,'assay',assay,{
344            def samples = apiService.flattenDomainData( assay.samples )
345
346            // define result
347            def result = [
348                    'count'     : samples.size(),
349                    'samples'   : samples
350            ]
351
352            // set output headers
353            response.status = 200
354            response.contentType = 'application/json;charset=UTF-8'
355
356            if (params.containsKey('callback')) {
357                render "${params.callback}(${result as JSON})"
358            } else {
359                render result as JSON
360            }
361        })
362    }
363
364    /**
365     * get all measurement data from a linked module for an assay
366     *
367     * @param string deviceID
368     * @param string assayToken
369     * @param string validation md5 sum
370     */
371    def getMeasurementDataForAssay = {
372        println "api::getMeasurementDataForAssay: ${params}"
373
374        // fetch assay
375        String assayToken   = (params.containsKey('assayToken')) ? params.assayToken : ''
376        def assay           = Assay.findByAssayUUID(assayToken)
377
378        // fetch user based on deviceID
379        String deviceID     = (params.containsKey('deviceID')) ? params.deviceID : ''
380        def user            = Token.findByDeviceID(deviceID)?.user
381
382        // wrap result in api call validator
383        apiService.executeApiCall(params,response,'assay',assay,{
384            // define sample measurement data matrix
385            def matrix = [:]
386            def measurementData = apiService.getMeasurementData(assay, user).toArray()
387            //def measurementMetaData = apiService.getMeasurementData(assay, user)
388
389            // iterate through measurementData and build data matrix
390            try {
391                measurementData.each { data ->
392                    try {
393                        if (!matrix.containsKey(data.sampleToken)) matrix[data.sampleToken] = [:]
394                        matrix[data.sampleToken][data.measurementToken] = data.value
395                    } catch (Exception e) {
396                        // it seems that some measurement data does not contain a sample token?
397                        println "getMeasurementDataForAssay error for data of assay '${assay.name}' (token ${assayToken}): ${e.getMessage()}"
398                        println data.dump()
399                    }
400                }
401
402                // define result
403                def result = [:]
404                result = [
405                    'measurements'  : matrix
406                ]
407
408                // set output headers
409                response.status = 200
410                response.contentType = 'application/json;charset=UTF-8'
411
412                if (params.containsKey('callback')) {
413                    render "${params.callback}(${result as JSON})"
414                } else {
415                    render result as JSON
416                }
417            } catch (Exception e) {
418                println "getMeasurementDataForAssay exception: ${e.getMessage()}"
419                response.sendError(500, "module '${assay.module}' does not properly implement getMeasurementData REST specification (${e.getMessage()})")
420            }
421        })
422    }
423}
Note: See TracBrowser for help on using the browser.