This article is the second installment in a two-part series on Java and
Bluetooth. Last month you got your feet wet in Bluetooth (JDJ, Vol. 7, issue
8); if you don't remember what the role of a Bluetooth stack or a Bluetooth
profile is in the context of a Bluetooth application, refer to Part 1.
Let's recap. The basic concepts of any Bluetooth application (Java or
otherwise) consist of the following components:
- Stack initialization
- Device management
- Device discovery
- Service discovery
- Service registration
- Communication
We covered stack initialization last month, so let's proceed!
Device Management
LocalDevice and RemoteDevice are the two main classes in the Java
Bluetooth Specification that let you perform device management. These
classes allow you to request some statistical information about your
Bluetooth device (LocalDevice) as well as some information about the devices
in the area (RemoteDevice). The static method LocalDevice.getLocalDevice()
returns an instantiated LocalDevice object for you to use. To get the unique
address of your Bluetooth radio, call getBluetoothAddress() on your local device object. The Bluetooth address serves the
same purpose as the MAC address on the network card of your computer; every
Bluetooth device has a unique address. If you want other Bluetooth devices
in the area to find you, call the setDiscoverable() method in LocalDevice
object.
That's about all it takes to perform device management with the Java
Bluetooth Specification APIs. Now, let's look at the concept that allows you
to discover other Bluetooth devices: device discovery.
Device Discovery
Your Bluetooth device doesn't know what other Bluetooth devices are in
the area. Perhaps there are laptops, desktops, printers, mobile phones, or
PDAs nearby. Who knows? The possibilities are endless. To find out, your
Bluetooth device uses Device Discovery classes that are provided in the Java
Bluetooth API to see what else is out there.
The two classes required for your Bluetooth device to discover remote
Bluetooth devices in the area are DiscoveryAgent and DiscoveryListener.
After getting a LocalDevice object, instantiate a DiscoveryAgent by
calling LocalDevice.getDiscoveryAgent().
LocalDevice localdevice = LocalDevice.getLocalDevice();
DiscoveryAgent discoveryagent = localdevice.getDiscoveryAgent();
The are multiple ways to discover remote Bluetooth devices, but I'll
discuss one particular method. First, your object must implement the
DiscoveryListener interface. This interface works like any listener, so it'll notify
you when an event occurs. In this case, you'll be notified when Bluetooth
devices are in the area. To start the discovery process, call the
startInquiry() method on your DiscoveryAgent. This method is nonblocking, so
you're free to do other things while you wait for other Bluetooth devices to
be found.
When a Bluetooth device is found, the JVM calls the deviceDiscovered()
method of the class that implemented the DiscoveryListener interface. This
method passes you a RemoteDevice object that represents the device
discovered by the inquiry.
Service Discovery
Now that you know how to find other Bluetooth devices, it would be nice
to see what services they offer. Of course, if the RemoteDevice is a
printer, you know it can offer a printing service. But what if the
RemoteDevice is a computer? Would it readily come to mind that you can also
print to a printer server?
That's where service discovery comes in. You can never be sure what
services a RemoteDevice may offer, so service discovery helps you find out.
Service discovery is just like device discovery you use the
DiscoveryAgent to do the "discovering." The searchServices() method of the
DiscoveryAgent class allows you to search for services on a RemoteDevice.
When services are found, the servicesDiscovered()
method will be called by the JVM if your object implemented the
DiscoveryListener interface. This callback method also passes in a ServiceRecord
object that pertains to the service you searched for. With a ServiceRecord
in hand, you can do plenty of things, but you would most likely want to
connect to the RemoteDevice where this ServiceRecord originated:
String connectionURL = servRecord[i].getConnectionURL(0,false);
Service Registration
Before a Bluetooth client device can use service discovery on a
Bluetooth server device, the Bluetooth server needs to register its services
internally in the service discovery database (SDDB). This process is called
service registration.
Note: In a peer-to-peer application, such as a file transfer or chat
application, any device can act as the client or the server, so you'll need
to incorporate that functionality (both client and server) into your code in
order to handle both scenarios of service discovery (the client) and service
registration (the server).
Here's an example of what's involved in getting your service registered
and stored in the SDDB (Listing 1 provides the code:
1. Call Connector.open() and cast the resulting connection to a
StreamConnectionNotifier. Connector.open() creates a new ServiceRecord and sets
some attributes.
2. Use the LocalDevice object and the StreamConnectionNotifier to obtain
the ServiceRecord that was created by the system.
3. Add or modify the attributes in the ServiceRecord (optional).
4. Use the StreamConnectionNotifier and call acceptAndOpen() and wait for
Bluetooth clients to discover this service and connect. The system creates a
service record in the SDDB.
5. Wait until a client connects.
6. When the server is ready to exit, call close() on the
StreamConnectionNotifier. The system removes the service record from the SDDB.
StreamConnectionNotifier and Connector come from the javax.microedition.io package of the J2ME platform.
That's all that you need to do service registration in Bluetooth. The
next step is communication.
Communication
Okay, Bluetooth is a communication protocol, so how do you communicate
with it? Well, the Java Bluetooth API gives you three ways to send and
receive data, but for now we'll cover only one of them, RFCOMM. RFCOMM is a
the protocol layer that the Serial Port Profile (SPP) uses to communicate,
but these two items are almost always used synonymously.
Server Connections with the Serial Port Profile
Listing 2 demonstrates how to open a connection on a Bluetooth device
that will act as a server. For the most part, this is the same code used in
service registration; service registration and server communication are both
accomplished using the same lines of code.
Here are a few items that I want to point out: the string URL begins
with btspp://localhost, which is required if you're going to use the
Bluetooth Serial Port Profile. Next comes the UUID part of the URL, which is
0011223344556677889900AABBCCDDEEFF. This is simply a custom UUID that I made up for this
service; I could have chosen any string that was either 32-bits or 128-bits
long. Finally, we have ;name=serialconn in the URL string. I could have left
this part off, but I want my custom service to have a name, so the actual
service record in the SDDB has the following entry:
ServiceName = serialconn
The implementation also assigned a channel identifier to this service.
The client must provide the channel number along with other parameters in
order to connect to a server.
Client Connections with the Serial Port Profile
Establishing a connection with the SPP for a J2ME client is simple
because the paradigm hasn't changed for J2ME I/O. Simply call Connector.open().
StreamConnection con =
(StreamConnection)Connector.open(url);
Obtain the URL string that you need to connect to the device from the
ServiceRecord object you get from service discovery. The following is a more
complete demonstration of how an SPP client makes a connection to an SPP
server.
String connectionURL =
serviceRecord.getConnectionURL(0,false);
StreamConnection con =
(StreamConnection)Connector.open(connectionURL);
What does an SPP client connection URL look like? If the address of the
server is 0001234567AB, the string for the SPP client would look something
like this:
btspp://0001234567AB:3
The "3" at the end of the URL string is the channel number that the
server assigned to this service when it was added to the SDDB.
Java Bluetooth Development Kits
Who makes this stuff and how can you get your hands on it? Here are your
options:
The JSR-82 Reference Implementation was created by Motorola, so they're responsible for distributing it (www.motorola.com/java). Unfortunately, this Reference Implementation is only the JSR-82 APIs (see Figure 1, section B) so you won't be able to do much with
it even if you have some Bluetooth hardware. To get the JSR-82 Reference
Implementation to work on your development system, you need to license the
Motorola CLDC as well.
Figure 1
If you already have Bluetooth devices for your development computers,
try out the JSR-82compliant Java Bluetooth solution from Atinav
(www.atinav.com). They support numerous RS-232, UART, USB, CF, and PCMCIA Bluetooth devices. Their solution is based on an all-Java stack and their SDK includes the following profiles: GAP, SDAP, SPP, and GOEP. This solution also includes a KVM, so you only need to obtain the Bluetooth hardware to
create and test your apps.
Rococo (www.rococosoft.com) is most famous for their Java Bluetooth simulator, although they also make a Java Bluetooth developer kit for the Palm OS. Using the Impronto Simulator, Java developers only need a single computer to compile and test their Java Bluetooth applications. The
simulator supports GAP, SDAP, SPP, and GOEP profiles, and is currently
priced at $1,000.
Esmertec (www.esmertec.com) is well known for their Jbed Micro Edition CLDC implementation and the Jbed RTOS package. The Jbed platform is based upon their FastBCC technology, which dynamically loads and executes Java bytecode at native speeds (much like the goals of the Project Monty KVMs).
One key advantage of Esmertec is that the Jbed CLDC implementation can run
on a variety of different hardware platforms with or without an operating
system! Esmertec implemented their Bluetooth stack completely in Java, and
they support GAP, SDAP, SPP, LAP, and PAN on a wide array of Bluetooth
hardware modules. They also included support for Palm OS and Pocket PC
devices.
Smart Network Devices (www.smartnd.com) has a unique approach in their
Java Bluetooth development kit; they include all the components shown in
Figure 1, section B, for a complete Java Bluetoothenabled device: a
Bluetooth device (radio), a Bluetooth stack, Bluetooth profiles, a KVM, and
the JSR-82 Java Bluetooth APIs. Their product is called Micro BlueTarget
Starter Kit Java version (see Figure 2), based on the Micro BlueTarget
reference board. It supports the GAP, SDAP, SPP, and GOEP profiles. The
Micro BlueTarget is a not a peripheral (like the 3Com Bluetooth module in
Figure 3). It's a self-contained Java Bluetooth host device, so it doesn't
need to be connected to a host computer to operate. It has its own operating
system and KVM built in, and you can download your code to the device using
its Ethernet or RS232 interface. You can buy the complete Java Bluetooth
development kit for $2,880 and the Micro BlueTarget boards in single
quantities for $425.
Figure 2
Figure 3
The Advantages of Java and Bluetooth
Let's look at a scenario where life is made simpler using Java and
Bluetooth technology: the Java Shared Whiteboard. Three employees of Acme
Widgets Inc. need to have an impromptu meeting. Unfortunately, no conference rooms are available, so the team is forced to hold their meeting in the cafeteria. They
would have preferred using a conference room because each room is equipped
with an electronic whiteboard. However, since every member of the team has a
Java Bluetoothenabled PDA, their meeting in the cafeteria is very
productive.
One member has a new program for his PDA called the Java Shared
Whiteboard. Using Bluetooth technology, he sends that program to the rest of
the team. Using Over-the-Air Provisioning (OTA) provided by J2ME, each
member installs and runs the application on the fly. The meeting can now
begin because the whiteboard is shared among the PDAs. Each participant can
draw figures on his or her device and the image will appear instantly on the
other screens. To save time, one member can take notes and send them to
everyone's device while the meeting is in progress.
What are the benefits of Java and Bluetooth? Of course, Java gives you
platform independence for the Shared Whiteboard application. Therefore, you
don't need to worry about what kind of PDA your fellow team members have
(Palm, Pocket PC, Sharp, Sony, Handspring, etc.) as long as a compatible KVM
and libraries are available. Bluetooth has an additional benefit it
enables you to create instant wireless networks with these devices in order
to collaborate and share data. This network is portable, so you can move it
to the cafeteria, a conference room, or outside it doesn't matter.
Summary
It's a great time to be a wireless developer. Bluetooth enables you to
share and collaborate in ways never imagined. Now, I can enable my clunky
old desktops, laptops, and PDAs to participate in a wireless network by
simply adding a KVM and a Bluetooth radio. The fun is just beginning.
. . .
Book Overview
We've only scratched the surface with Bluetooth. In our upcoming book,
Java Bluetooth, Ranjith Antony (my coauthor) and I show how to use Java and
Bluetooth with multiple vendor SDKs and Bluetooth devices. We'll also cover
many practical scenarios for using Java and Bluetooth in the real world for
file transfer, security, and encryption using a simulator, wireless
printing, and much more. The advanced chapters will even show you how to use
Bluetooth in a Jini network.
Author Bio
Bruce Hopkins is a senior Java
consultant at Great Lakes Technologies Group in Southfield, MI. He has
worked with Java for over six years, and has researched in
wireless networking for four. Bruce is the coauthor of an upcoming book
entitled Java Bluetooth by Apress (November 2002).
javaspaces@comcast.net
Listing 1
...
// lets name our variables
StreamConnectionNotifier notifier = null;
StreamConnection sconn = null;
LocalDevice localdevice = null;
ServiceRecord servicerecord = null;
// step #1
// the String url will already be defined with the
// correct url parameters
notifier = (StreamConnectionNotifier)Connector.open(url);
// step #2
// we will get the LocalDevice if not already done so
localdevice = LocalDevice.getLocalDevice();
servicerecord = localdevice.getRecord(notifier);
// step #3 is optional
// step #4
// this step will block the current thread until a client responds
// this step will also cause the service record to be
// stored in the SDDB
notifier.acceptAndOpen();
// step #5
// just wait...
// assume the client has connected and you are ready to exit
// step #6
// this causes the service record to be removed
// from the SDDB
notifier.close();
Listing 2
...
// let's name our variables
StreamConnectionNotifier notifier = null;
StreamConnection con = null;
LocalDevice localdevice = null;
ServiceRecord servicerecord = null;
InputStream input;
OutputStream output;
// let's create a URL that contains a UUID that
// has a very low chance of conflicting with anything
String url =
"btspp://localhost:0011223344556677889900AABBCCDDEEFF;name=serialconn";
// let's open the connection with the url and cast it into a
StreamConnectionNotifier
notifier = (StreamConnectionNotifier)Connector.open(url);
// block the current thread until a client responds
con = notifier.acceptAndOpen();
// the client has responded, so open some streams
input = con.openInputStream();
output = con.openOutputStream();
// now that the streams are open, send and receive some data