source: trunk/grails-app/controllers/dbnp/importer/ImporterController.groovy

Last change on this file was 1794, checked in by work@…, 10 years ago
  • added support for fuzzymatching (resolves #418)
  • removed debug lines
  • gdt up to 0.0.38
  • Property svn:keywords set to Rev Author Date
File size: 23.5 KB
Line 
1package dbnp.importer
2
3import dbnp.studycapturing.*
4import org.dbnp.gdt.*
5import grails.converters.JSON
6import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
7import grails.plugins.springsecurity.Secured
8import org.codehaus.groovy.grails.commons.ConfigurationHolder
9import grails.util.GrailsUtil
10
11
12/**
13 * Wizard Controller
14 *
15 * @author Jeroen Wesbeek
16 * @since 20101206
17 *
18 * Revision information:
19 * $Rev: 1794 $
20 * $Author: work@osx.eu $
21 * $Date: 2011-04-28 13:33:45 +0000 (do, 28 apr 2011) $
22 */
23@Secured(['IS_AUTHENTICATED_REMEMBERED'])
24class ImporterController {
25        // the pluginManager is used to check if the Grom
26        // plugin is available so we can 'Grom' development
27        // notifications to the unified notifications daemon
28        // (see http://www.grails.org/plugin/grom)
29        def pluginManager
30        def authenticationService
31        def fileService
32        def importerService
33        def validationTagLib = new ValidationTagLib()
34        def gdtService
35
36        /**
37         * index method, redirect to the webflow
38         * @void
39         */
40        def index = {
41                // Grom a development message
42                if (pluginManager.getGrailsPlugin('grom')) "redirecting into the webflow".grom()
43
44                /**
45                 * Do you believe it in your head?
46                 * I can go with the flow
47                 * Don't say it doesn't matter (with the flow) matter anymore
48                 * I can go with the flow (I can go)
49                 * Do you believe it in your head?
50                 */
51                redirect(action: 'pages')
52        }
53
54        /**
55         * WebFlow definition
56         * @void
57         */
58        def pagesFlow = {
59                // start the flow
60                onStart {
61                        // Grom a development message
62                        if (pluginManager.getGrailsPlugin('grom')) "entering the WebFlow".grom()
63
64                        // define variables in the flow scope which is availabe
65                        // throughout the complete webflow also have a look at
66                        // the Flow Scopes section on http://www.grails.org/WebFlow
67                        //
68                        // The following flow scope variables are used to generate
69                        // wizard tabs. Also see common/_tabs.gsp for more information
70                        flow.page = 0
71                        flow.pages = [
72                                [title: 'Import file'],
73                                [title: 'Assign properties'],
74                                [title: 'Check imported data'],
75                                //[title: 'Imported'],
76                                [title: 'Done']
77                        ]
78                        flow.cancel = true;
79                        flow.quickSave = true;
80
81                        success()
82                }
83
84                // render the main wizard page which immediately
85                // triggers the 'next' action (hence, the main
86                // page dynamically renders the study template
87                // and makes the flow jump to the study logic)
88                mainPage {
89                        render(view: "/importer/index")
90                        onRender {
91                                // Grom a development message
92                                if (pluginManager.getGrailsPlugin('grom')) "rendering the main Ajaxflow page (index.gsp)".grom()
93
94                                // let the view know we're in page 1
95                                flow.page = 1
96                                success()
97                        }
98                        on("next").to "pageOne"
99                }
100
101                // File import and entitie template selection page
102                pageOne {
103                        render(view: "_page_one")
104                        onRender {
105                                log.info ".entering import wizard"
106                                // Grom a development message
107                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_one.gsp".grom()
108
109                                flow.page = 1
110                                flow.studies = Study.findAllByOwner(authenticationService.getLoggedInUser(), [sort:"code", order:"asc"]).each {
111                    it.code = (it.code == null) ? "[no code]" : it.code
112                }
113                                flow.importer_fuzzymatching = "false"
114
115                                success()
116                        }
117
118                        on("refresh") {
119
120                                if (params.entity) {
121                                        flash.importer_datatemplates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
122                                }
123
124                                flash.importer_params = params
125
126                                // If the file already exists an "existing*" string is added, but we don't
127                                // want that after a refresh of the first step in the import wizard, so remove
128                                // that string
129                                flash.importer_params.importfile = params.importfile.replace('existing*', '')
130                //flash.importer_params.importfile = new XmlSlurper().parseText(flash.importer_params.importfile[flash.importer_params.importfile.indexOf('<pre')..-1]).toString()
131
132                                success()
133                        }.to "pageOne"
134
135                        on("next") {
136                                flash.wizardErrors = [:]
137
138                                flash.importer_params = params
139                                flash.importer_params.importfile = params.importfile.replace('existing*', '')               
140                //flash.importer_params.importfile = new XmlSlurper().parseText(flash.importer_params.importfile[flash.importer_params.importfile.indexOf('<pre')..-1]).toString()
141
142                                if (params.entity) {
143                                        flash.importer_datatemplates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
144                                        def importer_entity_type = gdtService.decryptEntity(params.entity.decodeURL()).toString().split(/\./)
145                                        flow.importer_entity_type = importer_entity_type[importer_entity_type.size()-1]
146                                }
147
148                                // Study selected?
149                                flow.importer_study = (params.study) ? Study.get(params.study.id.toInteger()) : null
150
151                                // Trying to import data into an existing study?
152                                if (flow.importer_study)
153                                        if (flow.importer_study.canWrite(authenticationService.getLoggedInUser()))
154                                                fileImportPage(flow, flash, params) ? success() : error()
155                                        else {
156                                                log.error ".importer wizard wrong permissions"
157                                                this.appendErrorMap(['error': "You don't have the right permissions"], flash.wizardErrors)
158                                                error()
159                                        }
160                                else {
161                                        fileImportPage(flow, flash, params) ? success() : error()
162                                }
163
164                                // put your bussiness logic (if applicable) in here
165                        }.to "pageTwo"
166                }
167
168                // Property to column assignment page
169                pageTwo {
170                        render(view: "_page_two")
171                        onRender {
172                                log.info ".import wizard properties page"
173
174                                def template = Template.get(flow.importer_template_id)
175
176                                // Grom a development message
177                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_two.gsp".grom()
178
179                                flow.importer_importmappings = ImportMapping.findAllByTemplate(template)
180
181                                flow.page = 2
182                                success()
183                        }
184                        on("refresh") {
185                                def template = Template.get(flow.importer_template_id)
186                                flow.importer_importmappings = ImportMapping.findAllByTemplate(template)
187
188                                // a name was given to the current property mapping, try to store it
189                                if (params.mappingname) {
190                                        flash.importer_columnproperty = params.columnproperty
191                                        propertiesSaveImportMappingPage(flow, flash, params)
192                                } else // trying to load an existing import mapping
193                                if (params.importmapping_id) {
194                                        propertiesLoadImportMappingPage(flow, flash, params)
195                                }
196
197                                if (params.fuzzymatching == "true")
198                                        flow.importer_fuzzymatching = "true" else
199                                        flow.importer_fuzzymatching = "false"
200
201                                success()
202                        }.to "pageTwo"
203
204                        on("next") {
205                                flow.importer_fuzzymatching = "false"
206                                if (propertiesPage(flow, flash, params)) {
207                                        success()
208                                } else {
209                                        log.error ".import wizard, properties are set wrong"
210                                        error()
211                                }
212                        }.to "pageThree"
213                        on("previous").to "pageOne"
214                }
215
216                // Mapping page
217                pageThree {
218                        render(view: "_page_three")
219                        onRender {
220                                log.info ".import wizard mapping page"
221                                // Grom a development message
222                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_three.gsp".grom()
223
224                                flow.page = 3
225                                success()
226                        }
227                        on("refresh") {
228                                success()
229                        }.to "pageThree"
230                        on("next") {
231                                if (mappingsPage(flow, flash, params)) {
232                                        flow.page = 4
233                                        success()
234                                } else {
235                                        log.error ".import wizard mapping error, could not validate all entities"
236                                        error()
237                                }
238                        }.to "save"
239                        on("previous").to "pageTwo"
240                }
241
242                // Imported data overview page
243                pageFour {
244                        render(view: "_page_four")
245                        onRender {
246                                // Grom a development message
247                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_four.gsp".grom()
248
249                                flow.page = 4
250                                success()
251                        }
252                        on("next") {
253                                if (importedPage(flow, params)) {
254                                        flow.page = 4
255                                        success()
256                                } else {
257                                        log.error ".import wizard imported error, something went wrong showing the imported entities"
258                                        error()
259                                }
260                        }.to "save"
261                        on("previous").to "pageThree"
262                }
263
264                // Save the imported data
265                save {
266                        action {
267                                // here you can validate and save the
268                                // instances you have created in the
269                                // ajax flow.
270                                // Grom a development message
271                                if (pluginManager.getGrailsPlugin('grom')) ".persisting instances to the database...".grom()
272
273                                // Always delete the uploaded file in the save step to be sure it doesn't reside there anymore
274                                if (GrailsUtil.environment != "test") fileService.delete(flow.importer_importedfile)
275
276                                // Save all entities
277                                if (saveEntities(flow, params)) {
278                                        success()
279                                } else {
280                                        log.error ".import wizard, could not save entities:\n"
281                                        flow.page = 4
282                                        error()
283                                }
284                        }
285                        on("error").to "error"
286                        on(Exception).to "error"
287                        on("success").to "finalPage"
288                }
289
290                // render errors
291                error {
292                        render(view: "_error")
293                        onRender {
294                                // Grom a development message
295                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_error.gsp".grom()
296
297                                // set page to 4 so that the navigation
298                                // works (it is disabled on the final page)
299                                flow.page = 4
300                        }
301                        on("next").to "save"
302                        on("previous").to "pageFour"
303                }
304
305                // last wizard page
306                finalPage {
307                        render(view: "_final_page")
308                        onRender {
309                                // Grom a development message
310                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_final_page.gsp".grom()
311                                success()
312                        }
313                        onEnd {
314                                // clean flow scope
315                                flow.clear()
316                        }
317                }
318        }
319
320        def propertiesManager = {
321                render(view: "common/_propertiesManager")
322        }
323
324        /**
325         * Return templates which belong to a certain entity type
326         *
327         * @param entity entity name string (Sample, Subject, Study et cetera)
328         * @return JSON object containing the found templates
329         */
330        def ajaxGetTemplatesByEntity = {
331                // fetch all templates for a specific entity
332                def templates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
333
334                // set output header to json
335                response.contentType = 'application/json'
336
337                // render as JSON
338                render templates as JSON
339        }
340
341        /**
342         * Handle the file import page.
343         *
344         * @param Map LocalAttributeMap (the flow scope)
345         * @param Map GrailsParameterMap (the flow parameters = form data)
346         * @returns boolean true if correctly validated, otherwise false
347         */
348        boolean fileImportPage(flow, flash, params) {       
349                def importedfile = fileService.get(params['importfile'])
350                flow.importer_importedfile = params['importfile']
351       
352        if (importedfile.exists()) {
353                        try {
354                                session.importer_workbook = importerService.getWorkbook(new FileInputStream(importedfile))
355                        } catch (Exception e) {
356                                log.error ".importer wizard could not load file: " + e
357                                this.appendErrorMap(['error': "Wrong file (format), the importer requires an Excel file as input"], flash.wizardErrors)
358                                return false
359                        }
360                }
361
362                if (params.entity && params.template_id) {
363
364                        try {
365                                session.importer_workbook = importerService.getWorkbook(new FileInputStream(importedfile))
366                        } catch (Exception e) {
367                                log.error ".importer wizard could not load file: " + e
368                                this.appendErrorMap(['error': "Excel file required as input"], flash.wizardErrors)
369                                return false
370                        }
371
372                        def selectedentities = []
373
374                        def entityName = gdtService.decryptEntity(params.entity.decodeURL())
375                        def entityClass = gdtService.getInstanceByEntityName(entityName)
376
377                        // Initialize some session variables
378                        //flow.importer_workbook = wb // workbook object must be serialized for this to work
379
380                        flow.importer_template_id = params.template_id
381                        flow.importer_sheetindex = params.sheetindex.toInteger() - 1 // 0 == first sheet
382                        flow.importer_datamatrix_start = params.datamatrix_start.toInteger() - 1 // 0 == first row
383                        flow.importer_headerrow = params.headerrow.toInteger()
384                        flow.importer_entityclass = entityClass
385                        flow.importer_entity = gdtService.cachedEntities.find { it.entity == entityName }
386
387                        // Get the header from the Excel file using the arguments given in the first step of the wizard
388                        flow.importer_header = importerService.getHeader(session.importer_workbook,
389                                flow.importer_sheetindex,
390                                flow.importer_headerrow,
391                                flow.importer_datamatrix_start,
392                                entityClass)
393
394                        session.importer_datamatrix = importerService.getDatamatrix(
395                                session.importer_workbook, flow.importer_header,
396                                flow.importer_sheetindex,
397                                flow.importer_datamatrix_start,
398                                5)
399
400                        flow.importer_templates = Template.get(flow.importer_template_id)
401                        flow.importer_allfieldtypes = "true"
402
403                        return true
404                }
405
406
407                log.error ".importer wizard not all fields are filled in"
408                this.appendErrorMap(['error': "Not all fields are filled in, please fill in or select all fields"], flash.wizardErrors)
409                return false
410        }
411
412        /**
413         * Load an existing import mapping
414         *
415         * @param Map LocalAttributeMap (the flow scope)
416         * @param Map GrailsParameterMap (the flow parameters = form data)
417         * @returns boolean true if correctly validated, otherwise false
418         */
419        boolean propertiesLoadImportMappingPage(flow, flash, params) {
420                def im = ImportMapping.get(params.importmapping_id.toInteger())
421                im.refresh()
422
423                im.mappingcolumns.each { mappingcolumn ->
424                        //def mc = new MappingColumn()
425                        //mc.properties = mappingcolumn.properties
426
427                        flow.importer_header[mappingcolumn.index.toInteger()] = mappingcolumn
428                }
429        }
430
431        /**
432         * Save the properties as an import mapping.
433         *
434         * @param Map LocalAttributeMap (the flow scope)
435         * @param Map GrailsParameterMap (the flow parameters = form data)
436         * @returns boolean true if correctly validated, otherwise false
437         */
438        boolean propertiesSaveImportMappingPage(flow, flash, params) {
439                flash.wizardErrors = [:]
440                def isPreferredIdentifier = false
441
442                // Find actual Template object from the chosen template name
443                def template = Template.get(flow.importer_template_id)
444
445                // Create new ImportMapping instance and persist it
446                def im = new ImportMapping(name: params.mappingname, entity: flow.importer_entityclass, template: template).save()
447
448                params.columnproperty.index.each { columnindex, property ->
449                        // Create an actual class instance of the selected entity with the selected template
450                        // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities                     
451                        //def entityClass = gdtService.getInstanceByEntityName(flow.importer_header[columnindex.toInteger()].entity.getName())
452                        def entityObj = flow.importer_entityclass.newInstance(template: template)
453
454                        def dontimport = (property == "dontimport") ? true : false
455
456                        // Loop through all fields and find the preferred identifier
457                        entityObj.giveFields().each {
458                                isPreferredIdentifier = (it.preferredIdentifier && (it.name == property)) ? true : false
459                        }
460
461                        // Create new MappingColumn instance
462                        def mc = new MappingColumn(importmapping: im,
463                                name: flow.importer_header[columnindex.toInteger()].name,
464                                property: property,
465                                index: columnindex,
466                                entityclass: flow.importer_entityclass,
467                                templatefieldtype: entityObj.giveFieldType(property),
468                                dontimport: dontimport,
469                                identifier: isPreferredIdentifier)
470
471                        // Save mappingcolumn
472                        if (mc.validate()) {
473                                im.addToMappingcolumns(mc)
474                        }
475                        else {
476                                mc.errors.allErrors.each {
477                                        //println it
478                                }
479                        }
480
481                        // Save importmapping
482                        if (im.validate()) {
483                                try {
484                                        im.save(flush: true)
485                                } catch (Exception e) {
486                                        //getNextException
487                                        log.error "importer wizard save importmapping error: " + e
488                                }
489                        }
490                        else {
491                                im.errors.allErrors.each {
492                                        //println it
493                                }
494                        }
495
496                }
497        }
498
499        /**
500         * Handle the property mapping page.
501         *
502         * @param Map LocalAttributeMap (the flow scope)
503         * @param Map GrailsParameterMap (the flow parameters = form data)
504         * @returns boolean true if correctly validated, otherwise false
505         */
506        boolean propertiesPage(flow, flash, params) {
507                flash.wizardErrors = [:]
508
509                // Find actual Template object from the chosen template name
510                def template = Template.get(flow.importer_template_id)
511
512                params.columnproperty.index.each { columnindex, property ->
513                        // Create an actual class instance of the selected entity with the selected template
514                        // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities
515                        def entityClass = Class.forName(flow.importer_header[columnindex.toInteger()].entityclass.getName(), true, this.getClass().getClassLoader())
516                        def entityObj = entityClass.newInstance(template: template)
517
518                        // Store the selected property for this column into the column map for the ImporterService
519                        flow.importer_header[columnindex.toInteger()].property = property
520
521                        // Look up the template field type of the target TemplateField and store it also in the map
522                        flow.importer_header[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property)
523
524                        // Is a "Don't import" property assigned to the column?
525                        flow.importer_header[columnindex.toInteger()].dontimport = (property == "dontimport") ? true : false
526
527                        //if it's an identifier set the mapping column true or false
528                        entityObj.giveFields().each {
529                                (it.preferredIdentifier && (it.name == property)) ? flow.importer_header[columnindex.toInteger()].identifier = true : false
530                        }
531                }
532
533                // Import the workbook and store the table with entity records and store the failed cells
534                def (table, failedcells) = importerService.importData(flow.importer_template_id,
535                        session.importer_workbook,
536                        flow.importer_sheetindex,
537                        flow.importer_datamatrix_start,
538                        flow.importer_header)
539
540                flow.importer_importeddata = table
541
542                // loop through all entities to validate them and add them to wizardErrors flash when invalid
543                /*table.each { record ->
544                                        record.each { entity ->
545                                                if (!entity.validate()) {
546                                                this.appendErrors(entity, flash.wizardErrors, 'entity_' + entity.getIdentifier() + '_')
547                                                }
548                                        }
549                                }*/
550
551                flow.importer_failedcells = failedcells
552
553                return true
554        }
555
556        /**
557         * Handle the mapping page.
558         *
559         * @param Map LocalAttributeMap (the flow scope)
560         * @param Map GrailsParameterMap (the flow parameters = form data)
561         * @returns boolean true if correctly validated, otherwise false
562         */
563        boolean mappingsPage(flow, flash, params) {
564                flash.wizardErrors = [:]
565                flow.importer_invalidentities = 0
566
567                flow.importer_importeddata.each { table ->
568                        table.each { entity ->
569                                def invalidfields = 0
570
571                                // Set the fields for this entity by retrieving values from the params
572                                entity.giveFields().each { field ->
573
574                                        // field is a date field, try to set it with the value, if someone enters a non-date value it throws
575                                        // an error, this should be caught to prevent a complete breakdown
576                                        if (field.type == org.dbnp.gdt.TemplateFieldType.DATE) {
577                                                try {
578                                                        entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
579                                                } catch (Exception e) {
580                                                        log.error ".importer wizard could not set date field with value: " +
581                                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()]
582                                                }
583                                        } else
584
585                                        // field of type ontology and value "#invalidterm"?
586                                        if (field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM &&
587                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] == "#invalidterm"
588                                        ) {
589                                                invalidfields++
590                                        } else
591                                        if (field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM &&
592                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] != "#invalidterm") {
593                                                if (entity) removeFailedCell(flow.importer_failedcells, entity, field)
594                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
595                                        }
596                                        else
597
598                                        if (field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST &&
599                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] != "#invalidterm") {
600                                                if (entity) removeFailedCell(flow.importer_failedcells, entity, field)
601                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
602                                        } else
603                                        if (field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST &&
604                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] == "#invalidterm"
605                                        ) {
606                                                invalidfields++
607                                        } else
608
609                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
610                                }
611
612                                // Determine entity class and add a parent (defined as Study in first step of wizard)
613                                switch (entity.getClass()) {
614                                        case [Subject, Sample, Event]: entity.parent = flow.importer_study
615                                }
616
617                                // Try to validate the entity now all fields have been set
618                                if (!entity.validate() || invalidfields) {
619                                        flow.importer_invalidentities++
620
621                                        // add errors to map
622                                        this.appendErrors(entity, flash.wizardErrors, "entity_" + entity.getIdentifier() + "_")
623
624                                        entity.errors.getAllErrors().each() {
625                                                log.error ".import wizard imported validation error:" + it
626                                        }
627                                } else {
628                                        //removeFailedCell(flow.importer_failedcells, entity)
629                                } // end else if
630
631                        } // end of record
632                } // end of table
633
634                return (flow.importer_invalidentities == 0) ? true : false
635        } // end of method
636
637        /**
638         * @param failedcell failed ontology cells
639         * @param entity entity to remove from the failedcells list
640         */
641        def removeFailedCell(failedcells, entity, field) {
642                // Valid entity, remove it from failedcells
643                def entityidfield = "entity_" + entity.getIdentifier() + "_" + field.name.toLowerCase()
644
645                failedcells.each { record ->
646                        def tempimportcells = []
647
648
649                        record.importcells.each { cell ->
650                                // remove the cell from the failed cells session
651                                if (cell.entityidentifier != entityidfield) {
652                                        //record.removeFromImportcells(cell)
653                                        tempimportcells.add(cell)
654                                }
655                        }
656
657                        record.importcells = tempimportcells
658                        // } // end of importcells
659                } // end of failedcells
660        }
661
662        /**
663         * Handle the imported entities page.
664         *
665         * @param Map LocalAttributeMap (the flow scope)
666         * @param Map GrailsParameterMap (the flow parameters = form data)
667         * @returns boolean true if correctly validated, otherwise false
668         */
669        boolean importedPage(flow, params) {
670                return true
671        }
672
673        boolean saveEntities(flow, params) {
674                //def (validatedSuccesfully, updatedEntities, failedToPersist) =
675                try {
676                        importerService.saveDatamatrix(flow.importer_study, flow.importer_entity_type, flow.importer_importeddata, authenticationService, log)
677                } catch (Exception e) {
678                        log.error ".import wizard saveEntities error\n" + e.dump()
679                        return false
680                }
681
682                //flow.importer_validatedsuccesfully = validatedSuccesfully
683                //flow.importer_failedtopersist = failedToPersist
684                //flow.imported_updatedentities = updatedEntities
685                //flow.importer_totalrows = flow.importer_importeddata.size
686                //flow.importer_referer = ""
687
688                return true
689        }
690
691        /**
692         * append errors of a particular object to a map
693         * @param object
694         * @param map linkedHashMap
695         * @void
696         */
697        def appendErrors(object, map) {
698                this.appendErrorMap(getHumanReadableErrors(object), map)
699        }
700
701        def appendErrors(object, map, prepend) {
702                this.appendErrorMap(getHumanReadableErrors(object), map, prepend)
703        }
704
705        /**
706         * append errors of one map to another map
707         * @param map linkedHashMap
708         * @param map linkedHashMap
709         * @void
710         */
711        def appendErrorMap(map, mapToExtend) {
712                map.each() {key, value ->
713                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
714                }
715        }
716
717        def appendErrorMap(map, mapToExtend, prepend) {
718                map.each() {key, value ->
719                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
720                }
721        }
722
723        /**
724         * transform domain class validation errors into a human readable
725         * linked hash map
726         * @param object validated domain class
727         * @return object  linkedHashMap
728         */
729        def getHumanReadableErrors(object) {
730                def errors = [:]
731                object.errors.getAllErrors().each() { error ->
732                        // error.codes.each() { code -> println code }           
733
734                        // generally speaking g.message(...) should work,
735                        // however it fails in some steps of the wizard
736                        // (add event, add assay, etc) so g is not always
737                        // availably. Using our own instance of the
738                        // validationTagLib instead so it is always
739                        // available to us
740                        errors[error.getArguments()[0]] = validationTagLib.message(error: error)
741                }
742
743                return errors
744        }
745
746}
Note: See TracBrowser for help on using the repository browser.