root/trunk/grails-app/services/dbnp/importer/ImporterService.groovy @ 632

Revision 632, 11.3 KB (checked in by tabma, 4 years ago)

- extra step for Simple Import Wizard implemented for easy adding and editing of cells (which were not imported yet)

  • Property svn:keywords set to Date Author Rev
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$
13 * $Author$
14 * $Date$
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() + 1
55        //def header = []
56        def header = [:]
57        def df = new DataFormatter()
58        def property = new String()
59
60        for (HSSFCell c: sheet.getRow(datamatrix_start)) {
61            def index   =   c.getColumnIndex()
62            def datamatrix_celltype = sheet.getRow(datamatrix_start).getCell(index).getCellType()
63            def headercell = sheet.getRow(sheet.getFirstRowNum()).getCell(index)
64            def tft = TemplateFieldType.STRING //default templatefield type
65           
66            // Check for every celltype, currently redundant code, but possibly this will be
67            // a piece of custom code for every cell type like specific formatting
68               
69            switch (datamatrix_celltype) {
70                    case HSSFCell.CELL_TYPE_STRING:
71                            //parse cell value as double
72                            def parsable = true
73                            def fieldtype = TemplateFieldType.STRING
74
75                            // is this string perhaps a double?
76                            try {
77                                formatValue(c.getStringCellValue(), TemplateFieldType.DOUBLE)
78                            } catch (NumberFormatException nfe) { parsable = false }
79                            finally {
80                                if (parsable) fieldtype = TemplateFieldType.DOUBLE
81                            }
82
83                            header[index] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
84                                                                            templatefieldtype:fieldtype,
85                                                                            index:index,
86                                                                            entity:theEntity,
87                                                                            property:property);
88
89                            break
90                    case HSSFCell.CELL_TYPE_NUMERIC:                   
91                            if (HSSFDateUtil.isCellDateFormatted(c)) {
92                                header[index] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
93                                                                                templatefieldtype:TemplateFieldType.DATE,
94                                                                                index:index,
95                                                                                entity:theEntity,
96                                                                                property:property)
97                            }
98                            else
99                                header[index] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
100                                                                                templatefieldtype:TemplateFieldType.INTEGER,
101                                                                                index:index,
102                                                                                entity:theEntity,
103                                                                                property:property);
104                            break
105                    case HSSFCell.CELL_TYPE_BLANK:
106                            header[index] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
107                                                                            templatefieldtype:TemplateFieldType.STRING,
108                                                                            index:index,
109                                                                            entity:theEntity,
110                                                                            property:property);
111                            break
112                    default:
113                            header[index] = new dbnp.importer.MappingColumn(name:df.formatCellValue(headercell),
114                                                                            templatefieldtype:TemplateFieldType.STRING,
115                                                                            index:index,
116                                                                            entity:theEntity,
117                                                                            property:property);
118                            break
119            } // end of switch
120        } // end of cell loop
121        return header
122    }
123
124    /**
125     * This method is meant to return a matrix of the rows and columns
126     * used in the preview
127     *
128     * @param wb workbook object
129     * @param sheetindex sheet index used
130     * @param rows amount of rows returned
131     * @return two dimensional array (matrix) of HSSFCell objects
132     */
133
134    HSSFCell[][] getDatamatrix(HSSFWorkbook wb, int sheetindex, int count) {
135        def sheet = wb.getSheetAt(sheetindex)
136        def rows  = []
137        def df = new DataFormatter()
138        def datamatrix_start = 1
139
140        // walk through all rows
141        (count <= sheet.getLastRowNum()) ?
142        ((datamatrix_start+sheet.getFirstRowNum())..count).each { rowindex ->
143            def row = []
144
145            // walk through every cell
146            for (HSSFCell c: sheet.getRow(rowindex))
147                row.add(c)
148                //row.add(df.formatCellValue(c))
149            rows.add(row)
150        } : 0
151
152        return rows
153    }
154
155    /**
156    * This method will move a file to a new location.
157    *
158    * @param file File object to move
159    * @param folderpath folder to move the file to
160    * @param filename (new) filename to give
161    * @return if file has been moved succesful, the new path and filename will be returned, otherwise an empty string will be returned
162    */
163    def moveFile(File file, String folderpath, String filename) {
164        try {
165                def rnd = ""; //System.currentTimeMillis()
166                file.transferTo(new File(folderpath, rnd+filename))
167                return folderpath + filename
168            } catch(Exception exception) {
169                log.error "File move error, ${exception}"
170                return ""
171                }
172    }
173
174    /**
175    * @return random numeric value
176    */
177    def random = {
178            return System.currentTimeMillis() + Runtime.runtime.freeMemory()
179        }
180
181    /**
182    * Method to read data from a workbook and to import data into the database
183    * by using mapping information
184    *
185    * @param template_id template identifier to use fields from
186    * @param wb POI horrible spreadsheet formatted workbook object
187    * @param mcmap linked hashmap (preserved order) of MappingColumns
188    * @param sheetindex sheet to use when using multiple sheets
189    * @param rowindex first row to start with reading the actual data (NOT the header)
190    * @return two dimensional array containing records (with entities)
191    *
192    * @see dbnp.importer.MappingColumn
193    */
194    def importdata(template_id, HSSFWorkbook wb, int sheetindex, int rowindex, mcmap) {
195        def sheet = wb.getSheetAt(sheetindex)
196        def table = []
197
198       
199        // walk through all rows       
200        (rowindex..sheet.getLastRowNum()).each { i ->
201            table.add(createRecord(template_id, sheet.getRow(i), mcmap))
202        }
203
204        /*table.each {
205            it.each { entity ->
206                entity.giveFields().each { field ->
207                    print field.name + ":" + entity.getFieldValue(field.name) + "/"
208                }
209                println
210            }
211        }*/
212
213        return table   
214    }
215   
216     /**
217                     // start transaction
218                        def transaction = sessionFactory.getCurrentSession().beginTransaction()
219                              // persist data to the database
220                                try {
221                                   // commit transaction
222                                        println "commit"
223                                        transaction.commit()
224                                        success()
225                                } catch (Exception e) {
226                                        // rollback
227                                        // stacktrace in flash scope
228                                        flash.debug = e.getStackTrace()
229
230                                        println "rollback"
231                                        transaction.rollback()
232                                        error()
233                                }
234      */
235
236    /**
237     * Method to store a matrix containing the entities in a record like structure. Every row in the table
238     * contains one or more entity objects (which contain fields with values). So actually a row represents
239     * a record with fields from one or more different entities.
240     *
241     * @param study entity Study
242     * @param datamatrix two dimensional array containing entities with values read from Excel file     *
243     */   
244    def saveDatamatrix(Study study, datamatrix) {
245        study.refresh()
246       
247        datamatrix.each { record ->
248            record.each { entity ->
249                switch (entity.getClass()) {
250                    case Study   :  print "Persisting Study `" + entity.title + "`: "
251                                    persistEntity(entity)
252                                    break
253                    case Subject :  print "Persisting Subject `" + entity.name + "`: "
254                                    persistEntity(entity)
255                                    study.addToSubjects(entity)
256                                    break
257                    case Event   :  print "Persisting Event `" + entity.eventdescription + "`: "
258                                    persistEntity(entity)
259                                    break
260                    case Sample  :  print "Persisting Sample `" + entity.name +"`: "
261                                    persistEntity(entity)
262                                    break
263                    default      :  println "Skipping persisting of `" + entity.getclass() +"`"
264                                    break
265                }
266            }
267        }
268    }
269
270    /**
271     * Method to persist entities into the database
272     * Checks whether entity already exists (based on identifier column 'name')
273     *
274     * @param entity entity object like Study, Subject, Protocol et cetera
275     *
276     */
277    def persistEntity(entity) {
278        if (entity.save(flush:true)) {  //.merge?           
279        } else entity.errors.allErrors.each {
280                println it
281        }
282    }
283
284    /**
285     * This method creates a record (array) containing entities with values
286     *
287     * @param template_id template identifier
288     * @param excelrow POI based Excel row containing the cells
289     * @param mcmap map containing MappingColumn objects
290     */
291    def createRecord(template_id, HSSFRow excelrow, mcmap) {
292        def df = new DataFormatter()
293        def template = Template.get(template_id)
294        def record = []
295       
296        def study = new Study(template:template)
297        def subject = new Subject(template:template)
298        def event = new Event(template:template)
299        def sample = new Sample(template:template)
300
301        for (HSSFCell cell: excelrow) {     
302            def mc = mcmap[cell.getColumnIndex()]
303            def value = formatValue(df.formatCellValue(cell), mc.templatefieldtype)
304
305            switch(mc.entity) {
306                case Study      :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(study)                                 
307                                    study.setFieldValue(mc.property, value)
308                                    break
309                case Subject    :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(subject)
310                                    subject.setFieldValue(mc.property, value)                               
311                                    break
312                case Event      :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(event)                                 
313                                    event.setFieldValue(mc.property, value)
314                                    break
315                case Sample     :   (record.any {it.getClass()==mc.entity}) ? 0 : record.add(sample)                               
316                                    sample.setFieldValue(mc.property, value)
317                                    break
318                case Object     :   // don't import
319                                    break
320            } // end switch
321        } // end for
322
323        return record
324    }
325
326    /**
327    * Method to parse a value conform a specific type
328    * @param value string containing the value
329    * @return object corresponding to the TemplateFieldType
330    */
331    def formatValue(String value, TemplateFieldType type) throws NumberFormatException {
332            switch (type) {
333                case TemplateFieldType.STRING       :   return value.trim()
334                case TemplateFieldType.TEXT         :   return value.trim()
335                case TemplateFieldType.INTEGER      :   return Integer.valueOf(value.replaceAll("[^0-9]",""))
336                case TemplateFieldType.FLOAT        :   return Float.valueOf(value.replace(",","."));
337                case TemplateFieldType.DOUBLE       :   return Double.valueOf(value.replace(",","."));
338                case TemplateFieldType.STRINGLIST   :   return value.trim()
339                case TemplateFieldType.ONTOLOGYTERM :   return value.trim()
340                case TemplateFieldType.DATE         :   return value
341                default                             :   return value
342            }
343    }
344}
Note: See TracBrowser for help on using the browser.