Upload
casonova20
View
224
Download
0
Embed Size (px)
Citation preview
8/9/2019 Bluetooth Music Store
1/12
8/9/2019 Bluetooth Music Store
2/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
As you can see from Figure 1, the server application is ready and waiting for clients to connect, so let'sfind out how to build the OBEX client application.
Creating an OBEX client application
As you can see in Figure 2, FileClient.java looks a lot like FileServer.java , so I'll skip the
details ofFileClient.java for now.
Figure 2. FileClient.java at startup
8/9/2019 Bluetooth Music Store
3/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
Now, as I stated in Part 1 of this series, Bluetooth clients have a lot more work to do in comparison withBluetooth servers -- and if you think about it for a second, you'll understand why. First of all, how doesthe client know where to find the server? (Don't worry, this problem exists for every Bluetoothclient/server application; it's not unique to your situation). In order for any Bluetooth client to find aBluetooth server, the client must first discover it.
Bluetooth device discovery
DeviceDiscoverer.java is a helper application used by FileClient.java to find any remote
Bluetooth devices in the vicinity. Listing 1 provides the import statements, class declarations, and theconstructor ofDeviceDiscoverer.java.
Listing 1. Import statement and constructor for DeviceDiscoverer.java
import javax.bluetooth.*;import java.util.*;
public class DeviceDiscoverer implements DiscoveryListener {
FileClient client;Vector remoteDevices = new Vector();
DiscoveryAgent discoveryAgent;
public DeviceDiscoverer(FileClient client) {
this.client = client;try {
8/9/2019 Bluetooth Music Store
4/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
LocalDevice localDevice = LocalDevice.getLocalDevice();discoveryAgent = localDevice.getDiscoveryAgent();
client.updateStatus("[client:] LocalDevice properties: " +localDevice.getFriendlyName() +" (" + localDevice.getBluetoothAddress() + ")");
client.updateStatus("[client:]Searching for Bluetooth devices in the vicinity...");
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);} catch(Exception e) {
e.printStackTrace();}
}
As you can see in Listing 1, DeviceDiscoverer.java implements
javax.bluetooth.DiscoveryListener . This way, the helper class gets notified when a remote
Bluetooth device is discovered. To start the device discovery process, you need to first get an instance ofjavax.bluetooth.LocalDevice , which allows you to get an instance of
javax.bluetooth.DiscoveryAgent. After you have instantiated a DiscoveryAgent, you're
free to call discoveryAgent.startInquiry(), which starts the device discovery process.
You may also notice in Listing 1 that LocalDevice has some pertinent information about your own
Bluetooth device, such as its friendly name (like "Bruce's laptop" or "Joe's PDA"). LocalDevice also
knows your 6-byte Bluetooth address; for instance, 00:0A:3E:56:57:B5. For informational purposes,DeviceDiscoverer.java displays that information before it enters the discovery process.
If you refer back to Figure 2, you'll see that FileClient.java has three buttons, of which one of
them is aptly named Discover Devices. When you click on the Discover Devices button, you'll instantiatethe helper class, DeviceDiscoverer.java . If you're new to Bluetooth, you may assume that the
device discovery process is instantaneous. Unfortunately, it isn't.
However, the good news is that because the helper class, DeviceDiscoverer.java, is a
DiscoveryListener , it is notified asynchronously when Bluetooth devices are found. For each
remote Bluetooth device found in the vicinity, the Java Virtual Machine (JVM) calls thedeviceDiscovered() method. When the device discovery process has ended, the JVM also calls the
inquiryCompleted() method. Listing 2 and Listing 3 demonstrate the code for
deviceDiscovered() and inquiryCompleted().
Listing 2. DeviceDiscoverer.deviceDiscovered()
public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass cod) {
try{ remoteDevices.addElement(remoteDevice);client.updateStatus("[client:] New device discovered : " +remoteDevice.getFriendlyName(true)+ " (" +remoteDevice.getBluetoothAddress() + ")" );
} catch(Exception e){e.printStackTrace();
}
}
8/9/2019 Bluetooth Music Store
5/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
Listing 3. DeviceDiscoverer.inquiryCompleted()
public void inquiryCompleted(int discType) {String inqStatus = null;
if (discType == DiscoveryListener.INQUIRY_COMPLETED) {
inqStatus = "[client:] Inquiry completed";} else if (discType == DiscoveryListener.INQUIRY_TERMINATED) {
inqStatus = "[client:] Inquiry terminated";} else if (discType == DiscoveryListener.INQUIRY_ERROR) {
inqStatus = "[client:] Inquiry error";}
client.updateStatus(inqStatus);client.serviceButton.setEnabled(true);client.deviceButton.setEnabled(false);
}
As you can see in Listing 2, whenever a new Bluetooth device is discovered, I just add it to a Vector anddisplay the friendly name and Bluetooth address of the remote device. When the device discovery processhas ended, I update the client with status of the discovery process, whether it succeeded or failed. Figure3 shows FileClient.java after it has instantiated DeviceDiscoverer.java and has
discovered all the Bluetooth devices in the vicinity.
Look at FileClient.java after the discovery process.
Figure 3. FileClient.java after the discovery process
8/9/2019 Bluetooth Music Store
6/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
OK, it looks like there's a slight problem. According to Figure 3, there are four remote Bluetooth devicesin the area, but how do we know which one of them is running FileServer.java? Good question.
That's where service discovery comes in very handy. And don't worry, I have another helper class that I'llintroduce to you that will aid in the search for the specific service that I want.
Bluetooth service discovery
Listing 4 contains the import statements, class declaration, and constructor forServiceDiscoverer.java.
Listing 4. Import statement and constructor for ServiceDiscoverer.java
import javax.bluetooth.*;import java.io.*;import java.util.Vector;
public class ServiceDiscoverer extends Thread implements DiscoveryListener { UUID[] uuidSet = {new UUID("8841", true)};
int[] attrSet = {0x0100, 0x0003, 0x0004};
FileClient client;ServiceRecord serviceRecord;String connectionURL;Vector deviceList;
8/9/2019 Bluetooth Music Store
7/12
8/9/2019 Bluetooth Music Store
8/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
that I iterated over the Vector of remote Bluetooth devices and searched for the services that exist on eachdevice.
These examples were tested on real Bluetooth hardware, so you should see that as I iterated through theVector, I "backed off" for two seconds before I continued through the loop. The "backing off" perioddepends on your hardware; you may not need it at all. Without it though, your Bluetooth hardware mayonly search for services on the first remote Bluetooth devices that you pass in, and it may ignore theothers. For each service that matches the UUID, the JVM calls the servicesDiscovered() method,
which is shown in Listing 6.
Listing 6. ServiceDiscoverer.servicesDiscovered()
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
for(int i = 0; i < servRecord.length; i++) {
DataElement serviceNameElement = servRecord[i].getAttributeValue(0x0100);String serviceName = (String)serviceNameElement.getValue();
if(serviceName.equals("FTP")){client.updateStatus("[client:] A matching service has been found");
try {
connectionURL = servRecord[i].getConnectionURL(1,false);} catch (Exception e){
client.updateStatus("[client:] oops");}
client.updateStatus("[client:] The connection URL is: " + connectionURL );client.serviceButton.setEnabled(false);client.connButton.setEnabled(true);
}}
}
You may recall from Part 1 that the UUID is mandatory and the service name is optional for all Bluetoothservers; however, we specified that the service name for our service would be "FTP." As you can see inListing 6, I'm checking to see if the service name is FTP, but just remember that every Bluetooth servicemay not specify a service name. After I've determined that a matching service has been found, I store theconnection URL in a String and display some information on the client. A screenshot ofFileClient.java after the service searching process is shown in Figure 4.
Figure 4. FileClient.java after the service searching process
8/9/2019 Bluetooth Music Store
9/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
of 12 11/7/05
Aha! So according to Figure 4, I've found a matching service and it exists on the ibook. You may noticethat although I found a matching service on the ibook, I continued to iterate through the Vector andsearch for services. As you can see, the two helper classes came in very handy in order to get theconnection URL to the server. Now that I have the URL to the server, let's connect and send a file to theserver!
Connecting to the server and sending a file
To keep the code FileClient.java as clean as possible, I isolated all the OBEX client code into a
file named ObjectPusher.java. Of course, ObjectPusher.java is multithreaded so that it
won't hang the GUI application during the file-transfer process. Listing 7 shows the code forObjectPusher.run().
Listing 7. ObjectPusher.run()
public void run(){
try{connection = Connector.open(connectionURL);client.updateStatus("Connection obtained");
ClientSession cs = (ClientSession)connection;HeaderSet hs = cs.createHeaderSet();
cs.connect(hs);
client.updateStatus("OBEX session created");
InputStream is = new FileInputStream(file);byte filebytes[] = new byte[is.available()];is.read(filebytes);is.close();
hs = cs.createHeaderSet();hs.setHeader(HeaderSet.NAME, file.getName());hs.setHeader(HeaderSet.TYPE, "text/plain");hs.setHeader(HeaderSet.LENGTH, new Long(filebytes.length));
8/9/2019 Bluetooth Music Store
10/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
0 of 12 11/7/05
Operation putOperation = cs.put(hs);client.updateStatus("Pushing file: " + file.getName());client.updateStatus("Total file size: " + filebytes.length + " bytes");
OutputStream outputStream = putOperation.openOutputStream();outputStream.write(filebytes);client.updateStatus("File push complete");
outputStream.close();
putOperation.close();
cs.disconnect(null);
connection.close();} catch (Exception e){}
}
Obviously, the main purpose ofObjectPusher.java is to push a file from a client to the server. I
start off by taking the connection URL and creating a connection object. With the connection in place,I'm able to create the OBEX session.
The next step is to convert the file that I want to send into a byte array. Afterwards, the OBEX headers areset and the OBEX PUT operation is initiated by the call to cs.put(). This returns a
javax.obex.Operation object, which I named putOperation. An OutputStreamwas then
created in order to send the file data, and the PUT operation was completed when the byte array waswritten to the OutputStream. Figure 5 shows FileClient.java after the file transfer process.
Figure 5. FileClient.java after the file transfer process
8/9/2019 Bluetooth Music Store
11/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
1 of 12 11/7/05
In conclusion: Creating the Bluetooth Music Store
In Part 1, you learned how to create an OBEX server application. In this article, you learned how tocreate a very versatile OBEX client application. You've seen that OBEX clients are more difficult tocreate, but this article presented a few helper classes to aid you in the device discovery and servicediscovery processes. Figure 6 shows a simple application that I call the Bluetooth Music Store.
Figure 6. The Bluetooth Music Store
It's a modified version ofFileClient.java that uses the helper classes
DeviceDiscoverer.java, ServiceDiscoverer.java, and ObjectPusher.java. With
the Bluetooth Music Store, you can select a song or ringtone in MP3 format and push it to any phone,PDA, or computer that supports OBEX. Cool, huh?
So why do I call it a "Music Store?" Well, of course, if you own the rights to any music file, ringtone, orpodcast, then you can easily use this application as a foundation to make a kiosk application and sell youraudio files. Enjoy!
Resources
Learn
Part 1 of this series "Bluetooth boogies, Part 1: File transfer with JSR-82 and OBEX"(developerWorks, September 2005) shows how JSR-82 and OBEX can be used to transfer filesfrom client to server.
IBM is a member of the Bluetooth SIG (Special Interest Group). The Bluetooth specifications canbe obtained at the Bluetooth SIG Web site.
"SIM Access Profile" (developerWorks, April 2003) is an excellent article on the Bluetooth SIMAccess profile that covers the basics of the profile and also included some example scenarios.
In "Securing the air: The PDA of tomorrow" (developerWorks, May 2002) Kim Getgen from RSAwrote an article about advanced security using Bluetooth.
"Syncing data" (developerWorks, October 2001) provides an overview of the open industryspecification for data synchronization that delivers a uniform synchronization protocol for
8/9/2019 Bluetooth Music Store
12/12
Bluetooth boogies, Part 2: Creating the Bluetooth Music Store http://www-128.ibm.com/developerworks/wireless/library/wi-boo
2 of 12 11/7/05
connecting multiple devices over any network to any data store.
"SyncML intensive" (developerWorks, April 2002) walks you through the steps of a two-wayclient/server SyncML procedure.
"The PalmOS data collection series" (developerWorks, November 2001) explores the keyingredients in developing data-collection applications for wireless devices.
"SyncML device management" (developerWorks, April 2003) shows you how to managedata-exchange on wireless devices without having to commit to a proprietary protocol.
Get more ideas and expertise on wireless technology in the developerWorks Wireless technologyzone.
Get products and technologies
Download the FileClient, FileServer, and Bluetooth Music Store Application, all three used in thisarticle, in a ZIP file.
The Open OBEX Project is crafting an open source implementation of the Object Exchange
protocol, a session protocol that can best be described as a binary HTTP protocol.
The examples in this article were created using the JB-22 Java Bluetooth Development kit. TheJB-22 is a complete Java Bluetooth development kit featuring both Bluetooth hardware andsoftware, starting at $199.
Discuss
Get involved in the developerWorks community by participating in developerWorks blogs.
About the author
Bruce Hopkins is the author of the book, Bluetooth for Java (Apress) and is the creator of theJB-22 developer kit. He graduated from Wayne State University in Detroit with a B.S. degreein Electrical and Computer Engineering. He currently works as a Technical Architect forGestalt LLC and focuses on distributed computing, Web services, and wireless technologies. Hecan be contacted at [email protected].