source: trunk/grails-app/services/dbnp/importer/ImporterService.groovy @ 655

Last change on this file since 655 was 655, checked in by tabma, 11 years ago
  • fixed header and column import with mouse test dataset
  • Property svn:keywords set to Date Author Rev
File size: 12.5 KB
Line 
1/**
2 * Importer service
3 *
4 * The importer service handles the import of tabular, comma delimited and Excel format
5 * based files.
6 *
7 * @package     importer
8 * @author      t.w.abma@umcutrecht.nl
9 * @since       20100126
10 *
11 * Revision information:
12 * $Rev: 655 $
13 * $Author: tabma $
14 * $Date: 2010-07-15 13:38:18 +0000 (do, 15 jul 2010) $
15 */
16
17package dbnp.importer
18import org.apache.poi.hssf.usermodel.*
19import org.apache.poi.poifs.filesystem.POIFSFileSystem
20import org.apache.poi.ss.usermodel.DataFormatter
21
22import dbnp.studycapturing.TemplateFieldType
23import dbnp.studycapturing.Template
24import dbnp.studycapturing.Study
25import dbnp.studycapturing.Subject
26import dbnp.studycapturing.Event
27
28import dbnp.studycapturing.Sample
29
30import dbnp.data.Term
31
32class ImporterService {
33
34    boolean transactional = true
35
36    /**
37    * @param is input stream representing the (workbook) resource
38    * @return high level representation of the workbook
39    */
40    HSSFWorkbook getWorkbook(InputStream is) {
41        POIFSFileSystem fs = new POIFSFileSystem(is)
42        HSSFWorkbook    wb = new HSSFWorkbook(fs);
43        return wb;
44    }
45
46    /**
47     * @param wb high level representation of the workbook
48     * @param sheetindex sheet to use within the workbook
49     * @return header representation as a MappingColumn hashmap
50     */
51    def getHeader(HSSFWorkbook wb, int sheetindex, theEntity=null){
52
53        def sheet = wb.getSheetAt(sheetindex)
54        def datamatrix_start = sheet.getFirstRowNum() + 2
55        def sheetrow = sheet.getRow(datamatrix_start)
56        //def header = []
57        def header = [:]
58        def df = new DataFormatter()
59        def property = new String()
60
61        //for (HSSFCell c: sheet.getRow(datamatrix_start)) {
62
63        (0..sheetrow.getLastCellNum() -1 ).each { columnindex ->
64
65            //def index =   c.getColumnIndex()
66            def datamatrix_celltype = sheet.getRow(datamatrix_start).getCell(columnindex, org.apache.poi.ss.usermodel.Row.CREATE_NULL_AS_BLANK).getCellType()
67            def datamatrix_celldata = df.formatCellValue(sheet.getRow(datamatrix_start).getCell(columnindex))
68            def datamatrix_cell     = sheet.getRow(datamatrix_start).getCell(columnindex)
69            def headercell = sheet.getRow(sheet.getFirstRowNum()).getCell(columnindex)
70            def tft = TemplateFieldType.STRING //default templatefield type
71
72            // Check for every celltype, currently redundant code, but possibly this will be
73            // a piece of custom code for every cell type like specific formatting         
74               
75            switch (datamatrix_celltype) {
76                    case HSSFCell.CELL_TYPE_STRING:
77                            //parse cell value as double
78                            def doubleBoolean = true
79                            def fieldtype = TemplateFieldType.STRING
80
81                            // is this string perhaps a double?
82                            try {                               
83                                formatValue(datamatrix_celldata, TemplateFieldType.DOUBLE)
84                            } catch (NumberFormatException nfe) { doubleBoolean = false }
85                            finally {                           
86                                if (doubleBoolean) fieldtype = TemplateFieldType.DOUBLE
87                            }
88
89                            header[columnindex] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
90                                                                            templatefieldtype:fieldtype,
91                                                                            index:columnindex,
92                                                                            entity:theEntity,
93                                                                            property:property);
94
95                            break
96                    case HSSFCell.CELL_TYPE_NUMERIC:
97                            def fieldtype = TemplateFieldType.INTEGER
98                            def doubleBoolean = true
99                            def integerBoolean = true
100
101                            // is this cell really an integer?
102                            try {                               
103                                Integer.valueOf(datamatrix_celldata)
104                            } catch (NumberFormatException nfe) { integerBoolean = false }
105                            finally {                           
106                                if (integerBoolean) fieldtype = TemplateFieldType.INTEGER
107                            }
108
109                            // it's not an integer, perhaps a double?
110                            if (!integerBoolean)
111                                try {
112                                    formatValue(datamatrix_celldata, TemplateFieldType.DOUBLE)
113                                } catch (NumberFormatException nfe) { doubleBoolean = false }
114                                finally {
115                                    if (doubleBoolean) fieldtype = TemplateFieldType.DOUBLE
116                                }
117
118                            if (HSSFDateUtil.isCellDateFormatted(datamatrix_cell)) fieldtype = TemplateFieldType.DATE
119                           
120                            header[columnindex] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
121                                                                            templatefieldtype:fieldtype,
122                                                                            index:columnindex,
123                                                                            entity:theEntity,
124                                                                            property:property);
125                            break
126                    case HSSFCell.CELL_TYPE_BLANK:
127                            header[columnindex] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
128                                                                            templatefieldtype:TemplateFieldType.STRING,
129                                                                            index:columnindex,
130                                                                            entity:theEntity,
131                                                                            property:property);
132                            break
133                    default:
134                            header[columnindex] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
135                                                                            templatefieldtype:TemplateFieldType.STRING,
136                                                                            index:columnindex,
137                                                                            entity:theEntity,
138                                                                            property:property);
139                            break
140            } // end of switch
141        } // end of cell loop
142        return header
143    }
144
145    /**
146     * This method is meant to return a matrix of the rows and columns
147     * used in the preview
148     *
149     * @param wb workbook object
150     * @param sheetindex sheet index used
151     * @param rows amount of rows returned
152     * @return two dimensional array (matrix) of HSSFCell objects
153     */
154
155    HSSFCell[][] getDatamatrix(HSSFWorkbook wb, header, int sheetindex, int count) {
156        def sheet = wb.getSheetAt(sheetindex)
157        def rows  = []
158        def df = new DataFormatter()
159        def datamatrix_start = 1
160
161        // walk through all rows
162        (count <= sheet.getLastRowNum()) ?
163        ((datamatrix_start+sheet.getFirstRowNum())..count).each { rowindex ->
164            def row = []
165
166            // walk through every cell
167            /*for (HSSFCell c: sheet.getRow(rowindex)) {
168                row.add(c)
169                println c.getColumnIndex() + "=" +c
170            }*/
171           
172            (0..header.size()-1).each { columnindex ->
173                def c = sheet.getRow(rowindex).getCell(columnindex, org.apache.poi.ss.usermodel.Row.CREATE_NULL_AS_BLANK)
174                println "DAS " + columnindex + ":" + c
175                row.add(c)
176            }
177                //row.add(df.formatCellValue(c))
178            rows.add(row)
179        } : 0
180
181        return rows
182    }
183
184    /**
185    * This method will move a file to a new location.
186    *
187    * @param file File object to move
188    * @param folderpath folder to move the file to
189    * @param filename (new) filename to give
190    * @return if file has been moved succesful, the new path and filename will be returned, otherwise an empty string will be returned
191    */
192    def moveFile(File file, String folderpath, String filename) {
193        try {
194                def rnd = ""; //System.currentTimeMillis()
195                file.transferTo(new File(folderpath, rnd+filename))
196                return folderpath + filename
197            } catch(Exception exception) {
198                log.error "File move error, ${exception}"
199                return ""
200                }
201    }
202
203    /**
204    * @return random numeric value
205    */
206    def random = {
207            return System.currentTimeMillis() + Runtime.runtime.freeMemory()
208        }
209
210    /**
211    * Method to read data from a workbook and to import data into the database
212    * by using mapping information
213    *
214    * @param template_id template identifier to use fields from
215    * @param wb POI horrible spreadsheet formatted workbook object
216    * @param mcmap linked hashmap (preserved order) of MappingColumns
217    * @param sheetindex sheet to use when using multiple sheets
218    * @param rowindex first row to start with reading the actual data (NOT the header)
219    * @return two dimensional array containing records (with entities)
220    *
221    * @see dbnp.importer.MappingColumn
222    */
223    def importdata(template_id, HSSFWorkbook wb, int sheetindex, int rowindex, mcmap) {
224        def sheet = wb.getSheetAt(sheetindex)
225        def table = []
226
227       
228        // walk through all rows       
229        (rowindex..sheet.getLastRowNum()).each { i ->
230            table.add(createRecord(template_id, sheet.getRow(i), mcmap))
231        }
232
233        /*table.each {
234            it.each { entity ->
235                entity.giveFields().each { field ->
236                    print field.name + ":" + entity.getFieldValue(field.name) + "/"
237                }
238                println
239            }
240        }*/
241
242        return table   
243    }
244   
245     /**
246                     // start transaction
247                        def transaction = sessionFactory.getCurrentSession().beginTransaction()
248                              // persist data to the database
249                                try {
250                                   // commit transaction
251                                        println "commit"
252                                        transaction.commit()
253                                        success()
254                                } catch (Exception e) {
255                                        // rollback
256                                        // stacktrace in flash scope
257                                        flash.debug = e.getStackTrace()
258
259                                        println "rollback"
260                                        transaction.rollback()
261                                        error()
262                                }
263      */
264
265    /**
266     * Method to store a matrix containing the entities in a record like structure. Every row in the table
267     * contains one or more entity objects (which contain fields with values). So actually a row represents
268     * a record with fields from one or more different entities.
269     *
270     * @param study entity Study
271     * @param datamatrix two dimensional array containing entities with values read from Excel file     *
272     */   
273    def saveDatamatrix(Study study, datamatrix) {
274        study.refresh()
275       
276        datamatrix.each { record ->
277            record.each { entity ->
278                switch (entity.getClass()) {
279                    case Study   :  print "Persisting Study `" + entity.title + "`: "
280                                    persistEntity(entity)
281                                    break
282                    case Subject :  print "Persisting Subject `" + entity.name + "`: "
283                                    persistEntity(entity)
284                                    study.addToSubjects(entity)
285                                    break
286                    case Event   :  print "Persisting Event `" + entity.eventdescription + "`: "
287                                    persistEntity(entity)
288                                    break
289                    case Sample  :  print "Persisting Sample `" + entity.name +"`: "
290                                    persistEntity(entity)
291                                    break
292                    default      :  println "Skipping persisting of `" + entity.getclass() +"`"
293                                    break
294                }
295            }
296        }
297    }
298
299    /**
300     * Method to persist entities into the database
301     * Checks whether entity already exists (based on identifier column 'name')
302     *
303     * @param entity entity object like Study, Subject, Protocol et cetera
304     *
305     */
306    def persistEntity(entity) { 
307        if (entity.save(flush:true)) {  //.merge?           
308        } else entity.errors.allErrors.each {
309                println it
310        }
311    }
312
313    /**
314     * This method creates a record (array) containing entities with values
315     *
316     * @param template_id template identifier
317     * @param excelrow POI based Excel row containing the cells
318     * @param mcmap map containing MappingColumn objects
319     */
320    def createRecord(template_id, HSSFRow excelrow, mcmap) {
321        def df = new DataFormatter()
322        def template = Template.get(template_id)
323        def record = [] 
324       
325        def study = new Study(template:template)
326        def subject = new Subject(template:template)
327        def event = new Event(template:template)
328        def sample = new Sample(template:template)
329
330        for (HSSFCell cell: excelrow) {     
331            def mc = mcmap[cell.getColumnIndex()]
332            def value = formatValue(df.formatCellValue(cell), mc.templatefieldtype)
333
334            switch(mc.entity) {
335                case Study      :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(study)                                 
336                                    study.setFieldValue(mc.property, value)
337                                    break
338                case Subject    :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(subject)
339                                    subject.setFieldValue(mc.property, value)                               
340                                    break
341                case Event      :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(event)                                 
342                                    event.setFieldValue(mc.property, value)
343                                    break
344                case Sample     :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(sample)                               
345                                    sample.setFieldValue(mc.property, value)
346                                    break
347                case Object     :   // don't import
348                                    break
349            } // end switch
350        } // end for
351
352        return record
353    }
354
355    /**
356    * Method to parse a value conform a specific type
357    * @param value string containing the value
358    * @return object corresponding to the TemplateFieldType
359    */
360    def formatValue(String value, TemplateFieldType type) throws NumberFormatException {
361            switch (type) {
362                case TemplateFieldType.STRING       :   return value.trim()
363                case TemplateFieldType.TEXT         :   return value.trim()
364                case TemplateFieldType.INTEGER      :   return Integer.valueOf(value)
365                case TemplateFieldType.FLOAT        :   return Float.valueOf(value.replace(",","."));
366                case TemplateFieldType.DOUBLE       :   return Double.valueOf(value.replace(",","."));
367                case TemplateFieldType.STRINGLIST   :   return value.trim()
368                case TemplateFieldType.ONTOLOGYTERM :   return value.trim()
369                case TemplateFieldType.DATE         :   return value
370                default                             :   return value
371            }
372    }
373}
Note: See TracBrowser for help on using the repository browser.