package de.unikassel.sdcframework;
import java.io.File;
import java.security.InvalidParameterException;
import java.security.PrivateKey;
import java.sql.SQLException;
import de.unikassel.android.sdcframework.util.FileUtils;
import de.unikassel.android.sdcframework.util.facade.Encryption;
/**
* SDF framework archive extractor.
*
* @author Katy Hilgenberg
*
*/
public class ArchiveProcessor implements Runnable
{
/**
* The log helper class
*/
private final LogUtil log;
/**
* The private key for decryption
*/
private final PrivateKey key;
/**
* The working directory
*/
private final File workdir;
/**
* Constructor
*
* @param keyFile
* the private key file
*
* @param path
* the working directory path
*/
public ArchiveProcessor( File keyFile, String path )
{
this.log = new LogUtil( this.getClass() );
if ( !keyFile.exists() )
{
throw new InvalidParameterException(
"rsa private key file does not exist!" );
}
this.key = Encryption.readPrivateKeyFromFile( keyFile );
this.workdir = new File( path );
if( !workdir.exists() || !workdir.isDirectory() )
{
throw new InvalidParameterException(
"invalid working directory!" );
}
}
/**
* Constructor
*
* @param path
* the working directory path
*/
public ArchiveProcessor( String path )
{
this.log = new LogUtil( this.getClass() );
this.key = null;
this.workdir = new File( path );
if( !workdir.exists() || !workdir.isDirectory() )
{
throw new InvalidParameterException(
"invalid working directory!" );
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
@Override
public void run()
{
int cnt = 0;
// new log file will be created -> mark older files for transfer
for ( File file : workdir.listFiles() )
{
if( file.isDirectory() ) continue;
try
{
String xmlFile = process( file );
if ( xmlFile != null )
{
if ( new File( xmlFile ).exists() )
{
// in case of success ... delete archive
file.delete();
}
cnt++;
log.info( "Successfully processed archive: "
+ file.getName() );
}
else
{
log.error( "Failed to process file "
+ file.getName() );
}
}
catch ( Exception e )
{
log.error( "Failed to query new data from mesurement table. Reason: "
+ e.getMessage() );
}
finally
{
}
}
log.info( "Processed " + cnt + " archives!" );
}
/**
* Does process the current record in a result set
*
* @param file
* the actual file to process
* @return the path to the extracted raw data XML file
* @throws SQLException
*/
public String process( File file ) throws SQLException
{
// The extraction process depends on the file format
String name = FileUtils.fileNameFromPath( file.getAbsolutePath() );
int pos = name.lastIndexOf( '.' );
String format = name.substring( pos + 1 );
String archiveFile = file.getAbsolutePath();
if ( "octet-stream".equals( format ) )
{
// decrypt rsa encrypted archives
String newArchiveFile = decrypt( archiveFile );
archiveFile = newArchiveFile;
}
// process the archive
return process( archiveFile );
}
/**
* Methods to extract archive content
*
* @param archiveFile
* the archive file
* @return the path to the extracted raw data XML file
*/
private String process( String archiveFile )
{
if ( archiveFile == null )
return null;
// remove file extension from filename
int extensionPos = archiveFile.lastIndexOf( '.' );
String rawFileName = archiveFile.substring( 0, extensionPos );
// create directories
int uuidEndPos = rawFileName.lastIndexOf( '-' );
StringBuffer path = new StringBuffer( rawFileName.substring( 0,
uuidEndPos ) );
// uuid directory
File dir = new File( path.toString() );
if ( !dir.exists() && !dir.mkdir() )
{
log.debug( "Failed to create device directory \"" + path.toString()
+ "\"" );
return null;
}
path.append( File.separatorChar );
path.append( rawFileName.substring( uuidEndPos + 1, extensionPos ) );
// time stamp subdirectory
dir = new File( path.toString() );
if ( !dir.exists() && !dir.mkdir() )
{
log.debug( "Failed to create timestamp directory \""
+ path.toString() + "\"" );
return null;
}
// store path as return value
String rawDataPath = dir.getPath();
// extract files
File archive = new File( archiveFile );
ArchiveContent content = ArchiveContent.createFromArchive( archive,
rawDataPath );
// clean up temporary files
File tmpFile = new File( rawFileName + ".tmp" );
if ( tmpFile.exists() )
{
tmpFile.delete();
}
if ( content != null )
{
// store serialized raw data
path.append( File.separatorChar );
path.append( SDCFRawData.FILE_NAME );
SDCFRawData rawData = content.getRawData();
String xmlFile = path.toString();
try
{
if ( FileUtils.writeToTextFile( SDCFRawData.toXML( rawData ),
xmlFile ) )
{
return xmlFile;
}
log.debug( "Failed to store serialized raw data to \""
+ xmlFile + "\". Reason: IO Error" );
}
catch ( Exception e )
{
log.debug( "Failed to store serialized raw data to \""
+ xmlFile + "\". Reason: " + e.getMessage() );
}
}
else
{
log.debug( "Failed to extract archive content to \"" + rawDataPath
+ "\"" );
}
return null;
}
/**
* Does decrypt an archive file
*
* @param archiveFile
* the archive file
* @return the decrypted files name
*/
private String decrypt( String archiveFile )
{
String filename = archiveFile.substring( 0,
archiveFile.lastIndexOf( '.' ) );
String decryptedFile = filename + ".tmp";
File destFile = new File( decryptedFile );
if ( key != null &&
Encryption.decryptRSA( key, new File( archiveFile ), destFile ) )
{
log.debug( "Decryption of file \"" + archiveFile + "\" done." );
}
else
{
log.error( "Decryption failed for file \"" + archiveFile + "\"" );
if ( destFile.exists() )
{
destFile.delete();
}
decryptedFile = null;
}
return decryptedFile;
}
}