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

Last change on this file since 1577 was 1577, checked in by robert@…, 12 years ago

Resolved problems with module communication

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