Changeset 1608


Ignore:
Timestamp:
Mar 9, 2011, 3:56:26 PM (6 years ago)
Author:
robert@…
Message:

Fixed bug with hibernate and transactional services in the simple wizard

Location:
trunk/grails-app
Files:
11 added
11 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/SimpleWizardController.groovy

    r1591 r1608  
    1515package dbnp.studycapturing
    1616
     17import org.apache.poi.ss.usermodel.DataFormatter
    1718import org.dbnp.gdt.*
    1819import grails.plugins.springsecurity.Secured
     
    2728        def fileService
    2829        def importerService
    29         def gdtService
     30        def gdtService = new GdtService()
    3031
    3132        /**
     
    3334         */
    3435        def index = {
    35                 redirect( action: "study" );
     36                if( params.id )
     37                        redirect( action: "simpleWizard", id: params.id );
     38                else
     39                        redirect( action: "simpleWizard" );
    3640        }
    3741
    38         /**
    39          * Shows the study page
    40          */
    41         def study = {
    42                 // Retrieve the correct study
    43                 Study study = getStudyInWizard( params );
    44 
    45                 // If no study is found in the wizard, this is the entry page of the
    46                 // wizard. Retrieve the study from request parameters
    47                 if( !study ) {
    48                         study = getStudyFromRequest( params );
    49 
    50                         // Some error might have occurred during the retrieval of the study
    51                         if( !study ) {
    52                                 redirect( controller: 'simpleWizard', action: 'study' );
    53                                 return;
    54                         }
    55 
    56                         session.simpleWizard = [ study: study ]
    57                 }
    58 
    59                 def event = getEvent(params);
    60 
    61                 // If any event on this page is triggered, we should save the entered data.
    62                 // If no event is triggered, the user gets here from another page. In that case,
    63                 // we don't set the values
    64                 if( event ) {
    65                         // Only continue to the next or previous page if the information entered is correct
    66                         if( handleStudy( study, params ) ) {
    67                                 // Now determine what action to perform
    68                                 // If the user clicks next, the study should be validated
    69                                 if( event == "next" && validateObject( study ) ) {
    70                                         if( study.samples?.size() ) {
    71                                                 // This wizard can only handle simple studies. If the
    72                                                 // study is too complex, this wizard doesn't provide the
    73                                                 // possibility to edit samples/subjects etc.
    74                                                 if( checkStudySimplicity( study ) ) {
    75                                                         toPage( "existingSamples" );
    76                                                 } else {
    77                                                         toPage( "complexStudy" );
    78                                                 }
    79                                         } else {
    80                                                 toPage( "samples" );
    81                                         }
    82                                        
    83                                         return;
    84                                 }
    85                         }
    86                 }
    87 
    88                 // Give the study to the user
    89                 [ study: study ]
    90         }
    91        
    92         /**
    93          * Shows a page to mention that the study being edited is too complex
    94          */
    95         def complexStudy = {
    96                 // Retrieve the correct study
    97                 study = getStudyInWizard( params );
    98                 if( !study ) {
    99                         redirect( controller: 'simpleWizard', action: 'study' );
    100                         return;
    101                 }
    102 
    103                 def event = getEvent(params);
    104 
    105                 // If any event on this page is triggered
    106                 if( event ) {
    107                         // Now determine what action to perform
    108                         if( event == "save" ) {
    109                                 toPage( "save" );
    110                                 return;
    111                         } else if( event == "previous" ) {
    112                                 toPage( "study" );
    113                                 return;
    114                         }
    115                 }
    116 
    117                 // Give the study and other data to the user
    118                 [ study: study ]
    119         }
    120 
    121         /**
    122          * Shows the samples page
    123          */
    124         def existingSamples = {
    125                 // Retrieve the correct study
    126                 study = getStudyInWizard( params );
    127                 if( !study ) {
    128                         redirect( controller: 'simpleWizard', action: 'study' );
    129                         return;
    130                 }
    131 
    132                 def event = getEvent(params);
    133 
    134                 // If any event on this page is triggered, we should save the entered data.
    135                 // If no event is triggered, the user gets here from another page. In that case,
    136                 // we don't set the values
    137                 if( event ) {
    138                         // Now determine what action to perform
    139                         if( event == "next" && handleExistingSamples( study, params )) {
     42        def simpleWizardFlow = {
     43                entry {
     44                        action{
     45                                flow.study = getStudyFromRequest( params )
     46                                if (!flow.study) retrievalError()
     47                        }
     48                        on("retrievalError").to "handleError"
     49                        on("success").to "study"
     50                }
     51
     52                study {
     53                        on("next") {
     54                                handleStudy( flow.study, params )
     55                                if( !validateObject( flow.study ) )
     56                                        error()
     57                        }.to "decisionState"
     58                        on("refresh") { handleStudy( flow.study, params ); }.to "study"
     59                        on( "success" ) { handleStudy( flow.study, params ) }.to "study"
     60                }
     61
     62                decisionState {
     63                        action {
     64                                // Create data in the flow
     65                                flow.templates = [
     66                                                        'Sample': Template.findAllByEntity( Sample.class ),
     67                                                        'Subject': Template.findAllByEntity( Subject.class ),
     68                                                        'Event': Template.findAllByEntity( Event.class ),
     69                                                        'SamplingEvent': Template.findAllByEntity( SamplingEvent.class )
     70                                ];
     71                                flow.encodedEntity = [
     72                                                        'Sample': gdtService.encryptEntity( Sample.class.name ),
     73                                                        'Subject': gdtService.encryptEntity( Subject.class.name ),
     74                                                        'Event': gdtService.encryptEntity( Event.class.name ),
     75                                                        'SamplingEvent': gdtService.encryptEntity( SamplingEvent.class.name )
     76                                                ]
     77
     78                                if (flow.study.samples)
     79                                        checkStudySimplicity(flow.study) ? existingSamples() : complexStudy()
     80                                else
     81                                        samples()
     82                        }
     83                        on ("existingSamples").to "startExistingSamples"
     84                        on ("complexStudy").to "complexStudy"
     85                        on ("samples").to "samples"
     86                }
     87               
     88                startExistingSamples {
     89                        action {
     90                                def records = importerService.getRecords( flow.study );
     91                                flow.records = records
     92                                flow.templateCombinations = records.templateCombination.unique()
     93                                success();
     94                        }
     95                        on( "success" ).to "existingSamples"
     96                }
     97
     98                existingSamples {
     99                        on("next") {
     100                                handleExistingSamples( flow.study, params, flow ) ? success() : error()
     101                        }.to "startAssays"
     102                        on("previous").to "study"
     103                        on("update") {
     104                                handleExistingSamples( flow.study, params, flow ) ? success() : error()
     105                        }.to "samples"
     106
     107                        on("skip").to "startAssays"
     108                }
     109
     110                complexStudy {
     111                        on("save").to "save"
     112                        on("previous").to "study"
     113                }
     114
     115                samples {
     116                        on("next") {
     117                                handleSamples( flow.study, params, flow ) ? success() : error ()
     118                               
     119                                // Add domain fields for all entities
     120                                flow.domainFields = [:]
     121                               
     122                                flow.templates.each {
     123                                        if( it.value ) {
     124                                                flow.domainFields[ it.key ] = it.value[0].entity.giveDomainFields();
     125                                        }
     126                                }
     127
     128                        }.to "columns"
     129                        on("previous").to "returnFromSamples"
     130                        on("study").to "study"
     131                        on("skip").to "startAssays"
     132                }
     133
     134                returnFromSamples {
     135                        action {
     136                                flow.study.samples ? existingSamples() : study();
     137                        }
     138                        on( "existingSamples" ).to "startExistingSamples"
     139                        on( "study" ).to "study"
     140                }
     141               
     142                columns {
     143                        on( "next" ) {
     144                                handleColumns( flow.study, params, flow ) ? success() : error()
     145                        }.to "checkImportedEntities"
     146                        on( "previous" ).to "samples"
     147                }
     148               
     149                checkImportedEntities {
     150                        action {
    140151                                // Only continue to the next page if the information entered is correct
    141                                 toPage( "assays" );
    142                                 return;
    143                         } else if( event == "previous" ) {
    144                                 // The user may go to the previous page, even if none of the data entered is OK.
    145                                 toPage( "study" );
    146                                 return;
    147                         } else if( event == "update" && handleExistingSamples( study, params ) ) {
    148                                 // The user may update the samples using excel. Before that, the sample date should be saved
    149                                 toPage( "samples" );
    150                                 return;
    151                         } else if( event == "skip" ) {
    152                                 // The user may skip the complete samples page
    153                                 toPage( "assays" );
    154                                 return;
    155                         }
    156                 }
    157 
    158                 // Give the study and other data to the user
    159                 def records = importerService.getRecords( study );
    160 
    161                 [ study: study,
    162                         records: records,
    163                         templateCombinations: records.templateCombination.unique(),
    164                         templates: [
    165                                 'Sample': Template.findAllByEntity( Sample.class ),
    166                                 'Subject': Template.findAllByEntity( Subject.class ),
    167                                 'Event': Template.findAllByEntity( Event.class ),
    168                                 'SamplingEvent': Template.findAllByEntity( SamplingEvent.class )
    169                         ],
    170                         encodedEntity: [
    171                                 'Sample': gdtService.encryptEntity( Sample.class.name ),
    172                                 'Subject': gdtService.encryptEntity( Subject.class.name ),
    173                                 'Event': gdtService.encryptEntity( Event.class.name ),
    174                                 'SamplingEvent': gdtService.encryptEntity( SamplingEvent.class.name )
    175                         ],
    176                         existingSampleForm: session.simpleWizard.existingSampleForm
    177                 ]
    178         }
    179 
    180         /**
    181          * Shows the samples page
    182          */
    183         def samples = {
    184                 // Retrieve the correct study
    185                 study = getStudyInWizard( params );
    186                 if( !study ) {
    187                         redirect( controller: 'simpleWizard', action: 'study' );
    188                         return;
    189                 }
    190 
    191                 def event = getEvent(params);
    192 
    193                 // If any event on this page is triggered, we should save the entered data.
    194                 // If no event is triggered, the user gets here from another page. In that case,
    195                 // we don't set the values
    196                 if( event ) {
    197                         // Now determine what action to perform
    198                         if( event == "next" && handleSamples( study, params )) {
    199                                 // Only continue to the next page if the information entered is correct
    200                                 toPage( "columns" );
    201                                 return;
    202                         } else if( event == "previous" ) {
    203                                 // The user may go to the previous page, even if none of the data entered is OK.
    204                                 if( study.samples?.size() )
    205                                         toPage( "existingSamples" );
    206                                 else
    207                                         toPage( "study" );
    208 
    209                                 return;
    210                         } else if( event == "skip" ) {
    211                                 // The user may skip the complete samples page
    212                                 toPage( "assays" );
    213                                 return;
    214                         }
    215                 }
    216 
    217                 // Give the study and other data to the user
    218                 [ study: study,
    219                         templates: [
    220                                 'Sample': Template.findAllByEntity( Sample.class ),
    221                                 'Subject': Template.findAllByEntity( Subject.class ),
    222                                 'Event': Template.findAllByEntity( Event.class ),
    223                                 'SamplingEvent': Template.findAllByEntity( SamplingEvent.class )
    224                         ],
    225                         encodedEntity: [
    226                                 'Sample': gdtService.encryptEntity( Sample.class.name ),
    227                                 'Subject': gdtService.encryptEntity( Subject.class.name ),
    228                                 'Event': gdtService.encryptEntity( Event.class.name ),
    229                                 'SamplingEvent': gdtService.encryptEntity( SamplingEvent.class.name )
    230                         ],
    231                         sampleForm: session.simpleWizard.sampleForm ]
    232         }
    233 
    234         /**
    235          * Shows the columns page
    236          */
    237         def columns = {
    238                 // Retrieve the correct study
    239                 study = getStudyInWizard( params );
    240                 if( !study ) {
    241                         redirect( controller: 'simpleWizard', action: 'study' );
    242                         return;
    243                 }
    244 
    245                 def event = getEvent(params);
    246 
    247                 // If any event on this page is triggered, we should save the entered data.
    248                 // If no event is triggered, the user gets here from another page. In that case,
    249                 // we don't set the values
    250                 if( event ) {
    251                         // Now determine what action to perform
    252                         if( event == "next" && handleColumns( study, params ) ) {
    253                                
    254                                 // Only continue to the next page if the information entered is correct
    255                                 if( session.simpleWizard.imported.numInvalidEntities > 0 ) {
    256                                         toPage( "missingFields" );
     152                                if( flow.imported.numInvalidEntities > 0 ) {
     153                                        missingFields();
    257154                                } else {
    258155                                        // The import of the excel file has finished. Now delete the excelfile
    259                                         if( session.simpleWizard.sampleForm.importFile )
    260                                                 fileService.delete( session.simpleWizard.sampleForm.importFile );
    261 
    262                                         session.simpleWizard.sampleForm = null
    263 
    264                                         toPage( "assays" );
    265                                 }
    266                                 return;
    267                         } else if( event == "previous" ) {
    268                                 // The user may go to the previous page, even if the data is not correct
    269                                 toPage( "samples" );
    270                                 return;
    271                         }
    272                 }
    273                
    274                 def templates = [:];
    275                 def domainFields = [:]
    276 
    277                 session.simpleWizard.sampleForm.templateId.each {
    278                         templates[ it.key ] = it.value ? Template.get( it.value ) : null;
    279                         if( it.value ) {
    280                                 domainFields[ it.key ] = templates[ it.key ].entity.giveDomainFields();
    281                         }
    282                 }
    283                
    284                 // Give the study and other data to the user
    285                 [ study: study,
    286                                         filename: session.simpleWizard.sampleForm.importFile,
    287                                         templates: templates,
    288                                         domainFields: domainFields,
    289                                         excel: session.simpleWizard.excel]
     156                                        if( flow.excel.filename )
     157                                                fileService.delete( flow.excel.filename );
     158       
     159                                        flow.sampleForm = null
     160       
     161                                        assays();
     162                                }
     163                        }
     164                        on( "missingFields" ).to "missingFields"
     165                        on( "assays" ).to "startAssays"
     166                }
     167               
     168                missingFields {
     169                        on( "next" ) {
     170                                if( !handleMissingFields( flow.study, params, flow ) ) {
     171                                        return error();
     172                                }
     173                               
     174                                // The import of the excel file has finished. Now delete the excelfile
     175                                if( flow.excel.filename )
     176                                        fileService.delete( flow.excel.filename );
     177
     178                                flow.sampleForm = null
     179                               
     180                                success();
     181                        }.to "startAssays"
     182                        on( "previous" ) {
     183                                // The user goes back to the previous page, so the already imported entities
     184                                // (of which some gave an error) should be removed again.
     185                                // Add all samples
     186                                flow.imported.data.each { record ->
     187                                        record.each { entity ->
     188                                                if( entity ) {
     189                                                        switch( entity.class ) {
     190                                                                case Sample:    flow.study.removeFromSamples( entity ); break;
     191                                                                case Subject:   flow.study.removeFromSubjects( entity ); break;
     192                                                                case Event:             flow.study.removeFromEvents( entity ); break;
     193                                                                case SamplingEvent:     flow.study.removeFromSamplingEvents( entity ); break;
     194                                                        }
     195                                                }
     196                                        }
     197                                }
     198                               
     199                                success();
     200                        }.to "columns"
     201                }
     202               
     203                startAssays {
     204                        action {
     205                                if( !flow.assay )
     206                                        flow.assay = new Assay( parent: flow.study );
     207                                       
     208                                success();
     209                        }
     210                        on( "success" ).to "assays"
     211                }
     212               
     213                assays {
     214                        on( "next" ) {
     215                                handleAssays( flow.assay, params, flow );
     216                                if( !validateObject( flow.assay ) )
     217                                        error();
     218                         }.to "overview"
     219                        on( "skip" ) {
     220                                // In case the user has created an assay before he clicked 'skip', it should only be kept if it
     221                                // existed before this step
     222                                if( flow.assay != null && !flow.assay.id ) {
     223                                        flow.remove( "assay" )
     224                                }
     225
     226                         }.to "overview"
     227                        on( "previous" ).to "returnFromAssays"
     228                        on("refresh") { handleAssays( flow.assay, params, flow ); success() }.to "assays"
     229                }
     230
     231                returnFromAssays {
     232                        action {
     233                                flow.study.samples ? existingSamples() : samples();
     234                        }
     235                        on( "existingSamples" ).to "existingSamples"
     236                        on( "samples" ).to "samples"
     237                }
     238               
     239                overview {
     240                        on( "save" ).to "saveStudy"
     241                        on( "previous" ).to "startAssays"
     242                }
     243               
     244                saveStudy {
     245                        action {
     246                                if( flow.assay && !flow.study.assays?.contains( flow.assay ) ) {
     247                                        flow.study.addToAssays( flow.assay );
     248                                }
     249                               
     250                                if( flow.study.save( flush: true ) ) {
     251                                        // Make sure all samples are attached to all assays
     252                                        flow.study.assays.each { assay ->
     253                                                def l = []+ assay.samples;
     254                                                l.each { sample ->
     255                                                        if( sample )
     256                                                                assay.removeFromSamples( sample );
     257                                                }
     258                                                assay.samples?.clear();
     259               
     260                                                flow.study.samples.each { sample ->
     261                                                        assay.addToSamples( sample )
     262                                                }
     263                                        }
     264                       
     265                                        flash.message = "Your study is succesfully saved.";
     266                                       
     267                                        finish();
     268                                } else {
     269                                        flash.error = "An error occurred while saving your study: <br />"
     270                                        flow.study.getErrors().each { flash.error += it.toString() + "<br />"}
     271                                       
     272                                        // Remove the assay from the study again, since it is still available
     273                                        // in the session
     274                                        if( flow.assay ) {
     275                                                flow.study.removeFromAssays( flow.assay );
     276                                                flow.assay.parent = flow.study;
     277                                        }
     278                                       
     279                                        overview();
     280                                }
     281                        }
     282                        on( "finish" ).to "finish"
     283                        on( "overview" ).to "overview"
     284                }
     285               
     286                finish()
     287               
     288                handleError{
     289                        redirect action: "errorPage"
     290                }
    290291        }
    291292
    292293        /**
    293          * Shows the page where missing fields can be filled in
     294         * Retrieves the required study from the database or return an empty Study object if
     295         * no id is given
     296         *
     297         * @param params        Request parameters with params.id being the ID of the study to be retrieved
     298         * @return                      A study from the database or an empty study if no id was given
    294299         */
    295         def missingFields = {
    296                 // Retrieve the correct study
    297                 study = getStudyInWizard( params );
    298                 if( !study ) {
    299                         redirect( controller: 'simpleWizard', action: 'study' );
    300                         return;
    301                 }
    302 
    303                 def event = getEvent(params);
    304 
    305                 // If any event on this page is triggered, we should save the entered data.
    306                 // If no event is triggered, the user gets here from another page. In that case,
    307                 // we don't set the values
    308                 if( event ) {
    309                         // Now determine what action to perform
    310                         if( event == "next" && handleMissingFields( study, params ) ) {
    311                                 if( session.simpleWizard.imported.numInvalidEntities == 0 ) {
    312                                         // Only continue to the next page if the information entered is correct
    313 
    314                                         // The import of the excel file has finished. Now delete the excelfile
    315                                         if( session.simpleWizard.sampleForm.importFile ) {
    316                                                 fileService.delete( session.simpleWizard.sampleForm.importFile );
    317                                         }
    318                                         session.simpleWizard.sampleForm = null
    319 
    320                                         toPage( "assays" );
    321                                         return;
    322                                 }
    323                         } else if( event == "previous" ) {
    324                                 // THe user may go to the previous page, even if the data is not correct
    325                                 toPage( "columns" );
    326                                 return;
    327                         }
    328                 }
    329 
    330                 // If any errors have occurred during validation, show them to the user. However,
    331                 // the same error might have occurred for multiple entities. For that reason,
    332                 // we only show unique errors
    333                 def rules
    334                 if( session.simpleWizard.imported.errors ) {
    335                         rules = session.simpleWizard.imported.errors*.values().flatten().unique().join( "<br /> \n" );
    336                 }
    337 
    338                 // Create the right format for showing the data
    339                 def records = [];
    340                 session.simpleWizard.imported.data.each { row ->
    341                         def record = [:];
    342                         row.each { object ->
    343                                 // Attach template to session
    344                                 if( object.template )
    345                                         attachTemplate( object.template );
    346                                
    347                                 def entityName = object.class.name[ object.class.name.lastIndexOf( '.' ) + 1 .. -1 ]
    348                                 record[ entityName ] = object;
    349                         }
    350                         records << record;
    351                 }
    352                
    353                 // Give the study and other data to the user
    354                 println "Imported: " + session.simpleWizard.imported.failedCells;
    355                
    356                 [ study: study, imported: session.simpleWizard.imported, records: records, rules: rules ]
     300        protected Study getStudyFromRequest( def params ) {
     301                int id = params.int( "id" );
     302
     303                if( !id ) {
     304                        return new Study( title: "New study", owner: authenticationService.getLoggedInUser() );
     305                }
     306
     307                Study s = Study.get( id );
     308
     309                if( !s ) {
     310                        flash.error = "No study found with given id";
     311                        return null;
     312                }
     313                if( !s.canWrite( authenticationService.getLoggedInUser() ) ) {
     314                        flash.error = "No authorization to edit this study."
     315                        return null;
     316                }
     317
     318                return s
    357319        }
    358320
    359321        /**
    360          * Shows the assay page
    361          */
    362         def assays = {
    363                 // Retrieve the correct study
    364                 Study study = getStudyInWizard( params );
    365                 if( !study ) {
    366                         redirect( controller: 'simpleWizard', action: 'study' );
    367                         return;
    368                 }
    369 
    370                 Assay assay = getAssayInWizard( study );
    371 
    372                 def event = getEvent(params);
    373 
    374                 // If any event on this page is triggered, we should save the entered data.
    375                 // If no event is triggered, the user gets here from another page. In that case,
    376                 // we don't set the values
    377                 if( event ) {
    378                         // Only continue to the next or previous page if the information entered is correct
    379                         if( event == "skip" ) {
    380                                 // The user may skip the complete assay page
    381 
    382                                 // In case the user has created an assay before, it should only be kept if it
    383                                 // existed before this step
    384                                 if( session.simpleWizard.assay != null && !session.simpleWizard.assay.id ) {
    385                                         session.simpleWizard.remove( "assay" )
    386                                 }
    387 
    388                                 toPage( "overview" );
    389                                 return;
    390                         } else if( handleAssays( assay, params ) ) {
    391                                 // Now determine what action to perform
    392                                 if( event == "next" && validateObject( assay ) ) {
    393                                         toPage( "overview" );
    394                                         return;
    395                                 } else if( event == "previous" ) {
    396                                         if( study.samples?.size() )
    397                                                 toPage( "existingSamples" )
    398                                         else
    399                                                 toPage( "samples" );
    400 
    401                                         return;
    402                                 }
    403                         }
    404                 }
    405 
    406                 // Give the study to the user
    407                 [ study: study, wizardAssay: assay ]
    408         }
    409 
    410         /**
    411          * Shows an overview of the entered study
    412          */
    413         def overview = {
    414                 // Retrieve the correct study
    415                 Study study = getStudyInWizard( params );
    416                 if( !study ) {
    417                         redirect( controller: 'simpleWizard', action: 'study' );
    418                         return;
    419                 }
    420 
    421                 Assay assay = getAssayInWizard();
    422 
    423                 def event = getEvent(params);
    424 
    425                 // If any event on this page is triggered, we should save the entered data.
    426                 // If no event is triggered, the user gets here from another page. In that case,
    427                 // we don't set the values
    428                 if( event ) {
    429                         // Now determine what action to perform
    430                         if( event == "save" ) {
    431                                 toPage( "save" );
    432                                 return;
    433                         } else if( event == "previous" ) {
    434                                 toPage( "assays" )
    435                                 return;
    436                         }
    437                 }
    438 
    439                 // Give the study to the user
    440                 [ study: study, wizardAssay: assay ]
    441         }
    442 
    443         def save = {
    444                 // Retrieve the correct study
    445                 Study study = getStudyInWizard( params );
    446                 if( !study ) {
    447                         redirect( controller: 'simpleWizard', action: 'study' );
    448                         return;
    449                 }
    450 
    451                 def event = getEvent(params);
    452 
    453                 if( event && event == "previous" ) {
    454                         toPage( "assays" );
    455                         return;
    456                 }
    457                
    458                 Assay newAssay = getAssayInWizard();
    459 
    460                 if( newAssay && !study.assays?.contains( newAssay ) ) {
    461                         study.addToAssays( newAssay );
    462                 }
    463 
    464                 //attachAndValidateEntities( study );
    465                
    466                 // Save the study. The study must be merged if it is loaded from
    467                 // the database before, since otherwise it will raise 'lazy initialization' errors
    468                 // The validation is done in the other steps, so it is skipped here.
    469                 def success
    470                
    471                 if(
    472                 study.id ?
    473                 study.merge( validate: false, flush: true ) :
    474                 study.save( flush: true )
    475                 ) {
    476                         // Make sure all samples are attached to all assays
    477                         study.assays.each { assay ->
    478                                 def l = []+ assay.samples;
    479                                 l.each { sample ->
    480                                         if( sample )
    481                                                 assay.removeFromSamples( sample );
    482                                 }
    483                                 assay.samples?.clear();
    484 
    485                                 study.samples.each { sample ->
    486                                         assay.addToSamples( sample )
    487                                 }
    488                         }
    489 
    490                         // Clear session
    491                         session.simpleWizard = null;
    492 
    493                         flash.message = "Your study is succesfully saved.";
    494                         success = true
    495                 } else {
    496                         flash.error = "An error occurred while saving your study";
    497 
    498                         study.getErrors().each { println it }
    499 
    500                         // Remove the assay from the study again, since it is still available
    501                         // in the session
    502                         if( newAssay ) {
    503                                 study.removeFromAssays( newAssay );
    504                                 newAssay.parent = study;
    505                         }
    506 
    507                         //validateObject( study );
    508                         success = false
    509                 }
    510 
    511                 // Give the study to the user
    512                 [ study: study, success: success ]
    513         }
    514 
    515         /**
    516322         * Handles study input
    517323         * @param study         Study to update
     
    552358                return true
    553359        }
    554 
    555         /**
    556          * Handles the editing of existing samples
    557          * @param study         Study to update
    558          * @param params                Request parameter map
    559          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    560          */
    561         def handleExistingSamples( study, params ) {
    562                 session.simpleWizard.existingSampleForm = params
    563                 flash.validationErrors = [:];
    564 
    565                 def errors = false;
    566                
    567                 // iterate through objects; set field values and validate the object
    568                 def eventgroups = study.samples.parentEventGroup.findAll { it }
    569                 def events;
    570                 if( !eventgroups )
    571                         events = []
    572                 else
    573                         events = eventgroups.events?.getAt(0);
    574                
    575                 def objects = [
    576                         'Sample': study.samples,
    577                         'Subject': study.samples.parentSubject.findAll { it },
    578                         'SamplingEvent': study.samples.parentEvent.findAll { it },
    579                         'Event': events.flatten().findAll { it }
    580                 ];     
    581                 objects.each {
    582                         def type = it.key;
    583                         def entities = it.value;
    584                        
    585                         entities.each { entity ->
    586                                 // iterate through entity fields
    587                                 entity.giveFields().each() { field ->
    588                                         def value = params.get( type.toLowerCase() + '_' + entity.getIdentifier() + '_' + field.escapedName())
    589 
    590                                         // set field value; name cannot be set to an empty value
    591                                         if (field.name != 'name' || value) {
    592                                                 log.info "setting "+field.name+" to "+value
    593                                                 entity.setFieldValue(field.name, value)
    594                                         }
    595                                 }
    596                                
    597                                 // has the template changed?
    598                                 def templateName = params.get(type.toLowerCase() + '_' + entity.getIdentifier() + '_template')
    599                                 if (templateName && entity.template?.name != templateName) {
    600                                         entity.template = Template.findByName(templateName)
    601                                 }
    602        
    603                                 // validate sample
    604                                 if (!entity.validate()) {
    605                                         errors = true;
    606                                         flash.validationErrors << getHumanReadableErrors( entity )
    607                                 }
    608                         }
    609                 }
    610 
    611                 return !errors
    612         }
     360       
     361        /**
     362        * Handles the editing of existing samples
     363        * @param study          Study to update
     364        * @param params         Request parameter map
     365        * @return                       True if everything went OK, false otherwise. An error message is put in flash.error
     366        */
     367   def handleExistingSamples( study, params, flow ) {
     368           flash.validationErrors = [];
     369
     370           def errors = false;
     371           
     372           // iterate through objects; set field values and validate the object
     373           def eventgroups = study.samples.parentEventGroup.findAll { it }
     374           def events;
     375           if( !eventgroups )
     376                   events = []
     377           else
     378                   events = eventgroups.events?.getAt(0);
     379           
     380           def objects = [
     381                   'Sample': study.samples,
     382                   'Subject': study.samples.parentSubject.findAll { it },
     383                   'SamplingEvent': study.samples.parentEvent.findAll { it },
     384                   'Event': events.flatten().findAll { it }
     385           ];
     386           objects.each {
     387                   def type = it.key;
     388                   def entities = it.value;
     389                   
     390                   entities.each { entity ->
     391                           // iterate through entity fields
     392                           entity.giveFields().each() { field ->
     393                                   def value = params.get( type.toLowerCase() + '_' + entity.getIdentifier() + '_' + field.escapedName())
     394
     395                                   // set field value; name cannot be set to an empty value
     396                                   if (field.name != 'name' || value) {
     397                                           log.info "setting "+field.name+" to "+value
     398                                           entity.setFieldValue(field.name, value)
     399                                   }
     400                           }
     401                           
     402                           // has the template changed?
     403                           def templateName = params.get(type.toLowerCase() + '_' + entity.getIdentifier() + '_template')
     404                           if (templateName && entity.template?.name != templateName) {
     405                                   entity.template = Template.findByName(templateName)
     406                           }
     407   
     408                           // validate sample
     409                           if (!entity.validate()) {
     410                                   errors = true;
     411                                   
     412                                   def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ]
     413                                   getHumanReadableErrors( entity ).each {
     414                                                flash.validationErrors << [ key: it.key, value: "(" + entityName + ") " + it.value ];
     415                                   }
     416                           }
     417                   }
     418           }
     419
     420           return !errors
     421   }
    613422
    614423        /**
     
    618427         * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    619428         */
    620         def handleSamples( study, params ) {
     429        def handleSamples( study, params, flow ) {
    621430                def filename = params.get( 'importfile' );
    622431
     
    629438                else if( filename[0..8] == 'existing*' )
    630439                        filename = filename[9..-1]
    631                
     440
    632441                def sampleTemplateId  = params.long( 'sample_template_id' )
    633442                def subjectTemplateId  = params.long( 'subject_template_id' )
    634443                def eventTemplateId  = params.long( 'event_template_id' )
    635444                def samplingEventTemplateId  = params.long( 'samplingEvent_template_id' )
    636                
     445
    637446                // These fields have been removed from the form, so will always contain
    638447                // their default value. The code however remains like this for future use.
     
    642451
    643452                // Save form data in session
    644                 session.simpleWizard.sampleForm = [
     453                flow.sampleForm = [
    645454                                        importFile: filename,
    646                                         templateId: [ 
     455                                        templateId: [
    647456                                                'Sample': sampleTemplateId,
    648457                                                'Subject': subjectTemplateId,
     
    650459                                                'SampingEvent': samplingEventTemplateId
    651460                                        ],
     461                                        template: [
     462                                                'Sample': sampleTemplateId ? Template.get( sampleTemplateId ) : null,
     463                                                'Subject': subjectTemplateId ? Template.get( subjectTemplateId ) : null,
     464                                                'Event': eventTemplateId ? Template.get( eventTemplateId ) : null,
     465                                                'SampingEvent': samplingEventTemplateId ? Template.get( samplingEventTemplateId ) : null
     466                                        ],
    652467                                        sheetIndex: sheetIndex,
    653468                                        dataMatrixStart: dataMatrixStart,
     
    661476                        return false
    662477                }
    663 
     478               
    664479                def importedfile = fileService.get( filename )
    665480                def workbook
     
    693508                def importerDataMatrix;
    694509
    695                 try {
     510                try {           
    696511                        importerHeader = importerService.getHeader(workbook,
    697512                                        sheetIndex - 1,                 // 0 == first sheet
     
    699514                                        dataMatrixStart - 1,    // 0 == first row
    700515                                        Sample.class)
    701 
     516               
    702517                        importerDataMatrix = importerService.getDatamatrix(
    703518                                        workbook,
     
    716531                }
    717532
     533                // Match excel columns with template fields
     534                def fieldNames = [];
     535                flow.sampleForm.template.each { template ->
     536                        if( template.value ) {
     537                                def fields = template.value.entity.giveDomainFields() + template.value.getFields();
     538                                fields.each { field ->
     539                                        if( !field.entity )
     540                                                field.entity = template.value.entity
     541                                               
     542                                        fieldNames << field
     543                                }
     544                        }
     545                }
     546                importerHeader.each { mc ->
     547                        def bestfit = importerService.mostSimilar( mc.name, fieldNames, 0.8);
     548                        if( bestfit ) {
     549                                // Remove this fit from the list
     550                                fieldNames.remove( bestfit );
     551                               
     552                                mc.entityclass = bestfit.entity
     553                                mc.property = bestfit.name
     554                        }
     555                }
     556               
    718557                // Save read excel data into session
    719                 session.simpleWizard.excel = [
    720                                         workbook: workbook,
     558                def dataMatrix = [];
     559                def df = new DataFormatter();
     560                importerDataMatrix.each {
     561                        dataMatrix << it.collect{ it ? df.formatCellValue(it) : "" }
     562                }
     563               
     564                flow.excel = [
     565                                        filename: filename,
    721566                                        sheetIndex: sheetIndex,
    722567                                        dataMatrixStart: dataMatrixStart,
     
    724569                                        data: [
    725570                                                header: importerHeader,
    726                                                 dataMatrix: importerDataMatrix
     571                                                dataMatrix: dataMatrix
    727572                                        ]
    728573                                ]
     
    731576        }
    732577
     578       
    733579        /**
    734580         * Handles the matching of template fields with excel columns by the user
     
    736582         * @param params        Request parameter map
    737583         * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    738          *                                      The field session.simpleWizard.imported.numInvalidEntities reflects the number of 
     584         *                                      The field session.simpleWizard.imported.numInvalidEntities reflects the number of
    739585         *                                      entities that have errors, and should be fixed before saving. The errors for those entities
    740586         *                                      are saved into session.simpleWizard.imported.errors
    741587         */
    742         def handleColumns( study, params ) {
     588        def handleColumns( study, params, flow ) {
    743589                // Find actual Template object from the chosen template name
    744590                def templates = [:];
    745                 session.simpleWizard.sampleForm.templateId.each {
     591                flow.sampleForm.templateId.each {
    746592                        templates[ it.key ] = it.value ? Template.get( it.value ) : null;
    747593                }
    748594               
    749                 def headers = session.simpleWizard.excel.data.header;
     595                def headers = flow.excel.data.header;
    750596
    751597                if( !params.matches ) {
     
    796642                println "Importing samples for study " + study + " (" + study.id + ")";
    797643               
     644                def importedfile = fileService.get( flow.excel.filename )
     645                def workbook
     646                if (importedfile.exists()) {
     647                        try {
     648                                workbook = importerService.getWorkbook(new FileInputStream(importedfile))
     649                        } catch (Exception e) {
     650                                log.error ".simple study wizard could not load file: " + e
     651                                flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
     652                                return false
     653                        }
     654                } else {
     655                        log.error ".simple study wizard no file given";
     656                        flash.error = "No file was given. Please provide an excel file for entering samples.";
     657                        return false;
     658                }
     659
     660                if( !workbook ) {
     661                        log.error ".simple study wizard could not load file into a workbook"
     662                        flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
     663                        return false
     664                }
     665               
     666               
    798667                def imported = importerService.importOrUpdateDataBySampleIdentifier(templates,
    799                                 session.simpleWizard.excel.workbook,
    800                                 session.simpleWizard.excel.sheetIndex - 1,
    801                                 session.simpleWizard.excel.dataMatrixStart - 1,
    802                                 session.simpleWizard.excel.data.header,
    803                                 study,
    804                                 true                    // Also create entities for which no data is imported but where templates were chosen 
     668                                workbook,
     669                                flow.excel.sheetIndex - 1,
     670                                flow.excel.dataMatrixStart - 1,
     671                                flow.excel.data.header,
     672                                flow.study,
     673                                true                    // Also create entities for which no data is imported but where templates were chosen
    805674                );
    806675
     
    808677                def failedcells = imported.failedCells
    809678
    810                 session.simpleWizard.imported = [
     679                flow.imported = [
    811680                        data: table,
    812681                        failedCells: failedcells
    813682                ];
    814 
     683       
    815684                // loop through all entities to validate them and add them to failedcells if an error occurs
    816685                def numInvalidEntities = 0;
     
    821690                        record.each { entity ->
    822691                                if( entity ) {
    823                                         // Determine entity class and add a parent
     692                                        // Determine entity class and add a parent. Add the entity to the study
    824693                                        def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );
    825694                                        def equalClosure = { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) }
    826        
     695                                        def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ]
     696
    827697                                        entity.parent = study
    828698                                       
     
    854724                                               
    855725                                                // Add this field to the list of failed cells, in order to give the user feedback
    856                                                 failedcells = addNonValidatingCells( failedcells, entity )
     726                                                failedcells = addNonValidatingCells( failedcells, entity, flow )
    857727       
    858728                                                // Also create a full list of errors
    859                                                 errors += getHumanReadableErrors( entity );
    860                                         }
    861                                 }
    862                         }
    863                 }
    864 
    865                 session.simpleWizard.imported.numInvalidEntities = numInvalidEntities + failedcells?.size();
    866                 session.simpleWizard.imported.errors = errors;
     729                                                def currentErrors = getHumanReadableErrors( entity )
     730                                                if( currentErrors ) {
     731                                                        currentErrors.each {
     732                                                                errors += "(" + entityName + ") " + it.value;
     733                                                        }
     734                                                }
     735                                        }
     736                                }
     737                        }
     738                }
     739
     740                flow.imported.numInvalidEntities = numInvalidEntities + failedcells?.size();
     741                flow.imported.errors = errors;
    867742
    868743                return true
    869744        }
    870 
     745       
    871746        /**
    872747         * Handles the update of the edited fields by the user
     
    878753         *                                      are saved into session.simpleWizard.imported.errors
    879754         */
    880         def handleMissingFields( study, params ) {
     755        def handleMissingFields( study, params, flow ) {
    881756                def numInvalidEntities = 0;
    882757                def errors = [];
    883758
    884759                // Check which fields failed previously
    885                 def failedCells = session.simpleWizard.imported.failedCells
    886 
    887                 session.simpleWizard.imported.data.each { table ->
     760                def failedCells = flow.imported.failedCells
     761                def newFailedCells = [];
     762
     763                flow.imported.data.each { table ->
    888764                        table.each { entity ->
    889765                                def invalidFields = 0
     766                                def failed = new ImportRecord();
     767                                def entityName = entity.class.name[ entity.class.name.lastIndexOf( "." ) + 1 .. -1 ]
     768                               
    890769
    891770                                // Set the fields for this entity by retrieving values from the params
     
    896775                                                // If the value '#invalidterm' is chosen, the user hasn't fixed anything, so this field is still incorrect
    897776                                                invalidFields++;
     777                                               
     778                                                // store the mapping column and value which failed
     779                                                def identifier = entityName.toLowerCase() + "_" + entity.getIdentifier() + "_" + fieldName
     780                                                def mcInstance = new MappingColumn()
     781                                                failed.addToImportcells(new ImportCell(mappingcolumn: mcInstance, value: params[ fieldName ], entityidentifier: identifier))
    898782                                        } else {
    899783                                                if( field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM || field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST ) {
     
    907791                                        }
    908792                                }
    909 
    910                                 // Determine entity class and add a parent
    911                                 entity.parent = study;
    912 
     793                               
    913794                                // Try to validate the entity now all fields have been set. If it fails, return an error
    914795                                if (!entity.validate() || invalidFields) {
     
    916797
    917798                                        // Add this field to the list of failed cells, in order to give the user feedback
    918                                         failedCells = addNonValidatingCells( failedCells, entity )
     799                                        failedCells = addNonValidatingCellsToImportRecord( failed, entity, flow )
    919800
    920801                                        // Also create a full list of errors
    921                                         errors += getHumanReadableErrors( entity );
     802                                        def currentErrors = getHumanReadableErrors( entity )
     803                                        if( currentErrors ) {
     804                                                currentErrors.each {
     805                                                        errors += "(" + entityName + ") " + it.value;
     806                                                }
     807                                        }
     808                                       
     809                                        newFailedCells << failed;
    922810                                } else {
    923811                                        importerService.removeFailedCell( failedCells, entity )
     
    926814                } // end of table
    927815
    928                 session.simpleWizard.imported.numInvalidEntities = numInvalidEntities;
    929                 session.simpleWizard.imported.errors = errors;
    930 
    931                 return true
     816                flow.imported.failedCells = newFailedCells
     817                flow.imported.numInvalidEntities = numInvalidEntities;
     818                flow.imported.errors = errors;
     819
     820                return numInvalidEntities == 0
    932821        }
    933 
    934         /**
    935          * Handles assay input
    936          * @param study         Study to update
    937          * @param params                Request parameter map
    938          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    939          */
    940         def handleAssays( assay, params ) {
    941                 // did the study template change?
    942                 if (params.get('template') && assay.template?.name != params.get('template')) {
    943                         // set the template
    944                         assay.template = Template.findByName(params.remove('template'))
    945                 }
    946 
    947                 // does the study have a template set?
    948                 if (assay.template && assay.template instanceof Template) {
    949                         // yes, iterate through template fields
    950                         assay.giveFields().each() {
    951                                 // and set their values
    952                                 assay.setFieldValue(it.name, params.get(it.escapedName()))
    953                         }
    954                 }
    955 
    956                 // Save the assay in session
    957                 session.simpleWizard.assay = assay;
    958 
    959                 return true
    960         }
     822       
     823        /**
     824        * Handles assay input
     825        * @param study          Study to update
     826        * @param params         Request parameter map
     827        * @return                       True if everything went OK, false otherwise. An error message is put in flash.error
     828        */
     829   def handleAssays( assay, params, flow ) {
     830           // did the study template change?
     831           if (params.get('template') && assay.template?.name != params.get('template')) {
     832                   // set the template
     833                   assay.template = Template.findByName(params.remove('template'))
     834           }
     835
     836           // does the study have a template set?
     837           if (assay.template && assay.template instanceof Template) {
     838                   // yes, iterate through template fields
     839                   assay.giveFields().each() {
     840                           // and set their values
     841                           assay.setFieldValue(it.name, params.get(it.escapedName()))
     842                   }
     843           }
     844
     845           return true
     846   }
     847       
    961848       
    962849        /**
    963850         * Checks whether the given study is simple enough to be edited using this controller.
    964          * 
    965          * The study is simple enough if the samples, subjects, events and samplingEvents can be 
    966          * edited as a flat table. That is: 
     851         *
     852         * The study is simple enough if the samples, subjects, events and samplingEvents can be
     853         * edited as a flat table. That is:
    967854         *              - Every subject belongs to 0 or 1 eventgroup
    968855         *              - Every eventgroup belongs to 0 or 1 sample
    969856         *              - Every eventgroup has 0 or 1 subjects, 0 or 1 event and 0 or 1 samplingEvents
    970857         *              - If a sample belongs to an eventgroup:
    971          *                      - If that eventgroup has a samplingEvent, that same samplingEvent must also be 
     858         *                      - If that eventgroup has a samplingEvent, that same samplingEvent must also be
    972859         *                              the sampling event that generated this sample
    973860         *                      - If that eventgroup has a subject, that same subject must also be the subject
    974861         *                              from whom the sample was taken
    975          * 
     862         *
    976863         * @param study         Study to check
    977864         * @return                      True if the study can be edited by this controller, false otherwise
     
    979866        def checkStudySimplicity( study ) {
    980867                def simplicity = true;
    981                
     868
    982869                if( !study )
    983870                        return false
     
    990877                                        simplicity = false;
    991878                                }
    992                                
     879
    993880                                // Check whether this eventgroup only belongs to (max) 1 sample
    994881                                def numSamples = 0;
    995882                                study.samples.each { sample ->
    996                                         // If no id is given for the eventGroup, it has been entered in this wizard, but 
     883                                        // If no id is given for the eventGroup, it has been entered in this wizard, but
    997884                                        // not yet saved. In that case, it is always OK
    998885                                        if( eventGroup.id && sample.parentEventGroup?.id == eventGroup.id )
    999886                                                numSamples++;
    1000887                                }
    1001                                
    1002                                 if( numSamples > 1 ) { 
     888
     889                                if( numSamples > 1 ) {
    1003890                                        flash.message = "One or more eventgroups belong to multiple samples."
    1004891                                        simplicity = false;
    1005892                                }
    1006893                        }
    1007                        
     894
    1008895                        if( !simplicity ) return false;
    1009896
     
    1018905                                                        numEventGroups++
    1019906                                        }
    1020                                        
     907
    1021908                                        if( numEventGroups > 1 ) {
    1022909                                                flash.message = "One or more subjects belong to multiple eventgroups."
     
    1027914
    1028915                        if( !simplicity ) return false;
    1029                        
     916
    1030917                        // Check whether the samples that belong to an eventgroup have the right parentObjects
    1031918                        study.samples.each { sample ->
     
    1039926                                                }
    1040927                                        }
    1041                                        
     928
    1042929                                        // If no id is given for the sampling event, it has been entered in this wizard, but
    1043930                                        // not yet saved. In that case, it is always OK
     
    1050937                                }
    1051938                        }
    1052                        
     939
    1053940                        if( !simplicity ) return false;
    1054941                }
    1055                
     942
    1056943                return simplicity;
    1057944        }
    1058945
    1059         def attachAndValidateEntities( def study ) {
    1060                 if( !session.simpleWizard?.imported?.data )
    1061                         return
    1062                          
    1063                 def table = session.simpleWizard.imported.data
    1064                 def numInvalidEntities = 0;
    1065                
    1066                 // Add all samples
    1067                 table.each { record ->
    1068                         println record*.class
    1069                         record.each { entity ->
    1070                                 if( entity ) {
    1071                                         if( entity.validate() ) {
    1072                                                 println "Saving: " + entity + " (" + entity.class.name + ")"
    1073                                                 println study.samples;
    1074                                                 println study.subjects;
    1075                                                
    1076                                                 // Determine entity class and add a parent
    1077                                                 def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );
    1078                                                 def equalClosure = { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) }
    1079                
    1080                                                 //entity.parent = study
    1081                                                 switch( entity.class ) {
    1082                                                         case Sample:
    1083                                                                 if( preferredIdentifier && !study.samples?.find( equalClosure ) ) {
    1084                                                                         study.addToSamples( entity );
    1085                                                                 }
    1086                                                                 break;
    1087                                                         case Subject:
    1088                                                                 if( preferredIdentifier && !study.subjects?.find( equalClosure ) ) {
    1089                                                                         study.addToSubjects( entity );
    1090                                                                 }
    1091                                                                 break;
    1092                                                         case Event:
    1093                                                                 if( preferredIdentifier && !study.events?.find( equalClosure ) ) {
    1094                                                                         study.addToEvents( entity );
    1095                                                                 }
    1096                                                                 break;
    1097                                                         case SamplingEvent:
    1098                                                                 if( preferredIdentifier && !study.samplingEvents?.find( equalClosure ) ) {
    1099                                                                         study.addToSamplingEvents( entity );
    1100                                                                 }
    1101                                                                 break;
    1102                                                 }
    1103                                                
    1104                                                 entity.save();
    1105                                                
    1106                                         } else {
    1107                                                 numInvalidEntities++;
    1108                                         }
    1109                                 }
    1110                         }
    1111                 }
    1112 
    1113                 return numInvalidEntities == 0;
     946       
     947        /**
     948         * Adds all fields of this entity that have given an error when validating to the failedcells list
     949         * @param failedcells   Current list of ImportRecords
     950         * @param entity                Entity to check. The entity must have been validated before
     951         * @return                              Updated list of ImportRecords
     952         */
     953        protected def addNonValidatingCells( failedcells, entity, flow ) {
     954                // Add this entity and the fields with an error to the failedCells list
     955                ImportRecord failedRecord = addNonValidatingCellsToImportRecord( new ImportRecord(), entity, flow );
     956
     957                failedcells.add( failedRecord );
     958
     959                return failedcells
    1114960        }
    1115                
     961       
     962        /**
     963        * Adds all fields of this entity that have given an error when validating to the failedcells list
     964        * @param failedcells    Current list of ImportRecords
     965        * @param entity         Entity to check. The entity must have been validated before
     966        * @return                               Updated list of ImportRecords
     967        */
     968   protected def addNonValidatingCellsToImportRecord( failedRecord, entity, flow ) {
     969           entity.getErrors().getFieldErrors().each { error ->
     970                   String field = error.getField();
     971                   
     972                   def mc = importerService.findMappingColumn( flow.excel.data.header, field );
     973                   def mcInstance = new MappingColumn( name: field, entityClass: Sample.class, index: -1, property: field.toLowerCase(), templateFieldType: entity.giveFieldType( field ) );
     974
     975                   // Create a clone of the mapping column
     976                   if( mc ) {
     977                           mcInstance.properties = mc.properties
     978                   }
     979
     980                   failedRecord.addToImportcells( new ImportCell(mappingcolumn: mcInstance, value: error.getRejectedValue(), entityidentifier: importerService.getFieldNameInTableEditor( entity, field ) ) )
     981           }
     982           
     983           return failedRecord
     984   }
     985
     986       
     987        /**
     988        * Checks an excel workbook whether the given sheetindex and rownumbers are correct
     989        * @param workbook                       Excel workbook to read
     990        * @param sheetIndex             1-based sheet index for the sheet to read (1=first sheet)
     991        * @param headerRow                      1-based row number for the header row (1=first row)
     992        * @param dataMatrixStart        1-based row number for the first data row (1=first row)
     993        * @return                                       True if the sheet index and row numbers are correct.
     994        */
     995   protected boolean excelChecks( def workbook, int sheetIndex, int headerRow, int dataMatrixStart ) {
     996           // Perform some basic checks on the excel file. These checks should be performed by the importerservice
     997           // in a perfect scenario.
     998           if( sheetIndex > workbook.getNumberOfSheets() ) {
     999                   log.error ".simple study wizard Sheet index is too high: " + sheetIndex + " / " + workbook.getNumberOfSheets();
     1000                   flash.error = "Your excel sheet contains too few excel sheets. The provided excel sheet has only " + workbook.getNumberOfSheets() + " sheet(s).";
     1001                   return false
     1002           }
     1003
     1004           def sheet = workbook.getSheetAt(sheetIndex - 1);
     1005           def firstRowNum = sheet.getFirstRowNum();
     1006           def lastRowNum = sheet.getLastRowNum();
     1007           def numRows = lastRowNum - firstRowNum + 1;
     1008
     1009           if( headerRow > numRows  ) {
     1010                   log.error ".simple study wizard Header row number is incorrect: " + headerRow + " / " + numRows;
     1011                   flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
     1012                   return false
     1013           }
     1014
     1015           if( dataMatrixStart > numRows  ) {
     1016                   log.error ".simple study wizard Data row number is incorrect: " + dataMatrixStart + " / " + numRows;
     1017                   flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
     1018                   return false
     1019           }
     1020
     1021           return true;
     1022   }
     1023       
    11161024        /**
    11171025         * Validates an object and puts human readable errors in validationErrors variable
     
    11251033                }
    11261034                return true;
    1127         }
    1128 
    1129         /**
    1130          * Adds all fields of this entity that have given an error when validating to the failedcells list
    1131          * @param failedcells   Current list of ImportRecords
    1132          * @param entity                Entity to check. The entity must have been validated before
    1133          * @return                              Updated list of ImportRecords
    1134          */
    1135         protected def addNonValidatingCells( failedcells, entity ) {
    1136                 // Add this entity and the fields with an error to the failedCells list
    1137                 ImportRecord failedRecord = new ImportRecord();
    1138 
    1139                 entity.getErrors().getFieldErrors().each { error ->
    1140                         String field = error.getField();
    1141                        
    1142                         def mc = importerService.findMappingColumn( session.simpleWizard.excel.data.header, field );
    1143                         def mcInstance = new MappingColumn( name: field, entityClass: Sample.class, index: -1, property: field.toLowerCase(), templateFieldType: entity.giveFieldType( field ) );
    1144 
    1145                         // Create a clone of the mapping column
    1146                         if( mc ) {
    1147                                 mcInstance.properties = mc.properties
    1148                         }
    1149 
    1150                         failedRecord.addToImportcells( new ImportCell(mappingcolumn: mcInstance, value: error.getRejectedValue(), entityidentifier: importerService.getFieldNameInTableEditor( entity, field ) ) )
    1151                 }
    1152                 failedcells.add( failedRecord );
    1153 
    1154                 return failedcells
    1155         }
    1156 
    1157 
    1158         /**
    1159          * Checks an excel workbook whether the given sheetindex and rownumbers are correct     
    1160          * @param workbook                      Excel workbook to read
    1161          * @param sheetIndex            1-based sheet index for the sheet to read (1=first sheet)
    1162          * @param headerRow                     1-based row number for the header row (1=first row)
    1163          * @param dataMatrixStart       1-based row number for the first data row (1=first row)
    1164          * @return                                      True if the sheet index and row numbers are correct.
    1165          */
    1166         protected boolean excelChecks( def workbook, int sheetIndex, int headerRow, int dataMatrixStart ) {
    1167                 // Perform some basic checks on the excel file. These checks should be performed by the importerservice
    1168                 // in a perfect scenario.
    1169                 if( sheetIndex > workbook.getNumberOfSheets() ) {
    1170                         log.error ".simple study wizard Sheet index is too high: " + sheetIndex + " / " + workbook.getNumberOfSheets();
    1171                         flash.error = "Your excel sheet contains too few excel sheets. The provided excel sheet has only " + workbook.getNumberOfSheets() + " sheet(s).";
    1172                         return false
    1173                 }
    1174 
    1175                 def sheet = workbook.getSheetAt(sheetIndex - 1);
    1176                 def firstRowNum = sheet.getFirstRowNum();
    1177                 def lastRowNum = sheet.getLastRowNum();
    1178                 def numRows = lastRowNum - firstRowNum + 1;
    1179 
    1180                 if( headerRow > numRows  ) {
    1181                         log.error ".simple study wizard Header row number is incorrect: " + headerRow + " / " + numRows;
    1182                         flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
    1183                         return false
    1184                 }
    1185 
    1186                 if( dataMatrixStart > numRows  ) {
    1187                         log.error ".simple study wizard Data row number is incorrect: " + dataMatrixStart + " / " + numRows;
    1188                         flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
    1189                         return false
    1190                 }
    1191 
    1192                 return true;
    1193         }
    1194 
    1195         /**
    1196          * Redirects the user to the page with the given name
    1197          * @param action
    1198          */
    1199         protected void toPage( String action ) {
    1200                 println "Redirecting to: " + action;
    1201                 redirect( action: action, params: [ "wizard": true ] );
    1202         }
    1203 
    1204         /**
    1205          * Returns the event that is specified by the user form
    1206          * @param params
    1207          * @return
    1208          */
    1209         protected String getEvent( def params ) {
    1210                 return params.get( 'event' );
    1211         }
    1212 
    1213         /**
    1214          * Retrieves the required study from the database or return an empty Study object if
    1215          * no id is given
    1216          *
    1217          * @param params        Request parameters with params.id being the ID of the study to be retrieved
    1218          * @return                      A study from the database or an empty study if no id was given
    1219          */
    1220         protected Study getStudyFromRequest( def params ) {
    1221                 int id = params.int( "id" );
    1222 
    1223                 if( !id ) {
    1224                         return new Study( title: "New study", owner: authenticationService.getLoggedInUser() );
    1225                 }
    1226 
    1227                 Study s = Study.get( id );
    1228 
    1229                 if( !s ) {
    1230                         flash.error = "No study found with given id";
    1231                         return null;
    1232                 }
    1233                 if( !s.canWrite( authenticationService.getLoggedInUser() ) ) {
    1234                         flash.error = "No authorization to edit this study."
    1235                         return null;
    1236                 }
    1237 
    1238                 return s
    1239         }
    1240 
    1241         /**
    1242          * Attach a template to the session
    1243          * @param t
    1244          * @return
    1245          */
    1246         protected attachTemplate( Template t ) {
    1247                 if( t && !t.isAttached() ) {
    1248                         t.attach();
    1249 
    1250                         t.fields.each { field ->
    1251                                 if( field && !field.isAttached() )
    1252                                         field.attach();
    1253        
    1254                                 field.listEntries?.each { entry ->
    1255                                         if( entry && !entry.isAttached() )
    1256                                                 entry.attach();
    1257                                 }
    1258                                 field.ontologies?.each { entry ->
    1259                                         if( entry && !entry.isAttached() )
    1260                                                 entry.attach();
    1261                                 }
    1262                         }
    1263                 }
    1264         }
    1265        
    1266         /**
    1267          * Retrieves the study that is saved in the wizard,
    1268          *
    1269          * @param params        Request parameters
    1270          * @return                      The found study object, or null if no study object is found
    1271          */
    1272         protected Study getStudyInWizard( def params ) {
    1273                 if( params.wizard && session.simpleWizard && session.simpleWizard.study ) {
    1274                         // The user came here by clicking previous or a link on another page. Use the existing study
    1275                         Study s = session.simpleWizard.study;
    1276 
    1277                         if( s.id && !s.isAttached() ) {
    1278                                 s.attach();
    1279                         }
    1280                        
    1281                         s.samples?.each {
    1282                                 if( it && it.id && !it.isAttached() )
    1283                                         it.attach();
    1284                                          
    1285                                 attachTemplate( it.template )
    1286                         }
    1287                         s.subjects?.each {
    1288                                 if( it && it.id && !it.isAttached() )
    1289                                         it.attach();
    1290                                          
    1291                                 attachTemplate( it.template )
    1292                         }
    1293                         s.events?.each {
    1294                                 if( it && it.id && !it.isAttached() )
    1295                                         it.attach();
    1296                                          
    1297                                 attachTemplate( it.template )
    1298                         }
    1299 
    1300                         s.samplingEvents?.each {
    1301                                 if( it && it.id && !it.isAttached() )
    1302                                         it.attach();
    1303                                          
    1304                                 attachTemplate( it.template )
    1305                         }
    1306                         s.assays?.each {
    1307                                 if( it && it.id && !it.isAttached() )
    1308                                         it.attach();
    1309                                          
    1310                                 attachTemplate( it.template )
    1311                         }
    1312 
    1313                         return s;
    1314                 } else {
    1315                         // The user didn't get here from the wizard or no study is found
    1316                         return null;
    1317                 }
    1318         }
    1319 
    1320         /**
    1321          * Retrieves the assay to edit in the wizard
    1322          * @param s             Study that the assay will be in
    1323          * @return              Assay object (may be empty)
    1324          */
    1325         protected Assay getAssayInWizard( Study study = null ) {
    1326                 if( session.simpleWizard && session.simpleWizard.assay ) {
    1327                         Assay a = session.simpleWizard.assay;
    1328 
    1329                         if( a.id && !a.isAttached() ) {
    1330                                 a.attach();
    1331 
    1332                                 attachTemplate( a.template );
    1333                         }
    1334 
    1335                         return a;
    1336                 } else if( study ) {
    1337                         // The user came on the assay page for the first time
    1338                         if( study.assays?.size() ) {
    1339                                 def assay = study.assays[0];
    1340 
    1341                                 return assay;
    1342                         } else {
    1343                                 return new Assay( parent: study );
    1344                         }
    1345                 } else {
    1346                         return null;
    1347                 }
    13481035        }
    13491036
  • trunk/grails-app/services/dbnp/importer/ImporterService.groovy

    r1603 r1608  
    2323        def authenticationService
    2424
    25         static transactional = true
     25        static transactional = false
    2626
    2727        /**
     
    339339                        importedEntities = importedRows.flatten().findAll { it.class == dbnp.studycapturing.Sample }.unique();
    340340
    341                 def importedSample = findEntityInImportedEntities( dbnp.studycapturing.Sample, excelRow, mcmap, importedEntities, df )
    342                 def imported = retrieveEntitiesBySample( importedSample );
     341                def importedSample = null // findEntityInImportedEntities( dbnp.studycapturing.Sample, excelRow, mcmap, importedEntities, df )
     342                def imported = [] // retrieveEntitiesBySample( importedSample );
    343343               
    344344                for( entity in entities ) {
     
    675675         * Retrieves a mapping column from a list based on the given fieldname
    676676         * @param mappingColumns                List of mapping columns
    677          * @param fieldName                     Field name to find
    678          * @return                                      Mapping column if a column is found, null otherwise
     677         * @param fieldName                             Field name to find
     678         * @return                                              Mapping column if a column is found, null otherwise
    679679         */
    680680        def findMappingColumn( mappingColumns, String fieldName ) {
Note: See TracChangeset for help on using the changeset viewer.