/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.resource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.commons.io.input.BOMInputStream; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.google.common.io.Files; import com.enonic.cms.framework.util.MimeTypeResolver; @Service("fileResourceService") public class FileResourceServiceImpl implements FileResourceService { private File resourceRoot; private MimeTypeResolver mimeTypeResolver; @Override public FileResource getResource( final FileResourceName name ) { final File entity = getFile( name ); if ( !entity.exists() && name.isRoot() ) { createFolder( name ); return newResource( name, resourceRoot ); } if ( entity.exists() ) { return newResource( name, entity ); } return null; } private boolean doCreateFolder( FileResourceName name ) { if ( name == null ) { return false; } File newFolder = getFile( name ); if ( newFolder.exists() ) { return false; } return newFolder.mkdirs(); } private FileResource newResource( FileResourceName name, File file ) { FileResource res = new FileResource( name ); res.setFolder( file.isDirectory() ); res.setSize( file.length() ); res.setMimeType( mimeTypeResolver.getMimeType( name.getName() ) ); res.setLastModified( new DateTime( file.lastModified() ) ); return res; } @Override public boolean createFolder( final FileResourceName name ) { return doCreateFolder( name ); } @Override public boolean createFile( FileResourceName name, FileResourceData data ) { return !name.isRoot() && doCreateFile( name, data ); } private boolean doCreateFile( FileResourceName name, FileResourceData data ) { final File newFile = getFile( name ); if ( newFile.exists() ) { return false; } try { Files.createParentDirs( newFile ); if ( data != null ) { Files.write( data.getAsBytes(), newFile ); } else { Files.touch( newFile ); } } catch ( IOException e ) { throw new RuntimeException( "Not able to create file " + newFile.getAbsolutePath(), e ); } return true; } @Override public boolean deleteResource( final FileResourceName name ) { File fileToDelete = getFile( name ); if ( fileToDelete.exists() ) { if ( fileToDelete.isDirectory() ) { try { FileUtils.deleteDirectory( fileToDelete ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to delete folder: " + fileToDelete.getAbsolutePath(), e ); } } else { return fileToDelete.delete(); } } return false; } @Override public List<FileResourceName> getChildren( final FileResourceName name ) { final ArrayList<FileResourceName> list = new ArrayList<FileResourceName>(); final File parent = getFile( name ); if ( !parent.exists() ) { return list; } if ( !parent.isDirectory() ) { return list; } final File[] files = parent.listFiles(); if ( files == null ) { return list; } // sort files, because listFiles does not guaranty any order. Arrays.sort( files ); for ( final File file : files ) { list.add( new FileResourceName( name, file.getName() ) ); } return list; } @Override public FileResourceData getResourceData( final FileResourceName name ) { File file = getFile( name ); if ( !file.exists() ) { return null; } if ( file.isDirectory() ) { return null; } try { final byte[] bytes = Files.toByteArray( file ); final FileResourceData data = new FileResourceData(); data.setAsBytes( bytes ); return data; } catch ( IOException e ) { throw new RuntimeException( "Not able to read file: " + file.getAbsolutePath(), e ); } } private File getFile( final FileResourceName name ) { if ( name.isRoot() ) { return resourceRoot; } return new File( resourceRoot, name.getPath() ); } @Override public boolean setResourceData( final FileResourceName name, final FileResourceData data ) { File file = getFile( name ); if ( !file.exists() ) { return false; } if ( file.isDirectory() ) { return false; } try { Files.write( data.getAsBytes(), file ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to write to file " + file.getAbsolutePath(), e ); } } @Override public boolean moveResource( final FileResourceName from, final FileResourceName to ) { File fromFile = getFile( from ); if ( !fromFile.exists() ) { return false; } File toFile = getFile( to ); if ( toFile.exists() ) { return false; } if ( fromFile.isDirectory() ) { return doMoveDirectory( fromFile, toFile ); } if ( fromFile.isFile() ) { return doMoveFile( fromFile, toFile ); } return false; } private boolean doMoveFile( final File fromFile, final File toFile ) { final File parent = toFile.getParentFile(); if ( !parent.exists() ) { return false; } try { Files.move( fromFile, toFile ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to move file " + fromFile.getAbsolutePath() + " to " + toFile.getAbsolutePath(), e ); } } private boolean doMoveDirectory( final File fromFile, final File toFile ) { if ( isSubFolderOf( fromFile, toFile ) ) { return false; } try { FileUtils.moveDirectory( fromFile, toFile ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to move folder " + fromFile.getAbsolutePath() + " to " + toFile.getAbsolutePath(), e ); } } private boolean isSubFolderOf( final File fromFile, final File toFile ) { File parent = toFile.getParentFile(); while ( parent != null ) { if ( parent.equals( resourceRoot ) ) { return false; } if ( parent.equals( fromFile ) ) { return true; } parent = parent.getParentFile(); } return false; } @Override public boolean copyResource( final FileResourceName from, final FileResourceName to ) { File fromFile = getFile( from ); if ( !fromFile.exists() ) { return false; } if ( fromFile.isFile() ) { return doCopyResourceFile( fromFile, to ); } if ( fromFile.isDirectory() ) { return doCopyResourceFolder( to, fromFile ); } return false; } private boolean doCopyResourceFolder( final FileResourceName to, final File fromFile ) { File toFile = getFile( to ); try { FileUtils.copyDirectory( fromFile, toFile ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to copy directory " + fromFile + " to " + toFile, e ); } } private boolean doCopyResourceFile( File fromFile, FileResourceName to ) { File toFile = getFile( to ); if ( toFile.exists() ) { return false; } try { Files.copy( fromFile, toFile ); return true; } catch ( IOException e ) { throw new RuntimeException( "Not able to copy from file " + fromFile.getAbsolutePath() + " to " + toFile.getAbsolutePath(), e ); } } @Override public InputStream getResourceStream( final FileResourceName name, final boolean ignoreBom ) { final File file = getFile( name ); if ( !file.isFile() ) { return null; } try { final FileInputStream in = new FileInputStream( file ); if ( ignoreBom ) { return new BOMInputStream( in, false ); } else { return in; } } catch ( final IOException e ) { throw new RuntimeException( "Failed to open " + name.getPath() ); } } @Value("${cms.resource.path}") public void setResourceRoot( final File resourceRoot ) { this.resourceRoot = resourceRoot; } @Autowired public void setMimeTypeResolver( final MimeTypeResolver mimeTypeResolver ) { this.mimeTypeResolver = mimeTypeResolver; } }