root/trunk/grails-app/services/api/ApiService.groovy @ 2210

Revision 2210, 6.9 KB (checked in by work@…, 2 years ago)

- improved api service

Line 
1/**
2 * ApiService Service
3 *
4 * Description of my service
5 *
6 * @author  Jeroen Wesbeek <work@osx.eu>
7 * @since       20120328
8 * @package     api
9 *
10 * Revision information:
11 * $Rev: 1430 $
12 * $Author: work@osx.eu $
13 * $Date: 2011-01-21 21:05:36 +0100 (Fri, 21 Jan 2011) $
14 */
15package api
16
17import java.security.MessageDigest
18import dbnp.studycapturing.Assay
19import dbnp.authentication.SecUser
20import grails.converters.JSON
21import org.dbnp.gdt.TemplateEntity
22
23class ApiService implements Serializable {
24    // inject the module communication service
25    def moduleCommunicationService
26
27    // the shared secret used to validate api calls
28    static final String API_SECRET = "th!s_sH0uld^Pr0bab7y_m0v3_t%_th3_uSeR_d0Ma!n_ins7ead!"
29
30    // transactional
31    static transactional = false
32
33    // characters to split on when converting a string to camelCased format
34    static camelCaseSeperators = " |-|_"
35
36    // hasMany keys to ignore when flattening domain data
37    static ignoreHasManyKeys = [
38            "systemFields",
39            "templateBooleanFields",
40            "templateDateFields",
41            "templateDoubleFields",
42            "templateExtendableStringListFields",
43            "templateFileFields",
44            "templateLongFields",
45            "templateModuleFields",
46            "templateTermFields",
47            "templateRelTimeFields",
48            "templateStringFields",
49            "templateStringListFields",
50            "templateTemplateFields",
51            "templateTextFields"
52    ]
53
54    /**
55     * validate a client request by checking the validation checksum
56     * @param deviceID
57     * @param validation
58     * @return
59     */
60    def validateRequest(String deviceID, String validation) {
61        // disable validation check on development and ci
62        if (['development', 'ci'].contains(grails.util.GrailsUtil.environment)) {
63            return true
64        }
65
66        // get token for this device ID
67        Token token = Token.findByDeviceID(deviceID)
68
69        // increase sequence
70        if (token) {
71            token.sequence = token.sequence+1
72            token.save()
73
74            // generate the validation checksum
75            MessageDigest digest = MessageDigest.getInstance("MD5")
76            String validationSum = new BigInteger(1,digest.digest("${token.deviceToken}${token.sequence}${API_SECRET}".getBytes())).toString(16).padLeft(32,"0")
77
78            // check if the validation confirms
79            return (validation == validationSum)
80        } else {
81            // no such token, re-authenticate
82            return false
83        }
84    }
85
86    /**
87     * flatten domain data to relevant data to return in an api
88     * call and not to expose domain internals
89     *
90     * @param elements (List or Set)
91     * @return
92     */
93    def flattenDomainData(elements) {
94        def items = []
95
96        // iterate through elements
97        elements.each {
98            def fields  = it.giveFields()
99            def item    = [:]
100
101            // add token
102            if (it.respondsTo('getToken')) {
103                // some domain methods implement getToken...
104                item['token'] = it.getToken()
105            } else if (it.respondsTo('giveUUID')) {
106                // ...while others implement giveUUID
107                item['token'] = it.giveUUID()
108            } else {
109                // and others don't at all, so far
110                // the consistency...
111                item['id'] = it.id
112            }
113
114            // add subject field values
115            fields.each { field ->
116                // get a camelCased version of the field name
117                def name = field.name.split(camelCaseSeperators).collect {it[0].toUpperCase() + it.substring(1)}.join('')
118                    name = name[0].toLowerCase() + name.substring(1)
119
120                // get the value for this field
121                def value = it.getFieldValue( field.name )
122
123                // add value
124                if (value.hasProperty('name')) {
125                    item[ name ] = value.name
126                } else {
127                    item[ name ] = value
128                }
129            }
130
131            // list hasMany sizes
132            it.properties.hasMany.each { hasManyItem ->
133                if (!ignoreHasManyKeys.contains(hasManyItem.key)) {
134                    // add count for this hasMany item
135                    item[ hasManyItem.key ] = it[ hasManyItem.key ].size()
136                }
137            }
138
139            // add item to resultset
140            items[ items.size() ] = item
141        }
142
143        return items
144    }
145
146    /**
147     * get the measurement tokens from the remote module
148     *
149     * @param assay
150     * @param user
151     * @return
152     */
153    def getMeasurements(Assay assay, SecUser user) {
154        def serviceURL = "${assay.module.url}/rest/getMeasurements"
155        def serviceArguments = "assayToken=${assay.assayUUID}"
156        def json
157
158        // call module method
159        try {
160            json = moduleCommunicationService.callModuleMethod(
161                    assay.module.url,
162                    serviceURL,
163                    serviceArguments,
164                    "POST",
165                    user
166            );
167        } catch (Exception e) {
168            log.error "api.getMeasurements failed :: ${e.getMessage()}"
169            json = new org.codehaus.groovy.grails.web.json.JSONArray()
170        }
171
172        return json
173    }
174
175    /**
176     * get measurement data from the remote module in verbose format
177     *
178     * @param assay
179     * @param user
180     * @return
181     */
182    def getMeasurementData(Assay assay, SecUser user) {
183        def serviceURL = "${assay.module.url}/rest/getMeasurementData"
184        def serviceArguments = "assayToken=${assay.assayUUID}&verbose=true"
185        def json
186
187        // call module method
188        try {
189            json = moduleCommunicationService.callModuleMethod(
190                    assay.module.url,
191                    serviceURL,
192                    serviceArguments,
193                    "POST",
194                    user
195            );
196        } catch (Exception e) {
197            log.error "api.getMeasurementData failed :: ${e.getMessage()}"
198            json = new org.codehaus.groovy.grails.web.json.JSONArray()
199        }
200
201        return json
202    }
203
204    /**
205     * get the measurement meta data from the remote module
206     *
207     * @param assay
208     * @param user
209     * @return
210     */
211    def getMeasurementMetaData(Assay assay, SecUser user) {
212        def serviceURL = "${assay.module.url}/rest/getMeasurementMetaData"
213        def serviceArguments = "assayToken=${assay.assayUUID}"
214        def json
215
216        // call module method
217        try {
218            json = moduleCommunicationService.callModuleMethod(
219                    assay.module.url,
220                    serviceURL,
221                    serviceArguments,
222                    "POST",
223                    user
224            );
225        } catch (Exception e) {
226            log.error "api.getMeasurementMetaData failed :: ${e.getMessage()}"
227            json = new org.codehaus.groovy.grails.web.json.JSONArray()
228        }
229
230        return json
231    }
232}
Note: See TracBrowser for help on using the browser.