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

Last change on this file was 2120, checked in by s.h.sikkema@…, 11 years ago

# GDT

  • fixed issue where dynamically populated template select boxes would open pop-up on wrong option
  • gdt version 0.1.9

# GDT Importer

  • fixed bug in gdtImporter where importer would hang when first choosing sample as data type and then changing to some other data type to import
  • when there are errors in the import, table editor is now always enabled (can be really slow still!)
  • changed text message under data preview
  • fixed bug where going from page 2 to 1 would show all rows instead of just 5
  • replaced "Please make any adjustments if required" with "The following data will be imported" when user can't change anything
  • removed space between import preview and next button
  • gdtImporter version 0.4.6.7

# GSCF

  • now includes sampletokens when retrieving assay data from modules to ensure match between data and samples (was mixed up!)
  • Property svn:keywords set to Rev Author Date
File size: 7.7 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: 2120 $
12 * $Author: work@osx.eu $
13 * $Date: 2011-11-25 14:36:45 +0000 (vr, 25 nov 2011) $
14 */
15package dbnp.modules
16
17import grails.converters.*
18import javax.servlet.http.HttpServletResponse
19import org.codehaus.groovy.grails.commons.ConfigurationHolder
20import org.hibernate.*
21import dbnp.authentication.SecUser;
22
23class ModuleCommunicationService implements Serializable {
24        static transactional = false
25        def authenticationService
26        def moduleNotificationService
27        SessionFactory sessionFactory
28       
29        /**
30         * Cache containing the contents of different URLs. These urls are
31         * saved per user, since the data could be different for different users.
32         */
33        def cache = [:]
34
35        /**
36         * Number of seconds to save the data in cache
37         */
38        def numberOfSecondsInCache = ConfigurationHolder.config.modules.cacheDuration ? Integer.valueOf( ConfigurationHolder.config.modules.cacheDuration.toString() ) : 300;
39
40        /**
41         * Sends a notification to assay modules that some part of a study has changed.
42         *
43         * Only modules that have the notify flag set to true will be notified. They will be notified on the URL
44         *
45         * [moduleUrl]/rest/notifyStudyChange?studyToken=abc
46         *
47         * Errors that occur when calling this URL are ignored. The module itself is responsible of
48         * maintaining a synchronized state.
49         *
50         * @param study
51         * @return
52         */
53        def invalidateStudy( def study ) {
54                moduleNotificationService.invalidateStudy( study );
55        }
56
57        /**
58         * Checks whether a specific method on a module is reachable and returns a SC_OK response code.
59         *
60         * This method will return false if a method returns an error (including 403 and 401 errors) or
61         * a redirect
62         *
63         * @param moduleUrl             URL of the module
64         * @param path                  Path of the rest method on that module. If omitted, the module reachablility itself is tested
65         * @return                              True if the module is reachable, false otherwise
66         */
67        def isModuleReachable(moduleUrl, path = "") {
68                def connection = ( moduleUrl + path ).toURL().openConnection()
69                try {
70                        return connection.responseCode == HttpServletResponse.SC_OK
71                } catch(e) {
72                        return false
73                }
74        }
75
76    /**
77         * Calls a rest method on a module
78         *
79         * @param consumer      Consumer of that specific module
80         * @param restUrl       Full URL for the method to call
81         * @return                      JSON    JSON object of the parsed text
82         * @deprecated          Use callModuleMethod instead
83         */
84        def callModuleRestMethodJSON( consumer, restUrl ) throws Exception {
85                def parts = restUrl.split( /\?/ );
86                def url = "";
87                def query = "";
88               
89                if( parts.size() > 1 ) {
90                        url = parts[ 0 ]
91                        query = parts[ 1 ]
92                } else if( parts.size() > 0 ) { 
93                        url = parts[ 0 ];
94                }
95               
96                return callModuleMethod( consumer, url, query );
97        }
98       
99        /**
100        * Calls a rest method on a module
101        *
102        * @param consumer       Consumer of that specific module
103        * @param restUrl        Full URL for the method to call, without query string
104        * @param args           Query string for the url to call (e.q. token=abc&field=xyz)
105        * @param requestMethod  GET or POST - HTTP request method to use
106        * @return                       JSON    JSON object of the parsed text
107        */
108        def callModuleMethod( String consumer, String restUrl, String args = null, String requestMethod = "GET", SecUser remoteUser = null) {
109                if (!remoteUser && !authenticationService.isLoggedIn()) {
110                        // should not happen because we can only get here when a user is
111                        // logged in...
112                        throw new Exception('User is not logged in.')
113                }
114
115                // Check whether the url is present in cache
116                def cacheData = retrieveFromCache( restUrl, args );
117                if( cacheData && cacheData[ "success" ] )
118                        return cacheData[ "contents" ];
119                else if( cacheData && !cacheData[ "success" ] )
120                        throw new Exception( "Error while fetching data from " + restUrl + " (from cache): " + cacheData[ "error" ] )
121
122                // create a random session token that will be used to allow to module to
123                // sync with gscf prior to presenting the measurement data
124                def sessionToken = UUID.randomUUID().toString()
125
126                // put the session token to work
127                authenticationService.logInRemotely( consumer, sessionToken, remoteUser ?: authenticationService.getLoggedInUser())
128
129                // Append the sessionToken to the parameters
130                if( !args ) {
131                        args = ""
132                } else {
133                        args += "&"
134                }
135               
136                args += "sessionToken=" + sessionToken
137               
138                // Perform a call to the url
139                def restResponse
140                try {
141                        log.trace "GSCF call (" + requestMethod + ") to " + consumer + " URL: " + restUrl + " (args: " + args + ")"
142
143                        def textResponse
144                        switch( requestMethod.toUpperCase() ) {
145                                case "GET":
146                                        log.trace( "Using GET method" );
147                                        def url = restUrl + "?" + args;
148                                        def connection = url.toURL().openConnection();
149               
150                                        textResponse = url.toURL().getText()
151                               
152                                        break
153                                case "POST":
154                                        log.trace( "Using POST method" );
155                                        def connection = restUrl.toURL().openConnection()
156                                        connection.setRequestMethod( "POST" );
157                                        connection.doOutput = true
158                                       
159                                        def writer = new OutputStreamWriter( connection.outputStream )
160                                        writer.write( args );
161                                        writer.flush()
162                                        writer.close()
163                                       
164                                        connection.connect();
165                                       
166                                        textResponse = connection.content.text
167
168                                        break
169                                default:
170                                        throw new Exception( "Unknown request method given. Use GET or POST" )
171                        }
172
173                        log.trace "GSCF response: " + textResponse
174                        restResponse = JSON.parse( textResponse )
175                } catch (Exception e) {
176                        storeErrorInCache( restUrl, e.getMessage(), args );
177                        throw new Exception( "An error occurred while fetching " + restUrl + ".", e )
178                } finally {
179                        // Dispose of the ephemeral session token
180                        authenticationService.logOffRemotely(consumer, sessionToken)
181                }
182
183                // Store the response in cache
184                storeInCache( restUrl, restResponse, args );
185
186                return restResponse
187
188        }
189       
190        /**
191         * Checks whether a specific url exists in cache
192         * @param url   URL to call
193         * @return              true if the url is present in cache
194         */
195        def existsInCache( url, args = null ) {
196                return retrieveFromCache( url, args ) == null;
197        }
198
199        /**
200         * Retrieves the contents of a specific URL from cache
201         * @param url   URL to call
202         * @return              JSON object with the contents of the URL or null if the url doesn't exist in cache
203         */
204        def retrieveFromCache( url, args = null ) {
205                def user = authenticationService.getLoggedInUser();
206                def userId = user ? user.id : -1;
207
208                url = cacheUrl( url, args )
209               
210                if( cache[ userId ] && cache[ userId ][ url ] && ( System.currentTimeMillis() - cache[ userId ][ url ][ "timestamp" ] ) < numberOfSecondsInCache * 1000 ) {
211                        return cache[ userId ][ url ];
212                } else {
213                        return null;
214                }
215        }
216
217        /**
218         * Store the retrieved contents from a url in cache
219         * @param url           URL that has been called
220         * @param contents      Contents of the URL
221         */
222        def storeInCache( url, contents, args = null ) {
223                def user = authenticationService.getLoggedInUser();
224                def userId = user ? user.id : -1;
225
226                if( !cache[ userId ] )
227                        cache[ userId ] = [:]
228
229                cache[ userId ][ cacheUrl( url, args ) ] = [
230                        "timestamp": System.currentTimeMillis(),
231                        "success": true,
232                        "contents": contents
233                ];
234        }
235       
236        /**
237        * Store the retrieved error from a url in cache
238        * @param url            URL that has been called
239        * @param contents       Contents of the URL
240        */
241   def storeErrorInCache( url, error, args = null ) {
242           def user = authenticationService.getLoggedInUser();
243           def userId = user ? user.id : -1;
244
245           if( !cache[ userId ] )
246                   cache[ userId ] = [:]
247
248           cache[ userId ][ cacheUrl( url, args ) ] = [
249                   "timestamp": System.currentTimeMillis(),
250                   "success": false,
251                   "error": error
252           ];
253   }
254   
255   /**
256    * Url used to save data in cache
257    */
258   def cacheUrl( url, args = null ) {
259                if( args ) {
260                        // Remove sessionToken from args
261                        args = args;
262                        def sessionFound = ( args =~ /sessionToken=[^&]/ );
263                        args = sessionFound.replaceAll( "sessionToken=" );
264                       
265                        url += '?' + args
266                }
267                       
268                return url;
269   }
270
271}
Note: See TracBrowser for help on using the repository browser.