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

Last change on this file since 897 was 897, checked in by keesvb, 10 years ago

fixed multiple bugs in importer, really implemented the header and start row functionality, updated Ontology setter with proper error message

  • Property svn:keywords set to Date Author Rev
File size: 10.7 KB
Line 
1/**
2 * Importer controller
3 *
4 * The importer controller handles the uploading of tabular, comma delimited and Excel format
5 * based files. When uploaded a preview is shown of the data and the user can adjust the column
6 * type. Data in cells which don't correspond to the specified column type will be represented as "#error".
7 *
8 * The importer controller catches the actions and consecutively performs the
9 * logic behind it.
10 *
11 * @package     importer
12 * @author      t.w.abma@umcutrecht.nl
13 * @since       20100126
14 *
15 * Revision information:
16 * $Rev: 897 $
17 * $Author: keesvb $
18 * $Date: 2010-09-21 08:58:35 +0000 (di, 21 sep 2010) $
19 */
20
21package dbnp.importer
22
23import dbnp.studycapturing.Template
24import dbnp.studycapturing.Study
25import dbnp.studycapturing.Subject
26import dbnp.studycapturing.Event
27
28import dbnp.studycapturing.Sample
29import dbnp.studycapturing.TemplateFieldType
30import dbnp.studycapturing.TemplateField
31import grails.converters.JSON
32import org.apache.poi.hssf.usermodel.HSSFWorkbook
33
34class ImporterController {
35    def ImporterService   
36
37    /**
38     * Default page
39     **/
40    def index = {       
41    }
42
43    def simpleWizard = {
44        render(view:"index_simple", model:[studies:Study.list(), entities: grailsApplication.config.gscf.domain.importableEntities])
45    }
46
47    def advancedWizard = {
48        render(view:"index_advanced", model:[templates:Template.list()])
49    }
50
51    /**
52    * This method will move the uploaded file to a temporary path and send the header
53    * and the first n rows to the preview
54    * @param importfile uploaded file to import
55    * @param study.id study identifier
56    */
57    def upload_advanced = {
58        def wb = handleUpload('importfile')
59
60        session.importer_header = ImporterService.getHeader(wb, 0)
61        session.importer_study = Study.get(params.study.id.toInteger())
62        session.importer_template_id = params.template_id
63        session.importer_workbook = wb
64
65        render (view:"step1_advanced", model:[header:session.importer_header, datamatrix:ImporterService.getDatamatrix(wb, session.importer_header, 0, 5)])
66    }
67
68    /**
69    * This method will move the uploaded file to a temporary path and send the header
70    * and the rows to the postview
71    *
72    * @param importfile uploaded file to import
73    * @param entity string representation of the entity chosen
74    */
75    def upload_simple = {
76        def wb = handleUpload('importfile')
77        def selectedentities = []
78        def entity = grailsApplication.config.gscf.domain.importableEntities.get(params.entity).entity
79        def entityClass = Class.forName(entity, true, this.getClass().getClassLoader())
80
81        // Initialize some session variables
82        session.importer_workbook = wb
83        session.importer_study = Study.get(params.study.id.toInteger())
84        session.importer_template_id = params.template_id
85        session.importer_sheetindex = params.sheetindex.toInteger() -1 // 0 == first sheet
86        session.importer_datamatrix_start = params.datamatrix_start.toInteger() -1 // 0 == first row
87        session.importer_headerrow = params.headerrow.toInteger()
88
89        // Get the header from the Excel file using the arguments given in the first step of the wizard
90        session.importer_header = ImporterService.getHeader(wb,
91                                                            session.importer_sheetindex,
92                                                            session.importer_headerrow,
93                                                            session.importer_datamatrix_start,
94                                                            entityClass)
95       
96        // Initialize 'selected entities', used to show entities above the columns
97        session.importer_header.each {
98            selectedentities.add([name:params.entity, columnindex:it.key.toInteger()])
99        }
100
101        def templates = Template.get(session.importer_template_id)
102       
103        render(view:"step2_simple", model:[entities: selectedentities,
104                                           header:session.importer_header,
105                                           datamatrix:ImporterService.getDatamatrix(
106                                               wb, session.importer_header,
107                                               session.importer_sheetindex,
108                                               session.importer_datamatrix_start,
109                                               5),
110                                           templates:templates])
111    }
112
113    /**
114     * This method handles a file being uploaded and storing it in a temporary directory
115     * and returning a workbook
116     *
117     * @param formfilename name used for the file field in the form
118     * @return workbook object reference
119     */
120    private HSSFWorkbook handleUpload(formfilename) {
121
122        def downloadedfile = request.getFile(formfilename);
123        def tempfile = new File(System.getProperty('java.io.tmpdir') + File.separatorChar + System.currentTimeMillis() + ".nmcdsp")
124        downloadedfile.transferTo(tempfile)
125
126        return ImporterService.getWorkbook(new FileInputStream(tempfile))
127    }
128
129    /**
130     * Method to save the missing properties
131     * @param entity entity class we are using (dbnp.studycapturing.Subject etc.)
132     */
133
134    def saveMissingProperties = {
135
136        session.importer_importeddata.each { table ->
137            table.each { entity ->
138                entity.giveFields().each { field ->
139                    //print ":" + params["entity_" + entity.hashCode() + "_" + field.escapedName()]
140                    entity.setFieldValue (field.toString(), params["entity_" + entity.hashCode() + "_" + field.escapedName()])
141                }               
142            }
143        }
144
145        render(view:"step3", model:[datamatrix:session.importer_importeddata]) 
146    }
147
148    /**
149    * User has assigned all entities and templatefieldtypes to the columns and continues to the next step (assigning properties to columns)
150    * All information of the columns is stored in a session as MappingColumn object
151    *
152    * @param entities list of entities and columns it has been assigned to (columnindex.entitytype)
153    * @param templatefieldtype list of celltypes and columns it has been assigned to (columnindex:templatefieldtype format)
154    * @return properties page
155    *
156    * @see celltype: http://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/Cell.html
157    */
158    def savePreview = {
159        def tft = null 
160        def identifiercolumnindex = (params.identifier!=null) ? params.identifier.toInteger() : -1
161        def selectedentities = []
162
163        // loop all entities and see which column has been assigned which entitytype
164        // and build an array containing the selected entities
165        params.entity.index.each { columnindex, entityname ->
166            def _entity = [name:entityname,columnindex:columnindex.toInteger()]
167            selectedentities.add(_entity)
168        }
169
170        params.templatefieldtype.index.each { columnindex, _templatefieldtype ->
171            switch (_templatefieldtype) {
172                case "STRING"       : tft = TemplateFieldType.STRING
173                                      break
174                case "TEXT"         : tft = TemplateFieldType.TEXT
175                                      break
176                case "INTEGER"      : tft = TemplateFieldType.INTEGER
177                                      break
178                case "FLOAT"        : tft = TemplateFieldType.FLOAT
179                                      break
180                case "DOUBLE"       : tft = TemplateFieldType.DOUBLE
181                                      break
182                case "STRINGLIST"   : tft = TemplateFieldType.STRINGLIST
183                                      break
184                case "ONTOLOGYTERM" : tft = TemplateFieldType.ONTOLOGYTERM
185                                      break
186                case "DATE"         : tft = TemplateFieldType.DATE
187                                      break
188                default: break
189            }
190           
191            // Set the templatefield type for this column
192            session.importer_header[columnindex.toInteger()].templatefieldtype = tft
193        }
194
195        // Detect the entity type
196        params.entity.index.each { columnindex, entityname ->
197            Class clazz = null
198
199            switch (entityname) {
200                case "Study"    : clazz = dbnp.studycapturing.Study
201                        break
202                case "Subject"  : clazz = dbnp.studycapturing.Subject
203                        break
204                case "Event"    : clazz = dbnp.studycapturing.Event
205                        break
206                case "Protocol" : clazz = dbnp.studycapturing.Protocol
207                        break
208                case "Sample"   : clazz = dbnp.studycapturing.Sample
209                        break
210                default: clazz = Object
211                        break
212            }
213
214            // Store properties for this column
215            session.importer_header[columnindex.toInteger()].identifier = (columnindex.toInteger() == identifiercolumnindex) ? true : false
216            session.importer_header[columnindex.toInteger()].index = columnindex.toInteger()
217            session.importer_header[columnindex.toInteger()].entity = clazz
218        }
219
220        // currently only one template is used for all entities
221        // TODO: show template fields per entity
222       
223        def templates = Template.get(session.importer_template_id)
224
225        render(view:"step2", model:[entities:selectedentities, header:session.importer_header, templates:templates])
226    }
227
228    /**
229    * @param columnproperty array of columns containing index and property (represented as a String)
230    *
231    */
232    def saveProperties = {
233
234        // Find actual Template object from the chosen template name
235        def template = Template.get(session.importer_template_id)
236
237        params.columnproperty.index.each { columnindex, property ->
238
239                // Create an actual class instance of the selected entity with the selected template
240                // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities
241                def entityClass = Class.forName(session.importer_header[columnindex.toInteger()].entity.getName(), true, this.getClass().getClassLoader())
242                def entityObj = entityClass.newInstance(template:template)
243
244                // Store the selected property for this column into the column map for the ImporterService
245                session.importer_header[columnindex.toInteger()].property = property
246
247                // Look up the template field type of the target TemplateField and store it also in the map
248                session.importer_header[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property)
249
250                // Is a "Don't import" property assigned to the column?
251                session.importer_header[columnindex.toInteger()].dontimport = (property=="dontimport") ? true : false
252
253                //if it's an identifier set the mapping column true or false
254                entityObj.giveFields().each {
255                    (it.preferredIdentifier && (it.name==property)) ? session.importer_header[columnindex.toInteger()].identifier = true : false
256                }
257        }
258
259        //import workbook
260        session.importer_importeddata = ImporterService.importdata(session.importer_template_id, session.importer_workbook, session.importer_sheetindex, session.importer_datamatrix_start, session.importer_header)
261
262        if (params.layout=="horizontal")
263            render(view:"step3_simple", model:[datamatrix:session.importer_importeddata])
264        else if (params.layout=="vertical")
265            render(view:"step3", model:[datamatrix:session.importer_importeddata])
266    }
267
268    /**
269     * Method which saves the data matrix to the database
270     */
271    def savePostview = {
272        def validatedSuccesfully = ImporterService.saveDatamatrix(session.importer_study, session.importer_importeddata)
273        render(view:"step4", model:[validatedSuccesfully:validatedSuccesfully, totalrows:session.importer_importeddata.size])
274    }
275
276    /**
277    * Return templates which belong to a certain entity type
278    *
279    * @param entity entity name string (Sample, Subject, Study et cetera)
280    * @return JSON object containing the found templates
281    */
282    def ajaxGetTemplatesByEntity = {
283        def entityClass = grailsApplication.config.gscf.domain.importableEntities.get(params.entity).entity
284       
285
286        // fetch all templates for a specific entity
287        def templates = Template.findAllByEntity(Class.forName(entityClass, true, this.getClass().getClassLoader()))   
288
289        // render as JSON
290        render templates as JSON
291    }
292}
Note: See TracBrowser for help on using the repository browser.