Java tutorial
/* * J2ME in a Nutshell By Kim Topley ISBN: 0-596-00253-X * */ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.StringItem; import javax.microedition.lcdui.TextField; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class RankingMIDlet extends MIDlet implements CommandListener, Runnable { private Command exitCommand; private Command okCommand; private Command cancelCommand; private Command newCommand; private Display display; private TextField isbnField; private StringItem isbnDisplay; private StringItem titleDisplay; private StringItem rankingDisplay; private StringItem reviewDisplay; private Form isbnForm; private Form searchForm; private Form resultForm; private BookInfo searchBookInfo; private Thread searchThread; protected void startApp() throws MIDletStateChangeException { if (display == null) { initialize(); display.setCurrent(isbnForm); } } protected void pauseApp() { } protected void destroyApp(boolean unconditional) throws MIDletStateChangeException { } public void commandAction(Command cmd, Displayable d) { if (cmd == exitCommand) { try { destroyApp(true); } catch (MIDletStateChangeException ex) { } notifyDestroyed(); } else if (cmd == okCommand) { String isbn = isbnField.getString().trim(); if (!isbn.equals("")) { searchForBook(new BookInfo(isbn)); } } else if (cmd == cancelCommand) { searchThread = null; isbnField.setString(null); display.setCurrent(isbnForm); } else if (cmd == newCommand) { isbnField.setString(null); display.setCurrent(isbnForm); } } public void searchForBook(BookInfo info) { searchBookInfo = info; isbnDisplay.setText(info.getIsbn().trim()); display.setCurrent(searchForm); searchThread = new Thread(this); searchThread.start(); } public void run() { try { boolean found = Fetcher.fetch(searchBookInfo); if (searchThread == Thread.currentThread()) { if (found && searchBookInfo.getTitle() != null) { titleDisplay.setText(searchBookInfo.getTitle()); rankingDisplay.setText( searchBookInfo.getRanking() == 0 ? "" : String.valueOf(searchBookInfo.getRanking())); reviewDisplay.setText( searchBookInfo.getReviews() == 0 ? "" : String.valueOf(searchBookInfo.getReviews())); display.setCurrent(resultForm); } else { Alert alert = new Alert("Book not found", null, null, AlertType.ERROR); alert.setTimeout(Alert.FOREVER); alert.setString("No book with ISBN " + searchBookInfo.getIsbn() + " was found."); isbnField.setString(null); display.setCurrent(alert, isbnForm); } } } catch (Throwable ex) { if (searchThread == Thread.currentThread()) { Alert alert = new Alert("Search Failed", null, null, AlertType.ERROR); alert.setTimeout(Alert.FOREVER); alert.setString("Search failed:\n" + ex.getMessage()); isbnField.setString(null); display.setCurrent(alert, isbnForm); } } } private void initialize() { display = Display.getDisplay(this); exitCommand = new Command("Exit", Command.EXIT, 0); okCommand = new Command("OK", Command.OK, 0); cancelCommand = new Command("Cancel", Command.CANCEL, 0); newCommand = new Command("New", Command.SCREEN, 1); isbnForm = new Form("Book Query"); isbnForm.append("Enter an ISBN and press OK:"); isbnField = new TextField("", null, 10, TextField.ANY); isbnForm.append(isbnField); isbnForm.addCommand(okCommand); isbnForm.addCommand(exitCommand); searchForm = new Form("Book Search"); searchForm.append("Searching for ISBN\n"); isbnDisplay = new StringItem(null, null); searchForm.append(isbnDisplay); searchForm.append("\nPlease wait...."); searchForm.addCommand(cancelCommand); resultForm = new Form("Search Results"); titleDisplay = new StringItem("Book title: ", null); rankingDisplay = new StringItem("Ranking: ", null); reviewDisplay = new StringItem("Reviews: ", null); resultForm.append(titleDisplay); resultForm.append(rankingDisplay); resultForm.append(reviewDisplay); resultForm.addCommand(newCommand); resultForm.addCommand(exitCommand); // Register for events from all of the forms isbnForm.setCommandListener(this); searchForm.setCommandListener(this); resultForm.setCommandListener(this); } } class Fetcher { private static final String BASE_URL = "http://www.amazon.com"; private static final String QUERY_URL = BASE_URL + "/exec/obidos/search-handle-form/0"; private static final int MAX_REDIRECTS = 5; // Fetches the title, ranking and review count // for a book with a given ISBN. public static boolean fetch(BookInfo info) throws IOException { InputStream is = null; OutputStream os = null; HttpConnection conn = null; int redirects = 0; try { String isbn = info.getIsbn(); String query = "index=books&field-keywords=" + isbn + "\r\n"; String requestMethod = HttpConnection.POST; String name = QUERY_URL; while (redirects < MAX_REDIRECTS) { conn = (HttpConnection) Connector.open(name, Connector.READ_WRITE); // Send the ISBN number to perform the query conn.setRequestMethod(requestMethod); conn.setRequestProperty("Connection", "Close"); if (requestMethod.equals(HttpConnection.POST)) { conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); os = conn.openOutputStream(); os.write(query.getBytes()); os.close(); os = null; } // Read the response from the server is = conn.openInputStream(); int code = conn.getResponseCode(); // If we get a redirect, try again at the new location if ((code >= HttpConnection.HTTP_MOVED_PERM && code <= HttpConnection.HTTP_SEE_OTHER) || code == HttpConnection.HTTP_TEMP_REDIRECT) { // Get the URL of the new location (always absolute) name = conn.getHeaderField("Location"); is.close(); conn.close(); is = null; conn = null; if (++redirects > MAX_REDIRECTS) { // Too many redirects - give up. break; } // Choose the appropriate request method requestMethod = HttpConnection.POST; if (code == HttpConnection.HTTP_MOVED_TEMP || code == HttpConnection.HTTP_SEE_OTHER) { requestMethod = HttpConnection.GET; } continue; } String type = conn.getType(); if (code == HttpConnection.HTTP_OK && type.equals("text/html")) { info.setFromInputStream(is); return true; } } } catch (Throwable t) { System.out.println(t); } finally { if (is != null) { try { is.close(); } catch (IOException ex) { } } if (os != null) { try { os.close(); } catch (IOException ex) { } } if (conn != null) { try { conn.close(); } catch (IOException ex) { } } } return false; } } /** * A class that represents a book listing at an online book set, including the * number of reviews for the book and its sales ranking. */ class BookInfo { int id; // Used when persisting String isbn; // The book ISBN String title; // The book title int reviews; // Number of reviews int ranking; // Current ranking int lastReviews; // Last review count int lastRanking; // Last ranking public BookInfo(String isbn) { this.isbn = isbn; } public String getIsbn() { return isbn; } public String getTitle() { return title; } public int getReviews() { return reviews; } public int getRanking() { return ranking; } public int getLastReviews() { return lastReviews; } public int getLastRanking() { return lastRanking; } // Installs details parsed from an input stream public void setFromInputStream(InputStream is) { // Use an InputHelper to search the input InputHelper helper = new InputHelper(is); try { // Default new values to current values int newRanking = this.ranking; int newReviews = this.reviews; boolean found = helper.moveAfterString("buying info: "); if (!found) { return; } // Gather the title from the rest of this line StringBuffer titleBuffer = helper.getRestOfLine(); // Look for the number of reviews found = helper.moveAfterString("Based on "); if (!found) { return; } // Gather the number of reviews from the current location String reviewString = helper.gatherNumber(); // Look for the sales rank found = helper.moveAfterString("Sales Rank: "); if (!found) { return; } // Gather the number from the current location String rankingString = helper.gatherNumber(); // Having safely found everything, set the new title title = titleBuffer.toString().trim(); // Now convert the reviews and ranking to integers. // If they fail to convert, just leave the existing // values. try { newRanking = Integer.parseInt(rankingString); } catch (NumberFormatException ex) { } if (newRanking != ranking) { lastRanking = ranking; ranking = newRanking; if (lastRanking == 0) { // First time, set last and current // to the same value lastRanking = ranking; } } try { newReviews = Integer.parseInt(reviewString); } catch (NumberFormatException ex) { } if (newReviews != reviews) { lastReviews = reviews; reviews = newReviews; if (lastReviews == 0) { // First time, set last and current // to the same value lastReviews = reviews; } } } catch (IOException ex) { } finally { // Allow garbage collection helper.dispose(); helper = null; } } } //A class that scans through an input //stream for strins without reading the //entire stream into a large string. class InputHelper { // Size of the input buffer private static final int BUFFER_SIZE = 1024; // The input buffer private final char[] buffer = new char[BUFFER_SIZE]; // Number of characters left in the buffer private int charsLeft; // Index of the next character in the buffer private int nextChar; // InputStreamReader used to map to Unicode private InputStreamReader reader; // Constructs a helper to read a given stream public InputHelper(InputStream is) { reader = new InputStreamReader(is); } // Cleans up when no longer needed public void dispose() { if (reader != null) { try { reader.close(); } catch (IOException ex) { } reader = null; } } // Looks for a given string in the input // stream and positions the stream so that the // next character read is one beyond the string. // Returns true if the string was found, false if // not (and the stream will have been completely read). public boolean moveAfterString(String str) throws IOException { char[] chars = str.toCharArray(); int count = chars.length; char firstChar = chars[0]; char c = (char) 0; for (;;) { if (c != firstChar && !findNext(firstChar)) { // Reached the end of the input stream return false; } boolean mismatch = false; for (int i = 1; i < count; i++) { c = getNext(); if (c != chars[i]) { mismatch = true; break; } } if (!mismatch) { return true; } // Mismatch. 'c' has the first mismatched // character - start the loop again with // that character. This is necessary because we // could have found "wweb" while looking for "web" } } // Gets the characters for a number, ignoring // the grouping separator. The number starts at the // current input position, but any leading non-numerics // are skipped. public String gatherNumber() throws IOException { StringBuffer sb = new StringBuffer(); boolean gotNumeric = false; for (;;) { char c = getNext(); // Skip until we find a digit. boolean isDigit = Character.isDigit(c); if (!gotNumeric && !isDigit) { continue; } gotNumeric = true; if (!isDigit) { if (c == '.' || c == ',') { continue; } break; } sb.append(c); } return sb.toString(); } // Gets the balance of the current line // and returns it as a StringBuffer public StringBuffer getRestOfLine() throws IOException { StringBuffer sb = new StringBuffer(); char c; for (;;) { c = getNext(); if (c == '\n' || c == (char) 0) { break; } sb.append(c); } return sb; } // Gets the next character from the stream, // returning (char)0 when all input has been read. private char getNext() throws IOException { if (charsLeft == 0) { charsLeft = reader.read(buffer, 0, BUFFER_SIZE); if (charsLeft < 0) { return (char) 0; } nextChar = 0; } charsLeft--; return buffer[nextChar++]; } // Finds the next instance of a given character in the // input stream. The input stream is positioned after // the located character. If EOF is reached without // finding the character, false is returned. private boolean findNext(char c) throws IOException { for (;;) { if (charsLeft == 0) { charsLeft = reader.read(buffer, 0, BUFFER_SIZE); if (charsLeft < 0) { return false; } nextChar = 0; } charsLeft--; if (c == buffer[nextChar++]) { return true; } } } }