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

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