Changeset 1993


Ignore:
Timestamp:
Sep 5, 2011, 1:13:22 PM (12 years ago)
Author:
taco@…
Message:

Improved visualization controller. Added some error handling.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/visualization/VisualizeController.groovy

    r1991 r1993  
    4545                        studies = input_object.get('studies').id
    4646                } catch(Exception e) {
    47                         // TODO: properly handle this exception
    48                         println e
     47                        returnError(400, "An error occured while retrieving the user input.")
     48            log.error("VisualizationController: getFields: "+e)
    4949                }
    5050
     
    7070                        fields += getFields(study, "samples", "domainfields")
    7171
    72                         /*
    73                          Gather fields related to this study from modules.
    74                          This will use the getMeasurements RESTful service. That service returns measurement types, AKA features.
    75                          It does not actually return measurements (the getMeasurementData call does).
    76                          The getFields method (or rather, the getMeasurements service) requires one or more assays and will return all measurement
    77                          types related to these assays.
    78                          So, the required variables for such a call are:
    79                          - a source variable, which can be obtained from AssayModule.list() (use the 'name' field)
    80                          - a list of assays, which can be obtained with study.getAssays()
    81                          */
    82                         AssayModule.list().each { module ->
    83                                 def list = []
    84                                 list = getFields(module.name, study.getAssays())
    85                                 if(list!=null){
    86                                         if(list.size()!=0){
    87                                                 fields += list
    88                                         }
    89                                 }
    90                         }
     72            /*
     73            Gather fields related to this study from modules.
     74            This will use the getMeasurements RESTful service. That service returns measurement types, AKA features.
     75            It does not actually return measurements (the getMeasurementData call does).
     76            The getFields method (or rather, the getMeasurements service) requires one or more assays and will return all measurement
     77            types related to these assays.
     78            So, the required variables for such a call are:
     79              - a source variable, which can be obtained from AssayModule.list() (use the 'name' field)
     80              - an assay, which can be obtained with study.getAssays()
     81             */
     82
     83            study.getAssays().each { assay ->
     84                def list = []
     85                list = getFields(assay.module.id, assay)
     86                if(list!=null){
     87                    if(list.size()!=0){
     88                        fields += list
     89
     90                    }
     91                }
     92            }
    9193
    9294                        // TODO: Maybe we should add study's own fields
     
    101103        }
    102104
    103         def getFields(source, assays){
    104                 /*
    105                  Gather fields related to this study from modules.
    106                  This will use the getMeasurements RESTful service. That service returns measurement types, AKA features.
    107                  It does not actually return measurements (the getMeasurementData call does).
    108                  The getFields method (or rather, the getMeasurements service) requires one or more assays and will return all measurement
    109                  types related to these assays.
    110                  So, the required variables for such a call are:
    111                  - a source variable, which can be obtained from AssayModule.list() (use the 'name' field)
    112                  - a list of assays, which can be obtained with study.getAssays()
    113                  */
    114                 def collection = []
    115                 def callUrl = ""
    116 
    117                 // Making a different call for each assay
    118                 // TODO: Change this to one call that requests fields for all assays, when you get that to work (in all cases)
    119                 assays.each { assay ->
    120                         def urlVars = "assayToken="+assay.assayUUID
    121                         AssayModule.list().each { module ->
    122                                 if(source==module.name){
    123                                         try {
    124                                                 callUrl = module.url + "/rest/getMeasurements/query?"+urlVars
    125                                                 def json = moduleCommunicationService.callModuleRestMethodJSON( module.url, callUrl );
    126                                                 json.each{ jason ->
    127                                                         collection.add(jason)
    128                                                 }
    129                                         } catch(Exception e){
    130                                                 // Todo: properly handle this exception
    131                                                 println "No success with\n\t"+callUrl+"\n"+e
    132                                                 return null
    133                                         }
    134                                 }
    135                         }
    136                 }
    137 
    138                 def fields = []
    139                 // Formatting the data
    140                 collection.each { field ->
    141                         fields << [ "id": createFieldId( name: field, source: source, type: "feature" ), "source": source, "category": "feature", "name": source+" feature "+field ]
    142                 }
    143                 return fields
    144         }
    145 
    146         def getFields(study, category, type){
    147                 /*
    148                  Gather fields related to this study from GSCF.
    149                  This requires:
    150                  - a study.
    151                  - a category variable, e.g. "events".
    152                  - a type variable, either "domainfields" or "templatefields".
    153                  */
    154 
    155                 // Collecting the data from it's source
    156                 def collection
    157                 def fields = []
    158                 def source = "GSCF"
    159 
    160                 // Gathering the data
    161                 if(category=="subjects"){
    162                         if(type=="domainfields"){
    163                                 collection = Subject.giveDomainFields()
    164                         }
    165                         if(type=="templatefields"){
    166                                 collection = study.giveSubjectTemplates().fields
    167                         }
    168                 }
    169                 if(category=="events"){
    170                         if(type=="domainfields"){
    171                                 collection = Event.giveDomainFields()
    172                         }
    173                         if(type=="templatefields"){
    174                                 collection = study.giveEventTemplates().fields
    175                         }
    176                 }
    177                 if(category=="samplingEvents"){
    178                         if(type=="domainfields"){
    179                                 collection = SamplingEvent.giveDomainFields()
    180                         }
    181                         if(type=="templatefields"){
    182                                 collection = study.giveSamplingEventTemplates().fields
    183                         }
    184                 }
    185                 if(category=="samples"){
    186                         if(type=="domainfields"){
    187                                 collection = Sample.giveDomainFields()
    188                         }
    189                         if(type=="templatefields"){
    190                                 collection = study.giveEventTemplates().fields
    191                         }
    192                 }
    193                 if(category=="assays"){
    194                         if(type=="domainfields"){
    195                                 collection = Event.giveDomainFields()
    196                         }
    197                         if(type=="templatefields"){
    198                                 collection = study.giveEventTemplates().fields
    199                         }
    200                 }
    201 
    202                 // Formatting the data
    203                 if(type=="domainfields"){
    204                         collection.each { field ->
    205                                 fields << [ "id": createFieldId( name: field.name, source: source, type: category ), "source": source, "category": category, "name": category.capitalize()+" "+field.name ]
    206                         }
    207                 }
    208                 if(type=="templatefields"){
    209                         collection.each { field ->
    210                                 for(int i = 0; i < field.size(); i++){
    211                                         fields << [ "id": createFieldId( id: field[i].id, name: field[i].name, source: source, type: category ), "source": source, "category": category, "name": category.capitalize()+" "+field[i].name ]
    212                                 }
    213                         }
    214                 }
    215 
    216                 return fields
    217         }
     105    def getFields(source, assay){
     106        /*
     107        Gather fields related to this study from modules.
     108        This will use the getMeasurements RESTful service. That service returns measurement types, AKA features.
     109        getMeasurements does not actually return measurements (the getMeasurementData call does).
     110        The getFields method (or rather, the getMeasurements service) requires one or more assays and will return all measurement
     111        types related to these assays.
     112        So, the required variables for such a call are:
     113          - a source variable, which can be obtained from AssayModule.list() (use the 'name' field)
     114          - a list of assays, which can be obtained with study.getAssays()
     115
     116        Output is a list of items. Each item contains
     117          - an 'id'
     118          - a 'source', which is a module identifier
     119          - a 'category', which indicates where the field can be found. When dealing with module data as we are here, this is the assay name(s)
     120          - a 'name', which is the the name of the field
     121         */
     122        def fields = []
     123        def callUrl = ""
     124
     125        // Making a different call for each assay
     126        // TODO: Change this to one call that requests fields for all assays, when you get that to work (in all cases)
     127
     128        def urlVars = "assayToken="+assay.assayUUID
     129        try {
     130            callUrl = ""+assay.module.url + "/rest/getMeasurements/query?"+urlVars
     131            def json = moduleCommunicationService.callModuleRestMethodJSON( assay.module.url /* consumer */, callUrl );
     132            def collection = []
     133            json.each{ jason ->
     134                collection.add(jason)
     135            }
     136            // Formatting the data
     137            collection.each { field ->
     138                // For getting this field from this assay
     139                fields << [ "id": createFieldId( id: field, name: field, source: assay.id, type: ""+assay.name), "source": source, "category": ""+assay.name, "name": field ]
     140            }
     141        } catch(Exception e){
     142            returnError(404, "An error occured while trying to collect field data from a module. Most likely, this module is offline.")
     143            log.error("VisualizationController: getFields: "+e)
     144        }
     145
     146        return fields
     147    }
     148
     149   def getFields(study, category, type){
     150        /*
     151        Gather fields related to this study from GSCF.
     152        This requires:
     153          - a study.
     154          - a category variable, e.g. "events".
     155          - a type variable, either "domainfields" or "templatefields".
     156
     157        Output is a list of items, which are formatted by the formatGSCFFields function.
     158        */
     159
     160        // Collecting the data from it's source
     161        def collection
     162        def fields = []
     163        def source = "GSCF"
     164
     165        // Gathering the data
     166        if(category=="subjects"){
     167            if(type=="domainfields"){
     168                collection = Subject.giveDomainFields()
     169            }
     170            if(type=="templatefields"){
     171                collection = study?.samples?.parentSubject?.template?.fields
     172            }
     173        }
     174        if(category=="events"){
     175            if(type=="domainfields"){
     176                collection = Event.giveDomainFields()
     177            }
     178            if(type=="templatefields"){
     179                collection = study?.samples?.parentEventGroup?.events?.template?.fields
     180            }
     181        }
     182        if(category=="samplingEvents"){
     183            if(type=="domainfields"){
     184                collection = SamplingEvent.giveDomainFields()
     185            }
     186            if(type=="templatefields"){
     187                collection = study?.samples?.parentEventGroup?.samplingEvents?.template?.fields
     188            }
     189        }
     190        if(category=="samples"){
     191            if(type=="domainfields"){
     192                collection = Sample.giveDomainFields()
     193            }
     194            if(type=="templatefields"){
     195                collection = study?.samples?.template?.fields
     196            }
     197        }
     198        if(category=="assays"){
     199            if(type=="domainfields"){
     200                collection = Assay.giveDomainFields()
     201            }
     202            if(type=="templatefields"){
     203                collection = study?.assays?.template?.fields
     204            }
     205        }
     206
     207        collection.unique()
     208
     209        // Formatting the data
     210        fields += formatGSCFFields(type, collection, source, category)
     211
     212        return fields
     213    }
     214
     215    def formatGSCFFields(type, inputObject, source, category){
     216        /*  The formatGSCFFields function can receive both lists of fields and single fields. If it receives a list, it calls itself again for each item in the list. This way, the original formatGSCFFields call will return single fields regardless of it's input.
     217
     218        Output is a list of items. Each item contains
     219          - an 'id'
     220          - a 'source', which in this case will be "GSCF"
     221          - a 'category', which indicates where the field can be found, e.g. "subjects", "samplingEvents"
     222          - a 'name', which is the the name of the field
     223         */
     224        if(inputObject==null || inputObject == []){
     225            return []
     226        }
     227        def fields = []
     228        if(inputObject instanceof Collection){
     229            // Apparently this field is actually a list of fields.
     230            // We will call ourselves again with the list's elements as input.
     231            // These list elements will themselves go through this check again, effectively flattening the original input
     232            for(int i = 0; i < inputObject.size(); i++){
     233                fields += formatGSCFFields(type, inputObject[i], source, category)
     234            }
     235            return fields
     236        } else {
     237            // This is a single field. Format it and return the result.
     238            if(type=="domainfields"){
     239                fields << [ "id": createFieldId( id: inputObject.name, name: inputObject.name, source: source, type: category ), "source": source, "category": category, "name": inputObject.name ]
     240            }
     241            if(type=="templatefields"){
     242                fields << [ "id": createFieldId( id: inputObject.id, name: inputObject.name, source: source, type: category ), "source": source, "category": category, "name": inputObject.name ]
     243            }
     244            return fields
     245        }
     246    }
    218247
    219248        /**
     
    240269                // TODO: handle categories and continuous data
    241270                def groupedData = groupFieldData( data );
    242                
     271
    243272                // Format data so it can be rendered as JSON
    244273                def returnData = formatData( groupedData, fields );
    245                
     274
    246275                render returnData as JSON
    247276        }
     
    269298                        visualizationType = "barchart"
    270299                } catch(Exception e) {
    271                         // TODO: properly handle this exception
    272                         println e
     300                        returnError(400, "An error occured while retrieving the user input")
     301                        log.error("VisualizationController: parseGetDataParams: "+e)
    273302                }
    274303
     
    330359                                // Closure could not be retrieved, probably because the type is incorrect
    331360                                data = samples.collect { return null }
     361                log.error("VisualizationController: getFieldData: Requested wrong field type: "+parsedField.type+". Parsed field: "+parsedField)
    332362                        }
    333363                } else {
     
    353383               
    354384                // TODO: Handle values that should be retrieved from multiple assays
    355                 // TODO: Use Assay ID or AssayModule ID in field-ids, instead of names
    356                 def assay = study.assays.find { it.module.name == source_module };
     385                def assay = Assay.get(source_module);
    357386               
    358387                if( assay ) {
     
    392421                               
    393422                        } catch(Exception e){
    394                                 // TODO: handle this exception properly
    395                                 println "No success with\n\t"+callUrl+"\n"+e
    396                                 e.printStackTrace();
    397                                
    398                                 // Returns an empty list with as many elements as there are samples
    399                                 data = samples.collect { return null }
     423                returnError(404, "An error occured while trying to collect data from a module. Most likely, this module is offline.")
     424                log.error("VisualizationController: getFields: "+e)
    400425                        }
    401426                } else {
     
    685710         */
    686711        protected String createFieldId( Map attrs ) {
    687                 // TODO: What is one of the attributes contains a comma?
     712                // TODO: What if one of the attributes contains a comma?
    688713                def name = attrs.name;
    689714                def id = attrs.id ?: name;
     
    694719        }
    695720
     721    protected void returnError(code, msg){
     722        response.sendError(code , msg)
     723    }
     724
    696725}
Note: See TracChangeset for help on using the changeset viewer.