source: trunk/grails-app/services/dbnp/modules/ModuleCommunicationService.groovy @ 1458

Last change on this file since 1458 was 1458, checked in by robert@…, 10 years ago
  • Implemented a cache for module rest calls, to increase performance (see moduleCommunicationService)
  • Implemented searching in module data.
  • Property svn:keywords set to Rev Author Date
File size: 5.5 KB
Line 
1/**
2 * SynchronizationService Service
3 *
4 * Description of my service
5 *
6 * @author  your email (+name?)
7 * @since       2010mmdd
8 * @package     ???
9 *
10 * Revision information:
11 * $Rev: 1458 $
12 * $Author: robert@isdat.nl $
13 * $Date: 2011-01-31 19:16:03 +0000 (ma, 31 jan 2011) $
14 */
15package dbnp.modules
16
17import dbnp.studycapturing.*
18import grails.converters.*
19import javax.servlet.http.HttpServletResponse
20
21class ModuleCommunicationService implements Serializable {
22        boolean transactional = false
23        def authenticationService
24        def moduleNotificationService
25
26        /**
27         * Cache containing the contents of different URLs. These urls are
28         * saved per user, since the data could be different for different users.
29         */
30        def cache = [:]
31
32        /**
33         * Number of seconds to save the data in cache
34         */
35        def numberOfSecondsInCache = 10 * 60;
36
37        /**
38         * Sends a notification to assay modules that some part of a study has changed.
39         *
40         * Only modules that have the notify flag set to true will be notified. They will be notified on the URL
41         *
42         * [moduleUrl]/rest/notifyStudyChange?studyToken=abc
43         *
44         * Errors that occur when calling this URL are ignored. The module itself is responsible of
45         * maintaining a synchronized state.
46         *
47         * @param study
48         * @return
49         */
50        def invalidateStudy( Study study ) {
51                moduleNotificationService.invalidateStudy( study );
52        }
53
54        /**
55         * Checks whether a specific method on a module is reachable and returns a SC_OK response code.
56         *
57         * This method will return false if a method returns an error (including 403 and 401 errors) or
58         * a redirect
59         *
60         * @param moduleUrl             URL of the module
61         * @param path                  Path of the rest method on that module. If omitted, the module reachablility itself is tested
62         * @return                              True if the module is reachable, false otherwise
63         */
64        def isModuleReachable(moduleUrl, path = "") {
65                def connection = ( moduleUrl + path ).toURL().openConnection()
66                try {
67                        return connection.responseCode == HttpServletResponse.SC_OK
68                } catch(e) {
69                        return false
70                }
71        }
72
73        /**
74         * Calls a rest method on a module
75         *
76         * @param consumer      Consumer of that specific module
77         * @param restUrl       Full URL for the method to call
78         * @return                      JSON    JSON object of the parsed text
79         */
80        def callModuleRestMethodJSON( consumer, restUrl ) throws Exception {
81                if (!authenticationService.isLoggedIn()) {
82                        // should not happen because we can only get here when a user is
83                        // logged in...
84                        throw new Exception('User is not logged in.')
85                }
86
87                // Check whether the url is present in cache
88                def cacheData = retrieveFromCache( restUrl );
89                if( cacheData && cacheData[ "success" ] )
90                        return cacheData[ "contents" ];
91                else if( cacheData && !cacheData[ "success" ] )
92                        throw new Exception( "Error while fetching data from " + restUrl + " (from cache): " + cacheData[ "error" ] )
93
94                // create a random session token that will be used to allow to module to
95                // sync with gscf prior to presenting the measurement data
96                def sessionToken = UUID.randomUUID().toString()
97
98                // put the session token to work
99                authenticationService.logInRemotely( consumer, sessionToken, authenticationService.getLoggedInUser() )
100
101                // Append the sessionToken to the URL
102                def url = restUrl
103                if( restUrl.indexOf( '?' ) > 0 ) {
104                        // The url itself also has parameters
105                        url += '&sessionToken=' + sessionToken
106                } else {
107                        // The url itself doesn't have parameters
108                        url += '?sessionToken=' + sessionToken
109                }
110
111                // Perform a call to the url
112                def restResponse
113                try {
114                        def textResponse = url.toURL().getText()
115                        println "GSCF call to " + consumer + " URL: " + url
116                        println "GSCF response: " + textResponse
117                        restResponse = JSON.parse( textResponse )
118                } catch (Exception e) {
119                        storeErrorInCache( restUrl, e.getMessage() );
120                        throw new Exception( "An error occurred while fetching " + url + ".", e )
121                } finally {
122                        // Dispose of the ephemeral session token
123                        authenticationService.logOffRemotely(consumer, sessionToken)
124                }
125
126                // Store the response in cache
127                storeInCache( restUrl, restResponse );
128               
129                return restResponse
130        }
131
132        /**
133         * Checks whether a specific url exists in cache
134         * @param url   URL to call
135         * @return              true if the url is present in cache
136         */
137        def existsInCache( url ) {
138                return retrieveFromCache( url ) == null;
139        }
140
141        /**
142         * Retrieves the contents of a specific URL from cache
143         * @param url   URL to call
144         * @return              JSON object with the contents of the URL or null if the url doesn't exist in cache
145         */
146        def retrieveFromCache( url ) {
147                def user = authenticationService.getLoggedInUser();
148                def userId = user ? user.id : -1;
149
150                if( cache[ userId ] && cache[ userId ][ url ] && ( System.currentTimeMillis() - cache[ userId ][ url ][ "timestamp" ] ) < numberOfSecondsInCache * 1000 ) {
151                        return cache[ userId ][ url ];
152                } else {
153                        return null;
154                }
155        }
156
157        /**
158         * Store the retrieved contents from a url in cache
159         * @param url           URL that has been called
160         * @param contents      Contents of the URL
161         */
162        def storeInCache( url, contents ) {
163                def user = authenticationService.getLoggedInUser();
164                def userId = user ? user.id : -1;
165
166                if( !cache[ userId ] )
167                        cache[ userId ] = [:]
168
169                cache[ userId ][ url ] = [
170                        "timestamp": System.currentTimeMillis(),
171                        "success": true,
172                        "contents": contents
173                ];
174        }
175       
176        /**
177        * Store the retrieved error from a url in cache
178        * @param url            URL that has been called
179        * @param contents       Contents of the URL
180        */
181   def storeErrorInCache( url, error ) {
182           def user = authenticationService.getLoggedInUser();
183           def userId = user ? user.id : -1;
184
185           if( !cache[ userId ] )
186                   cache[ userId ] = [:]
187
188           cache[ userId ][ url ] = [
189                   "timestamp": System.currentTimeMillis(),
190                   "success": false,
191                   "error": error
192           ];
193   }
194
195}
Note: See TracBrowser for help on using the repository browser.