/* * 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.util.Arrays; import java.util.Map; import java.util.Set; import java.util.Timer; import java.util.TimerTask; import net.rim.ejde.internal.core.ContextManager; import net.rim.ejde.internal.model.BlackBerryProject; import net.rim.ejde.internal.model.preferences.SignatureToolPreferences; import net.rim.ejde.internal.packaging.PackagingJob; import net.rim.ejde.internal.packaging.PackagingJobWrapper; import net.rim.ejde.internal.ui.launchers.LaunchUtils; import net.rim.ejde.internal.util.Messages; import net.rim.ejde.internal.util.ProjectUtils; import net.rim.ejde.internal.util.StatusFactory; import net.rim.ide.RIA; import net.rim.ide.core.Util; import org.apache.log4j.Logger; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.jdt.launching.IVMConnector; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.osgi.util.NLS; /** * config delegate for BB device launch * * @author bchabot * */ public class DeviceLaunchConfigurationDelegate extends AbstractDebugLaunchConfigurationDelegate implements IDeviceLaunchConstants { Logger _logger = Logger.getLogger( DeviceLaunchConfigurationDelegate.class ); Timer _refreshTimer; /* * A Timer class to constantly scan the device USB connection. If the device to which the debugger was attached is * disconnected the class disconnects the debugging session The way we check if the USB device has been disconnected is we get * a list of devices which are connected to the computer via USB and if the device to which the debugger is attached is not * one of the devices in the list we disconnect the debugging session. */ class RefreshTask extends TimerTask { @Override public void run() { // get RIA RIA debugServer = RIA.getCurrentDebugger(); // if RIA is null return if( debugServer == null ) { return; } // get a list of degub devices which are attached to the computer String[] deviceList = debugServer.getDebugDeviceList(); // get the machine to which the debugger is attached to (it can be a // USB device or a Simulator) String debugAttachedTo = debugServer.getDebugAttachTo(); // boolean flag to keep track if the device to which the debugger is // attached is still in the list of connected devices boolean containsTarget = false; // if debugger is attached to nothing or the debugger is not // attached to a USB or if the debugger is not attached // return. When we disconnect to a device and disconnect it the // "debugAttachedTo" would still not be null but the // "isDebuggerAttached" would show the correct status. Thats why I // put in the 3rd condition also in the if condition. if( debugAttachedTo == null || !( debugAttachedTo.contains( "USB" ) ) //$NON-NLS-1$ || !debugServer.isDebuggerAttached() ) { return; } // System.out.println(debugServer.isDebuggerAttached()); // System.out.println(debugAttachedTo); /* * go through the device list to see if the device to which the debugger is attached is still in the list of devices. */ for( int i = 0; i < deviceList.length; i++ ) { if( debugAttachedTo.equals( deviceList[ i ] ) ) { containsTarget = true; // if the device to which the // debugger is attached is in the // list of devices mark the // containsTarget // flag as true. } } if( !containsTarget ) { _logger.debug( "Device unplugged" ); // if the deviceList is of length 0 or if it does not contain // the target get the launches and from the launches // get the debugTarget and disconnect the debug Target. try { ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); if( launches.length != 0 ) { _logger.debug( "Terminating launch: " + launches[ 0 ].getLaunchConfiguration().getName() ); _refreshTimer.cancel(); LaunchUtils.closeLaunch( launches[ 0 ] ); _logger.debug( "Launch terminated." ); } } catch( DebugException e ) { _logger.error( e ); } } } } /** * Deploy projects in the launch configuration into simulator folder. It packages the projects if necessary. * * @param configuration * The launch configuration * @throws CoreException * @throws OperationCanceledException */ protected void packageProjects( ILaunchConfiguration configuration ) throws CoreException, OperationCanceledException { String jobName = "Packaging " + configuration.getName(); //$NON-NLS-1$ _logger.debug( jobName ); Set< IProject > iProjects = LaunchUtils.getProjectsFromConfiguration( configuration ); Set< BlackBerryProject > bbProjects = ProjectUtils.getBlackBerryProjects( iProjects ); // for device debugging, we always want to sign the cod files boolean needSign = SignatureToolPreferences.getRunSignatureToolAutomatically(); PackagingJobWrapper packagingJob = new PackagingJobWrapper( jobName, bbProjects, needSign ? PackagingJob.SIGN_IF_PROTECTED_API_USED : PackagingJob.SIGN_NO ); packagingJob.setUser( true ); packagingJob.schedule(); try { packagingJob.join(); } catch( InterruptedException e ) { _logger.error( e ); } } /** * Default constructor. */ public DeviceLaunchConfigurationDelegate() { // do nothing } @Override protected String getDebugDestination( ILaunchConfiguration configuration ) throws CoreException { // fixed DPI221813, we should set the default return value as // ANY_DEVICE, so that a user can // start the debugger by clicking the run->debug as-> BB device without // creating a device debug // launch configuration first. return configuration.getAttribute( IDeviceLaunchConstants.DEVICE, IDeviceLaunchConstants.ANY_DEVICE ); } /** * Override parent method to check for "connect to any device" mode * * @param device * @param debugServer * @return */ @Override protected void setDebugAttach( final RIA debugServer, String debugDest ) throws CoreException { _logger.debug( "Set debugger attach:" + debugDest ); if( debugDest.equals( IDeviceLaunchConstants.ANY_DEVICE ) ) { for( ;; ) { String[] attachedDevices = debugServer.getDebugDeviceList(); if( attachedDevices.length > 0 ) { debugDest = attachedDevices[ 0 ]; break; } Util.sleep( 5000 ); } } super.setDebugAttach( debugServer, debugDest ); } @Override protected void doConnect( IVMConnector connector, Map< String, String > argMap, IProgressMonitor monitor, ILaunch launch ) throws CoreException { for( ;; ) { try { _logger.debug( "Connecting to VM connector..." ); connector.connect( argMap, monitor, launch ); _logger.debug( "Connected" ); break; } catch( CoreException e ) { _logger.debug( "Connection failed, retry" ); // debug target is not available, wait a while Util.sleep( 5000 ); } } } @Override protected void debug( ILaunchConfiguration configuration, final ILaunch launch, IProgressMonitor monitor ) throws CoreException { super.debug( configuration, launch, monitor ); // create a new refresh timer and task _refreshTimer = new Timer( "Device refresh timer" ); //$NON-NLS-1$ _refreshTimer.scheduleAtFixedRate( new RefreshTask(), REFRESH_TIME, REFRESH_TIME ); } @Override public boolean preLaunchCheck( ILaunchConfiguration configuration, String mode, IProgressMonitor monitor ) throws CoreException { IVMInstall vm = LaunchUtils.getVMFromConfiguration( configuration ); RIA ria = ContextManager.PLUGIN.getRIA( vm.getInstallLocation().getAbsolutePath() ); if( ria == null ) { throw new CoreException( StatusFactory.createErrorStatus( NLS.bind( Messages.RIA_NO_RIA_INSTANCE_ERROR_MSG, vm.getName() ) ) ); } // Fix 788345 (checks if device is still connected before launching) String currentDevice = configuration.getAttribute( DEVICE, ANY_DEVICE ); if( !currentDevice.equals( IDeviceLaunchConstants.ANY_DEVICE ) && !Arrays.asList( ria.getDebugDeviceList() ).contains( currentDevice ) ) { currentDevice = currentDevice.substring( currentDevice.indexOf( '(' ) + 1, currentDevice.indexOf( ')' ) ).trim(); throw new CoreException( StatusFactory.createErrorStatus( NLS.bind( "USB Device not found. (PIN: " + currentDevice + ')', vm.getId() ) ) ); } ILaunch launch = LaunchUtils.getRunningBBLaunch(); if( launch != null ) { ILaunchConfigurationType launchType = launch.getLaunchConfiguration().getType(); if( !launchType.getIdentifier().equals( IDeviceLaunchConstants.LAUNCH_CONFIG_ID ) ) { throw new CoreException( StatusFactory.createErrorStatus( Messages.AbstractLaunchConfigurationDelegate_debuggerActiveMsg ) ); } } return super.preLaunchCheck( configuration, mode, monitor ); } }