View Javadoc
1   /*
2    * Copyright (c) 2002-2017, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.directory.web.action;
35  
36  import fr.paris.lutece.plugins.directory.business.Category;
37  import fr.paris.lutece.plugins.directory.business.Directory;
38  import fr.paris.lutece.plugins.directory.business.DirectoryHome;
39  import fr.paris.lutece.plugins.directory.business.DirectoryXsl;
40  import fr.paris.lutece.plugins.directory.business.DirectoryXslFilter;
41  import fr.paris.lutece.plugins.directory.business.DirectoryXslHome;
42  import fr.paris.lutece.plugins.directory.business.Entry;
43  import fr.paris.lutece.plugins.directory.business.EntryFilter;
44  import fr.paris.lutece.plugins.directory.business.EntryHome;
45  import fr.paris.lutece.plugins.directory.business.Field;
46  import fr.paris.lutece.plugins.directory.business.File;
47  import fr.paris.lutece.plugins.directory.business.FileHome;
48  import fr.paris.lutece.plugins.directory.business.IEntry;
49  import fr.paris.lutece.plugins.directory.business.PhysicalFile;
50  import fr.paris.lutece.plugins.directory.business.PhysicalFileHome;
51  import fr.paris.lutece.plugins.directory.business.Record;
52  import fr.paris.lutece.plugins.directory.business.RecordFieldFilter;
53  import fr.paris.lutece.plugins.directory.service.DirectoryPlugin;
54  import fr.paris.lutece.plugins.directory.service.DirectoryResourceIdService;
55  import fr.paris.lutece.plugins.directory.service.parameter.DirectoryParameterService;
56  import fr.paris.lutece.plugins.directory.service.record.IRecordService;
57  import fr.paris.lutece.plugins.directory.service.record.RecordService;
58  import fr.paris.lutece.plugins.directory.utils.DirectoryUtils;
59  import fr.paris.lutece.plugins.workflowcore.business.state.State;
60  import fr.paris.lutece.portal.business.user.AdminUser;
61  import fr.paris.lutece.portal.service.admin.AccessDeniedException;
62  import fr.paris.lutece.portal.service.html.XmlTransformerService;
63  import fr.paris.lutece.portal.service.i18n.I18nService;
64  import fr.paris.lutece.portal.service.plugin.Plugin;
65  import fr.paris.lutece.portal.service.plugin.PluginService;
66  import fr.paris.lutece.portal.service.rbac.RBACService;
67  import fr.paris.lutece.portal.service.spring.SpringContextService;
68  import fr.paris.lutece.portal.service.util.AppLogService;
69  import fr.paris.lutece.portal.service.util.AppPathService;
70  import fr.paris.lutece.portal.service.util.AppPropertiesService;
71  import fr.paris.lutece.portal.service.workflow.WorkflowService;
72  import fr.paris.lutece.portal.web.pluginaction.AbstractPluginAction;
73  import fr.paris.lutece.portal.web.pluginaction.DefaultPluginActionResult;
74  import fr.paris.lutece.portal.web.pluginaction.IPluginActionResult;
75  import fr.paris.lutece.util.ReferenceList;
76  import fr.paris.lutece.util.UniqueIDGenerator;
77  import fr.paris.lutece.util.filesystem.FileSystemUtil;
78  import fr.paris.lutece.util.filesystem.UploadUtil;
79  import fr.paris.lutece.util.string.StringUtil;
80  import fr.paris.lutece.util.xml.XmlUtil;
81  
82  import org.apache.commons.io.IOUtils;
83  import org.apache.commons.lang.StringUtils;
84  
85  import java.io.BufferedWriter;
86  import java.io.FileInputStream;
87  import java.io.FileOutputStream;
88  import java.io.IOException;
89  import java.io.OutputStream;
90  import java.io.OutputStreamWriter;
91  import java.io.PrintWriter;
92  
93  import java.nio.channels.Channels;
94  import java.nio.channels.FileChannel;
95  import java.nio.channels.WritableByteChannel;
96  
97  import java.util.ArrayList;
98  import java.util.Arrays;
99  import java.util.HashMap;
100 import java.util.List;
101 import java.util.Locale;
102 import java.util.Map;
103 
104 import javax.servlet.http.HttpServletRequest;
105 import javax.servlet.http.HttpServletResponse;
106 
107 /**
108  *
109  * Exports records (search records or all records)
110  *
111  */
112 public class ExportDirectoryAction extends AbstractPluginAction<DirectoryAdminSearchFields> implements IDirectoryAction
113 {
114     private static final String ACTION_NAME = "Export Directory XSL";
115     private static final String TEMPLATE_BUTTON = "actions/export.html";
116     private static final String PROPERTY_PATH_TMP = "path.tmp";
117     private static final String PROPERTY_ENTRY_TYPE_DATE_CREATION_TITLE = "directory.entry_type_date_creation.title";
118     private static final String PROPERTY_ENTRY_TYPE_DATE_MODIFICATION_TITLE = "directory.entry_type_date_modification.title";
119     private static final String MESSAGE_ACCESS_DENIED = "directory.message.accessDenied";
120     private static final String PARAMETER_BUTTON_EXPORT_ALL = "export_search_all";
121     private static final String PARAMETER_BUTTON_EXPORT_SEARCH = "export_search_result";
122     private static final String PARAMETER_ID_DIRECTORY = "id_directory";
123     private static final String PARAMETER_ID_DIRECTORY_XSL = "id_directory_xsl";
124     private static final String PARAMETER_SELECTED_RECORD = "selected_record";
125     private static final String TAG_STATUS = "status";
126     private static final String TAG_DISPLAY = "display";
127     private static final String TAG_YES = "yes";
128     private static final String TAG_NO = "no";
129     private static final String XSL_UNIQUE_PREFIX_ID = UniqueIDGenerator.getNewId( ) + "directory-";
130 
131     // Export
132     private static final int EXPORT_STRINGBUFFER_MAX_CONTENT_SIZE = 500000;
133     private static final int EXPORT_STRINGBUFFER_INITIAL_SIZE = 600000;
134     private static final int EXPORT_RECORD_STEP = 100;
135     private static final String EXPORT_TMPFILE_PREFIX = "exportDirectory";
136     private static final String EXPORT_TMPFILE_SUFIX = ".part";
137     private static final String EXPORT_XSL_BEGIN_PARTIAL_EXPORT = "<partialexport>";
138     private static final String EXPORT_XSL_END_PARTIAL_EXPORT = "</partialexport>";
139     private static final String EXPORT_XSL_BEGIN_LIST_RECORD = "<list-record>";
140     private static final String EXPORT_XSL_END_LIST_RECORD = "</list-record>";
141     private static final String EXPORT_XSL_EMPTY_LIST_RECORD = "<list-record/>";
142     private static final String EXPORT_XSL_END_DIRECTORY = "</directory>";
143     private static final String EXPORT_XSL_NEW_LINE = "\r\n";
144     private static final String EXPORT_CSV_EXT = "csv";
145     private static final String CONSTANT_MIME_TYPE_CSV = "application/csv";
146     private static final String CONSTANT_MIME_TYPE_OCTETSTREAM = "application/octet-stream";
147     private static final String MARK_XSL_EXPORT_LIST = "xsl_export_list";
148 
149     /**
150      * {@inheritDoc}
151      */
152     @Override
153     public void fillModel( HttpServletRequest request, AdminUser adminUser, Map<String, Object> model )
154     {
155         // add xslExport
156         DirectoryXslFilter directoryXslFilter = new DirectoryXslFilter( );
157 
158         directoryXslFilter.setIdCategory( Category.ID_CATEGORY_EXPORT );
159 
160         ReferenceList refListXslExport = DirectoryXslHome.getRefList( directoryXslFilter, getPlugin( ) );
161         model.put( MARK_XSL_EXPORT_LIST, refListXslExport );
162     }
163 
164     /**
165      * {@inheritDoc}
166      */
167     @Override
168     public String getName( )
169     {
170         return ACTION_NAME;
171     }
172 
173     /**
174      * {@inheritDoc}
175      */
176     @Override
177     public String getButtonTemplate( )
178     {
179         return TEMPLATE_BUTTON;
180     }
181 
182     /**
183      * {@inheritDoc}
184      */
185     @Override
186     public boolean isInvoked( HttpServletRequest request )
187     {
188         return ( request.getParameter( PARAMETER_BUTTON_EXPORT_SEARCH ) != null ) || ( request.getParameter( PARAMETER_BUTTON_EXPORT_ALL ) != null );
189     }
190 
191     /**
192      * {@inheritDoc}
193      */
194     @Override
195     public IPluginActionResult process( HttpServletRequest request, HttpServletResponse response, AdminUser adminUser, DirectoryAdminSearchFields searchFields )
196             throws AccessDeniedException
197     {
198         DefaultPluginActionResult result = new DefaultPluginActionResult( );
199 
200         String strIdDirectory = request.getParameter( PARAMETER_ID_DIRECTORY );
201         int nIdDirectory = DirectoryUtils.convertStringToInt( strIdDirectory );
202         Directory directory = DirectoryHome.findByPrimaryKey( nIdDirectory, getPlugin( ) );
203         String strIdDirectoryXsl = request.getParameter( PARAMETER_ID_DIRECTORY_XSL );
204         int nIdDirectoryXsl = DirectoryUtils.convertStringToInt( strIdDirectoryXsl );
205         WorkflowService workflowService = WorkflowService.getInstance( );
206         boolean bWorkflowServiceEnable = workflowService.isAvailable( );
207         String strShotExportFinalOutPut = null;
208         DirectoryXsl directoryXsl = DirectoryXslHome.findByPrimaryKey( nIdDirectoryXsl, getPlugin( ) );
209 
210         // -----------------------------------------------------------------------
211         if ( ( directory == null ) || ( directoryXsl == null )
212                 || !RBACService.isAuthorized( Directory.RESOURCE_TYPE, strIdDirectory, DirectoryResourceIdService.PERMISSION_MANAGE_RECORD, adminUser ) )
213         {
214             throw new AccessDeniedException( I18nService.getLocalizedString( MESSAGE_ACCESS_DENIED, request.getLocale( ) ) );
215         }
216 
217         String strFileExtension = directoryXsl.getExtension( );
218         String strFileName = directory.getTitle( ) + "." + strFileExtension;
219         strFileName = UploadUtil.cleanFileName( strFileName );
220 
221         boolean bIsCsvExport = strFileExtension.equals( EXPORT_CSV_EXT );
222         boolean bDisplayDateCreation = directory.isDateShownInExport( );
223         boolean bDisplayDateModification = directory.isDateModificationShownInExport( );
224 
225         List<Integer> listResultRecordId = new ArrayList<Integer>( );
226 
227         if ( request.getParameter( PARAMETER_BUTTON_EXPORT_SEARCH ) != null )
228         {
229             String [ ] selectedRecords = request.getParameterValues( PARAMETER_SELECTED_RECORD );
230             List<String> listSelectedRecords;
231 
232             if ( selectedRecords != null )
233             {
234                 listSelectedRecords = Arrays.asList( selectedRecords );
235 
236                 if ( ( listSelectedRecords != null ) && ( listSelectedRecords.size( ) > 0 ) )
237                 {
238                     for ( String strRecordId : listSelectedRecords )
239                     {
240                         listResultRecordId.add( Integer.parseInt( strRecordId ) );
241                     }
242                 }
243             }
244             else
245             {
246                 // sort order and sort entry are not needed in export
247                 listResultRecordId = DirectoryUtils.getListResults( request, directory, bWorkflowServiceEnable, true, null, RecordFieldFilter.ORDER_NONE,
248                         searchFields, adminUser, adminUser.getLocale( ) );
249             }
250         }
251         else
252         {
253             // sort order and sort entry are not needed in export
254             listResultRecordId = DirectoryUtils.getListResults( request, directory, bWorkflowServiceEnable, false, null, RecordFieldFilter.ORDER_NONE,
255                     searchFields, adminUser, adminUser.getLocale( ) );
256         }
257 
258         EntryFilter entryFilter = new EntryFilter( );
259         entryFilter.setIdDirectory( directory.getIdDirectory( ) );
260         entryFilter.setIsGroup( EntryFilter.FILTER_FALSE );
261         entryFilter.setIsComment( EntryFilter.FILTER_FALSE );
262         entryFilter.setIsShownInExport( EntryFilter.FILTER_TRUE );
263 
264         List<IEntry> listEntryResultSearch = EntryHome.getEntryList( entryFilter, getPlugin( ) );
265 
266         Map<Integer, Field> hashFields = DirectoryUtils.getMapFieldsOfListEntry( listEntryResultSearch, getPlugin( ) );
267 
268         StringBuffer strBufferListRecordXml = null;
269 
270         java.io.File tmpFile = null;
271         BufferedWriter bufferedWriter = null;
272         OutputStreamWriter outputStreamWriter = null;
273 
274         File fileTemplate = null;
275         String strFileOutPut = DirectoryUtils.EMPTY_STRING;
276 
277         if ( directoryXsl.getFile( ) != null )
278         {
279             fileTemplate = FileHome.findByPrimaryKey( directoryXsl.getFile( ).getIdFile( ), getPlugin( ) );
280         }
281 
282         XmlTransformerService xmlTransformerService = null;
283         PhysicalFile physicalFile = null;
284         String strXslId = null;
285 
286         if ( ( fileTemplate != null ) && ( fileTemplate.getPhysicalFile( ) != null ) )
287         {
288             fileTemplate.setPhysicalFile( PhysicalFileHome.findByPrimaryKey( fileTemplate.getPhysicalFile( ).getIdPhysicalFile( ), getPlugin( ) ) );
289 
290             xmlTransformerService = new XmlTransformerService( );
291             physicalFile = fileTemplate.getPhysicalFile( );
292             strXslId = XSL_UNIQUE_PREFIX_ID + physicalFile.getIdPhysicalFile( );
293         }
294 
295         int nSize = listResultRecordId.size( );
296         boolean bIsBigExport = ( nSize > EXPORT_RECORD_STEP );
297 
298         // Encoding export
299         String strEncoding = StringUtils.EMPTY;
300 
301         if ( bIsCsvExport )
302         {
303             strEncoding = DirectoryParameterService.getService( ).getExportCSVEncoding( );
304         }
305         else
306         {
307             strEncoding = DirectoryParameterService.getService( ).getExportXMLEncoding( );
308         }
309 
310         if ( bIsBigExport )
311         {
312             try
313             {
314                 String strPath = AppPathService.getWebAppPath( ) + AppPropertiesService.getProperty( PROPERTY_PATH_TMP );
315                 java.io.File tmpDir = new java.io.File( strPath );
316                 tmpFile = java.io.File.createTempFile( EXPORT_TMPFILE_PREFIX, EXPORT_TMPFILE_SUFIX, tmpDir );
317             }
318             catch( IOException e )
319             {
320                 AppLogService.error( "Unable to create temp file in webapp tmp dir" );
321 
322                 try
323                 {
324                     tmpFile = java.io.File.createTempFile( EXPORT_TMPFILE_PREFIX, EXPORT_TMPFILE_SUFIX );
325                 }
326                 catch( IOException e1 )
327                 {
328                     AppLogService.error( e1 );
329                 }
330             }
331 
332             try
333             {
334                 tmpFile.deleteOnExit( );
335                 outputStreamWriter = new OutputStreamWriter( new FileOutputStream( tmpFile ), strEncoding );
336                 bufferedWriter = new BufferedWriter( outputStreamWriter );
337             }
338             catch( IOException e )
339             {
340                 AppLogService.error( e );
341             }
342         }
343 
344         Plugin plugin = this.getPlugin( );
345         Locale locale = request.getLocale( );
346 
347         // ---------------------------------------------------------------------
348         StringBuffer strBufferListEntryXml = new StringBuffer( );
349 
350         if ( bDisplayDateCreation && bIsCsvExport )
351         {
352             Map<String, String> model = new HashMap<String, String>( );
353             model.put( Entry.ATTRIBUTE_ENTRY_ID, "0" );
354             XmlUtil.beginElement( strBufferListEntryXml, Entry.TAG_ENTRY, model );
355 
356             String strDateCreation = I18nService.getLocalizedString( PROPERTY_ENTRY_TYPE_DATE_CREATION_TITLE, locale );
357             XmlUtil.addElementHtml( strBufferListEntryXml, Entry.TAG_TITLE, strDateCreation );
358             XmlUtil.endElement( strBufferListEntryXml, Entry.TAG_ENTRY );
359         }
360 
361         if ( bDisplayDateModification && bIsCsvExport )
362         {
363             Map<String, String> model = new HashMap<String, String>( );
364             model.put( Entry.ATTRIBUTE_ENTRY_ID, "0" );
365             XmlUtil.beginElement( strBufferListEntryXml, Entry.TAG_ENTRY, model );
366 
367             String strDateModification = I18nService.getLocalizedString( PROPERTY_ENTRY_TYPE_DATE_MODIFICATION_TITLE, locale );
368             XmlUtil.addElementHtml( strBufferListEntryXml, Entry.TAG_TITLE, strDateModification );
369             XmlUtil.endElement( strBufferListEntryXml, Entry.TAG_ENTRY );
370         }
371 
372         for ( IEntry entry : listEntryResultSearch )
373         {
374             entry.getXml( plugin, locale, strBufferListEntryXml );
375         }
376 
377         Map<String, String> model = new HashMap<String, String>( );
378 
379         if ( ( directory.getIdWorkflow( ) != DirectoryUtils.CONSTANT_ID_NULL ) && bWorkflowServiceEnable )
380         {
381             model.put( TAG_DISPLAY, TAG_YES );
382         }
383         else
384         {
385             model.put( TAG_DISPLAY, TAG_NO );
386         }
387 
388         XmlUtil.addEmptyElement( strBufferListEntryXml, TAG_STATUS, model );
389 
390         StringBuilder strBufferDirectoryXml = new StringBuilder( );
391         strBufferDirectoryXml.append( XmlUtil.getXmlHeader( ) );
392 
393         if ( bIsBigExport )
394         {
395             strBufferDirectoryXml.append( directory.getXml( plugin, locale, new StringBuffer( ), strBufferListEntryXml ) );
396 
397             strBufferListRecordXml = new StringBuffer( EXPORT_STRINGBUFFER_INITIAL_SIZE );
398 
399             strFileOutPut = xmlTransformerService.transformBySourceWithXslCache( strBufferDirectoryXml.toString( ), physicalFile.getValue( ), strXslId, null,
400                     null );
401 
402             String strFinalOutPut = null;
403 
404             if ( !bIsCsvExport )
405             {
406                 int pos = strFileOutPut.indexOf( EXPORT_XSL_EMPTY_LIST_RECORD );
407                 strFinalOutPut = strFileOutPut.substring( 0, pos ) + EXPORT_XSL_BEGIN_LIST_RECORD;
408             }
409             else
410             {
411                 strFinalOutPut = strFileOutPut;
412             }
413 
414             try
415             {
416                 bufferedWriter.write( strFinalOutPut );
417             }
418             catch( IOException e )
419             {
420                 AppLogService.error( e );
421             }
422         }
423         else
424         {
425             strBufferListRecordXml = new StringBuffer( );
426         }
427 
428         // -----------------------------------------------------------------------
429         List<Integer> nTmpListId = new ArrayList<Integer>( );
430         int idWorflow = directory.getIdWorkflow( );
431         IRecordService recordService = SpringContextService.getBean( RecordService.BEAN_SERVICE );
432 
433         if ( bIsBigExport )
434         {
435             int nXmlHeaderLength = XmlUtil.getXmlHeader( ).length( ) - 1;
436             int max = nSize / EXPORT_RECORD_STEP;
437             int max1 = nSize - EXPORT_RECORD_STEP;
438 
439             for ( int i = 0; i < max1; i += EXPORT_RECORD_STEP )
440             {
441                 AppLogService.debug( "Directory export progress : " + ( ( (float) i / nSize ) * 100 ) + "%" );
442 
443                 nTmpListId = new ArrayList<Integer>( );
444 
445                 int k = i + EXPORT_RECORD_STEP;
446 
447                 for ( int j = i; j < k; j++ )
448                 {
449                     nTmpListId.add( listResultRecordId.get( j ) );
450                 }
451 
452                 List<Record> nTmpListRecords = recordService.loadListByListId( nTmpListId, plugin );
453 
454                 for ( Record record : nTmpListRecords )
455                 {
456                     State state = workflowService.getState( record.getIdRecord( ), Record.WORKFLOW_RESOURCE_TYPE, idWorflow,
457                             Integer.valueOf( directory.getIdDirectory( ) ) );
458 
459                     if ( bIsCsvExport )
460                     {
461                         strBufferListRecordXml.append( record.getXmlForCsvExport( plugin, locale, false, state, listEntryResultSearch, false, false, true,
462                                 bDisplayDateCreation, bDisplayDateModification, hashFields ) );
463                     }
464                     else
465                     {
466                         strBufferListRecordXml.append( record.getXml( plugin, locale, false, state, listEntryResultSearch, false, false, true,
467                                 bDisplayDateCreation, bDisplayDateModification, hashFields ) );
468                     }
469                 }
470 
471                 strBufferListRecordXml = this.appendPartialContent( strBufferListRecordXml, bufferedWriter, physicalFile, bIsCsvExport, strXslId,
472                         nXmlHeaderLength, xmlTransformerService );
473             }
474 
475             // -----------------------------------------------------------------------
476             int max2 = EXPORT_RECORD_STEP * max;
477             nTmpListId = new ArrayList<Integer>( );
478 
479             for ( int i = max2; i < nSize; i++ )
480             {
481                 nTmpListId.add( listResultRecordId.get( ( i ) ) );
482             }
483 
484             List<Record> nTmpListRecords = recordService.loadListByListId( nTmpListId, plugin );
485 
486             for ( Record record : nTmpListRecords )
487             {
488                 State state = workflowService.getState( record.getIdRecord( ), Record.WORKFLOW_RESOURCE_TYPE, idWorflow,
489                         Integer.valueOf( directory.getIdDirectory( ) ) );
490 
491                 if ( bIsCsvExport )
492                 {
493                     strBufferListRecordXml.append( record.getXmlForCsvExport( plugin, locale, false, state, listEntryResultSearch, false, false, true,
494                             bDisplayDateCreation, bDisplayDateModification, hashFields ) );
495                 }
496                 else
497                 {
498                     strBufferListRecordXml.append( record.getXml( plugin, locale, false, state, listEntryResultSearch, false, false, true,
499                             bDisplayDateCreation, bDisplayDateModification, hashFields ) );
500                 }
501             }
502 
503             strBufferListRecordXml = this.appendPartialContent( strBufferListRecordXml, bufferedWriter, physicalFile, bIsCsvExport, strXslId, nXmlHeaderLength,
504                     xmlTransformerService );
505 
506             strBufferListRecordXml.insert( 0, EXPORT_XSL_BEGIN_PARTIAL_EXPORT );
507             strBufferListRecordXml.insert( 0, XmlUtil.getXmlHeader( ) );
508             strBufferListRecordXml.append( EXPORT_XSL_END_PARTIAL_EXPORT );
509             strFileOutPut = xmlTransformerService.transformBySourceWithXslCache( strBufferListRecordXml.toString( ), physicalFile.getValue( ), strXslId, null,
510                     null );
511 
512             try
513             {
514                 if ( bIsCsvExport )
515                 {
516                     bufferedWriter.write( strFileOutPut );
517                 }
518                 else
519                 {
520                     bufferedWriter.write( strFileOutPut.substring( nXmlHeaderLength ) );
521                     bufferedWriter.write( EXPORT_XSL_END_LIST_RECORD + EXPORT_XSL_NEW_LINE + EXPORT_XSL_END_DIRECTORY );
522                 }
523             }
524             catch( IOException e )
525             {
526                 AppLogService.error( e );
527             }
528             finally
529             {
530                 IOUtils.closeQuietly( bufferedWriter );
531                 IOUtils.closeQuietly( outputStreamWriter );
532             }
533         }
534         else
535         {
536             List<Record> nTmpListRecords = recordService.loadListByListId( listResultRecordId, plugin );
537 
538             for ( Record record : nTmpListRecords )
539             {
540                 State state = workflowService.getState( record.getIdRecord( ), Record.WORKFLOW_RESOURCE_TYPE, idWorflow,
541                         Integer.valueOf( directory.getIdDirectory( ) ) );
542 
543                 if ( bIsCsvExport )
544                 {
545                     strBufferListRecordXml.append( record.getXmlForCsvExport( plugin, locale, false, state, listEntryResultSearch, false, false, true,
546                             bDisplayDateCreation, bDisplayDateModification, hashFields ) );
547                 }
548                 else
549                 {
550                     strBufferListRecordXml.append( record.getXml( plugin, locale, false, state, listEntryResultSearch, false, false, true,
551                             bDisplayDateCreation, bDisplayDateModification, hashFields ) );
552                 }
553             }
554 
555             strBufferDirectoryXml.append( directory.getXml( plugin, locale, strBufferListRecordXml, strBufferListEntryXml ) );
556             strShotExportFinalOutPut = xmlTransformerService.transformBySourceWithXslCache( strBufferDirectoryXml.toString( ), physicalFile.getValue( ),
557                     strXslId, null, null );
558         }
559 
560         // -----------------------------------------------------------------------
561         DirectoryUtils.addHeaderResponse( request, response, strFileName );
562         response.setCharacterEncoding( strEncoding );
563 
564         if ( bIsCsvExport )
565         {
566             response.setContentType( CONSTANT_MIME_TYPE_CSV );
567         }
568         else
569         {
570             String strMimeType = FileSystemUtil.getMIMEType( strFileName );
571 
572             if ( strMimeType != null )
573             {
574                 response.setContentType( strMimeType );
575             }
576             else
577             {
578                 response.setContentType( CONSTANT_MIME_TYPE_OCTETSTREAM );
579             }
580         }
581 
582         if ( bIsBigExport )
583         {
584             FileChannel in = null;
585             WritableByteChannel writeChannelOut = null;
586             OutputStream out = null;
587 
588             try
589             {
590                 in = new FileInputStream( tmpFile ).getChannel( );
591                 out = response.getOutputStream( );
592                 writeChannelOut = Channels.newChannel( out );
593                 response.setContentLength( Long.valueOf( in.size( ) ).intValue( ) );
594                 in.transferTo( 0, in.size( ), writeChannelOut );
595                 response.getOutputStream( ).close( );
596             }
597             catch( IOException e )
598             {
599                 AppLogService.error( e );
600             }
601             finally
602             {
603                 if ( in != null )
604                 {
605                     try
606                     {
607                         in.close( );
608                     }
609                     catch( IOException e )
610                     {
611                         AppLogService.error( e.getMessage( ), e );
612                     }
613                 }
614 
615                 IOUtils.closeQuietly( out );
616 
617                 tmpFile.delete( );
618             }
619         }
620         else
621         {
622             PrintWriter out = null;
623 
624             try
625             {
626                 out = response.getWriter( );
627                 out.print( strShotExportFinalOutPut );
628             }
629             catch( IOException e )
630             {
631                 AppLogService.error( e.getMessage( ), e );
632             }
633             finally
634             {
635                 if ( out != null )
636                 {
637                     out.flush( );
638                     out.close( );
639                 }
640             }
641         }
642 
643         result.setNoop( true );
644 
645         return result;
646     }
647 
648     /**
649      * Gets the plugin
650      * 
651      * @return the plugin
652      */
653     private Plugin getPlugin( )
654     {
655         return PluginService.getPlugin( DirectoryPlugin.PLUGIN_NAME );
656     }
657 
658     /**
659      * Append partial export result to temporary file if need
660      * 
661      * @param strBufferListRecordXml
662      *            The partial XML content
663      * @param bufferedWriter
664      *            The bufferedWriter used to append content to temporary file
665      * @param physicalFile
666      *            The XSL physical File
667      * @param bIsCsvExport
668      *            is CSV export
669      * @param strXslId
670      *            The XSL unique ID
671      * @param nXmlHeaderLength
672      *            XML header length
673      * @param xmlTransformerService
674      *            he XmlTransformer service
675      * @return The string buffer containing the partial export
676      */
677     private StringBuffer appendPartialContent( StringBuffer strBufferListRecordXml, BufferedWriter bufferedWriter, PhysicalFile physicalFile,
678             boolean bIsCsvExport, String strXslId, int nXmlHeaderLength, XmlTransformerService xmlTransformerService )
679     {
680         if ( strBufferListRecordXml.length( ) > EXPORT_STRINGBUFFER_MAX_CONTENT_SIZE )
681         {
682             strBufferListRecordXml.insert( 0, EXPORT_XSL_BEGIN_PARTIAL_EXPORT );
683             strBufferListRecordXml.insert( 0, XmlUtil.getXmlHeader( ) );
684             strBufferListRecordXml.append( EXPORT_XSL_END_PARTIAL_EXPORT );
685 
686             String strFileOutPut = xmlTransformerService.transformBySourceWithXslCache( strBufferListRecordXml.toString( ), physicalFile.getValue( ), strXslId,
687                     null, null );
688 
689             try
690             {
691                 if ( bIsCsvExport )
692                 {
693                     bufferedWriter.write( strFileOutPut );
694                 }
695                 else
696                 {
697                     bufferedWriter.write( strFileOutPut.substring( nXmlHeaderLength ) );
698                 }
699             }
700             catch( IOException e )
701             {
702                 AppLogService.error( e );
703             }
704             finally
705             {
706                 strBufferListRecordXml = new StringBuffer( EXPORT_STRINGBUFFER_INITIAL_SIZE );
707             }
708         }
709 
710         return strBufferListRecordXml;
711     }
712 }