/*
* Copyright (c) 2010-2012 Research In Motion Limited. All rights reserved.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License, Version 1.0,
* which accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*
*/
package net.rim.ejde.internal.launching;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import net.rim.ejde.internal.model.BlackBerryProject;
import net.rim.ejde.internal.model.BlackBerryProperties;
import net.rim.ejde.internal.util.Messages;
import net.rim.ejde.internal.util.PackagingUtils;
import net.rim.ejde.internal.util.StatusFactory;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.osgi.util.NLS;
/**
* A helper class to deploy a BlackBerry project to destination folder.
*
* @author dmeng
*
*/
public class DeploymentHelper {
static final String defExtension = ".def";
static final String alxExtension = ".alx";
static final String codeExtension = ".cod";
static final String cslExtension = ".wts";
static final String wtsExtension = ".csl";
static final String csoExtension = ".cso";
static final String csvExtension = ".csv";
static final String debugExtension = ".debug";
static final String dmpExtension = ".dmp";
static final String dllExtension = ".dll";
static final String exportExtension = ".export.xml";
static final String gifExtension = ".gif";
static final String htmlExtension = ".html";
static final String jarExtension = ".jar";
static final String jadExtension = ".jad";
static final String javaExtension = ".java";
static final String jsExtension = ".js";
static final String projectExtension = ".jdp";
static final String workspaceExtension = ".jdw";
static final String jpgExtension = ".jpg";
static final String keyExtension = ".key";
static final String lstExtension = ".lst";
static final String pngExtension = ".png";
static final String rapcExtension = ".rapc";
static final String languageResourceExtension = ".rrc";
static final String languageHeaderExtension = ".rrh";
static final String keyMapResourceExtension = ".rcmap";
static final String keyMapHeaderExtension = ".rhmap";
static final String txtExtension = ".txt";
static final String xmlExtension = ".xml";
static final String manifestExtension = ".manifest.xml";
public static final String deployableFileExtensions[] = { codeExtension, jarExtension, lstExtension, debugExtension,
cslExtension, csoExtension, wtsExtension };
private static final Logger _logger = Logger.getLogger( DeploymentHelper.class );
/**
* Deploy the given project.
*
* @param project
* The project to be deployed
* @param deploymentPath
* The deployment path
* @param internalMode
* If we are running in internal model
*
* @return <code>true</code> if deployment completes successfully. otherwise return <code>false</code>.
*/
public static int deploy( BlackBerryProject project, String deploymentPath, boolean internalMode ) throws CoreException {
int rc;
// undeploy existing files first
rc = deploy( project, deploymentPath, true, internalMode );
if( rc != 0 ) {
return rc;
}
// deploy new files
rc = deploy( project, deploymentPath, false, internalMode );
return rc;
}
/**
* Checks if the file represented by the <code>fileName</code> needs to be deployed.
*
* @param fileName
* @return
*/
public static final boolean isDeploymentFile( String fileName ) {
for( int i = 0; i < DeploymentHelper.deployableFileExtensions.length; i++ ) {
if( fileName.endsWith( DeploymentHelper.deployableFileExtensions[ i ] ) ) {
return true;
}
}
return false;
}
private static int deploy( BlackBerryProject project, String depolymentPath, boolean erase, boolean isRIMModel )
throws CoreException {
BlackBerryProperties properties = project.getProperties();
String outputFileName = properties._packaging.getOutputFileName();
String outputPath = project.getProject().getLocation().toOSString();
String[] outputPaths = PackagingUtils.getPackagingOutputFolders( project );
// we deploy the standard deliverables
outputPath += IPath.SEPARATOR + outputPaths[ PackagingUtils.STANDARD_DEPLOYMENT ];
_logger.trace( "Project " + project.getElementName() + ( erase ? " undeploy from " : " deploy --> " ) + depolymentPath );
for( int i = 0; i < deployableFileExtensions.length; ++i ) {
int rc = deploy( outputFileName, outputPath, depolymentPath, deployableFileExtensions[ i ], erase );
if( rc != 0 ) {
return rc;
}
}
// if it is RIM model, also deploy the cod file to the lynx/debug/java folder
if( isRIMModel ) {
int rc = deploy( outputFileName, outputPath, depolymentPath + File.separator + "Java", codeExtension, erase );
if( rc != 0 ) {
return rc;
}
}
return 0;
}
private static int deploy( String projectName, String srcPath, String dstPath, String extension, boolean erase )
throws CoreException {
if( erase ) {
List< File > list = getSiblingList( projectName, dstPath, extension );
int rc = 0;
int count = list.size();
for( int i = 0; i < count; ++i ) {
File f = list.get( i );
if( !f.exists() ) {
break;
}
rc = executeErase( f );
if( rc != 0 ) {
_logger.error( "error deleting " + f.getName() );
return rc;
}
}
return 0;
} else {
// _logger.info( "Deploy " + projectName + extension + " from " + srcPath + " to " + dstPath );
int rc = 0;
int i = 0;
String sibling = "";
for( ;; ) {
String name = projectName + sibling + extension;
File srcFile = new File( srcPath + File.separator + name );
if( !srcFile.exists() ) {
break;
}
File dstFile = new File( dstPath + File.separator + name );
rc = deployFile( srcFile, dstFile );
if( rc != 0 ) {
return rc;
}
sibling = makeSiblingExtension( Integer.toString( ++i ) );
}
return rc;
}
}
private static int deployFile( File srcFile, File dstFile ) throws CoreException {
if( srcFile.lastModified() != dstFile.lastModified() ) {
int rc = executeCopy( srcFile, dstFile );
if( rc != 0 ) {
return rc;
}
} else {
_logger.info( "File " + srcFile.getName() + " is skipped because the destination file is newer" );
}
return 0;
}
private static List< File > getSiblingList( String fileName, String path, String extension ) {
List< File > v = new ArrayList< File >();
String sibling = "";
int i = 0;
for( ;; ) {
StringBuffer sb = new StringBuffer( path );
sb.append( File.separator );
sb.append( fileName );
sb.append( sibling );
sb.append( extension );
File f = new File( sb.toString() );
if( !f.exists() ) {
break;
}
v.add( f );
sibling = makeSiblingExtension( Integer.toString( ++i ) );
}
return v;
}
private static String makeSiblingExtension( String s ) {
return "-" + s;
}
/**
* Erase a file. File.delete() is an acceptable implementation
*
* @param f
* the file to erase. It is guaranteed to exist
* @return 0 for success, non-zero if error
*/
private static int executeErase( File file ) {
_logger.trace( "Erase " + file.getName() );
return file.delete() ? 0 : -1;
}
/**
* Copy a file. Util.copyFile( srcFile, dstFile ) is an acceptable implementation
*
* @param srcFile
* the source of the copy
* @param dstFile
* the destination of the copy
* @return 0 for success, non-zero for failure
* @throws CoreException
*/
public static int executeCopy( final File srcFile, final File dstFile ) throws CoreException {
_logger.trace( "Copy " + srcFile.getName() ); // + " --> " + dstFile );
if( !srcFile.exists() ) {
String msg = NLS.bind( Messages.DeploymentHelper_FILE_NOT_EXIST_MSG, srcFile.getAbsolutePath() );
_logger.error( msg );
throw new CoreException( StatusFactory.createErrorStatus( msg ) );
}
InputStream in = null;
OutputStream out = null;
int retValue = 0;
try {
in = new FileInputStream( srcFile );
out = new FileOutputStream( dstFile );
byte[] buf = new byte[ 64 * 1024 ];
int len;
while( ( len = in.read( buf ) ) > 0 ) {
out.write( buf, 0, len );
}
} catch( final IOException e ) {
if(e instanceof FileNotFoundException) {
String msg = NLS.bind( Messages.DeploymentHelper_FILE_NOT_WRITABLE_MSG, dstFile.getParent() );
_logger.error( msg );
throw new CoreException( StatusFactory.createErrorStatus( msg ) );
}
_logger.error( e.getMessage(), e );
retValue = -1;
} finally {
try {
if( in != null ) {
in.close();
}
} catch( IOException e ) {
_logger.error( e.getMessage(), e );
retValue = -1;
}
try {
if( out != null ) {
out.close();
}
} catch( IOException e ) {
_logger.error( e.getMessage(), e );
retValue = -1;
}
}
if( retValue == 0 ) {
dstFile.setLastModified( srcFile.lastModified() );
}
return retValue;
}
}