/*
* 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.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Properties;
import net.rim.ejde.internal.core.ContextManager;
import net.rim.ejde.internal.core.IConstants;
import net.rim.ejde.internal.model.BlackBerryVMInstallType;
import net.rim.ejde.internal.ui.dialogs.VCWarningDialog;
import net.rim.ejde.internal.ui.preferences.PreferenceConstants;
import net.rim.ide.OSUtils;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.LibraryLocation;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.osgi.framework.Bundle;
/**
* The Class is used to manage VM tools. It copies the tools (e.g. SignatureTool.jar, JavaLoader.exe, etc) from the highest
* version of the VM installed into a local cache. If the VM is uninstalled, the local cache will be removed.
*
* @author jheifetz
*/
public class VMToolsUtils {
static private final Logger _log = Logger.getLogger( VMToolsUtils.class );
private static IPath _storedVMToolFolder;
private static IPath _oldVMToolFolder;
/**
* Gets the VM tools folder name.
*
* @return the VM tools folder name
*/
public static String getVMToolsFolderName() {
return ContextManager.getDefault().getPreferenceStore().getString( IConstants.VMTOOLS_LOCATION_KEY );
}
/**
* Gets the bundle data folder name.
*
* @return the bundle data folder name
*/
public static String getBundleDataFolderName() {
return ContextManager.getDefault().getPreferenceStore().getString( IConstants.BUNDLE_DATA_LOCATION_KEY );
}
/**
* Gets the VM tools folder path.
*
* @return the VM tools folder path
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getVMToolsFolderPath() throws IOException {
if( _storedVMToolFolder == null ) {
Bundle bundle = Platform.getBundle( ContextManager.PLUGIN_ID );
FileLocator.resolve( FileLocator.find( bundle, Path.ROOT, null ) );
URL bundleURL = FileLocator.resolve( FileLocator.find( bundle, Path.ROOT, null ) );
String bundlePath = bundleURL.getFile();
bundlePath = bundlePath.substring( bundlePath.indexOf( IPath.SEPARATOR ) + 1 );
_storedVMToolFolder = new Path( bundlePath ).removeLastSegments( 1 ).append(
VMToolsUtils.getBundleDataFolderName() + IPath.SEPARATOR + VMToolsUtils.getVMToolsFolderName() );
}
return _storedVMToolFolder;
}
/**
* Gets the Signature tools path.
*
* @return the Signature tool path
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getSignatureToolPath() throws IOException {
return VMToolsUtils.getVMToolsFolderPath().append( IPath.SEPARATOR + IConstants.SIGNATURE_TOOL_FILE_NAME );
}
/**
* Gets the JavaLoader path.
*
* @return the JavaLoader path
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getJavaLoaderPath() throws IOException {
return VMToolsUtils.getVMToolsFolderPath().append( IPath.SEPARATOR + IConstants.JAVA_LOADER_FILE_NAME );
}
/**
* Gets the version file path.
*
* @return the version path
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getVersionFilePath() throws IOException {
return VMToolsUtils.getVMToolsFolderPath().append( IPath.SEPARATOR + IConstants.VERSION_PROPERTY_FILE_NAME );
}
/**
* Gets the path for the given tool.
*
* @param name
* The tool name
* @return the tool path
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getToolPath( String name ) throws IOException {
return VMToolsUtils.getVMToolsFolderPath().append( IPath.SEPARATOR + name );
}
/**
* Gets the fledgehook path.
*
* @param file
* name. i.e fledgehook.exe or fledgehook.dll the vm that has been added.
*
* @return the fledgehook path
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getFledgeHookPath( String name ) throws IOException {
return VMToolsUtils.getVMToolsFolderPath().append( IPath.SEPARATOR + name );
}
/**
* Updates the VM tools on the addition of a VM. If the VM version is greater than the stored version, it is copied. If not,
* nothing happens
*
* VMs are compared based on modification stamp of the Jar.
*
* @param vm
* the vm that has been added.
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void addVMTools( IVMInstall vm ) throws IOException {
if( ( null == vm ) || !BlackBerryVMInstallType.VM_ID.equals( vm.getVMInstallType().getId() ) ) {
return;
}
// check source attachment
LibraryLocation[] libraryLocations = vm.getLibraryLocations();
IPath sourcePath;
if( libraryLocations != null ) {
for( int i = 0; i < libraryLocations.length; i++ ) {
sourcePath = libraryLocations[ i ].getSystemLibrarySourcePath();
if( sourcePath == null || sourcePath.isEmpty() ) {
sourcePath = ImportUtils.getSourceJarPath( libraryLocations[ i ].getSystemLibraryPath() );
if( sourcePath.toFile().exists() ) {
_log.trace( "Source has been attached to library jar "
+ libraryLocations[ i ].getSystemLibraryPath().lastSegment() + " in JRE " + vm.getName() );
libraryLocations[ i ].setSystemLibrarySource( sourcePath );
}
}
}
}
IPath sigToolPath = new Path( vm.getInstallLocation().getAbsolutePath() + IPath.SEPARATOR + IConstants.BIN_FOLD_NAME
+ IPath.SEPARATOR + IConstants.SIGNATURE_TOOL_FILE_NAME );
File sigToolFile = sigToolPath.toFile();
if( !sigToolFile.exists() ) {
throw new IOException( "Cannot Find Signature Tool At: " + sigToolPath.toString() );
}
IPath javaLoaderPath = new Path( vm.getInstallLocation().getAbsolutePath() + IPath.SEPARATOR + IConstants.BIN_FOLD_NAME
+ IPath.SEPARATOR + IConstants.JAVA_LOADER_FILE_NAME );
File javaLoaderFile = javaLoaderPath.toFile();
if( !javaLoaderFile.exists() ) {
throw new IOException( "Cannot Find JavaLoader.exe At: " + javaLoaderPath.toString() );
}
// if()
// copyFledgeHookFile();
File fledgeHookFile = null;
File fledgeHookDllFile = null;
if( OSUtils.isWindows() ) {
IPath fledgeHookPath = new Path( vm.getInstallLocation().getAbsolutePath() + IPath.SEPARATOR
+ IConstants.BIN_FOLD_NAME + IPath.SEPARATOR + IConstants.FLEDGE_HOOK_FILE_NAME );
fledgeHookFile = fledgeHookPath.toFile();
IPath fledgeHookDllPath = new Path( vm.getInstallLocation().getAbsolutePath() + IPath.SEPARATOR
+ IConstants.BIN_FOLD_NAME + IPath.SEPARATOR + IConstants.FLEDGE_HOOK_DLL_FILE_NAME );
fledgeHookDllFile = fledgeHookDllPath.toFile();
}
File storedSigTool = VMToolsUtils.getSignatureToolPath().toFile();
File storedJavaLoader = VMToolsUtils.getJavaLoaderPath().toFile();
File storedVersionFile = VMToolsUtils.getVersionFilePath().toFile();
File storedFledgeHookFile = null;
File storedFledgeHookDllFile = null;
if( OSUtils.isWindows() ) {
storedFledgeHookFile = VMToolsUtils.getFledgeHookPath( IConstants.FLEDGE_HOOK_FILE_NAME ).toFile();
storedFledgeHookDllFile = VMToolsUtils.getFledgeHookPath( IConstants.FLEDGE_HOOK_DLL_FILE_NAME ).toFile();
}
// Compare the VM version against the stored version, if it is greater, copy the tools to the stored folder.
// If the version file does not exist, just copy the tools and create the version file.
boolean checkFlag = false;
if( OSUtils.isWindows() ) {
checkFlag = !storedFledgeHookFile.exists() || !storedFledgeHookDllFile.exists();
}
if( ( !storedVersionFile.exists() ) || ( VMUtils.getVMVersion( vm ).compareTo( getStoredVersion() ) > 0 )
|| !storedSigTool.exists() || !storedJavaLoader.exists() || checkFlag ) {
FileUtils.copyOverwrite( sigToolFile, storedSigTool );
FileUtils.copyOverwrite( javaLoaderFile, storedJavaLoader );
if( !storedJavaLoader.canExecute() ) {
storedJavaLoader.setExecutable( true );
}
setStoredVersion( VMUtils.getVMVersion( vm ) );
if( OSUtils.isWindows() ) {
if( fledgeHookFile.exists() && fledgeHookDllFile.exists() ) {
// copy from new cp/bin to vmTools
FileUtils.copyOverwrite( fledgeHookFile, storedFledgeHookFile );
FileUtils.copyOverwrite( fledgeHookDllFile, storedFledgeHookDllFile );
} else {// force copy from bundle to vmTools
copyFledgeHookFile();
}
}
}
if( !OSUtils.isWindows() ) {
// For non windows environments
File jnilibFileInCP = new Path( vm.getInstallLocation().getAbsolutePath() + IPath.SEPARATOR
+ IConstants.BIN_FOLD_NAME + IPath.SEPARATOR + IConstants.CP_JNI_LIB_2_FILE_NAME ).toFile();
// Currently we do not copy the libRIMUsbJni.jnilib file into the VMTools directory
// but in this code blog we make sure if such file exists then it has the executable permission.
File storedJniLibFile = VMToolsUtils.getToolPath( IConstants.CP_JNI_LIB_2_FILE_NAME ).toFile();
if( storedJniLibFile.exists() && ( !storedJniLibFile.canExecute() ) ) {
storedJniLibFile.setExecutable( true );// In VMTools directory
} else if( jnilibFileInCP.exists() && ( !jnilibFileInCP.canExecute() ) ) {
jnilibFileInCP.setExecutable( true );// In CP
}
}
// Copy csk and db file from old vm tool folder (i.e signTool) if it exists to new location
File cskFile = VMToolsUtils.getToolPath( IConstants.CSK_FILE_NAME ).toFile();
File dbFile = VMToolsUtils.getToolPath( IConstants.DB_FILE_NAME ).toFile();
if( !cskFile.exists() || !dbFile.exists() ) {
// try to copy the files from old signTool folder if there is
File oldCskFile = new File( VMToolsUtils.getOldVMToolsFolderPath() + File.separator + IConstants.CSK_FILE_NAME );
File oldDbFile = new File( VMToolsUtils.getOldVMToolsFolderPath() + File.separator + IConstants.DB_FILE_NAME );
if( oldCskFile.exists() && oldDbFile.exists() ) {
FileUtils.copyOverwrite( oldCskFile, cskFile );
FileUtils.copyOverwrite( oldDbFile, dbFile );
_log.info( Messages.CodeSigningPrefsPage_MessageDialogMsg8 );
}
}
// show BlackBerry getting started page upon first-time Eclipse launch.
showStartupPage();
String eeVersion = VMUtils.getVMVersion( vm );
if( OSUtils.isWindows() && is6OrLater( eeVersion ) && ( !WindowsRegistryReader.isVC2008RuntimeInstalled() ) ) {
_log.debug( "Using 6.0+ but missing key FF66E9F6-83E7-3A3E-AF14-8DE9A809A6A4" );
warnMissingVC2008( eeVersion );
}
}
/**
* Updates the VM tools on the removal of a VM. If the VM version is the same as the stored version, it is removed, and all
* VMs are re-scanned. If not, nothing happens
*
* @param vm
* the vm that has been removed.
*
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static void removeVMTools( IVMInstall vm ) throws IOException {
if( ( null == vm ) || !BlackBerryVMInstallType.VM_ID.equals( vm.getVMInstallType().getId() ) ) {
return;
}
String vmVersion = VMUtils.getVMVersion( vm );
String storedVersion = getStoredVersion();
if( vmVersion.equals( storedVersion ) ) {
File storedSigTool = VMToolsUtils.getSignatureToolPath().toFile();
storedSigTool.delete();
File storedJavaLoader = VMToolsUtils.getJavaLoaderPath().toFile();
storedJavaLoader.delete();
File storedVersionFile = VMToolsUtils.getVersionFilePath().toFile();
boolean deleted = storedVersionFile.delete();
System.out.println( deleted );
for( IVMInstall otherVMs : VMUtils.getInstalledBBVMs() ) {
if( !otherVMs.equals( vm ) ) {
VMToolsUtils.addVMTools( otherVMs );
}
}
}
}
public static String getStoredVersion() {
String version = IConstants.DEFAULT_VM_VERSION;
FileInputStream fis = null;
try {
String fileName = getVersionFilePath().toOSString();
Properties properties = new Properties();
fis = new FileInputStream( fileName );
properties.load( fis );
version = properties.getProperty( IConstants.VM_VERSION );
} catch( IOException e ) {
_log.error( e );
} finally {
if( fis != null ) {
try {
fis.close();
} catch( IOException e ) {
}
}
}
return version;
}
private static void setStoredVersion( String version ) throws IOException {
Properties properties = new Properties();
properties.setProperty( IConstants.VM_VERSION, version );
String fileName = getVersionFilePath().toOSString();
FileOutputStream fos = null;
try {
fos = new FileOutputStream( fileName );
properties.store( fos, null );
} finally {
if( fos != null ) {
try {
fos.close();
} catch( IOException e ) {
}
}
}
}
/**
* Checks if all the vm tools are valid.
*
* @return
* @throws IOException
*/
static public final boolean isVMToolValid() throws IOException {
IPath javaLoaderPath = getJavaLoaderPath();
IPath signatureToolPath = getSignatureToolPath();
if( !javaLoaderPath.toFile().exists() || !signatureToolPath.toFile().exists() ) {
addVMTools( VMUtils.getLatestSDK() );
}
if( !javaLoaderPath.toFile().exists() || !signatureToolPath.toFile().exists() ) {
return false;
}
return true;
}
/**
* Checks if the signature tool is valid to be used.
*
* @return
* @throws IOException
*/
static public final boolean isSignatureToolValid() throws IOException {
IPath signatureToolPath = getSignatureToolPath();
// check if the signaturetool.jar is there
if( !signatureToolPath.toFile().exists() ) {
addVMTools( VMUtils.getLatestSDK() );
}
if( !signatureToolPath.toFile().exists() ) {
return false;
}
// check if there is any csk and db file
File cskFile = new File( VMToolsUtils.getVMToolsFolderPath() + File.separator + IConstants.CSK_FILE_NAME );
File dbFile = new File( VMToolsUtils.getVMToolsFolderPath() + File.separator + IConstants.DB_FILE_NAME );
if( ( !cskFile.exists() ) && ( !dbFile.exists() ) ) {
return false;
}
return true;
}
/**
* Copy FledgeHook.exe to the vm tools folder.
*
* @throws IOException
*/
static private void copyFledgeHookFile() throws IOException {
String[] names = { IConstants.FLEDGE_HOOK_FILE_NAME, IConstants.FLEDGE_HOOK_DLL_FILE_NAME };
IPath location = new Path( VMToolsUtils.getVMToolsFolderPath() + File.separator );
InputStream inputStream;
OutputStream outputStream;
File fledgeFile;
byte[] buf;
int numbytes;
URL bundUrl;
for( String fledgeFileName : names ) {
inputStream = null;
outputStream = null;
try {
fledgeFile = location.append( fledgeFileName ).toFile();
Bundle bundle = Platform.getBundle( ContextManager.PLUGIN_ID );
if( fledgeFile.exists() ) {
if( !fledgeFile.delete() ) {
_log.warn( "Could not replace file " + fledgeFile ); //$NON-NLS-1$
return;
}
}
bundUrl = bundle.getResource( fledgeFileName );
if( bundUrl == null )
continue;
inputStream = bundUrl.openStream();
outputStream = new FileOutputStream( fledgeFile );
buf = new byte[ 4096 ];
numbytes = 0;
while( ( numbytes = inputStream.read( buf ) ) > 0 )
outputStream.write( buf, 0, numbytes );
} catch( IOException t ) {
_log.error( t.getMessage(), t );
} finally {
try {
if( inputStream != null )
inputStream.close();
if( outputStream != null )
outputStream.close();
} catch( IOException t ) {
_log.error( t.getMessage(), t );
}
}
}
}
/**
* Gets old VM tools (i.e. signTool) folder path.
*
* @return the old VM tools folder path
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public static IPath getOldVMToolsFolderPath() throws IOException {
if( _oldVMToolFolder == null ) {
Bundle bundle = Platform.getBundle( ContextManager.PLUGIN_ID );
FileLocator.resolve( FileLocator.find( bundle, Path.ROOT, null ) );
URL bundleURL = FileLocator.resolve( FileLocator.find( bundle, Path.ROOT, null ) );
String bundlePath = bundleURL.getFile();
bundlePath = bundlePath.substring( bundlePath.indexOf( IPath.SEPARATOR ) + 1 );
_oldVMToolFolder = new Path( bundlePath ).removeLastSegments( 1 ).append(
VMToolsUtils.getBundleDataFolderName() + IPath.SEPARATOR + IConstants.OLD_VMTOOLS_LOCATION );
}
return _oldVMToolFolder;
}
/**
* Displays a warning dialog indicating that no VC2008 install when running CP 6.0.
*/
private static void warnMissingVC2008( String eeVersion ) {
final String message = NLS.bind( Messages.MissingVC2008WarningMsg, eeVersion );
IEclipsePreferences pref = ( new InstanceScope() ).getNode( ContextManager.PLUGIN_ID );
boolean pop = pref.getBoolean( PreferenceConstants.POP_FOR_MISSING_VC, true );
if( pop ) {
final Display display = getDisplay();
display.asyncExec( new Runnable() {
@Override
public void run() {
VCWarningDialog dialog = new VCWarningDialog( display.getActiveShell(), Messages.MissingVC2008WarningTitle,
message );
dialog.open();
}
} );
}
}
static private Display getDisplay() {
Display display = Display.getCurrent();
// may be null if outside the UI thread
if( display == null ) {
display = Display.getDefault();
}
return display;
}
/**
* compare eeVersion is 6.0+ CP
*/
public static boolean is6OrLater( String eeVersion ) {
try {
return ( Integer.valueOf( eeVersion.substring( 0, eeVersion.indexOf( "." ) ) ).intValue() >= 6 );
} catch( Exception e ) {
}
return false;
}
/**
* Displays BlackBerry startup page only when first time eclipse is started.
*/
private static void showStartupPage() {
IEclipsePreferences pref = ( new InstanceScope() ).getNode( ContextManager.PLUGIN_ID );
boolean showStartupPage = pref.getBoolean( PreferenceConstants.OPEN_STARTUP_PAGE_ON_ECLPSE_FIRST_START, true );
if( showStartupPage ) {
pref.putBoolean( PreferenceConstants.OPEN_STARTUP_PAGE_ON_ECLPSE_FIRST_START, false );
final Display display = getDisplay();
display.asyncExec( new Runnable() {
@Override
public void run() {
ProjectUtils.openStartupPage();
}
} );
}
}
}