MIT OpenCourseWare
  • OCW home
  • Course List
  • about OCW
  • Help
  • Feedback
  • Support MIT OCW

Exercises 6: Foliotracker, Part 2

Due: Week 7

Handout E6

We recommend that you read the entire problem set before you begin work.

Introduction

In Exercise 5, you decided on the basic functionality of your FolioTracker program, designed a graphical user interface (GUI) for it, and specified an application programmer's interface (API) through which the GUI will access the components of the code that obtain stock quotes, maintain a database of values, and so on. But beyond specifying the interface and functionality, you didn't deal too much with the design or implementation of the backend.
The focus of the exercise 6 is design of the backend and its implementation. You shouldn't need to learn anything new, but will have an opportunity to refine your skills in designing with abstract data types, object models, etc. You don't need to implement the code for obtaining the stock quotes; we provide a class for you that has a simple method that takes a ticker symbol as a string and returns a price.
We have provided a QuoteServer module for your convenience. If you are curious, you can look at the source code for QuoteServer, but you should be able to make use of it using the specification alone. You should not need to take any additional steps to use this module (it should automatically be in your classpath).

Exercise 6

Your task in this exercise is to complete your Foliotracker by implementing the API which you defined in Exercise 5. You will need to design the internal structure of your Foliotracker backend, and test the program as a whole. This program is difficult to test because it involves a GUI, and because the changing stock prices make it hard to do repeatable tests. So you will need to devise a reasonable testing strategy that gives you some confidence that the application works reliably, and that the stock prices and position and portfolio valuations can be trusted. You will probably want to take advantage of the programmatic interface you designed in Exercise 5, and test the GUI separately in a more ad hoc manner.

You should hand in the following artifacts:

(a) Code Object Model [One page] An object model that summarizes the internal state of the application. It should include both the primary GUI objects, and the objects used to implement the API.

(b) Module Dependency Diagram [One page] A module dependency diagram of the entire application. To explain any special techniques or abstractions you devised for decoupling or other purposes, add a short note.

(c) Code The code for the backend implementation of your API, and any test code you wrote. You should include specifications in the modules of your implementation where appropriate (that is, for public methods and for any private methods that are obscure).

(d) Testing [One page or less] A terse but convincing overview your testing strategy, what kind of testing you performed, and what test cases you used.

Errata

QuoteServer value format check
The QuoteServer code incorrectly attempted to check the format of the returned value. This caused problems, however, if commas were are part of the returned number format (for example NASDAQ => "2,494.00"). We have removed the verification code and ammended the specification of getLastValue() to allow for commas.

Q & A

This section will list clarifications and answers to common questions about the exercises. We'll try to keep it as up-to-date as possible, so this should be the first place to look (after carefully rereading the handout) when you have a problem.

Q: How can we get the company name if we have a ticker symbol?

A: Reuben Sterling came up with a nice solution for this. Thanks, Reuben!

Info: getNameFromTicker2() is the method that actually talks to the web site. getNameFromTicker() is the method that should be called, since it keeps a record of ticker symbols that have been looked up previously, so it potentially runs faster.

Add to QuoteServer.



protected static final String _NAME_LOOKUP_URL = "http://quote.fool.com/lookup.asp?company=";


protected static final String _TOKEN3 = "currticker=";


protected static final String _TOKEN4 = "&symbols=";


protected static final String _TOKEN5 = "mw_symbollookup_standard";





protected static HashMap names = new HashMap();





public static String getNameFromTicker(String tickerSymbol) throws WebsiteDataException, NoSuchTickerException {


   String name = (String)QuoteServer.names.get(tickerSymbol);


   if (name == null) {


      name = QuoteServer.getNameFromTicker2(tickerSymbol);


      QuoteServer.names.put(tickerSymbol, name);


   }


   return name;


}





private static String getNameFromTicker2(String tickerSymbol) throws WebsiteDataException, NoSuchTickerException {


   tickerSymbol = tickerSymbol.toUpperCase();


   String strURLStart = _NAME_LOOKUP_URL;


   URL urlWebPage = null;





   InputStreamReader isr = null;


   BufferedReader brWebPage = null;


   String nameLookupToken = _TOKEN3+tickerSymbol+_TOKEN4+tickerSymbol;


   String strStockName;





   // open the web page for reading


   try {


      urlWebPage = new URL(strURLStart + tickerSymbol);


      isr = new InputStreamReader(urlWebPage.openStream());


      brWebPage = new BufferedReader(isr);


   } catch(Exception e) {


      throw new WebsiteDataException();


   }





   // find the line with the stock quote on it


   String strLine = null;


   try {


      while(true) {


         strLine = brWebPage.readLine();


         if(strLine == null) {


            throw new WebsiteDataException("Parse failed!");


         }


         if(strLine.indexOf(nameLookupToken) != -1)


            break;


      }


   }


   catch(IOException e) {


      throw new WebsiteDataException();


   }


      


   // find the stock quote in the line


   StringTokenizer strtok = new StringTokenizer(strLine, _DELIMITER);





   while(true) {


      if(strtok.hasMoreTokens() == false) {


         throw new NoSuchTickerException();


      }


      if(strtok.nextToken().compareTo(_TOKEN5) == 0) {


         strStockName = strtok.nextToken();


         if (strStockName.substring(0, 5).compareTo("nbsp;") == 0)


            break;


      }


   }


        


   strStockName = strStockName.substring(5);


   return strStockName;


}