source: trunk/grails-app/controllers/nl/tno/massSequencing/files/ExportController.groovy @ 74

Last change on this file since 74 was 74, checked in by robert@…, 8 years ago
  • Several bugfixes
  • Added an extra step in the worker process for importing data
File size: 9.6 KB
Line 
1package nl.tno.massSequencing.files
2
3import groovy.xml.MarkupBuilder
4import groovy.xml.StreamingMarkupBuilder
5
6import java.util.Date;
7import java.util.zip.ZipEntry
8import java.util.zip.ZipOutputStream
9import nl.tno.massSequencing.*;
10import org.codehaus.groovy.grails.commons.ConfigurationHolder
11
12class ExportController {
13        def fileService
14        def workerService
15       
16        /**
17         * Exports all studies to XML
18         */
19        def zip = {
20                // Determine the number of samples and sequences to be processed.
21                // The number of samples gives an indication for the time to export the xml
22                // the number of sequences give an indication for the tim to export the files
23                def studies = Study.findAll( "FROM Study s WHERE exists( FROM Auth a WHERE a.study = s AND a.user = :user AND a.canRead = true )", [ "user": session.user ] );
24                def totalProgress = 0
25               
26                if( studies ) {
27                        def measures = AssaySample.executeQuery( "SELECT COUNT(*), SUM(a.numSequences) FROM AssaySample a WHERE a.assay.study IN (:studies)", [ 'studies': studies ] )[0]
28                        totalProgress = measures[ 0 ] + measures[ 1 ];
29                }
30               
31                def httpSession = session;
32               
33                // Create a worker screen to create the fasta file in the background
34                def processId = workerService.initProcess( httpSession, "Creating your download", 1, totalProgress )
35
36                // Create URLs to return to after downloading
37                def returnUrl = createLink( controller: "run" ).toString()
38                def finishUrl = createLink( controller: "export", action: 'downloadZip', params: [ processId: '%s' ] ).toString();
39                finishUrl = sprintf( finishUrl, processId );
40
41                httpSession.process[ processId ][ "returnUrl" ] = returnUrl
42               
43                // Retrieve worker URL; returnUrl is the same as the errorUrl
44                def url = workerService.startProcess( httpSession, processId, finishUrl, returnUrl, returnUrl )
45               
46                // Make sure the background process can send the progress to the HTTP session.
47                def onProgress = { progress ->
48                        // Update progress
49                        httpSession.progress[ processId ].stepProgress += progress;
50                }
51
52                // Perform the real work in a background thread
53                def studyIds = studies.collect { it.id }
54                studies = null;
55               
56                runAsync {
57                        def filename = fileService.getUniqueFilename( "zipdownload" );
58                        def file = fileService.get( filename );
59                       
60                        studies = studyIds ? Study.findAll( "FROM Study WHERE id in (:ids)", [ "ids": studyIds ] ) : [] 
61                       
62                        try {
63                                createZip( file, studies, onProgress );
64                        } catch( Exception e ) {
65                                log.error( "Exception occurred during export of data: " );
66                                e.printStackTrace();
67
68                                httpSession.progress[ processId ].error = true;
69                                httpSession.progress[ processId ].errorMessage += e.getMessage();
70                        }
71                       
72                        // Store the filename for later download
73                        httpSession.process[ processId ].filename = filename;
74                       
75                        // Tell the frontend we are finished
76                        httpSession.progress[ processId ].finished = true;
77                }
78 
79                // Show a waiting screen
80                redirect( url: url );
81        }
82       
83        protected void createZip( File file, def studies, Closure onProgress ) {
84                // Find all runs
85                def runs = Run.list();
86               
87                // First create zip file
88                ZipOutputStream zipFile = new ZipOutputStream( new BufferedOutputStream( new FileOutputStream( file ) ) );
89                BufferedWriter zipWriter = new BufferedWriter( new OutputStreamWriter( zipFile, 'utf-8' ) );
90               
91                try {
92                        // Add the study XML file
93                        zipFile.putNextEntry( new ZipEntry( "studies.xml" ) );
94                        createStudiesXML( zipWriter, studies, runs, onProgress )
95                        zipWriter.flush();
96                        zipFile.closeEntry();
97                       
98                        // Add all other files. These files are stored in the directory given in the configuration
99                        def permanentDir = fileService.absolutePath( ConfigurationHolder.config.massSequencing.fileDir );
100                        def buffer = new byte[ 1024 ];
101               
102                        // First add all sequence and quality files
103                        studies.each { study -> study.assays?.each { assay -> assay.assaySamples?.each { assaySample -> assaySample.sequenceData?.each { data ->
104                                if( data ) {
105                                        // Loop through all sequence- and quality files.
106                                        def files = [ data.sequenceFile, data.qualityFile ];
107                                        files.each { filename ->
108                                                if( filename ) {
109                                                        // Create a zip entry for each file
110                                                        // All filenames are unique, so the filenames are taken just the way they are
111                                                        zipFile.putNextEntry( new ZipEntry( filename ) );
112                                                       
113                                                        zipFile << new FileInputStream( fileService.get( filename, permanentDir ) )
114                                                       
115                                                        // Close the zip entry
116                                                        zipWriter.flush();
117                                                        zipFile.closeEntry();
118                                                }
119                                        }
120                                }
121                               
122                        } 
123                       
124                        // Update progress
125                        onProgress( assaySample.numSequences() );
126                        } } }
127                       
128                        // Afterwards, add all parameterFiles for the runs
129                        runs.each { run ->
130                                if( run.parameterFile ) {
131                                        // Create a zip entry for each file
132                                        // All filenames are unique, so the filenames are taken just the way they are
133                                        zipFile.putNextEntry( new ZipEntry( run.parameterFile ) );
134                                       
135                                        zipFile << new FileInputStream( fileService.get( run.parameterFile, permanentDir ) )
136                                       
137                                        // Close the zip entry
138                                        zipWriter.flush();
139                                        zipFile.closeEntry();
140                                }
141                        }
142                } catch( Exception e ) {
143                        log.warn "An error occurred during download of export zip file. Error message is: " + e.getMessage();
144                        e.printStackTrace()
145                       
146                        // An exception might occur if the user cancels the download. Continue (with finally) anyway
147                        try {
148                                if( zipFile )
149                                        zipFile.closeEntry();
150                        } catch( Exception e2 ) {}
151                } finally {
152                        try {
153                                if( zipFile )
154                                        zipFile.close();
155                        } catch( Exception e2 ) {}
156                }
157
158        } 
159   
160   def downloadZip = {
161           def processId = params.processId;
162           
163           // Retrieve the file
164           def file = fileService.get( session.process[ processId ].filename );
165
166           try {
167                   // Send the file to the user
168                   response.setHeader "Content-disposition", "attachment; filename=sequencing_studies.zip"
169                   response.setHeader "Content-Length", file.size().toString();
170                   
171                   response.outputStream << file.newInputStream();
172                   response.outputStream.flush();
173           } catch( Exception e ) {
174                   log.error( "Exception occurred during download of exported data. " );
175                   e.printStackTrace();
176           } finally {
177                   // Delete the file since it has to be downloaded only once
178                   fileService.delete( session.process[ processId ].filename );
179           }
180   }
181       
182       
183       
184       
185
186        /**
187         * Exports all studies to XML
188         */
189        def xml = {
190                response.contentType = "text/xml";
191               
192                def writer = new PrintWriter( new OutputStreamWriter( response.getOutputStream(), 'utf-8' ) );
193                createStudiesXML( writer )
194        }
195
196        protected void createStudiesXML( Writer w, def studyObjects = null, def runObjects = null, Closure onProgress = null ) {
197                if( !studyObjects )
198                        studyObjects = Study.list().findAll { it.canRead( session.user ) };
199                       
200                if( !runObjects )
201                        runObjects = Run.list()
202                       
203               
204                def gscfInstance = ConfigurationHolder.config.gscf.baseURL;
205                def sequencingInstance = ConfigurationHolder.config.grails.serverURL
206
207                def xml = new StreamingMarkupBuilder().bind {
208                        mkp.xmlDeclaration()    // Show XML declaration on top
209                       
210                        sequencingData( application: 'dbNP Mass Sequencing', version: '1.0', time: new Date().dateTimeString, instance: sequencingInstance, gscfInstance: gscfInstance ) {
211                                studies {
212                                        studyObjects.each { studyObject ->
213                                                study( trash: studyObject.trashcan, numAssays: studyObject.assays?.size(), numSamples: studyObject.samples?.size() ) {
214                                                        token( studyObject.studyToken )
215                                                        name( studyObject.name )
216               
217                                                        // Export all study assays
218                                                        assays {
219                                                                studyObject.assays?.each { assayObject ->
220                                                                        assay( numAssaySamples: assayObject.assaySamples?.size() ) {
221                                                                                token( assayObject.assayToken )
222                                                                                name( assayObject.name )
223                                                                        }
224                                                                }
225                                                        }
226               
227                                                        // Export all study samples
228                                                        samples {
229                                                                studyObject.samples?.each { sampleObject ->
230                                                                        sample( numAssaySamples: sampleObject.assaySamples?.size() ) {
231                                                                                token( sampleObject.sampleToken )
232                                                                                name( sampleObject.name )
233                                                                        }
234                                                                }
235                                                        }
236               
237                                                        // Also export all assay samples
238                                                        assaySamples {
239                                                                studyObject.assays*.assaySamples?.flatten().each { assaySampleObject ->
240                                                                        assaySample( numSequences: assaySampleObject.numSequences() ) {
241                                                                                assayToken( assaySampleObject.assay?.assayToken )
242                                                                                sampleToken( assaySampleObject.sample?.sampleToken )
243                                                                                runId( assaySampleObject.run?.id )
244               
245                                                                                fwOligo( assaySampleObject.fwOligo )
246                                                                                fwMidName( assaySampleObject.fwMidName )
247                                                                                fwTotalSeq( assaySampleObject.fwTotalSeq )
248                                                                                fwMidSeq( assaySampleObject.fwMidSeq )
249                                                                                fwPrimerSeq( assaySampleObject.fwPrimerSeq )
250               
251                                                                                revOligo( assaySampleObject.revOligo )
252                                                                                revMidName( assaySampleObject.revMidName )
253                                                                                revTotalSeq( assaySampleObject.revTotalSeq )
254                                                                                revMidSeq( assaySampleObject.revMidSeq )
255                                                                                revPrimerSeq( assaySampleObject.revPrimerSeq )
256               
257                                                                                sequenceData {
258                                                                                        if( assaySampleObject.sequenceData ) {
259                                                                                                assaySampleObject.sequenceData.each { sequenceDataObject ->
260                                                                                                        file( numSequences: sequenceDataObject.numSequences ) {
261                                                                                                                sequenceFile( sequenceDataObject.sequenceFile )
262                                                                                                                qualityFile( sequenceDataObject.qualityFile )
263                                                                                                        }
264                                                                                                }
265                                                                                        }
266                                                                                }
267                                                                               
268                                                                                // Update progress of exporting
269                                                                                if( onProgress )
270                                                                                        onProgress( 1 );
271                                                                        }
272                                                                }
273                                                        } // End assay samples
274               
275                                                }
276                                        }
277                                } // End studies
278                               
279                                runs {
280                                        runObjects.each { runObject ->
281                                                run { 
282                                                        id( runObject.id )
283                                                        name( runObject.name )
284                                                        date( runObject.date )
285                                                        machine( runObject.machine )
286                                                        supplier( runObject.supplier )
287                                                        parameterFile( runObject.parameterFile )
288                                                }
289                                        }
290                                }
291                               
292                        }
293                }       // End bind
294               
295                // Send XML to the writer
296                w << xml;
297        }
298}
Note: See TracBrowser for help on using the repository browser.