Refactor UI interface to allow dynamically adding tabs

An example of how to attach a tab to SparkUI is in `org.apache.spark.ui.FooTab`. (Delete after use)

The hierarchy structure is as follows: a WebUI has many UITabs and/or UIPages. Each UITab in turn has many UIPages. Attaching a UITab to a WebUI means attaching all of the tab's attached pages to the WebUI, prefixing the paths appropriately. Attaching a UIPage to a WebUI, on the other hand, means creating the appropriate handlers and attaching them to the server.

**Example**: `SparkUI` is a WebUI, and it has many tabs, one of which is the `BlockManagerTab`. The BlockManagerTab's prefix is "storage", which means it can be reached through "/storage". The BlockManagerTab has two pages: the `IndexPage` and the `RddPage`, with prefixes "" and "rdd" respectively. This means the IndexPage can be reached through "/storage" and the RddPage through "/storage/rdd".