Changeset 1458 for trunk/grails-app


Ignore:
Timestamp:
Jan 31, 2011, 8:16:03 PM (10 years ago)
Author:
robert@…
Message:
  • Implemented a cache for module rest calls, to increase performance (see moduleCommunicationService)
  • Implemented searching in module data.
Location:
trunk/grails-app
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/query/AdvancedQueryController.groovy

    r1456 r1458  
    11package dbnp.query
     2import dbnp.modules.*
     3import org.dbnp.gdt.*
    24
    35// TODO: Make use of the searchable-plugin possibilities instead of querying the database directly
     
    911 */
    1012class AdvancedQueryController {
     13        def moduleCommunicationService;
     14       
    1115        def entitiesToSearchFor = [ 'Study': 'Studies', 'Sample': 'Samples']
    1216    def index = {
     
    5660                def fields = [:];
    5761               
     62                // Retrieve all local search fields
    5863                getEntities().each {
    5964                        def entity = getEntity( 'dbnp.studycapturing.' + it );
     
    6671                               
    6772                                fields[ it ] = fieldNames.sort { a, b -> a[0].toUpperCase() + a[1..-1] <=> b[0].toUpperCase() + b[1..-1] };
     73                        }
     74                }
     75               
     76                // Loop through all modules and check which fields are searchable
     77                // Right now, we just combine the results for different entities
     78                AssayModule.list().each { module ->
     79                        def callUrl = module.url + '/rest/getQueryableFields'
     80                        try {
     81                                def json = moduleCommunicationService.callModuleRestMethodJSON( module.url, callUrl );
     82                                def moduleFields = [];
     83                                entitiesToSearchFor.each { entity ->                                   
     84                                        if( json[ entity.key ] ) {
     85                                                json[ entity.key ].each { field ->
     86                                                        moduleFields << field.toString();
     87                                                }
     88                                        }
     89                                }
     90                               
     91                                // Remove 'module' from module name
     92                                def moduleName = module.name.replace( 'module', '' ).trim()
     93                               
     94                                fields[ moduleName ] = moduleFields.unique();
     95                        } catch( Exception e ) {
     96                                log.error( "Error while retrieving queryable fields from " + module.name + ": " + e.getMessage() )
    6897                        }
    6998                }
  • trunk/grails-app/services/dbnp/modules/ModuleCommunicationService.groovy

    r1455 r1458  
    2020
    2121class ModuleCommunicationService implements Serializable {
    22     boolean transactional = false
     22        boolean transactional = false
    2323        def authenticationService
    2424        def moduleNotificationService
    25        
    26     /**
    27      * Sends a notification to assay modules that some part of a study has changed.
    28      *
    29      * Only modules that have the notify flag set to true will be notified. They will be notified on the URL
    30      *
    31      * [moduleUrl]/rest/notifyStudyChange?studyToken=abc
    32      *
    33      * Errors that occur when calling this URL are ignored. The module itself is responsible of
    34      * maintaining a synchronized state.
    35      *
    36      * @param study
    37      * @return
    38      */
     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         */
    3950        def invalidateStudy( Study study ) {
    4051                moduleNotificationService.invalidateStudy( study );
    41     }
    42        
     52        }
     53
    4354        /**
    4455         * Checks whether a specific method on a module is reachable and returns a SC_OK response code.
     
    5566                try {
    5667                        return connection.responseCode == HttpServletResponse.SC_OK
    57                 } catch(e) { 
    58                         return false 
     68                } catch(e) {
     69                        return false
    5970                }
    6071        }
    61        
     72
    6273        /**
    6374         * Calls a rest method on a module
     
    6879         */
    6980        def callModuleRestMethodJSON( consumer, restUrl ) throws Exception {
    70                 // create a random session token that will be used to allow to module to
    71                 // sync with gscf prior to presenting the measurement data
    72                 def sessionToken = UUID.randomUUID().toString()
    73 
    7481                if (!authenticationService.isLoggedIn()) {
    7582                        // should not happen because we can only get here when a user is
     
    7784                        throw new Exception('User is not logged in.')
    7885                }
     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()
    7997
    8098                // put the session token to work
     
    90108                        url += '?sessionToken=' + sessionToken
    91109                }
    92                
     110
    93111                // Perform a call to the url
    94112                def restResponse
    95113                try {
    96114                        def textResponse = url.toURL().getText()
     115                        println "GSCF call to " + consumer + " URL: " + url
     116                        println "GSCF response: " + textResponse
    97117                        restResponse = JSON.parse( textResponse )
    98118                } catch (Exception e) {
     119                        storeErrorInCache( restUrl, e.getMessage() );
    99120                        throw new Exception( "An error occurred while fetching " + url + ".", e )
    100121                } finally {
     
    102123                        authenticationService.logOffRemotely(consumer, sessionToken)
    103124                }
     125
     126                // Store the response in cache
     127                storeInCache( restUrl, restResponse );
    104128               
    105129                return restResponse
    106130        }
     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
    107195}
  • trunk/grails-app/views/advancedQuery/sampleresults.gsp

    r1430 r1458  
    2727</p>
    2828
     29
    2930<g:if test="${search.getNumResults() > 0}">
    3031
     
    3233                <thead>
    3334                <tr>
    34                         <th colspan="2"></th>
    3535                        <th>Study</th>
    3636                        <th>Name</th>
  • trunk/grails-app/views/advancedQuery/studyresults.gsp

    r1430 r1458  
    2626        resulted in ${search.getNumResults()} <g:if test="${search.getNumResults() == 1}">study</g:if><g:else>studies</g:else>.
    2727</p>
    28 
    2928<g:if test="${search.getNumResults() > 0}">
    3029
  • trunk/grails-app/views/user/search.gsp

    r1430 r1458  
    6565        <g:if test='${searched}'>
    6666
    67 <%
    68 def queryParams = [username: username, enabled: enabled, accountExpired: accountExpired, accountLocked: accountLocked, passwordExpired: passwordExpired]
    69 %>
     67        <%
     68        def queryParams = [username: username, enabled: enabled, accountExpired: accountExpired, accountLocked: accountLocked, passwordExpired: passwordExpired]
     69        %>
    7070
    7171        <div class="list">
Note: See TracChangeset for help on using the changeset viewer.