/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.upgrade.task;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.jdbc.core.RowMapper;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.io.Files;
import com.enonic.cms.framework.blob.BlobKey;
import com.enonic.cms.upgrade.UpgradeContext;
import com.enonic.cms.upgrade.UpgradeException;
final class UpgradeModel0204
extends AbstractUpgradeTask
{
private static final String GET_CHILDREN_OF_SQL = "select * from tVirtualFile where vf_sParentKey = ?";
private static final String ROOT_KEY = DigestUtils.shaHex( "/".getBytes() );
private File resourceRoot;
private File blobstoreRoot;
public UpgradeModel0204()
{
super( 204 );
}
@Override
public void upgrade( final UpgradeContext context )
throws Exception
{
context.logInfo( "Moving all resource files from blobstore to resource folder" );
initBlobstore( context );
initResourceRoot( context );
VirtualFileItem root = getRootElement( context );
if ( root == null )
{
context.logInfo( "No resource root found, no resources to process." );
}
else
{
processFiles( context, root, "" );
}
}
private void initResourceRoot( final UpgradeContext context )
throws UpgradeException
{
resourceRoot = new File( context.getProperty( "cms.resource.path" ) );
if ( resourceRoot.exists() )
{
context.logWarning( "Resource folder " + resourceRoot.getAbsolutePath() + " already exists" );
}
context.logInfo( "Initializing resource root at " + resourceRoot.getAbsolutePath() );
resourceRoot.mkdirs();
if ( !resourceRoot.exists() )
{
throw new UpgradeException( "Not able to create resource folder " + resourceRoot.getAbsolutePath() );
}
}
private void initBlobstore( final UpgradeContext context )
throws UpgradeException
{
blobstoreRoot = new File( context.getProperty( "cms.blobstore.dir" ) );
if ( !blobstoreRoot.exists() || !blobstoreRoot.canRead() )
{
throw new UpgradeException( ( "Cannot read blobstore " + blobstoreRoot.getAbsolutePath() ) );
}
}
private void processFiles( final UpgradeContext context, final VirtualFileItem root, final String currentPath )
throws Exception
{
final List<VirtualFileItem> elementsWithParent = getElementsWithParent( context, root.key );
for ( VirtualFileItem item : elementsWithParent )
{
final String itemPath = createPath( currentPath, item );
final boolean isFolder = item.length < 0;
if ( isFolder )
{
createFolder( context, itemPath );
processFiles( context, item, itemPath );
}
else
{
createFile( context, item, itemPath );
}
}
}
private boolean createFolder( UpgradeContext context, String path )
{
context.logInfo( "Create folder: " + path );
File newFolder = new File( resourceRoot + "/" + path );
if ( newFolder.exists() )
{
return false;
}
return newFolder.mkdirs();
}
private boolean createFile( UpgradeContext context, VirtualFileItem fileItem, String path )
{
context.logInfo( "Copy file: " + path );
if ( Strings.isNullOrEmpty( fileItem.blobkey ) )
{
context.logWarning( "No blobkey found for file " + fileItem.name );
return false;
}
File blobFile = getBlobFile( new BlobKey( fileItem.blobkey ) );
if ( !blobFile.exists() )
{
context.logWarning(
"No blobfile found for file with name " + fileItem.name + ", blobKey = " + fileItem.blobkey + ", blobFile = " +
blobFile.getAbsolutePath() );
return false;
}
File newFile = new File( resourceRoot + "/" + path );
try
{
Files.copy( blobFile, newFile );
return true;
}
catch ( IOException e )
{
context.logError( "Not able to copy file " + blobFile.getAbsolutePath() + " to " + newFile.getAbsolutePath(), e );
return false;
}
}
private File getBlobFile( final BlobKey key )
{
final String id = key.toString();
File file = blobstoreRoot;
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 String createPath( final String currentPath, final VirtualFileItem item )
{
return currentPath + "/" + item.name;
}
private List<VirtualFileItem> getElementsWithParent( UpgradeContext context, String parentKey )
throws Exception
{
List<VirtualFileItem> children = Lists.newArrayList();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = context.getConnection();
ps = conn.prepareStatement( GET_CHILDREN_OF_SQL );
ps.setString( 1, parentKey );
rs = ps.executeQuery();
while ( rs.next() )
{
children.add( createVirtualFileItem( rs ) );
}
}
finally
{
context.close( rs );
context.close( ps );
context.close( conn );
}
return children;
}
private VirtualFileItem getRootElement( UpgradeContext context )
throws Exception
{
context.logInfo( "Fetching root with key: " + ROOT_KEY );
final List<VirtualFileItem> rootItems =
context.getJdbcTemplate().query( "SELECT * FROM tVirtualFile where vf_skey = '" + ROOT_KEY + "'",
new VirtualFileItemExtractor() );
return rootItems != null && rootItems.size() == 1 ? rootItems.get( 0 ) : null;
}
private static VirtualFileItem createVirtualFileItem( final ResultSet rs )
throws SQLException
{
VirtualFileItem item = new VirtualFileItem();
final String vf_skey = rs.getString( "vf_skey" );
item.key = vf_skey;
item.name = rs.getString( "vf_sname" );
item.parentKey = rs.getString( "vf_sparentkey" );
item.length = rs.getLong( "vf_llength" );
item.blobkey = rs.getString( "vf_sblobkey" );
return item;
}
private static class VirtualFileItemExtractor
implements RowMapper
{
@Override
public Object mapRow( final ResultSet resultSet, final int i )
throws SQLException
{
return createVirtualFileItem( resultSet );
}
}
private static class VirtualFileItem
{
String key;
String parentKey;
String name;
long length;
String blobkey;
}
}