import au.com.bytecode.opencsv.CSVWriter import au.com.bytecode.opencsv.CSVReader /** * Provides some csv import/export methods. * Requires the opencsv jar to be available which is included in the grails-export plugin. */ class CsvService { boolean transactional = false /** * Import an asset tree creating items as required. * @param request The http request to run getFile against. * Get file should return a csv format file containing the asset tree as per template. */ def importAssetTree(request) { Asset.withTransaction { status -> def result = [:] def megaByteMultiplier = 1000 * 1000 def fileMaxSize = 10 * megaByteMultiplier //Mb def multiPartFile = request.getFile('file') InputStreamReader sr = new InputStreamReader(multiPartFile.inputStream) CSVReader reader = new CSVReader(sr) def fail = { Map m -> status.setRollbackOnly() reader.close() result.error = [ code: m.code, args: m.args ] return result } if(!multiPartFile || multiPartFile.isEmpty()) return fail(code: "asset.tree.import.file.not.supplied") if (multiPartFile.getSize() > fileMaxSize) return fail(code: "asset.tree.import.file.over.max.size", args: [fileMaxSize/megaByteMultiplier]) def line = reader.readNext() def lineNumber = 1 def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"] if(line != header) return fail(code: "asset.tree.import.no.header") log.info "Import checks passed, start processing asset file." // Prepare the first body line. line = reader.readNext() lineNumber ++ def siteInstance def sectionInstance def assetInstance while(line) { def lineSize = line.size() // log.info lineNumber+ "(" + lineSize + ")" + " : " + line if(line[0]) { if( !Site.findByName(line[0]) ) siteInstance = new Site(name: line[0]) if(!siteInstance.save()) return fail(code: "asset.tree.import.failure", args: [lineNumber]) } else continue if(line[1]) { if( !Section.findByName(line[1]) ) sectionInstance = new Section(name: line[1], site: siteInstance) if(!sectionInstance.save()) return fail(code: "asset.tree.import.failure", args: [lineNumber]) } else continue if(line[2]) { if( !Asset.findByName(line[2]) ) assetInstance = new Asset(name: line[2], section: sectionInstance) if(!sectionInstance.save()) return fail(code: "asset.tree.import.failure", args: [lineNumber]) } else continue line = reader.readNext() lineNumber ++ } //while(line) // Success. reader.close() return result } //end withTransaction } // end importAssetTree() /** * Build an asset tree template csv file. * This template can then be populated for import. * @returns The template as a String in csv format. */ def buildAssetTreeTemplate() { StringWriter sw = new StringWriter() CSVWriter writer = new CSVWriter(sw) //Header def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"] def blankLine = [] def noteLine = ["Note: the header is required, start by replacing this line."] writer.writeNext(header as String[]) writer.writeNext(blankLine as String[]) writer.writeNext(noteLine as String[]) writer.close() return sw.toString() } /** * Build complete asset trees for export. * @param assetList The list of assets to build and export trees for. * @returns The tree as a String in csv format. */ def buildAssetTree(List assetList) { StringWriter sw = new StringWriter() CSVWriter writer = new CSVWriter(sw) //Header def header = ["Site", "Section", "Asset", "Sub Asset", "Functional Assembly", "Sub Assembly Group"] writer.writeNext(header as String[]) //Rows def row def writeAssetSubItem4 = { assetSubItem -> row.add(assetSubItem) writer.writeNext(row as String[]) } def writeAssetSubItem3 = { assetSubItem -> row.add(assetSubItem) if(assetSubItem.subItems.size() > 0) { assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem4 -> writeAssetSubItem4(assetSubItem4) row.remove(row.last()) } } else { writer.writeNext(row as String[]) } } def writeAssetSubItem2 = { assetSubItem -> row.add(assetSubItem) if(assetSubItem.subItems.size() > 0) { assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem3 -> writeAssetSubItem3(assetSubItem3) row.remove(row.last()) } } else { writer.writeNext(row as String[]) } } def writeAssetSubItem1 = { assetSubItem -> row.add(assetSubItem) if(assetSubItem.subItems.size() > 0) { assetSubItem.subItems.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { assetSubItem2 -> writeAssetSubItem2(assetSubItem2) row.remove(row.last()) } } else { writer.writeNext(row as String[]) } } assetList.sort { p1, p2 -> p1.name.compareToIgnoreCase(p2.name) }.each() { asset -> row = [] writer.writeNext(row as String[]) //blank row between assets. row.add(asset.section.site) row.add(asset.section) row.add(asset.name) if(asset.assetSubItems.size() > 0) { asset.assetSubItems.each() { assetSubItem1 -> writeAssetSubItem1(assetSubItem1) row.remove(row.last()) } } else { writer.writeNext(row as String[]) } } writer.close() return sw.toString() } // end buildAssetTree } // end class