/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.framework.blob.file; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.enonic.cms.framework.blob.BlobKey; import com.enonic.cms.framework.blob.BlobKeyCreator; import com.enonic.cms.framework.blob.BlobRecord; import com.enonic.cms.framework.blob.BlobStore; import com.enonic.cms.framework.blob.BlobStoreException; @Component public final class FileBlobStore implements InitializingBean, BlobStore { private final static Logger LOG = LoggerFactory.getLogger( FileBlobStore.class ); private static final String TMP = "tmp-"; private File dir; @Value("${cms.blobstore.dir}") public void setDirectory( final File dir ) { this.dir = dir; } public void afterPropertiesSet() { mkdirs( this.dir, true ); } public BlobRecord getRecord( final BlobKey key ) throws BlobStoreException { final File file = getBlobFile( key ); if ( !file.exists() ) { return null; } return new FileBlobRecord( key, file ); } public BlobRecord addRecord( final InputStream in ) throws BlobStoreException { File tmpFile = null; try { tmpFile = newTemporaryFile(); final BlobKey key = BlobKeyCreator.createKey( in, new FileOutputStream( tmpFile ) ); return addRecord( key, tmpFile ); } catch ( IOException e ) { throw new BlobStoreException( "Failed to open tempoary file", e ); } finally { delete( tmpFile ); } } private synchronized BlobRecord addRecord( final BlobKey key, final File tmpFile ) throws BlobStoreException { final File file = getBlobFile( key ); if ( !file.exists() ) { mkdirs( file.getParentFile(), false ); if ( !tmpFile.renameTo( file ) ) { throw new BlobStoreException( "Failed to rename file [" + key.toString() + "]" ); } } return new FileBlobRecord( key, file ); } public Iterable<BlobKey> getAllKeys() throws BlobStoreException { final ArrayList<File> files = new ArrayList<File>(); findFiles( files, this.dir ); final ArrayList<BlobKey> identifiers = new ArrayList<BlobKey>(); for ( final File f : files ) { String name = f.getName(); if ( !name.startsWith( TMP ) ) { identifiers.add( new BlobKey( name ) ); } } return identifiers; } public boolean deleteRecord( final BlobKey key ) throws BlobStoreException { final File file = getBlobFile( key ); return delete( file ); } private File getBlobFile( final BlobKey key ) { final String id = key.toString(); File file = this.dir; file = new File( file, id.substring( 0, 2 ) ); file = new File( file, id.substring( 2, 4 ) ); file = new File( file, id.substring( 4, 6 ) ); return new File( file, id ); } private void findFiles( final List<File> list, final File file ) { final File[] files = file.listFiles(); if ( files != null ) { for ( final File f : files ) { if ( f.isDirectory() ) { findFiles( list, f ); } else { list.add( f ); } } } } private File newTemporaryFile() throws BlobStoreException { try { return File.createTempFile( TMP, null, this.dir ); } catch ( IOException e ) { throw new BlobStoreException( "Failed to create temporary file", e ); } } private boolean mkdirs( final File dir, final boolean error ) { if ( dir.isDirectory() ) { return false; } final boolean flag = dir.mkdirs(); if ( flag ) { LOG.debug( "Created directory [" + dir.getAbsolutePath() + "]" ); } else if ( error ) { throw new BlobStoreException( "Failed to create directory [" + dir.getAbsolutePath() + "]" ); } return flag; } private boolean delete( final File file ) { if ( file == null ) { return false; } if ( !file.exists() ) { return false; } final boolean flag = file.delete(); if ( flag ) { LOG.debug( "File deleted [" + file.getAbsolutePath() + "]" ); } return flag; } }