source: trunk/grails-app/services/CsvService.groovy @ 290

Last change on this file since 290 was 290, checked in by gav, 10 years ago

Secure and work on import asset tree functions.
Improvements to CustomTagLib.

File size: 7.0 KB
Line 
1import au.com.bytecode.opencsv.CSVWriter
2import au.com.bytecode.opencsv.CSVReader
3
4/**
5 * Provides some csv import/export methods.
6 * Requires the opencsv jar to be available which is included in the grails-export plugin.
7 */
8class CsvService {
9
10    boolean transactional = false
11
12    /**
13    * Import an asset tree creating items as required.
14    * @param request The http request to run getFile against.
15    * Get file should return a csv format file containing the asset tree as per template.
16    */
17    def importAssetTree(request) {
18        Asset.withTransaction { status ->
19            def result = [:]
20
21            def megaByteMultiplier = 1000 * 1000
22            def fileMaxSize = 10 * megaByteMultiplier //Mb
23
24            def multiPartFile = request.getFile('file')
25
26            InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream)
27            CSVReader reader = new CSVReader(sr)
28
29            def fail = { Map m ->
30                status.setRollbackOnly()
31                reader.close()
32                result.error = [ code: m.code, args: m.args ]
33                return result
34            }
35
36            if(!multiPartFile || multiPartFile.isEmpty())
37                return fail(code: "asset.tree.import.file.not.supplied")
38
39            if (multiPartFile.getSize() > fileMaxSize)
40                return fail(code: "asset.tree.import.file.over.max.size", args: [fileMaxSize/megaByteMultiplier])
41
42            def line = reader.readNext()
43            def lineNumber = 1
44
45            def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]
46
47            if(line != header)
48                return fail(code: "asset.tree.import.no.header")
49
50            log.info "Import checks passed, start processing asset file."
51
52            // Prepare the first body line.
53            line = reader.readNext()
54            lineNumber ++
55
56            def siteInstance
57            def sectionInstance
58            def assetInstance
59
60            while(line) {
61                def lineSize = line.size()
62    //             log.info lineNumber+ "(" + lineSize + ")" + " : " + line
63
64                if(line[0]) {
65                        if( !Site.findByName(line[0]) )
66                            siteInstance = new Site(name: line[0])
67                            if(!siteInstance.save())
68                                return fail(code: "asset.tree.import.failure", args: [lineNumber])
69                }
70                else continue
71
72                if(line[1]) {
73                        if( !Section.findByName(line[1]) )
74                           sectionInstance =  new Section(name: line[1],
75                                                                                site: siteInstance)
76                            if(!sectionInstance.save())
77                                return fail(code: "asset.tree.import.failure", args: [lineNumber])
78                }
79                else continue
80
81                if(line[2]) {
82                        if( !Asset.findByName(line[2]) )
83                            assetInstance = new Asset(name: line[2],
84                                                                        section: sectionInstance)
85                            if(!sectionInstance.save())
86                                return fail(code: "asset.tree.import.failure", args: [lineNumber])
87                }
88                else continue
89
90                line = reader.readNext()
91                lineNumber ++
92            } //while(line)
93
94            // Success.
95            reader.close()
96            return result
97
98        } //end withTransaction
99    } // end importAssetTree()
100
101    /**
102    * Build an asset tree template csv file.
103    * This template can then be populated for import.
104    * @returns The template as a String in csv format.
105    */
106    def buildAssetTreeTemplate() {
107
108        StringWriter sw = new StringWriter()
109        CSVWriter writer = new CSVWriter(sw)
110
111        //Header
112        def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]
113        def blankLine = []
114        def noteLine = ["Note: the header is required, start by replacing this line."]
115
116        writer.writeNext(header as String[])
117        writer.writeNext(blankLine as String[])
118        writer.writeNext(noteLine as String[])
119
120        writer.close()
121        return sw.toString()
122    }
123
124    /**
125    * Build complete asset trees for export.
126    * @param assetList The list of assets to build and export trees for.
127    * @returns The tree as a String in csv format.
128    */
129    def buildAssetTree(List assetList) {
130
131        StringWriter sw = new StringWriter()
132        CSVWriter writer = new CSVWriter(sw)
133
134        //Header
135        def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"]
136        writer.writeNext(header as String[])
137
138        //Rows
139        def row
140
141        def writeAssetSubItem4 = { assetSubItem ->
142            row.add(assetSubItem)
143            writer.writeNext(row as String[])
144        }
145
146        def writeAssetSubItem3 = { assetSubItem ->
147            row.add(assetSubItem)
148
149            if(assetSubItem.subItems.size() > 0) {
150                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem4 ->
151                    writeAssetSubItem4(assetSubItem4)
152                    row.remove(row.last())
153                }
154            }
155            else {
156                writer.writeNext(row as String[])
157            }
158
159        }
160
161        def writeAssetSubItem2 = { assetSubItem ->
162            row.add(assetSubItem)
163
164            if(assetSubItem.subItems.size() > 0) {
165                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem3 ->
166                    writeAssetSubItem3(assetSubItem3)
167                    row.remove(row.last())
168                }
169            }
170            else {
171                writer.writeNext(row as String[])
172            }
173
174        }
175
176        def writeAssetSubItem1 = { assetSubItem ->
177            row.add(assetSubItem)
178
179            if(assetSubItem.subItems.size() > 0) {
180                assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem2 ->
181                    writeAssetSubItem2(assetSubItem2)
182                    row.remove(row.last())
183                }
184            }
185            else {
186                writer.writeNext(row as String[])
187            }
188
189        }
190
191        assetList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { asset ->
192            row = []
193            writer.writeNext(row as String[]) //blank row between assets.
194            row.add(asset.section.site)
195            row.add(asset.section)
196            row.add(asset.name)
197
198            if(asset.assetSubItems.size() > 0) {
199                asset.assetSubItems.each() { assetSubItem1 ->
200                    writeAssetSubItem1(assetSubItem1)
201                    row.remove(row.last())
202                }
203            }
204            else {
205                writer.writeNext(row as String[])
206            }
207
208        }
209
210        writer.close()
211        return sw.toString()
212    } // end buildAssetTree
213
214} // end class
Note: See TracBrowser for help on using the repository browser.