Lab 4: HTTP Access from a
SPOT
Background Reading:
SunSPOT Developer's Guide, pages 41-42: These two pages of the Developer's Guide demonstrate how to open and use HTTP connections on SPOTs. This lab is based on the code provided here, so it is useful to read this beforehand.
Introduction to fetching files with HTTP in Java: http://www.davidreilly.com/java/java_network_programming/. Read all of section 2: “HTTP Questions”. This will introduce you to using HTTP connections with Java's URL and URLConnection objects. It will also provide you with some good-to-know details about working with HTTP in Java and things you might encounter.
Prelab Questions:
Introduction:
You've seen how to perform radio communication between SPOTs. Now we see an example of an application opening and using HTTP connections. The program that we create will grab an HTML file from a web server with the HTTP protocol. We will then have the SPOT parse the page and flash its LED's whenever certain tags are encountered. Obviously SPOTs do not have direct connections to the Internet. To use HTTP, a basestation must be running from a PC with access to the Internet, and the Socket Proxy program must be started.
HttpConnection connection
= (HttpConnection)Connector.open("http://www.sunspotworld.com/");
connection.setRequestProperty("Connection",
"close");
InputStream in = connection.openInputStream();
StringBuffer buf = new StringBuffer();
int ch;
while ((ch = in.read()) > 0) {
buf.append((char)ch);
}
System.out.println(buf.toString());
in.close();
connection.close();
3.
Prepare the
startApp() method. Now open up the source file for your new project that
Netbeans has provided you, called “StartApplication.java.” It would make sense to rename this file to
coincide with the name of your project, but is not necessary. If you wish to rename it, right-click on the
source file and select refactoring->rename.
This will bring up a dialog where you can change the name of the file
(and the class inside). After you enter
the desired name, click “next.” The
output window at the bottom of the screen will now display a refactoring
tree. Click the “Do Refactoring” button,
and the file and class will be renamed.
Inside the source file, you will notice that Netbeans has taken care of
most of the necessary imports for you, and has given you three methods. The only method that has any code in it so
far is startApp(); you have probably already guessed that this is the starting
point of all Sun SPOT applications, similar to main() in normal Java
programs. For the HtmlRetriever, you
can either put the code that establishes the connection, grabs the page, and
parses it (provided later) directly into startApp() or create another method
that is called from startApp(). The
latter approach is usually preferred, since it is considered cleaner to keep
your startApp() method as short as possible, and provide important code pieces
with their own methods. Regardless of
what you choose to do, we need to clean up the contents of startApp() that we
have been given. You can get rid of everything that Netbeans put in startApp(). You will notice that one line Netbeans put in for you was
this:
private ITriColor leds[] = EdemoBoard.getInstance().getLEDs();
We want to keep this line,
however, we want leds to be a class field and not a local variable (unless you
want to paste all your code directly into startApp() and modify flashLights()
to take an additional argument, in which case you would leave the line as it
was); add this line inside the class, but
outside of any method:
private
ITriColorLED leds[] = EdemoBoard.getInstance().getLEDs();
One last thing you will need to
do as preparation is to add the following
import:
import
com.sun.spot.sensorboard.peripheral.LEDColor;
4.
Add the
flashLights() method. After our
application reads in a web page it will parse the HTML file and flash its LEDs
when we tell it to (when certain tags are encountered). We need to provide a method to do this, so
here it is:
protected void flashLights(int num, LEDColor
color) {
for(int i=0; i < 8; i++) {
leds[i].setColor(color);
}
for(int i=0; i < num; i++) {
for(int j=0; j < 8; j++) {
leds[j].setOn();
}
Utils.sleep(500);
for(int k=0; k <8; k++) {
leds[k].setOff();
}
Utils.sleep(500);
}
}
It should
be pretty clear what is happening here.
First we set the color of the LEDs (all eight of them), based on the
“color” parameter. Then we turn each LED
on, wait a little bit, and then turn them off.
One tells flashLights() how many times to flash the LED's with the “num”
argument.
5.
Add the rest of the
code.
Now all we have to do is add the code that opens an HTTP connection,
uses an InputStream to grab the page and place it in a StringBuffer, and
finally goes through the buffer and flashes the lights green every time an
opening or closing script tag (“</script>” or “<script”) is
encountered and blue whenever an image occurs (“<img “). Much of the code is identical to the
Developer's Guide example. Here we use a
second StringBuffer object to hold the current word as we go through the page
(stored in “buf”) and check for our target tags whenever whitespace characters
(a newline or a space) occur. This code
first has the lights flash orange right before it starts parsing the web page,
then flashes three times when it finds either of our two target strings, and
flashes the lights red once after finding a tag to separate different
occurrences of the same tag. Place this code either directly in startApp() or in another
method that you have startApp() call. If you leave it as is, this code will only
parse the page once; if you want it to happen more than once, you can placing
the parsing code (the “for” loop) inside a new loop and do it as many times as
you wish.
HttpConnection connection =
(HttpConnection)Connector.open("http://www.sunspotworld.com/");
connection.setRequestProperty("Connection",
"close");
InputStream in =
connection.openInputStream();
StringBuffer buf = new StringBuffer();
StringBuffer word = new StringBuffer();
flashLights(2, LEDColor.ORANGE);
int ch;
while ((ch = in.read()) > 0) {
buf.append((char)ch);
}
for(int i=0; i < buf.length(); i++)
{
char c = buf.charAt(i);
if(c == ' ' || c == '\n') {
int flashes = 3;
if
(word.toString().equals("</script>") ||
word.toString().equals("<script")) {
flashLights(flashes,
LEDColor.GREEN);
flashLights(1,
LEDColor.RED);
} else if
(word.toString().equals("<img")) {
flashLights(flashes,
LEDColor.BLUE);
flashLights(1,
LEDColor.RED);
}
word.delete(0,word.length());
} else {
word.append((char) c);
}
}
in.close();
connection.close();
6.
Start the Socket
Proxy application. Now its time to plug in the basestation
and start the Socket Proxy program. Once
your basestation is connected to the PC, start
a shared basestation with the SPOT Manager. Then, open up a command line, navigate to any project folder (C:\Program
Files\Sun\SunSPOT\Demos\BounceDemo\BounceDemo-OnSPOT will do, or even
better, use the folder of your current project), and run the command “ant socket-proxy.” A command line can be opened from the desktop shortcut we
have placed for you. Once Socket Proxy
is running, you should be ready to deploy and test your application.
7.
Deploy and test the
application. Its time to check out what we've done. Deploy
your new application to a SPOT and see
what happens. You should see your SPOT
flash its lights blue and green a number of times in sets of four flashes. As of this writing, there are three places
where </script> tags occur on www.sunspotworld.com, and many more occurrences of “<img .” Open up a web browser and go to
view->source (or something similar, depending on your browser); you should
be able to determine which tag is making the SPOT flash its lights each time.
Challenges:
1.
Add functionality to recognize more tags (or other frequently
occurring strings), and assign a new color to each. Do this enough, and you will get quite a
colorful display. Try having your SPOT access different sites and see how the
results change. You could also have your SPOT parse several pages one after
another on one run (make the URL string an argument to your method and call it
several times with different values in startApp()).
2.
Have your program use the Radiogram protocol to send out messages
to another SPOT when special strings encountered, sending it the arguments to
flashLights(). You can make both SPOTs
flash their LEDs on each tag, only have the remote SPOT (the one that is not
parsing the page) do the flashing, or alternate
which SPOT is to flash. You will
need to create a new application for the second SPOT that includes the
flashLights() method and allows the SPOT to receive Radiograms that contain the
arguments to flashLights(). Come up with
some ideas for utilizing even more SPOTs, or to make sure your SPOTs only act
on communication from each other, and not SPOTs programmed by other groups (as
in last lab's challenge).
Conclusion:
The
goal of this lab was to demonstrate how SPOTs can interact with web sites over
HTTP connections. You should be getting
more comfortable writing SPOT applications and starting to become familiar with
the code behind common SPOT tasks, like working with the LEDs and opening and
using connections for various protocols.