org.symbian.tools.mtw.ui/src/org/symbian/tools/mtw/ui/deployment/bluetooth/BluetoothTarget.java
changeset 461 7a8f9fa8d278
parent 460 c0bff5ed874c
child 462 cdc4995b1677
equal deleted inserted replaced
460:c0bff5ed874c 461:7a8f9fa8d278
     1 /**
       
     2  * Copyright (c) 2010 Symbian Foundation and/or its subsidiary(-ies).
       
     3  * All rights reserved.
       
     4  * This component and the accompanying materials are made available
       
     5  * under the terms of the License "Eclipse Public License v1.0"
       
     6  * which accompanies this distribution, and is available
       
     7  * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8  *
       
     9  * Initial Contributors:
       
    10  * Symbian Foundation - initial contribution.
       
    11  * Contributors:
       
    12  * Description:
       
    13  * Overview:
       
    14  * Details:
       
    15  * Platforms/Drives/Compatibility:
       
    16  * Assumptions/Requirement/Pre-requisites:
       
    17  * Failures and causes:
       
    18  */
       
    19 package org.symbian.tools.mtw.ui.deployment.bluetooth;
       
    20 
       
    21 import java.io.EOFException;
       
    22 import java.io.File;
       
    23 import java.io.FileInputStream;
       
    24 import java.io.IOException;
       
    25 import java.io.InputStream;
       
    26 import java.io.OutputStream;
       
    27 import java.text.MessageFormat;
       
    28 import java.util.Collection;
       
    29 import java.util.LinkedList;
       
    30 
       
    31 import javax.bluetooth.BluetoothConnectionException;
       
    32 import javax.bluetooth.BluetoothStateException;
       
    33 import javax.bluetooth.DeviceClass;
       
    34 import javax.bluetooth.DiscoveryListener;
       
    35 import javax.bluetooth.LocalDevice;
       
    36 import javax.bluetooth.RemoteDevice;
       
    37 import javax.bluetooth.ServiceRecord;
       
    38 import javax.bluetooth.UUID;
       
    39 import javax.microedition.io.Connector;
       
    40 import javax.obex.ClientSession;
       
    41 import javax.obex.HeaderSet;
       
    42 import javax.obex.Operation;
       
    43 import javax.obex.ResponseCodes;
       
    44 
       
    45 import org.eclipse.core.runtime.CoreException;
       
    46 import org.eclipse.core.runtime.IProgressMonitor;
       
    47 import org.eclipse.core.runtime.IStatus;
       
    48 import org.eclipse.core.runtime.MultiStatus;
       
    49 import org.eclipse.core.runtime.PlatformObject;
       
    50 import org.eclipse.core.runtime.Status;
       
    51 import org.eclipse.core.runtime.SubProgressMonitor;
       
    52 import org.eclipse.ui.IMemento;
       
    53 import org.symbian.tools.mtw.core.MTWCore;
       
    54 import org.symbian.tools.mtw.core.projects.IMTWProject;
       
    55 import org.symbian.tools.mtw.core.runtimes.IPackager;
       
    56 import org.symbian.tools.mtw.ui.deployment.IDeploymentTarget;
       
    57 
       
    58 public class BluetoothTarget extends PlatformObject implements IDeploymentTarget {
       
    59     private static final UUID OBEX_OBJECT_PUSH = new UUID(0x1105);
       
    60     private String serviceURL;
       
    61     private RemoteDevice device;
       
    62     protected String[] exceptionCodes = new String[] { "OBEX_HTTP_UNSUPPORTED_TYPE", "OBEX_HTTP_FORBIDDEN" };
       
    63     private String message = "Deployment was successful. Please follow on-screen instructions to complete application deployment on your device.";
       
    64     private final String name;
       
    65     private final BluetoothTargetType provider;
       
    66     private final Collection<IStatus> statuses = new LinkedList<IStatus>();
       
    67 
       
    68     public BluetoothTarget(String name, RemoteDevice device, BluetoothTargetType provider) {
       
    69         this.name = name;
       
    70         this.device = device;
       
    71         this.provider = provider;
       
    72     }
       
    73 
       
    74     public IStatus deploy(IMTWProject project, IPackager packager, IProgressMonitor monitor) throws CoreException {
       
    75         message = "Deployment was successful. Please follow on-screen instructions to complete application deployment on your device.";
       
    76         statuses.clear();
       
    77         monitor.beginTask(String.format("Deploying application %s to %s", project.getName(), name),
       
    78                 IProgressMonitor.UNKNOWN);
       
    79         final File application = packager.packageApplication(project, new SubProgressMonitor(monitor, 100));
       
    80         try {
       
    81             deployWidget(application, packager.getFileType(project), new SubProgressMonitor(monitor, 10));
       
    82         } finally {
       
    83             application.delete();
       
    84         }
       
    85         monitor.done();
       
    86         MultiStatus multiStatus = new MultiStatus(MTWCore.PLUGIN_ID, 0, message, null);
       
    87         for (IStatus status : statuses) {
       
    88             multiStatus.add(status);
       
    89         }
       
    90         return multiStatus;
       
    91     }
       
    92 
       
    93     private void deployWidget(File inputWidget, String fileType, IProgressMonitor progressMonitor) throws CoreException {
       
    94         if (device == null) {
       
    95             provider.discoverTargets(new SubProgressMonitor(progressMonitor, 10));
       
    96             if (device == null) {
       
    97                 throw new CoreException(new Status(IStatus.ERROR, MTWCore.PLUGIN_ID, String.format(
       
    98                         "Device %s is not available", name)));
       
    99             }
       
   100         }
       
   101         progressMonitor.beginTask("Deploying application", IProgressMonitor.UNKNOWN);
       
   102         InputStream in = null;
       
   103         OutputStream os = null;
       
   104         Operation putOperation = null;
       
   105         ClientSession clientSession = null;
       
   106         try {
       
   107             if (!provider.isBloothToothConnected()) {
       
   108                 String msg = "Bluetooth is either disabled or not present in the system.";
       
   109                 emitStatus(IStatus.ERROR, msg, progressMonitor);
       
   110                 return;
       
   111             }
       
   112 
       
   113             String message = MessageFormat.format("Searching for the service for the selected device \"{0}\"",
       
   114                     new Object[] { getName() });
       
   115             emitStatus(IStatus.OK, message, progressMonitor);
       
   116             String servicesFound = getServicesFound();
       
   117             if (servicesFound == null || servicesFound.length() < 1) {
       
   118                 message = MessageFormat.format("Cannot find service to the device \"{0}\"", new Object[] { getName() });
       
   119                 emitStatus(IStatus.ERROR, message, progressMonitor);
       
   120                 return;
       
   121             }
       
   122 
       
   123             message = MessageFormat.format("Service for the device \"{0}\" found", new Object[] { getName() });
       
   124             emitStatus(IStatus.OK, message, progressMonitor);
       
   125 
       
   126             clientSession = (ClientSession) Connector.open(servicesFound);
       
   127             HeaderSet hsConnectReply = clientSession.connect(null);
       
   128             if (hsConnectReply.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
       
   129                 emitStatus(IStatus.OK, "Failed to connect to the service", progressMonitor);
       
   130             }
       
   131 
       
   132             emitStatus(IStatus.OK, "Deployment Started", progressMonitor);
       
   133 
       
   134             HeaderSet hsOperation = clientSession.createHeaderSet();
       
   135 
       
   136             if (progressMonitor.isCanceled()) {
       
   137                 emitStatus(IStatus.CANCEL, "Deployment was canceled", progressMonitor);
       
   138                 return;
       
   139             }
       
   140 
       
   141             // Send widget to server
       
   142             in = new FileInputStream(inputWidget);
       
   143             message = MessageFormat.format("Deploying file from {0}", new Object[] { inputWidget.getAbsolutePath() });
       
   144             emitStatus(IStatus.OK, message, progressMonitor);
       
   145 
       
   146             hsOperation.setHeader(HeaderSet.NAME, inputWidget.getName());
       
   147             hsOperation.setHeader(HeaderSet.TYPE, fileType);
       
   148             int size = (int) inputWidget.length();
       
   149             byte file[] = new byte[size];
       
   150             hsOperation.setHeader(HeaderSet.LENGTH, new Long(file.length));
       
   151 
       
   152             // Create PUT Operation
       
   153             putOperation = clientSession.put(hsOperation);
       
   154 
       
   155             os = putOperation.openOutputStream();
       
   156 
       
   157             long start = System.currentTimeMillis();
       
   158 
       
   159             byte[] buf = new byte[16 * 1024];
       
   160             int len;
       
   161             while ((len = in.read(buf)) > 0) {
       
   162                 os.write(buf, 0, len);
       
   163                 if (progressMonitor.isCanceled()) {
       
   164                     putOperation.abort();
       
   165                     emitStatus(IStatus.CANCEL, "Deployment was canceled", progressMonitor);
       
   166                     return;
       
   167                 }
       
   168             }
       
   169 
       
   170             os.flush();
       
   171             os.close();
       
   172 
       
   173             long elapsed = System.currentTimeMillis() - start;
       
   174             emitStatus(IStatus.OK, "elapsed time: " + elapsed / 1000.0 + " seconds", progressMonitor);
       
   175 
       
   176             int responseCode = putOperation.getResponseCode();
       
   177             if (responseCode == ResponseCodes.OBEX_HTTP_OK) {
       
   178                 message = MessageFormat.format("File deployed to {0}", new Object[] { getName() });
       
   179                 emitStatus(IStatus.OK, message, progressMonitor);
       
   180             } else {
       
   181                 message = "Error during deployment, OBEX error: " + responseCode;
       
   182                 emitStatus(IStatus.ERROR, message, progressMonitor);
       
   183             }
       
   184 
       
   185         } catch (BluetoothConnectionException x) {
       
   186             String message = getExceptionMessage(x.getMessage());
       
   187             emitStatus(IStatus.ERROR, message, progressMonitor);
       
   188         } catch (IOException e) {
       
   189             String message = getExceptionMessage(e.getMessage());
       
   190             emitStatus(IStatus.ERROR, message, progressMonitor);
       
   191         } finally {
       
   192             try {
       
   193                 if (in != null) {
       
   194                     in.close();
       
   195                 }
       
   196                 if (putOperation != null) {
       
   197                     putOperation.close();
       
   198                 }
       
   199                 if (clientSession != null) {
       
   200                     clientSession.disconnect(null);
       
   201                     clientSession.close();
       
   202                 }
       
   203             } catch (EOFException eof) {
       
   204                 // EOFException is now caught 
       
   205                 // Ignore the error since deployment has already completed
       
   206                 //Activator.log(IStatus.ERROR, "EOF encountered while cleaning up Bluetooth deployment", eof);
       
   207             } catch (IOException x) {
       
   208                 MTWCore.log("Error cleaning up BlueTooth deployment", x);
       
   209             }
       
   210         }
       
   211         return;
       
   212     }
       
   213 
       
   214     protected void emitStatus(int severity, String statusDescription, IProgressMonitor monitor) {
       
   215         statuses.add(new Status(severity, MTWCore.PLUGIN_ID, statusDescription));
       
   216         monitor.setTaskName(statusDescription);
       
   217         if (severity != IStatus.OK) {
       
   218             message = statusDescription;
       
   219         }
       
   220     }
       
   221 
       
   222     /**
       
   223      * Returns the customized methods from the exception error code. If it
       
   224      * matches it returns the customized message else returns the exception itself
       
   225      * @param message exception message
       
   226      * @return the customized message
       
   227      */
       
   228     protected String getExceptionMessage(String message) {
       
   229 
       
   230         if (message.contains(exceptionCodes[0])) {
       
   231             return "Device does not support the widget deployment";
       
   232         } else if (message.contains(exceptionCodes[1])) {
       
   233             return "Deployment rejected by the device";
       
   234         }
       
   235         return message;
       
   236     }
       
   237 
       
   238     public String getId() {
       
   239         return getName();
       
   240     }
       
   241 
       
   242     public String getName() {
       
   243         return name;
       
   244     }
       
   245 
       
   246     private String getServicesFound() {
       
   247         try {
       
   248             serviceURL = "";
       
   249             UUID serviceUUID = OBEX_OBJECT_PUSH;
       
   250 
       
   251             final Object serviceSearchCompletedEvent = new Object();
       
   252 
       
   253             DiscoveryListener listener = new DiscoveryListener() {
       
   254 
       
   255                 public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
       
   256                 }
       
   257 
       
   258                 public void inquiryCompleted(int discType) {
       
   259                 }
       
   260 
       
   261                 public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
       
   262                     try {
       
   263                         for (int i = 0; i < servRecord.length; i++) {
       
   264                             if (servRecord[i].getHostDevice().getFriendlyName(false).equals(name)) {
       
   265                                 serviceURL = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT,
       
   266                                         false);
       
   267                             }
       
   268                         }
       
   269                     } catch (BluetoothStateException e) {
       
   270                         MTWCore.log(e.getMessage(), e);
       
   271                     } catch (IOException e) {
       
   272                         MTWCore.log(e.getMessage(), e);
       
   273                     }
       
   274                 }
       
   275 
       
   276                 public void serviceSearchCompleted(int transID, int respCode) {
       
   277                     synchronized (serviceSearchCompletedEvent) {
       
   278                         serviceSearchCompletedEvent.notifyAll();
       
   279                     }
       
   280                 }
       
   281 
       
   282             };
       
   283 
       
   284             UUID[] searchUuidSet = new UUID[] { serviceUUID };
       
   285             int[] attrIDs = new int[] { 0x0100 }; // Service name
       
   286 
       
   287             synchronized (serviceSearchCompletedEvent) {
       
   288                 LocalDevice.getLocalDevice().getDiscoveryAgent()
       
   289                         .searchServices(attrIDs, searchUuidSet, device, listener);
       
   290                 serviceSearchCompletedEvent.wait();
       
   291             }
       
   292 
       
   293         } catch (IOException e) {
       
   294             MTWCore.log("Error in Bluetooth service discovery", e);
       
   295         } catch (InterruptedException e) {
       
   296             MTWCore.log("Error in Bluetooth service discovery", e);
       
   297         }
       
   298         return serviceURL;
       
   299     }
       
   300 
       
   301     public void init(IMTWProject project, IPackager packager, IMemento memento) {
       
   302         // nothing
       
   303     }
       
   304 
       
   305     public void save(IMemento memento) {
       
   306         // nothing
       
   307     }
       
   308 
       
   309     public void setAddress(RemoteDevice device) {
       
   310         this.device = device;
       
   311     }
       
   312 
       
   313     public boolean isDiscovered() {
       
   314         return device != null;
       
   315     }
       
   316 
       
   317     public String getDescription() {
       
   318         return device == null ? "This device was remembered from past sessions and may not be available" : String
       
   319                 .format("Remote device with address %s", device.getBluetoothAddress());
       
   320     }
       
   321 }