View Javadoc
1   /*
2    * Copyright (c) 2002-2021, City of 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.blobstore.business.filesystem;
35  
36  import fr.paris.lutece.plugins.blobstore.business.BytesBlobStore;
37  import fr.paris.lutece.plugins.blobstore.business.InputStreamBlobStore;
38  import fr.paris.lutece.portal.service.util.AppPropertiesService;
39  
40  import org.apache.commons.io.FileUtils;
41  import org.apache.commons.io.IOUtils;
42  
43  import java.io.File;
44  import java.io.FileInputStream;
45  import java.io.FileOutputStream;
46  import java.io.IOException;
47  import java.io.InputStream;
48  import java.io.OutputStream;
49  
50  /**
51   * Uses filesystem to store blob. <i>Note that <code>strBasePath</code> is the path were blobs are put.</i>
52   */
53  public class FileSystemBlobStoreDAO implements IFileSystemBlobStoreDAO
54  {
55      /** The Constant WORD_SIZE. */
56      private static final Integer WORD_SIZE = AppPropertiesService.getPropertyInt( "blobstore.folder.split.word_size", 3 );
57  
58      /**
59       * Creates the dir.
60       *
61       * @param fileLevel1
62       *            the file level1
63       */
64      private void createDir( final File fileLevel1 )
65      {
66          if ( !fileLevel1.exists( ) )
67          {
68              fileLevel1.mkdir( );
69          }
70      }
71  
72      /*
73       * (non-Javadoc)
74       *
75       * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #delete(java.lang.String, java.lang.String)
76       */
77      @Override
78      public boolean delete( final String strKey, final String strBasePath, final Integer depth ) throws IOException
79      {
80          final File file = this.getPath( strKey, strBasePath, depth );
81  
82          boolean ret = file.delete( );
83  
84          // cleans up useless remaining folders.
85          if ( depth.equals( 1 ) )
86          {
87              final File folderLevel1 = file.getParentFile( );
88  
89              if ( folderLevel1.list( ).length == 0 )
90              {
91                  folderLevel1.delete( );
92              }
93          }
94          else
95              if ( depth.equals( 2 ) )
96              {
97                  final File folderLevel2 = file.getParentFile( );
98  
99                  if ( folderLevel2.list( ).length == 0 )
100                 {
101                     folderLevel2.delete( );
102                 }
103 
104                 File folderLevel1 = folderLevel2.getParentFile( );
105 
106                 if ( folderLevel1.list( ).length == 0 )
107                 {
108                     folderLevel1.delete( );
109                 }
110             }
111 
112         return ret;
113     }
114 
115     /**
116      * Gets the path.
117      *
118      * @param blobstoeId
119      *            the blobstoe id
120      * @param strBasePath
121      *            the str base path
122      * @param depth
123      * @return the path
124      */
125     private File getPath( final String blobstoeId, final String strBasePath, Integer depth )
126     {
127         final File ret;
128 
129         if ( depth.equals( 2 ) )
130         {
131             final String level1 = blobstoeId.substring( 0, WORD_SIZE );
132             final String level2 = blobstoeId.substring( WORD_SIZE, WORD_SIZE * 2 );
133             final File folderLevel1 = new File( strBasePath, level1 );
134             createDir( folderLevel1 );
135 
136             final File folderLevel2 = new File( folderLevel1.getAbsolutePath( ), level2 );
137             createDir( folderLevel2 );
138             ret = new File( folderLevel2.getAbsolutePath( ), blobstoeId );
139         }
140         else
141             if ( depth.equals( 1 ) )
142             {
143                 final String level1 = blobstoeId.substring( 0, WORD_SIZE );
144                 final File folderLevel1 = new File( strBasePath, level1 );
145                 createDir( folderLevel1 );
146                 ret = new File( folderLevel1.getAbsolutePath( ), blobstoeId );
147             }
148             else
149             {
150                 ret = new File( strBasePath, blobstoeId );
151             }
152 
153         return ret;
154     }
155 
156     /*
157      * (non-Javadoc)
158      *
159      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #insert(fr.paris.lutece.plugins.blobstore.business.BytesBlobStore,
160      * java.lang.String)
161      */
162     @Override
163     public void insert( final BytesBlobStore blobStore, final String strBasePath, final Integer depth ) throws IOException, FileAlreadyExistsException
164     {
165         final File file = getPath( blobStore.getId( ), strBasePath, depth );
166 
167         // create parents directories if they does not exist.
168         file.getParentFile( ).mkdirs( );
169 
170         if ( file.exists( ) )
171         {
172             throw new FileAlreadyExistsException( "File " + blobStore.getId( ) + " already exists." );
173         }
174 
175         FileUtils.writeByteArrayToFile( file, blobStore.getValue( ) );
176     }
177 
178     /*
179      * (non-Javadoc)
180      *
181      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO
182      * #insert(fr.paris.lutece.plugins.blobstore.business.InputStreamBlobStore, java.lang.String)
183      */
184     @Override
185     public void insert( final InputStreamBlobStore blobStore, final String strBasePath, final Integer depth ) throws FileAlreadyExistsException, IOException
186     {
187         final File file = this.getPath( blobStore.getId( ), strBasePath, depth );
188 
189         // create parents directories if they does not exist.
190         file.getParentFile( ).mkdirs( );
191 
192         if ( file.exists( ) )
193         {
194             throw new FileAlreadyExistsException( "File " + blobStore.getId( ) + " already exists." );
195         }
196 
197         final OutputStream out = new FileOutputStream( file );
198         final InputStream in = blobStore.getInputStream( );
199 
200         try
201         {
202             IOUtils.copyLarge( in, out );
203         }
204         finally
205         {
206             IOUtils.closeQuietly( out );
207             IOUtils.closeQuietly( in );
208         }
209     }
210 
211     /*
212      * (non-Javadoc)
213      *
214      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #load(java.lang.String, java.lang.String)
215      */
216     @Override
217     public BytesBlobStore load( final String strId, final String strBasePath, final Integer depth ) throws IOException
218     {
219         final File file = this.getPath( strId, strBasePath, depth );
220 
221         if ( !file.exists( ) )
222         {
223             return null;
224         }
225 
226         final BytesBlobStore blobStore = new BytesBlobStore( );
227         blobStore.setId( strId );
228         blobStore.setValue( FileUtils.readFileToByteArray( file ) );
229 
230         return blobStore;
231     }
232 
233     /*
234      * (non-Javadoc)
235      *
236      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #loadInputStream(java.lang.String, java.lang.String)
237      */
238     @Override
239     public InputStream loadInputStream( final String strId, final String strBasePath, final Integer depth ) throws IOException
240     {
241         final File file = this.getPath( strId, strBasePath, depth );
242 
243         if ( !file.exists( ) )
244         {
245             return null;
246         }
247 
248         return new FileInputStream( file );
249     }
250 
251     /*
252      * (non-Javadoc)
253      *
254      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #store(fr.paris.lutece.plugins.blobstore.business.BytesBlobStore,
255      * java.lang.String)
256      */
257     @Override
258     public void store( final BytesBlobStore blobStore, final String strBasePath, final Integer depth ) throws IOException
259     {
260         final File file = getPath( blobStore.getId( ), strBasePath, depth );
261         FileUtils.writeByteArrayToFile( file, blobStore.getValue( ) );
262     }
263 
264     /*
265      * (non-Javadoc)
266      *
267      * @see fr.paris.lutece.plugins.blobstore.business.filesystem.IFileSystemBlobStoreDAO #storeInputStream(fr.paris.lutece.plugins.blobstore.business.
268      * InputStreamBlobStore, java.lang.String)
269      */
270     @Override
271     public void storeInputStream( final InputStreamBlobStore blobStore, final String strBasePath, final Integer depth ) throws IOException
272     {
273         final File file = this.getPath( blobStore.getId( ), strBasePath, depth );
274         final OutputStream out = new FileOutputStream( file );
275         final InputStream in = blobStore.getInputStream( );
276 
277         try
278         {
279             IOUtils.copyLarge( blobStore.getInputStream( ), out );
280         }
281         finally
282         {
283             IOUtils.closeQuietly( out );
284             IOUtils.closeQuietly( in );
285         }
286     }
287 }