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

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