Here's a description of the fourth programming assignment for CSE 11. In this assignment, you will learn about the inheritance and Java's error handling scheme, exceptions.
>>> Due deadline: ...
>>> Required solution files: FullPerson.java FullAccount.java ElevenDollar.java NoUserDataException.java ErrorInBalanceException.java IMAccount.java
This means that the files that contain your solution to the assignment must be turned in by the due deadline. Use the bundleP4 script to turn in your assignment.
As usual, it's a good idea to plan to do the assignment well before the deadline; terminals and tutors can get very busy at the last minute. And of course In doing this assignment, it's your responsibility to understand the course rules for integrity of scholarship.
This assignment explores these OOP principles with P3 as its background. We will extend Person and Account so they do everything they used to and a bit more. Then we will extend our new Account, this time picking and choosing what we want to use, and applying those to a different applcation. Along the way we will attempt to get the most "bang for the buck". That is, we'll try to re-use code, to write as little new code as possible, and yet have it still fulfill our varying needs. Each of the classes you write in this assignment should be relatively small--less than fifty lines in most cases, with a good deal of those being whitespaces or comments. Consequently, you'll be writing a number of small class definitions.
We'll also be adding some error handling the way Java wants it to be done, with exceptions. Exceptions are objects that act as packages of error information. Exception classes are also extremely short--often no more than a single constructor. These will allow us to create our own customized errors for our application, and will fix some shortcomings that P3 had in checkBalance and updateInformation.
As a side note, the base classes Person and Account are immutable here--that is, we will assume they were published a year ago(time flies in the quarter system) and have now become code that we simply cannot modify. In this respect, old code is like an old furniture layout--notoriously difficult to modify after some time has passed.
~/../public/P4/
directory after the P3 deadline.
These files will be used by us when we test your P4
code. Or, you can use your P3 definitions of these
classes and
everything will work if they are correct. In fact, the big picture will
be clearer for
you if you've written them and understand the source code.
Instead we will create a new file,
FullPerson.javawhich will extend the original class. In this manner, the old Person still exists, and any program that used the old Person will still run. But we will still make use of it, and create a new class that does all a Person does and more. You will add four instance variables in FullPerson, with their associated accessors and mutators:
//accessors(If this seems like a lot of code, see the footnote below.) You will add two constructors, to match the original two in Person. One will take six separate Strings, and the other will take a netString, which is a format similar to the server output.
public String getQuote()
public String getTrades()
public String getEmail()
public String getScreen()
//mutators
public void setQuote(String newField)
public void setTrades(String newField)
public void setEmail(String newField)
public void setScreen(String newField)
public FullPerson(String nick, String pass,You will also override the toString() and netString() operators so they will output all six fields in a human readable format and a tab-delimited format(suitable for ElevenClient, as before).
String quote, String trades,
String email, String screen)
public FullPerson(String netString)
/**Prints out the data in a human readable format.*/Note that because the original Person class's fields are private, you will need to use the original toString() and netString() inside the methods you'll be writing.
/**If the following code is executed...
System.out.println(new FullPerson("John", "Doe",
"To be or not to be",
"Surfboard lessons",
"john_doe@imaginary.place.net",
"sdKing15123"));
Then the following will be printed...
Name:John
Password:Doe
Quote:To be or not to be
Trades:Surfboard lessons
Email:john_doe@imaginary.place.net
Screen:sdKing15123
*/
public String toString()
/**Prints out the data in a tab-delimited format.*/
public String netString()
Command Format | Description | Server Reply |
---|---|---|
GETINFO\t[name]\t[password] | Get another user's info, and uses their password. Only returns the user and password, so its use is limited. | USERINFO\t[nickname]\t[password] |
GETDETAILS | Get your detailed information(quote, trades, email and screen) from the server. | USERINFO\t[quote]\t[trades]\t[email]\t[screen] |
GETDETAILS\t[name] | Get another user's detailed info(quote, trades, email and screen) without using their password. Without the password, the server will hide the email and screen on response. | USERINFO\t[quote]\t[trades]\t*PRIVATE*\t*PRIVATE* |
GETDETAILS\t[name]\t[password] | Get another user's detailed info(quote, trades, email and screen), this time using their password. All fields will be returned. | USERINFO\t[quote]\t[trades]\t[email]\t[screen] |
UPDATEINFO\t[name]\t[password] \t[quote]\t[trades]\t[email]\t[screen] | Update your stored information. | UPDATE CONFIRMED |
FullAccount will extend Account and override the original getInformation methods in Account so they return a FullPerson. Note that by overriding the original methods the return type is unchanged.
This may seem a bit worrisome--how do you return a FullPerson if you're say you're going to return a Person? The answer is that Java allows this because FullPerson extends Person. A FullPerson "is a" Person. Anything you could ask of a Person, you can ask of a FullPerson. So the calling code won't break if you return a subclass of what it expects.
In addition you will add another method that overloads the original getInformation, so that it can take a user and a password. This one will be called to retrieve all information about another user, even the fields that are password-protected by the server.
public Person getInformation()Sends a GETINFO request and a GETDETAILS request to the server. Parses the replies and creates a new FullPerson object with all six of its fields initialized. Returns this new FullPerson object.
public Person getInformation(String username)Sends a GETINFO request and a GETDETAILS request to the server, each with one argument. Parses the replies and returns a FullPerson object. Note that the password replied by the server will be "*SECRET*". The email and screen replied by the server will both be "*PRIVATE*"
public Person getInformation(String username, String password)Sends a GETINFO request and a GETDETAILS request to the server, each with two arguments. Parses the replies and returns a FullPerson object. All fields will be returned by the server in this case.
public static void main(String [] args) {
System.out.println(getInformation());
System.out.println(getInformation("cs11w2"));
System.out.println(checkBalance()));
/*
.
. Continue to test until you're satisfied that your FullAccount and
. FullPerson work.
.
*/
}
Start by modifying the line in main that creates the Account. It should read something like this:
Account myAccount = new Account();Modify it so it now reads:
Account myAccount = new FullAccount();
Now we have just two methods to work on.
Most of this will be the same--Something important to note is the use of dynamic binding. That is, the original getInformation() and getInformation(name) will provide a different output, even though the call is exactly the same. This is because Java will decide on which method to call based on which object it's being called on. It doesn't matter that the original variable is of type Account, it matters that at runtime it's actually a FullAccount.
When actually making the call to the getInformation(name, password) method, however, you'll need to use a typecast. This is because although you as the programmer know that you have a FullAccount inside handleGetInformation, the compiler doesn't. It sees the type as Account, and can't find any two-argument getInformation there.
Often times you'll need to tell the compiler you know that what you have is a certain kind of class, or that in this case a Person is actually a FullPerson. The typecast forces it to assume you're right--consequently, if you're wrong and you actually had a Person, and you tried to call a method FullPersons know about and Persons don't, then you'll receive a ClassCastException as it runs.
Be sure to parenthesize appropriately when you typecast, as follows:
((FullAccount) myAccount).getInformation(arg1, arg2);
Here our typecast problem will crop up many times. For every prompt you'll use an accessor, and for every user input you'll use a mutator. This, to put it mildly, is painful, and it'd be only worse if we decided we needed to make some more changes.
So instead of doing that, we will modify the method prototype so it expects a FullAccount. We can do this because we're not overriding anything--the method prototype is ours to change. Modify it so it reads as follows:
public static void handleUpdateInformation(FullAccount myAccount)
Now you only need one typecast, inside the method call.
See the sample run for how ElevenDollar should behave differently after your changes.
Likewise in P3, if an Account was created and its person never initialized, it could fail in updateInformation. And if you tried to check your balance and it somehow returned ERROR, you couldn't return ERROR in a string because it said it would return a double.
Exceptions provide a mechanism for a method to tell the caller about things that the method can't handle. The caller can handle the exception in a clean fashion, instead of dying with an unsightly stack trace.
Exceptions follow an interesting baseball-ish sort of analogy. Exceptions are "thrown" from a method that doesn't know what to do. If it was called from within a "try" block, then execution moves to the "catch" block after the try. This would take a lengthy explanation, so if you are unfamiliar with exceptions, take a look at chapter 9 of the textbook for the details.
We will be writing two exceptions in FullAccount, both of which will extend RuntimeException. This way we won't need to declare them in a throws clause, and so we won't have to modify the method signatures. Remember that because we extended a class, to override methods we have to use the same signature. This allows us to add exception handling, and override the methods appropriately.
ElevenDollar.javaso it has a try/catch clause and prints out an appropriate error message if an exception is thrown. After handling the exeception, return to normal execution and prompt the user as usual.
The code we have now is something similar to an ATM--it has accounts, information, the ability to transfer money and remember the transaction history. However, suppose we wanted to build a messaging client with the existing software, similar to AIM or Yahoo Messenger. Note that our server has no way of asking a client to respond. Therefore, a client must always poll, i.e. ask, for messages, which is a bit different from AIM.
Part of the code is similar--we need an interface to a server, accounts with information, and the ability to get and update that information. This we will inherit.
Part of the code is different--we don't need anything relating to 11-dollars anymore, such as checking your balance, transferring money, and remembering a transaction history. These we will "hide" with the UnsupportedOperationException.
Finally we'll need to add a few methods, and create a different user interface. But at the end of it, we'll have re-used a lot of old code to apply to a completely different application.
To start with, the server will understand three final commands for this new application.
Command Format | Description | Server Reply |
---|---|---|
BUDDYLIST\t[name]\t[password] | Adds a user to your buddylist. The password must be correct for this to be successful. | BUDDYLIST UPDATED |
LEAVEMESSAGE\t[user]\t[message] | Leave a message for another user. The user must be on your buddylist for this to be successful. | MESSAGE SENT |
CHECKIMINFO | See when your buddies were last connected to the server, and if there are any messages left for you. The last 100 messages are stored on the server and all of them will be retrieved in this message. | Buddy activity:\n [last logins of buddies] Messages:\n [messages] |
Create a class named
IMAccount.javathat extends FullAccount. Add three methods to implement the previous three commands.
/**Add a user to the owner's buddy list.*/
public String addToBuddyList(String user, String pass)
/**Send a message to another user. This user must be on the buddy list,
otherwise error is returned. The server's reply is returned.*/
public String leaveMessage(String target, String message)
/**Get info about buddies, and retrieve all messages.*/
public String checkIMInfo()
Add three methods to override the unwanted abilities of
FullAccount. Each of these will simply throw
UnsupportedOperationException.
public double checkBalance()Finally, we will need to write a new front-end for our IMClient. This is the analogue of ElevenDollar with a similar interface and format, but written for a different application. This portion of code will be given to you in a file named IMClient.class--if the rest of your code works, this should allow you to run a text-based and time-delayed version of a messenging client.
public String transferToAcct(String user, double amount, String comment)
public String getHistory()
Updating the information looks easy when I'm using my program,
but
it's a lot of repeated code. Is there a better way than copy-pasting
from
P3's ElevenDollar a whole lot?
Often times user input interaction is a lot of work. There are some
things
you could do, for instance. If you wrote a static method that took in
input
and returned a boolean of whether it was blank...
The server seems to be remembering more than the last 100
messages. What's going on?
This is a bug discovered after the server was released in P3. Sorry
folks.
a. 5 points for your FullPerson.javaIn each case, doing a part of the assignment means that your code compiles, runs correctly, satisfies the specifications, is well-written and commented.
b. 5 points for your FullAccount.java
c. 4 points for your ElevenDollar.java
d. 1 points for your NoUserDataException.java
e. 1 points for your ErrorInBalanceException.java
f. 4 points for your IMAccount.java
Hence the advice to copy paste.