As discussed in class, Lab 7 is the first part of a two-part lab that will produce a "web collage" program. The program will crawl the web looking for images, and it will display them in an image collage, using the image collage panel that you wrote for Lab 6. The program will use threads, blocking queues, and some basic networking.
The program has three main components: The window that displays the image collage, a "web crawler" that crawls the web looking for URLs that link to images, and an "image grabber" that downloads the images from the web. Note that all the GUI stuff is in the collage window component. Both the web crawler and the image grabber will use multiple threads to do their work. A blocking queue will be used to feed URLs from the web crawler to the image grabber, and another blocking queue will feed downloaded images from the image grabber to the collage window.
For part 1 of the lab, you will write the image grabber and the collage display window. The display window should come almost directly from Lab 6: You should already have a subclass of JFrame that creates an image collage, with a Timer that takes images from a short list of images. The web collage window is the same, except it gets the images from the queue of images that are produced by the image grabber. The image grabber itself will be completely new.
To begin the lab, start a new Eclipse project. Copy-and-paste your work from Lab 6, including the images folder. (The images in this folder will not be part of the final program, but they will be used for testing the work that you do today.)
You should also copy the file /classes/s11/cs225/TestImageGrabber.java into your project. (My files are in a package named "webcollage". You might want to do the same; otherwise, you should remove the package declaration from my file.) TestImageGrabber is a main program that you can use to test the work that you do today. It assumes that your image grabber class is named ImageGrabber and that the name of the class that defines the collage window is WebCollageWindow. You should consider renaming your window class to WebCollageWindow. If you don't do that, you will have to change the name in TextImageGrabber.
This lab is due next Thursday. It will be collected and graded separately from the second part of the project.
Create a new class named ImageGrabber.
The purpose of an ImageGrabber is to take URLs from a queue, try to download images from those URLs, and put the downloaded images into another queue. Since the program is multithreaded, the queues will be BlockingQueues. The queues connect the image grabber to other parts of the program, and they should be created somewhere else and provided to the image grabber when the image grabber is created. That is, the ImageGrabber should have a constructor that takes two queues as parameters, one of type BlockingQueue<URL> and one of type BlockingQueue<BufferedImage>. The main job of the constructor is to create and start all the threads that will do the actual downloading
The ImageGrabber class should contain a nested class to define the threads. The class should be a subclass of Thread. The run() method for the thread should run in an infinite loop in which it gets URLs from one queue and puts BufferedImages into the other queue. Various errors can occur as you try to download an image from a given URL. You should catch these errors so that they do not crash the thread. You should, of course, only put an image into the image queue if you have actually downloaded an image successfully.
Remember that if bqueue is a blocking queue, then the method bqueue.take() can be used to remove an item from the queue. This method will block until an item is actually available. It can throw an InterruptedException that has to be handled (although it won't ever throw this exception in this program). Similarly, use bqueue.put() to add an item to a blocking queue; this method blocks until space in the queue is available.
Java makes it easy to download an image from a URL. Here's one way to do it, if url is a variable of type URL:
URLConnection connection = URL.openConnection(); InputStream input = connection.getInputStream(); BufferedImage image = ImageIO.read(input);
The method ImageIO.read() can throw an IOException. It can also return null, if it was possible to read data from the stream, but the data could not be interpreted as an image.
After getting the input stream from the connection, there are several methods that can be called to get information about the data before you actually read the data. In particular, you can say
int size = connection.getContentLength();
to find out the size of the data (in bytes). This method will return -1 if the size is not known (which can happen when data is read from the internet -- the size is only known in advance if the server sends that information).
Two other features that you should add to your class: The option to limit the size of images that will be downloaded. A second constructor with a way to specify the number of threads that will be created.
The WebCollageWindow should be a relatively small modification of your window class from Lab 6. The collage window will get BufferedImages from a blocking queue, and that queue should be specified as a parameter to the constructor.
Use a Timer with an ActionListener that removes images from the queue and adds them to the collage.
One important point is that you do not want the actionPerformed method to block: That method runs in the event-handling thread, and if it blocks, the whole GUI interface blocks. To avoid this, you should remove items from the queue using bqueue.poll(). This method never blocks. Instead, if there are not items in the queue, it returns null, and if the queue is non-empty, it dequeues an item and returns. it.