Ignore:
Timestamp:
Feb 24, 2011, 5:14:08 PM (12 years ago)
Author:
s.h.sikkema@…
Message:

Assay export functionality

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/services/dbnp/studycapturing/AssayService.groovy

    r1455 r1559  
    1616import org.apache.poi.xssf.usermodel.XSSFWorkbook
    1717import org.apache.poi.hssf.usermodel.HSSFWorkbook
    18 import grails.converters.JSON
    19 import javax.servlet.http.HttpServletResponse
    2018
    2119class AssayService {
     
    2422    def authenticationService
    2523    def moduleCommunicationService
     24
     25    /**
     26     * Collects the assay field names per category in a map as well as the
     27     * module's measurements.
     28     *
     29     * @param assay the assay for which to collect the fields
     30     * @return a map of categories as keys and field names or measurements as
     31     *  values
     32     */
     33    def collectAssayTemplateFields(assay) throws Exception {
     34
     35        def getUsedTemplateFieldNames = { templateEntities ->
     36
     37            // gather all unique and non null template fields that haves values
     38            templateEntities*.giveFields().flatten().unique().findAll{ field ->
     39
     40                field && templateEntities.any { it.fieldExists(field.name) && it.getFieldValue(field.name) }
     41
     42            }*.name
     43
     44        }
     45
     46        // check whether module is reachable
     47        if (!moduleCommunicationService.isModuleReachable(assay.module.url)) {
     48
     49            throw new Exception('Module is not reachable')
     50
     51        }
     52
     53        def samples = assay.samples
     54
     55        [   'Subject Data' :            getUsedTemplateFieldNames( samples*."parentSubject".unique() ),
     56            'Sampling Event Data' :     getUsedTemplateFieldNames( samples*."parentEvent".unique() ),
     57            'Sample Data' :             getUsedTemplateFieldNames( samples ),
     58            'Event Group' :             ['name'],
     59            'Module Measurement Data':  requestModuleMeasurementNames(assay)
     60        ]
     61
     62    }
    2663
    2764    /**
     
    3471     *
    3572     * @param assay the assay to collect data for
    36      * @consumer the module url
     73     * @fieldMap map with categories as keys and fields as values
     74     * @measurementTokens selection of measurementTokens
    3775     * @return The assay data structure as described above.
    3876     */
    39     def collectAssayData(assay, consumer) throws Exception {
    40 
    41         def path = "/rest/getMeasurementData?assayToken=$assay.assayUUID"
    42 
    43         // check whether module is reachable
    44         if (!moduleCommunicationService.isModuleReachable(consumer)) {
    45 
    46             throw new Exception('Module is not reachable')
    47 
    48         }
    49 
    50         // Gather sample meta data from GSCF
    51         def samples = assay.samples
    52 
    53         def getUsedTemplateFieldNames = { templateEntities ->
    54 
    55             // gather all unique and non null template fields that haves values
    56             templateEntities*.giveFields().flatten().unique().findAll{ field ->
    57 
    58                 field && templateEntities.any { it.fieldExists(field.name) && it.getFieldValue(field.name) }
    59 
    60             }*.name
    61 
    62         }
     77    def collectAssayData(assay, fieldMap, measurementTokens) throws Exception {
    6378
    6479        def collectFieldValuesForTemplateEntities = { templateFieldNames, templateEntities ->
     
    7893        }
    7994
    80         def getFieldValues = { templateEntities, propertyName = '' ->
     95        def getFieldValues = { templateEntities, fieldNames, propertyName = '' ->
    8196
    8297            def returnValue
     
    86101            if (propertyName == '') {
    87102
    88                 returnValue = collectFieldValuesForTemplateEntities(getUsedTemplateFieldNames(templateEntities), templateEntities)
     103                returnValue = collectFieldValuesForTemplateEntities(fieldNames, templateEntities)
    89104
    90105            } else {
     
    96111                // samples, there may be less than 10 parent subjects. Maybe
    97112                // there's only 1 parent subject. We don't want to collect field
    98                 // values for this subject 10 times ...
    99                 def fieldNames, fieldValues
     113                // values for this single subject 10 times ...
     114                def fieldValues
    100115
    101116                // we'll get the unique list of properties to make sure we're
     
    104119                def uniqueProperties = templateEntities*."$propertyName".unique()
    105120
    106                 fieldNames =    getUsedTemplateFieldNames(uniqueProperties)
    107                 fieldValues =   collectFieldValuesForTemplateEntities(fieldNames, uniqueProperties)
     121                fieldValues = collectFieldValuesForTemplateEntities(fieldNames, uniqueProperties)
    108122
    109123                // prepare a lookup hashMap to be able to map an entities'
     
    137151        }
    138152
    139         [   'Subject Data' :            getFieldValues(samples, 'parentSubject'),
    140             'Sampling Event Data' :     getFieldValues(samples, 'parentEvent'),
    141             'Sample Data' :             getFieldValues(samples),
    142             'Event Group' :             [name: samples*.parentEventGroup*.name.flatten()],
    143             'Module Measurement Data':  requestModuleMeasurements(consumer, path)]
     153        // check whether module is reachable
     154        if (!moduleCommunicationService.isModuleReachable(assay.module.url)) {
     155
     156            throw new Exception('Module is not reachable')
     157
     158        }
     159
     160        def samples = assay.samples
     161
     162        def eventFieldMap = [:]
     163
     164        // check whether event group data was requested
     165        if (fieldMap['Event Group']) {
     166
     167            def names = samples*.parentEventGroup*.name.flatten()
     168
     169            // only set name field when there's actual data
     170            if (!names.every {!it}) eventFieldMap['name'] = names
     171
     172        }
     173
     174        [   'Subject Data' :            getFieldValues(samples, fieldMap['Subject Data'], 'parentSubject'),
     175            'Sampling Event Data' :     getFieldValues(samples, fieldMap['Sampling Event Data'], 'parentEvent'),
     176            'Sample Data' :             getFieldValues(samples, fieldMap['Sample Data']),
     177            'Event Group' :             eventFieldMap,
     178            'Module Measurement Data':  measurementTokens ? requestModuleMeasurements(assay, measurementTokens) : [:]
     179        ]
     180    }
     181
     182    /**
     183     * Retrieves measurement names from the module through a rest call
     184     *
     185     * @param consumer the url of the module
     186     * @param path path of the rest call to the module
     187     * @return
     188     */
     189    def requestModuleMeasurementNames(assay) {
     190
     191        def moduleUrl = assay.module.url
     192
     193        def path = moduleUrl + "/rest/getMeasurementMetaData?assayToken=$assay.assayUUID"
     194
     195        moduleCommunicationService.callModuleRestMethodJSON(moduleUrl, path)
     196
    144197    }
    145198
     
    148201     *
    149202     * @param consumer the url of the module
    150      * @param path of the rest call to the module
     203     * @param path path of the rest call to the module
    151204     * @return
    152205     */
    153     def requestModuleMeasurements(consumer, path) {
    154 
    155         def (sampleTokens, measurementTokens, moduleData) = moduleCommunicationService.callModuleRestMethodJSON(consumer, consumer+path)
     206    def requestModuleMeasurements(assay, fields) {
     207
     208        def moduleUrl = assay.module.url
     209
     210        def tokenString = ''
     211
     212        fields.each{tokenString+="&measurementToken=${it.name.encodeAsURL()}"}
     213
     214        def path = moduleUrl + "/rest/getMeasurementData?assayToken=$assay.assayUUID" + tokenString
     215       
     216        def (sampleTokens, measurementTokens, moduleData) = moduleCommunicationService.callModuleRestMethodJSON(moduleUrl, path)
    156217
    157218        if (!sampleTokens?.size()) return []
     
    172233
    173234    /**
    174      * Export column wise data in Excel format to a stream.
    175      *
     235     * Converts column
    176236     * @param columnData multidimensional map containing column data.
    177237     * On the top level, the data must be grouped by category. Each key is the
     
    194254     * | 3          | 6         | 9         | 12        | 15        |
    195255     *
    196      * @param outputStream the stream to write to
    197      * @param useOfficeOpenXML flag to specify xlsx (standard) or xls output
    198      * @return
    199      */
    200     def exportColumnWiseDataToExcelFile(columnData, outputStream, useOfficeOpenXML = true) {
    201 
    202         def convertColumnToRowStructure = { data ->
     256     * @return row wise data
     257     */
     258    def convertColumnToRowStructure(columnData) {
    203259
    204260            // check if all columns have the dimensionality 2
    205             if (data.every { it.value.every { it.value instanceof ArrayList } }) {
     261            if (columnData.every { it.value.every { it.value instanceof ArrayList } }) {
    206262
    207263                def headers = [[],[]]
    208264
    209                 data.each { category ->
     265                columnData.each { category ->
    210266
    211267                    if (category.value.size()) {
     
    225281
    226282                // add all column wise data into 'd'
    227                 data.each { it.value.each { d << it.value } }
     283                columnData.each { it.value.each { d << it.value } }
    228284
    229285                // transpose d into row wise data and combine with header rows
     
    232288
    233289        }
     290
     291    /**
     292     * Export column wise data in Excel format to a stream.
     293     *
     294     * @param columnData Multidimensional map containing column data
     295     * @param outputStream Stream to write to
     296     * @param useOfficeOpenXML Flag to specify xlsx (standard) or xls output
     297     * @return
     298     */
     299    def exportColumnWiseDataToExcelFile(columnData, outputStream, useOfficeOpenXML = true) {
     300
    234301        // transform data into row based structure for easy writing
    235302        def rows = convertColumnToRowStructure(columnData)
     
    250317     * Export row wise data in Excel format to a stream
    251318     *
    252      * @param rowData a list of lists containing for each row all cell values
    253      * @param outputStream the stream to write to
    254      * @param useOfficeOpenXML flag to specify xlsx (standard) or xls output
     319     * @param rowData List of lists containing for each row all cell values
     320     * @param outputStream Stream to write to
     321     * @param useOfficeOpenXML Flag to specify xlsx (standard) or xls output
    255322     * @return
    256323     */
Note: See TracChangeset for help on using the changeset viewer.