/* * 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.util; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Set; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.core.IConstants; import net.rim.ejde.internal.model.BasicBlackBerryProperties; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.model.BlackBerryProjectCoreNature; import net.rim.ejde.internal.model.BlackBerryProperties; import net.rim.ejde.internal.model.BlackBerryPropertiesFactory; import net.rim.ejde.internal.model.BlackBerrySDKInstall; import net.rim.ejde.internal.model.BlackBerryVMInstallType; import net.rim.ejde.internal.validation.BBPropertiesValidator; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; /** * A util class to deal with the tasks needed for steps in the packaging process. * * @author jheifetz */ public class PackagingUtils { static Logger _log = Logger.getLogger( PackagingUtils.class ); static char _replaceChar; /** * The index of standard deployment folder name */ static final public int STANDARD_DEPLOYMENT = 0; /** * The index of web deployment folder name */ static final public int WEB_DEPLOYMENT = 1; /** * Gets the default project output folder. * * @return the default project output folder */ public static String getDefaultProjectOutputPrefix() { return ContextManager.getDefault().getPreferenceStore().getString( IConstants.PROJECT_OUTPUT_FOLDER_PREFIX_KEY ); } /** * Gets the default generate alx file value. * * @return the default generate alx file value */ public static boolean getDefaultGenerateAlxFile() { return ContextManager.getDefault().getPreferenceStore().getBoolean( IConstants.GENERATE_ALX_FILE_KEY ); } /** * Gets the default BlackBerry model version. * * @return the default BlackBerry model version */ public static String getDefaultModelVersion() { // ContextManager.getDefault().getPreferenceStore().getString( IConstants.BB_MODEL_VERSION ); return BasicBlackBerryProperties.DEFAULT_MODEL_VERSION; } /** * If the exported jars in a BlackBerry project should be packaged into the project's cod file. * * @return */ public static boolean getPackagExportedJar() { return ContextManager.getDefault().getPreferenceStore().getBoolean( IConstants.PACKAGE_EXPORTED_JAR ); } /** * Cleans the contents of the project output folder. * * @param javaProj * the java project * * @throws CoreException * Exceptions in the process */ public static void cleanProjectOutputFolder( final IJavaProject javaProj ) throws CoreException { if( javaProj != null ) { boolean isBBProject = javaProj.getProject().hasNature( BlackBerryProjectCoreNature.NATURE_ID ); final String projName = javaProj.getProject().getName(); BlackBerryProperties bbProperties = null; if( isBBProject ) { bbProperties = ContextManager.PLUGIN.getBBProperties( projName, false ); } else { bbProperties = BlackBerryPropertiesFactory.createBlackBerryProperties( javaProj ); } if( bbProperties != null ) { // clean the deployment files of the current project String[] outputFolderPaths = PackagingUtils.getPackagingOutputFolders( new BlackBerryProject( javaProj, bbProperties ) ); for( int i = 0; i < outputFolderPaths.length; i++ ) { String outputFolder = outputFolderPaths[ i ]; String outputFileN = bbProperties._packaging.getOutputFileName(); if( ( null != outputFolder ) && ( null != outputFileN ) && ( outputFileN.length() > 0 ) ) { final IResource outputFolderRes = javaProj.getProject().findMember( outputFolder ); removeFiles( (IContainer) outputFolderRes, null ); } } // clean the deployment files of the dependency projects List< IJavaProject > dependentProjects = ProjectUtils.getAllReferencedJavaProjects( javaProj ); String outputFileName; for( IJavaProject dependentProject : dependentProjects ) { bbProperties = ContextManager.PLUGIN.getBBProperties( dependentProject.getProject().getName(), false ); outputFileName = bbProperties._packaging.getOutputFileName(); outputFolderPaths = PackagingUtils.getPackagingOutputFolders( new BlackBerryProject( dependentProject, bbProperties ) ); for( int i = 0; i < outputFolderPaths.length; i++ ) { String outputFolder = outputFolderPaths[ i ]; if( ( null != outputFolder ) && ( null != outputFileName ) && ( outputFileName.length() > 0 ) ) { final IResource outputFolderRes = javaProj.getProject().findMember( outputFolder ); removeFiles( (IContainer) outputFolderRes, outputFileName ); } } } } else { if( isBBProject ) { throw new CoreException( new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, "Cannot retrieve metadata from project " + projName ) ); } } } else { throw new CoreException( new Status( IStatus.ERROR, ContextManager.PLUGIN_ID, "Cannot change output folder for null IJavaProject" ) ); } } private static void removeFiles( IContainer container, String fileName ) throws CoreException { if( ( container != null ) && container.exists() ) { IResource[] resources = ( container ).members(); for( final IResource child : resources ) { if( StringUtils.isBlank( fileName ) || child.getName().startsWith( fileName ) ) { child.delete( true, new NullProgressMonitor() ); } } } } /** * Gets the bbsdk install for the given JavaProject * * @param javaProj * the java proj * * @return The BlackBerrySDKInstall for JavaProject or <code>null</code> */ public static BlackBerrySDKInstall getBBSDKInstall( IJavaProject javaProj ) { if( javaProj == null ) { return null; } try { IVMInstall vm = null; if( javaProj.getProject().hasNature( BlackBerryProjectCoreNature.NATURE_ID ) ) { if( javaProj.getProject().isOpen() ) { vm = JavaRuntime.getVMInstall( javaProj ); if( vm != null && vm instanceof BlackBerrySDKInstall ) { return (BlackBerrySDKInstall) vm; } } } else { if( javaProj.getProject().isOpen() ) { // for java proejct, we use the default BB jre return (BlackBerrySDKInstall) VMUtils.getDefaultBBVM(); } } } catch( CoreException e ) { _log.error( e ); } return null; } /** * Get the output folder name of the BlackBerry JRE of the given <code>bbProject</code>. * * @param bbProject * @return */ public static String getVMOutputFolderName( BlackBerryProject bbProject ) { BlackBerrySDKInstall bbVM = PackagingUtils.getBBSDKInstall( bbProject.getJavaProject() ); if( bbVM == null ) { return IConstants.DEFAULT_VM_OUTPUT_FOLDER_NAME; } String name = bbVM.getAttribute( BlackBerryVMInstallType.ATTR_RAPC_OUTPUT_FOLDER ); if( name == null ) { return IConstants.DEFAULT_VM_OUTPUT_FOLDER_NAME; } return name; } /** * Gets the array of output folders of packaging. * * @param javaProj * the java proj * * @return The output folders of packaging. If there is not output folder found, an empty string array is returned not * <code>null</code>. * * @see PackagingUtils#STANDARD_DEPLOYMENT * @see PackagingUtils#WEB_DEPLOYMENT */ public static String[] getPackagingOutputFolders( BlackBerryProject bbProject ) { String outputRootFolder = bbProject.getProperties()._packaging.getOutputFolder(); final BlackBerrySDKInstall bbVM = PackagingUtils.getBBSDKInstall( bbProject.getJavaProject() ); String[] outputFolders; String outputFolderPrefix = StringUtils.isBlank( outputRootFolder ) ? IConstants.EMPTY_STRING : outputRootFolder + IPath.SEPARATOR; if( bbVM != null ) { outputFolders = new String[ 2 ]; final String outputFolderSuffix = bbVM.getAttribute( BlackBerryVMInstallType.ATTR_RAPC_OUTPUT_FOLDER ); if( ( outputFolderSuffix != null ) && !StringUtils.isBlank( outputFolderSuffix ) ) { outputFolders[ STANDARD_DEPLOYMENT ] = outputFolderPrefix + getStandardDeploymentFolderName() + IPath.SEPARATOR + outputFolderSuffix; outputFolders[ WEB_DEPLOYMENT ] = outputFolderPrefix + getWebDeploymentFolderName() + IPath.SEPARATOR + outputFolderSuffix; } else { outputFolders[ STANDARD_DEPLOYMENT ] = outputFolderPrefix + getStandardDeploymentFolderName(); outputFolders[ WEB_DEPLOYMENT ] = outputFolderPrefix + getWebDeploymentFolderName(); } } else { outputFolders = new String[ 2 ]; outputFolders[ STANDARD_DEPLOYMENT ] = outputFolderPrefix + getStandardDeploymentFolderName(); outputFolders[ WEB_DEPLOYMENT ] = outputFolderPrefix + getWebDeploymentFolderName(); } return outputFolders; } /** * Gets the relative web output folder. * * @param bbProject * @return */ public static String getRelativeWebOutputFolder( BlackBerryProject bbProject ) { String[] outputFolders = getPackagingOutputFolders( bbProject ); if( outputFolders.length > WEB_DEPLOYMENT ) { return outputFolders[ WEB_DEPLOYMENT ]; } else { return IConstants.EMPTY_STRING; } } /** * Gets the relative standard output folder. * * @param bbProject * @return */ public static String getRelativeStandardOutputFolder( BlackBerryProject bbProject ) { String[] outputFolders = getPackagingOutputFolders( bbProject ); if( outputFolders.length > STANDARD_DEPLOYMENT ) { return outputFolders[ STANDARD_DEPLOYMENT ]; } else { return IConstants.EMPTY_STRING; } } /** * Gets the relative standard output folder for the given <code>vm</code>. * * @param bbProject * @return */ public static String getRelativeStandardOutputFolder( BlackBerryProject bbProject, BlackBerrySDKInstall vm ) { String bbVersion = vm.getAttribute( BlackBerryVMInstallType.ATTR_RAPC_OUTPUT_FOLDER ); String outputFolder = bbProject.getProperties()._packaging.getOutputFolder(); if( !StringUtils.isBlank( outputFolder ) ) { outputFolder += IPath.SEPARATOR + getStandardDeploymentFolderName() + IPath.SEPARATOR + bbVersion; } else { outputFolder = getStandardDeploymentFolderName(); } return outputFolder; } /** * Gets the output folder of alx file. * * @param bbProject * @return */ public static String getRelativeAlxFileOutputFolder( BlackBerryProject bbProject ) { String outputFolder = bbProject.getProperties()._packaging.getOutputFolder(); if( !StringUtils.isBlank( outputFolder ) ) { outputFolder += IPath.SEPARATOR + getStandardDeploymentFolderName(); } else { outputFolder = getStandardDeploymentFolderName(); } return outputFolder; } /** * Gets the absolute path of the output file for standard deployment, e.g. * c:/workspace/project1/deliverable/Standard/5.0.0/Helloworld * * @param project * @return */ static public IPath getAbsoluteStandardOutputFilePath( BlackBerryProject bbProject ) { IPath standardOutputPath = bbProject.getProject().getLocation(); standardOutputPath = standardOutputPath.append( getRelativeStandardOutputFilePath( bbProject ) ); return standardOutputPath; } /** * Gets the relative path of the output file for standard deployment, e.g. /deliverable/Standard/5.0.0/Helloworld. * * @param project * @return */ static public IPath getRelativeStandardOutputFilePath( BlackBerryProject bbProject ) { String[] outputPaths = getPackagingOutputFolders( bbProject ); IPath standardOutputPath = new Path( outputPaths[ STANDARD_DEPLOYMENT ] ); standardOutputPath = standardOutputPath.append( bbProject.getProperties()._packaging.getOutputFileName() ); return standardOutputPath; } /** * Gets the web deployment folder name. * * @return */ public static String getWebDeploymentFolderName() { return ImportUtils.getImportPref( "web_deployment_folder_name" ); } /** * Gets the standard deployment folder name. * * @return */ public static String getStandardDeploymentFolderName() { return ImportUtils.getImportPref( "standard_deployment_folder_name" ); } /** * Replaces special characters in the given string to conform to Java standard. * * @param val * @return */ public static String replaceSpecialChars( String val ) { // replace special characters final char replaceChr = getProjectOutputReplaceChar(); for( char chr : BBPropertiesValidator.CHARS_WARN ) { if( val.indexOf( chr ) >= 0 && replaceChr != 0 ) { val = val.replace( chr, replaceChr ); } } // append "_" in front if the first character is digit if( !val.isEmpty() && Character.isDigit( val.charAt( 0 ) ) ) { val = IConstants.UNDERSCORE_STRING + val; } return val; } /** * Returns the preferences.ini project_output_file_replace_space or 0 * * @return */ public static char getProjectOutputReplaceChar() { if( _replaceChar <= 0 ) { String replaceVal; if( ( replaceVal = ContextManager.getDefault().getPreferenceStore() .getString( IConstants.PROJECT_OUTPUT_FILE_REPLACE_CHAR ) ) != null && replaceVal.length() > 0 ) { _replaceChar = replaceVal.charAt( 0 ); } } return _replaceChar; } public static String[] getDependantProjectOutputFolders( BlackBerryProject parentProject, BlackBerryProject dependantProject ) { String outputRootFolder = parentProject.getProperties()._packaging.getOutputFolder(); final BlackBerrySDKInstall bbVM = PackagingUtils.getBBSDKInstall( dependantProject.getJavaProject() ); String[] outputFolders = null; if( bbVM != null ) { outputFolders = new String[ 2 ]; final String outputFolderSuffix = bbVM.getAttribute( BlackBerryVMInstallType.ATTR_RAPC_OUTPUT_FOLDER ); String outputFolderPrefix = StringUtils.isBlank( outputRootFolder ) ? IConstants.EMPTY_STRING : outputRootFolder + IPath.SEPARATOR; if( ( outputFolderSuffix != null ) && !StringUtils.isBlank( outputFolderSuffix ) ) { outputFolders[ STANDARD_DEPLOYMENT ] = outputFolderPrefix + getStandardDeploymentFolderName() + IPath.SEPARATOR + outputFolderSuffix; outputFolders[ WEB_DEPLOYMENT ] = outputFolderPrefix + getWebDeploymentFolderName() + IPath.SEPARATOR + outputFolderSuffix; } else { outputFolders[ STANDARD_DEPLOYMENT ] = outputFolderPrefix + getStandardDeploymentFolderName(); outputFolders[ WEB_DEPLOYMENT ] = outputFolderPrefix + getWebDeploymentFolderName(); } } return outputFolders; } public static List< String > getCodFilePathsFromProjects( Set< BlackBerryProject > projects ) { List< String > codFiles = new ArrayList< String >(); // Add the output files. These are the *.cod's of all active projects in // the RIM workspace for( BlackBerryProject project : projects ) { String outputFolderPath = project.getProject().getLocation().toOSString() + File.separator + getRelativeStandardOutputFolder( project ); String outputFileName = project.getProperties()._packaging.getOutputFileName(); File codFile = new File( outputFolderPath + File.separator + outputFileName + IConstants.COD_FILE_EXTENSION_WITH_DOT ); File cslFile; codFiles.add( codFile.getPath() ); try { List< BlackBerryProject > dependantProjects = ProjectUtils.getAllReferencedProjects( project ); for( BlackBerryProject dependantProject : dependantProjects ) { outputFolderPath = project.getProject().getLocation().toOSString() + File.separator + getRelativeStandardOutputFolder( dependantProject ); outputFileName = dependantProject.getProperties()._packaging.getOutputFileName(); codFile = new File( outputFolderPath + File.separator + outputFileName + IConstants.COD_FILE_EXTENSION_WITH_DOT ); cslFile = new File( outputFolderPath + File.separator + outputFileName + IConstants.CSL_FILE_EXTENSION_WITH_DOT ); // The signature tool brakes if we add a file that doesn't exist to // the list of files to import. This might happen if a project has // build errors, for instance. if( codFile.exists() && cslFile.exists() ) { codFiles.add( codFile.getPath() ); } } } catch( CoreException ce ) { _log.error( "launchSignatureTool: Cannot find dependant projects ", ce ); } } return codFiles; } /** * Returns if the given <code>BlackBerryProject</code> needs to be signed. This method only checks the * <code>BlackBerryProject</code> itself. * * @param project * The project to be tested * @return <code>true</code> if the project needs to be signed; otherwise returns <code>false</code> */ public static boolean isSigningNeeded( BlackBerryProject project ) { boolean signingNeeded = false; String outputFolderPath = project.getProject().getLocation().toOSString() + File.separator + getRelativeStandardOutputFolder( project ); String outputFileName = project.getProperties()._packaging.getOutputFileName(); File codFile = new File( outputFolderPath + File.separator + outputFileName + IConstants.COD_FILE_EXTENSION_WITH_DOT ); File cslFile = new File( outputFolderPath + File.separator + outputFileName + IConstants.CSL_FILE_EXTENSION_WITH_DOT ); if( codFile.exists() && cslFile.exists() ) { signingNeeded = true; } return signingNeeded; } /** * Returns if the given <code>BlackBerryProject</code> or any of its dependent projects needs to be signed * * @param bbProject * @return <code>true</code> if the project or any of its dependent project needs to be signed; otherwise returns * <code>false</code> */ public static boolean isSigningNeededForDependency( BlackBerryProject bbProject ) { try { if( isSigningNeeded( bbProject ) ) { return true; } List< BlackBerryProject > dependencies = ProjectUtils.getAllReferencedProjects( bbProject ); for( BlackBerryProject project : dependencies ) { if( isSigningNeeded( project ) ) { return true; } } return false; } catch( CoreException e ) { _log.error( e ); return false; } } /** * Gets the custom jad file form the root of the given <code>project</code>. * * @param bbproj * @return */ public static String getCustomJadFile( BlackBerryProject bbproj ) { return getProjectCustomFile( bbproj, IConstants.JAD_FILE_EXTENSION ); } /** * Gets the custom rapc file from the root of the given <code>project</code>. * * @param bbproj * @return */ public static String getCustomRapcFile( BlackBerryProject bbproj ) { return getProjectCustomFile( bbproj, IConstants.RAPC_FILE_EXTENSION ); } /** * Gets the custom file with given <project-name>.<code>fileExtension</code> form the root of the <code>project</code>. * * @param bbproj * @return */ public static String getProjectCustomFile( BlackBerryProject bbproj, String fileExtension ) { if( bbproj != null && !StringUtils.isEmpty( fileExtension ) ) { try { IProject project = bbproj.getProject(); IResource[] resources = project.members(); for( IResource res : resources ) { if( ( res instanceof IFile ) && fileExtension.equalsIgnoreCase( res.getFileExtension())) { String resn = res.getName().substring(0, res.getName().length() - fileExtension.length() -1); if(resn.equals(bbproj.getProperties()._packaging.getOutputFileName()) || resn.equals(project.getName())) { return res.getLocation().toOSString(); } } } } catch( CoreException e ) { _log.error( e ); } } return null; } }