View Javadoc
1   /*
2    * Copyright (c) 2002-2014, 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.dila.service.impl;
35  
36  import fr.paris.lutece.plugins.dila.exception.DilaException;
37  import fr.paris.lutece.plugins.dila.service.IDilaExtractService;
38  import fr.paris.lutece.plugins.dila.utils.constants.DilaConstants;
39  import fr.paris.lutece.plugins.dila.utils.filter.FilenameFilterArchive;
40  import fr.paris.lutece.portal.service.util.AppLogService;
41  import fr.paris.lutece.portal.service.util.AppPropertiesService;
42  
43  import java.io.BufferedInputStream;
44  import java.io.BufferedOutputStream;
45  import java.io.File;
46  import java.io.FileInputStream;
47  import java.io.FileOutputStream;
48  import java.io.IOException;
49  
50  import org.apache.commons.compress.archivers.ArchiveEntry;
51  import org.apache.commons.compress.archivers.ArchiveException;
52  import org.apache.commons.compress.archivers.ArchiveInputStream;
53  import org.apache.commons.compress.archivers.ArchiveStreamFactory;
54  import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
55  import org.apache.commons.compress.compressors.bzip2.BZip2Utils;
56  import org.apache.commons.io.FileUtils;
57  import org.apache.commons.io.IOUtils;
58  import org.apache.commons.lang.StringUtils;
59  import org.apache.log4j.Logger;
60  
61  
62  /**
63   * Implementation of {@link IDilaExtractService}
64   */
65  public class DilaExtractService implements IDilaExtractService
66  {
67      private static final Logger LOGGER = Logger.getLogger( DilaExtractService.class );
68      /**
69       * Directory path to archives
70       */
71      private String _strArchivesDirPath;
72  
73      /**
74       * Archives filter
75       */
76      private FilenameFilterArchive _filenameFilterArchive = new FilenameFilterArchive( );
77  
78      @Override
79      public void extractAll( ) throws DilaException
80      {
81          AppLogService.info( "Begin extract" );
82  
83          _strArchivesDirPath = AppPropertiesService.getProperty( DilaConstants.PROPERTY_TMP_DIRECTORY );
84  
85          if ( !isValidParameters( _strArchivesDirPath ) )
86          {
87              AppLogService.error( "Could not extract archives : invalid parameter(s)." );
88              throw new DilaException( "Could not extract archives : invalid parameter(s)." );
89          }
90          else
91          {
92              File dirZip = new File( _strArchivesDirPath );
93  
94              File[] listFileZip = dirZip.listFiles( _filenameFilterArchive );
95  
96              if ( listFileZip.length != 4 )
97              {
98                  AppLogService.debug( "Archives directory doesn't contain all archives" );
99              }
100 
101             // List archives
102             for ( File file : listFileZip )
103             {
104                 AppLogService.debug( "Processing archive : " + file.getName( ) );
105 
106                 // Define extract directory
107                 String strArchiveName = file.getName( );
108                 String strDirPathExtract = null;
109                 String strDirPathCopy = null;
110 
111                 if ( AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_NAME_INDIVIDUALS ).equals(
112                         strArchiveName ) )
113                 {
114                     AppLogService.debug( "Archive type : individual" );
115                     strDirPathExtract = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_TMP_INDIVIDUALS );
116                     strDirPathCopy = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_FINAL_INDIVIDUALS );
117                 }
118                 else if ( AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_NAME_ASSO ).equals(
119                         strArchiveName ) )
120                 {
121                     AppLogService.debug( "Archive type : association" );
122                     strDirPathExtract = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_TMP_ASSO );
123                     strDirPathCopy = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_FINAL_ASSO );
124                 }
125                 else if ( AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_NAME_PME ).equals(
126                         strArchiveName ) )
127                 {
128                     AppLogService.debug( "Archive type : professional" );
129                     strDirPathExtract = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_TMP_PME );
130                     strDirPathCopy = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_FINAL_PME );
131                 }
132                 else if ( AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_NAME_LOCALES ).equals(
133                         strArchiveName ) )
134                 {
135                     AppLogService.debug( "Archive type : local data" );
136                     strDirPathExtract = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_TMP_LOCALES );
137                     strDirPathCopy = AppPropertiesService.getProperty( DilaConstants.PROPERTY_XML_FINAL_LOCALES );
138                 }
139                 else
140                 {
141                     AppLogService.error( "Could not define extract directory path" );
142                     throw new DilaException( "Could not define extract directory path" );
143                 }
144 
145                 try
146                 {
147                     extract( file, strArchiveName, strDirPathExtract, strDirPathCopy );
148                 }
149                 catch ( IOException e )
150                 {
151                     throw new DilaException( e.getMessage( ) );
152                 }
153                 catch ( Exception e )
154                 {
155                     throw new DilaException( e.getMessage( ) );
156                 }
157             }
158         }
159 
160         AppLogService.info( "End extract" );
161     }
162 
163     @Override
164     public void extract( File file, String strArchiveName, String strDirPathExtract, String strDirPathCopy )
165             throws Exception
166     {
167         if ( StringUtils.isNotBlank( strDirPathExtract ) )
168         {
169             File dirExtract = new File( strDirPathExtract );
170 
171             if ( ( dirExtract.exists( ) ) )
172             {
173                 FileUtils.forceDelete( dirExtract );
174             }
175 
176             FileUtils.forceMkdir( dirExtract );
177         }
178 
179         if ( StringUtils.isNotBlank( strDirPathCopy ) )
180         {
181             File dirCopy = new File( strDirPathCopy );
182             FileUtils.deleteDirectory( dirCopy );
183         }
184 
185         if ( strArchiveName.endsWith( DilaConstants.EXTENSION_ZIP ) )
186         {
187             // Extract archive
188             extractArchive( file.getAbsolutePath( ), strDirPathExtract );
189             copyFiles( strDirPathExtract, strDirPathCopy, false );
190             deleteArchiveFile( file );
191         }
192         else if ( strArchiveName.endsWith( DilaConstants.EXTENSION_BZIP2 ) )
193         {
194             BZip2CompressorInputStream bzis = null;
195             BufferedOutputStream bos = null;
196 
197             try
198             {
199                 // Uncompress
200                 BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) );
201                 String strUncompressedFilename = BZip2Utils.getUncompressedFilename( file.getName( ) );
202                 String strOutputPath = strDirPathExtract + File.separator + strUncompressedFilename;
203                 bzis = new BZip2CompressorInputStream( bis );
204 
205                 FileOutputStream fos = new FileOutputStream( strOutputPath );
206                 bos = new BufferedOutputStream( fos );
207                 IOUtils.copy( bzis, bos );
208 
209                 bzis.close( );
210                 bos.close( );
211                 // Extract archive
212                 extractArchive( strOutputPath, strDirPathExtract );
213                 copyFiles( strDirPathExtract, strDirPathCopy, true );
214                 deleteArchiveFile( file );
215             }
216             catch ( Exception e )
217             {
218                 AppLogService.debug( e.getMessage( ) );
219                 throw new DilaException( "Error during extract of " + file.getName( ) );
220             }
221             finally
222             {
223                 IOUtils.closeQuietly( bzis );
224                 IOUtils.closeQuietly( bos );
225             }
226         }
227         else
228         {
229             throw new DilaException( "Could not define extract directory path." );
230         }
231     }
232 
233     @Override
234     public boolean isValidParameters( String strArchivesDirPath )
235     {
236         boolean bValid = true;
237 
238         if ( StringUtils.isBlank( strArchivesDirPath ) )
239         {
240             bValid = false;
241             LOGGER.error( "Invalid parameter : blank archive dir path " + strArchivesDirPath );
242         }
243         else
244         {
245             File dirZip = new File( strArchivesDirPath );
246 
247             if ( !dirZip.isDirectory( ) )
248             {
249                 bValid = false;
250                 LOGGER.error( "Invalid parameter : archive dir "+ strArchivesDirPath +" is not a directory" );
251             }
252             else
253             {
254                 File[] listFileZip = dirZip.listFiles( _filenameFilterArchive );
255 
256                 if ( ( listFileZip == null ) || ( listFileZip.length < 1 ) )
257                 {
258                     bValid = false;
259                     LOGGER.error( "Invalid parameter : archive dir "+ strArchivesDirPath +" is empty" );
260                 }
261             }
262         }
263 
264         return bValid;
265     }
266 
267     /**
268      * Extract an archive
269      * @param strArchive the archive
270      * @param strDirPathExtract the extract path dir
271      * @throws Exception on batch error
272      */
273     private void extractArchive( String strArchive, String strDirPathExtract ) throws Exception
274     {
275         BufferedOutputStream out = null;
276 
277         try
278         {
279             BufferedInputStream bis = new BufferedInputStream( new FileInputStream( strArchive ) );
280             ArchiveInputStream in = new ArchiveStreamFactory( ).createArchiveInputStream( bis );
281             ArchiveEntry entry = in.getNextEntry( );
282 
283             while ( entry != null )
284             {
285                 File entryFile = new File( strDirPathExtract, entry.getName( ) );
286 
287                 if ( entry.isDirectory( ) && !entryFile.exists( ) )
288                 {
289                     FileUtils.forceMkdir( entryFile );
290                 }
291                 else
292                 {
293                     out = new BufferedOutputStream( new FileOutputStream( entryFile ) );
294                     IOUtils.copy( in, out );
295                     out.close( );
296                 }
297 
298                 entry = in.getNextEntry( );
299             }
300 
301             in.close( );
302         }
303         catch ( IOException e )
304         {
305             throw new DilaException( e.getMessage( ) );
306         }
307         catch ( ArchiveException e )
308         {
309             throw new DilaException( e.getMessage( ) );
310         }
311         finally
312         {
313             IOUtils.closeQuietly( out );
314         }
315     }
316 
317     /**
318      * Method to copy files
319      * @param srcDir the src dir
320      * @param destDir the dest dir
321      * @param copySubFolders if need to copy all subfolders
322      * @throws IOException occurs during treatment
323      */
324     private void copyFiles( String srcDir, String destDir, boolean copySubFolders ) throws IOException
325     {
326         File source = new File( srcDir );
327         File dest = new File( destDir );
328 
329         if ( copySubFolders )
330         {
331             for ( File f : source.listFiles( ) )
332             {
333                 if ( f.isDirectory( ) )
334                 {
335                     FileUtils.moveDirectory( f, dest );
336                 }
337             }
338 
339             // Clean locales folder
340             FileUtils.forceDelete( source );
341         }
342         else
343         {
344             FileUtils.moveDirectory( source, dest );
345         }
346     }
347 
348     /**
349      * Delete archive file
350      * @param file file to delete
351      * @throws IOException occurs during treatment
352      */
353     private void deleteArchiveFile( File file ) throws IOException
354     {
355         if ( !file.delete( ) )
356         {
357             throw new IOException( "Erreur lors de la suppression du fichier." );
358         }
359     }
360 }