2016/7/17 CSC 216: Project 2, Part 2
Project 2, Part 2 WolfLibrary WolfPackLibrary
After speaking with the legal department, your development team was advised to change the name of the project to WolfPackLibrary to better reflect the connection to North Carolina State University. Part 1 of this assignment laid out the requirements for the WolfPackLibrary system that you must create. Part 2 details the design that you must implement. For this part, you must create a complete Java program consisting of multiple source code files and JUnit test cases. You must electronically submit your files by your section’s due date.
Set Up Your Work Environment
Before you think about any code, prepare your work environment to be compatible with the teaching staff grading criteria. The teaching staff relies on NCSU GitHub and Jenkins for grading your code. Follow these steps:
1. Create an Eclipse project named WolfPackLibrary. (The project naming is case sensitive) 2. Share WolfPackLibrary with your CSC 216 repository.
Design
Your project must follow the design guidelines laid out here. If you do not follow the provided design exactly, the automated teaching staff unit tests will fail when run against your program.
There are five major areas of the system, which correspond to five Java packages in your project: patron, catalog, loan_system, util, and ui. The classes and interfaces in the project are listed below under their respective packages.
edu.ncsu.csc216.pack_library.patron
AccountManager. Describes the patron management part of the application noted in UC2, UC3, UC5, and UC6. This interface is given to you. Do not modify this code!
AccountSystem. Implements AccountManager.
Patron. A library patron. Each patron has a checkedOutQueue and a reserveQueue of books currently checked out and books on reserve. PatronDB. A database of Patrons that provides the list operations required to support the singlepatron operations described in AccountManager. The upper limit of the number of patrons in the database is 20. PatronDB is implemented as a custom arraybased list of Patrons.
User. Abstract class for system users (patrons or admin). edu.ncsu.csc216.pack_library.catalog
Book. A library book.
BookDB. The database of books in the library catalog. edu.ncsu.csc216.pack_library.util
UniversalList<T>. A generic class that supports the underlying list operations for the library catalog, reserve queues, and checked out queues. UniversalList has a nested class named Node and is a custom implementation of a linked list.
Constants.java. String constants that can be used in the program as well as test code. (We opted not to show the members of this class below in order to simplify the UML diagram.) This class is given to you. Do not modify this code!
edu.ncsu.csc216.pack_library.loan_system
LoanManager. Describes the library system operations noted in UC7 UC12. This interface is given to you. Do not modify this code!
LoanSystem. Implements LoanManager. edu.ncsu.csc216.pack_library.ui
PackLibraryManagerGUI. The graphical user interface (GUI) for the project. Parts of this class is given to you, but you are required to complete the GUI. PackLibraryManagerGUI contains a data member of declared type LoanManager, which provides the connection to the backend. (We hid members of this class in the UML diagram to simplify the diagram display.)
The UML class diagram for the design is shown in the figure below. Your project must keep the same directory structure as discussed above and shown here. You can modify the names of the private fields. However, you MUST have the public methods and constants (names, return types, parameter types and order) exactly as shown below for the teaching staff tests to compile.
Important. A primary purpose of this assignment is for you to write operations on linked lists and to define and use generic classes. You are not allowed to use any of the Java API collection classes such as ArrayList or LinkedList. If you use a Java collections class in your project, you will be penalized 50 points!
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 1/6
2016/7/17 CSC 216: Project 2, Part 2
See Project 1 for a description of standard UML class diagram notation. As before, you may create as many different private methods for this project as you wish. Utility Classes
The util subpackage contains two classes, Constants.java and UniversalList.java. Constants.java, which we provide for you, defines static constant strings. Most of those are useful for exception messages.
UniversalList.java contains the definition of the generic class UniversalList<T>. T, which is the type of element that the list will contain, is determined when the class is instantiated (Book for this project). The following objects are instantiations of UniversalList<Book>:
1. BookDB.books 2. Patron.checkedOut 3. Patron.reserveQueue
Most UniversalList methods are strictly position based, where the position of the first element is 0, the second is 1, and so on. In the method descriptions below, the int parameter is the given position. If the method should throw an exception, it is noted in the description below.
UniversalList(). Constructs an empty list.
insertItem(int, T). Adds an element (second parameter) at the given position. Throws a NullPointerException if the item is null. Throws an IndexOutOfBoundsException if the position is negative or greater than the list size.
isEmpty(). Returns true if the list contains no elements.
lookAtItemN(int). Returns the element at the given position. Throws an IndexOutOfBoundsException if the position is negative or greater than
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 2/6
2016/7/17 CSC 216: Project 2, Part 2
or equal to size.
insertAtRear(T). Adds an element to the rear of the list. Throws a NullPointerException if the item is null.
remove(int). Removes and returns the element in the given position. Throws an IndexOutOfBoundsException if the position is negative or greater than or equal to size.
shiftForwardOne(int). Moves the element at the given position ahead one position in the list. Does nothing if the element is already at the front of the list. Throws an IndexOutOfBoundsException if the position is negative or greater than or equal to size.
size(). Returns the number of elements in the list.
UniversalList uses a nested class named Node for its implementation. UniversalList has two Node type data members: head, which points to the front of the list, and iterator, which can traverse through the list elements. You can think of an iterator as a cursor to the list, pointing to the “next” element to be visited. By storing the iterator as a field of UniversalList, this means that UniversalList has only one iterator. There are three iterator methods.
resetIterator(). Sets iterator to point to the first element in the list.
next(). Returns the element iterator is pointing to and moves iterator to point to the next element in the list. Throws a NoSuchElementException if iterator is null or not pointing to a list element.
hasNext(). True whenever iterator is pointing to a list element.
There are some important things to remember when using iterator methods:
1. Whenever the iterator is being used for the first time in a method, call resetIterator() prior to using the other iterator methods. 2. Immediately before calling next(), be sure to call hasNext(). Otherwise, the code could throw a NoSuchElementException. 3. If the list changes, call resetIterator() prior to any subsequent use of the iterator.
Book and Book Lists
Book represents a book in the library. It is not dependent on any other classes in the project, and its methods are useful for both catalog and patron behaviors:
Book(String). Constructs a Book from a string of the format <number-in-stock><whitespace><book-info>. This constructor throws an IllegalArgumentException if the string argument is not valid (exception should be thrown if the number-in-stock cannot be read or if the book- info is an empty string after trimming white space). If <number-in-stock> is negative, this constructor sets it to 0.
getInfo(). Returns the book information (title and author as they appear in the input file). See [UC9]
toString(). Returns the book info, prepended by “* ” if there are no copies of the book currently in the library catalog. See [UC7, S1]. isAvailable(). Returns whether there are copies of this book in stock in the catalog.
backToInventory(). Puts a copy of the book back into the catalog stock [UC10].
removeOneCopyFromInventory(). Removes a copy of the book from the catalog stock [UC8, S1]. Throws an IllegalStateException if there are no copies of the book currently in the catalog.
compareTo(Book). Compares info of two books to determine their order in the catalog. The comparison is caseinsensitive and ignores “A”, “An”, and “The” leading tokens. Throws a NullPointerException upon comparison to null. See [UC7, S2].
BookDB represents an internal database of books. It hasa UniversalList<Book> for maintaining its collection of items this is one of the composition relationships in the design. BookDB has three public methods and private data:
books (type UniversalList<Book>). The list of elements that comprise the books in the library catalog.
BookDB(String). Constructs the database from a file [UC1, S3], where the parameter is the name of the file. Throws an IllegalArgumentException if the file cannot be read.
traverse(). Returns a string corresponding to the books in the database in the proper order. Strings for successive books are separated by newlines, including the last book in the list (that means the resulting string ends in a newline unless the BookDB is empty). The string is appropriate for the display in the Library catalog area [UC7].
findItemAt(int). Returns the book at the given position. Throws an IndexOutOfBoundsException if the position is out of range (less than 0 or >= size).
Users, Patrons, and Patron Lists
There are two different kinds of users of the library system: administrator and patron. Both types must have an id (username) and password. The abstract User class captures those attributes and corresponding operations with the following:
User(String, String). Constructor uses the first parameter for the id and the second for the password. Throws an IllegalArgumentException if the arguments are null or of length 0 after trimming whitespace from the ends or if the arguments contain any whitespace after the trim [UC5, E2]. id. The user’s username.
password. The user’s password stored as the password’s hashCode().
verifyPassword(String). Returns true if the hashCode() of the parameter matches the password (which is stored as a hashCode() of the password string). [UC2].
getId(). Returns the user’s id.
compareTo(User). Caseinsensitive comparison of two users by id [UC3, S2].
There are two child classes of User: Patron and Admin. Admin represents the library system administrator, and it has no attributes or operations apart from those inherited from User. The constructor creates an Admin with the appropriate id and password [UC2, S2]. Admin is an inner class of AccountSystem.
Patron, which represents a patron of the library, has members are as follows:
maxCheckedOut. The maximum allowable number of books this patron is allowed to check out.
nowCheckedOut. The number of books this patron currently has checked out.
checkedOut (type UniversalList<Book>). Books that the patron currently has checked out. Elements are added to the end of this list. reserveQueue (type UniversalList<Book>). Books in the patron’s reserve queue. Elements are added to the end of this list. Patron(String,String,int). The first parameter is the patron’s id, the next is the password, and the last is the maximum number of books this patron can check out. Throws an IllegalArgumentException if the arguments are null or of length 0 after trimming whitespace from if the arguments contain any whitespace after the trim [UC5, E2]. If the maximum number of books is less than 1, an IllegalArugmentException is thrown. If the patron’s id is “admin” and IllegalArgumentException is thrown.
traverseReserveQueue(). Returns a string of books in the reserve queue in the order in which they were reserved. Books are shown by info and successive books are separated by newlines, including a trailing newline [UC9, S1].
traverseCheckedOut(). Returns a string of checked out books in the order in which they were checked out. Books are shown by info and successive books are separated by newlines, including a trailing newline [UC9, S2].
closeAccount(). Closes this account and returns all checked out books to the library [UC6].
returnBook(int). Removes the book in the given position from the checked out list and returns it to the library catalog [UC10]. Throws an IndexOutOfBoundsException if the position is out of bounds.
moveAheadOneInReserves(int). Moves the book in the given position ahead one position in the reserve queue [UC12]. Throws anIndexOutOfBoundsException if the position is out of bounds. If the position is 0, there is no exception but there is also no change in the list. unReserve(int). Removes the book in the given position from the reserve queue [UC11]. Throws anIndexOutOfBoundsException if the position is out of bounds.
reserve(Book). Places the book at the end of the reserve queue [UC8]. Throws an IllegalArgumentException if the argument is null.
PatronDB maintains a list of library patrons as a custom arraybased list. It has the following data members and public methods: MAX_SIZE. The maximum number of patrons the system can support.
Did you know? The Java API defines an Iterator interface for methods similar to those for UniversalList. Ours is a “simple iterator,” which provides two of the three behaviors described in the API Iterator.
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 3/6
2016/7/17 CSC 216: Project 2, Part 2
size. The number of patrons currently in the system.
list. The list of patrons currently in the system.
verifyPatron(String, String). Returns the patron in the list whose id matches the first parameter and password matches the second. Throws an IllegalArgumentException if the id or password are null or if the password is incorrect for the given id or if the patron is not in the database. listAccounts(). Used only for testing. Returns a string of ids of patrons in the list in list order. Successive ids are separated by newlines, including a trailing newline.
addNewPatron(String, String, int). Adds a new patron to the list, where the id is the first parameter, password is the second, and maximum allowed books checked out is the third. Throws an IllegalStateException if the database is full. Throws an IllegalArgumentException if there is whitespace in the id or password, or if the id or password are empty, or if there is already a patron in the database with the same id. cancelAccount(String). Removes the patron with the given id from the list and returns any books that patron has checked out to the catalog. Throws an IllegalArgumentException if the account does not exist. [UC4]
AccountSystem, which manages the patron accounts for the library system, implements AccountManager. See AccountManager.java for documentation of the public methods. AccountSystem has the following private data:
patronList (type PatronDB). Database of library patrons.
adminUser. The single administrator for the system. This is a static variable. currentPatron. The patron currently logged into the system. adminLoggedIn. True if and only if the administrator is logged into the system. patronLoggedIn. True if and only if a patron is logged into the system.
Tying Patrons and Books Together
LoanSystem implements the backend for the library system. It implements LoanManager. Both of these are in the loan_system subpackage. LoanSystem has only two attributes, which are both private:
accounts (type AccountManager). The patron account part of the system. bookCatalog (type BookDB). The database of books in the system.
See LoanManager.java for documentation on the public methods.
Implementation
Every Java file for this assignment must be in the package edu.ncsu.csc216.pack_library.*, where * is a subpackage for different parts of the system as
described above. You are not allowed to modify the three files that are given to you:
AccountManager.java LoanManager.java Constants.java
You are allowed to modify the GUI for this project, since we are providing you with an incomplete version of the GUI: PackLibraryManagerGUI.java
Popup Error Messages, Exceptions, and Constants.java
The error messages in the popup windows in the GUI are from calling getMessage() on the exception caught by the GUI. That means the messages, which are stored in Constants.java, must be passed to the Exception during construction:
throw new IllegalArgumentException(Constants.EXP_CANNOT_COMPARE);
The comments in Constants.java describe when to use each message. The feedback from the teaching staff unit tests will also help you identify when the
messages are incorrect.
Lists of Patrons
PatronDB maintains a list of patrons. You must implement the list as an arraybased list, using three instance variables:
1. MAX_SIZE. The maximum capacity of the list.
2. list. An array of patrons. (See the UML diagram Patron[] is the type of this variable.)
3. size. The number of array elements that are actually patrons in the database. Unless size is 0, the index of the last patron in the database is size 1.
You cannot use ArrayList or any of the other Java collection classes in your implementation. When you add a new patron to the list, make sure to insert it in the proper position relative to the other patrons already in the list.
Lists of Books
Lists of books occur in three different places: BookDB.books, Patron.reserveQueue, and Patron.checkedOut. You must define all of these to be of type UniversalList<Book>.
You must implement UniversalList<T> as a linked list, with Node as its node type and head as a pointer to the fist node in the list. Define all of the list operations shown in the design. You cannot use LinkedList, TreeSet, or any of the other Java collection classes of the Java API in your list implementation.
The three kinds of lists share the same Book objects. For example, when you add a book to a patron’s reserve queue, do not create a new Book object. Rather, use the same Book object as is in the BookDB list.
Where to start
Before writing any code with logic, follow the bullets below.
The teaching staff recommends you follow these coding steps and strategies:
Compile a skeleton. The class diagram provides a full skeleton of what the implemented program should look like. Start by creating an Eclipse project named WolfPackLibary. Copy in provided code and create the skeletons of the classes you will implement. Ensure that the packages, class names, and method signatures match the class diagram exactly! If a method has a return type, put in a place holder (for example, return 0; or return null;) so that your code will compile. Push to GitHub and make sure that your Jenkins job shows a yellow ball. A yellow ball on Jenkins means that 1) your code compiles and 2) that the teaching staff tests compile against your code, which means that you have the correct code skeleton for the design.
Comment your code. Javadoc your classes and methods. When writing Javadoc for methods, think about the inputs, outputs, preconditions, and post conditions. Run the CheckStyle and PMD tools locally and make sure that all your Javadoc is correct. Make sure the tools are configured correctly (see configuration instructions) and set up the tools to run with each build so you are alerted to style notifications shortly after creating them.
Really, Really Important: You are not allowed to use any of the Java collection classes for your code. None of your classes should import java.util. If you use a Java collections class in your program, you will be penalized 50 points!!!
A compiling skeleton is due before the process point deadline to earn the associated process points.
Fully commented classes and methods on at least a skeleton program are due before the process point deadline to earn the associated process points.
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 4/6
2016/7/17 CSC 216: Project 2, Part 2
Commit with meaningful messages.
The quality of your commit messages for the entire project history will be evaluated for meaning and professionalism as part of the process points.
Practice testdriven development. Start by writing your test cases. This will help you think about how a client would use your class (and will help you see how that class might be used by other parts of your program). Then write the code to pass your tests. Another fine benefit of starting with tests is that you can work on having 80% statement coverage and you will have one of the minimum thresholds for the project grading rubric.
An easy place to begin writing code that has actual logic is the Book class. Both Book and UniversalList<T> are the only classes that do not depend on any of the others. Book is the easiest class to define and test. When you finished doing that, we suggest you start on UniversalList<T>.
Testing
Testing increases your confidence that your program meets the requirements. You will report the results of the black box tests that you wrote for Part 1 (possibly including an update to the tests based on feedback from Part 1 grading) and write, document, and report the results of unit tests written using JUnit and submitted to GitHub/Jenkins.
White Box Testing
You must write JUnit test cases for the following classes.
1. Patron 2. PatronDB 3. AccountSystem 4. Book 5. BookDB 6. UniversalList 7. LoanSystem
Do not unit test the user interface class, PackLibraryManagerGUI.
When doing unit testing, at a minimum, you must exercise every method in ALL classes that you wrote at least once. You will likely cover the simple getters and setters as part of testing more complex functionality in your system. Start by testing constructors and all methods that are not simple getters or simple setters for all of the classes that you must write, and check that you’re covering all methods. If you’re not, write tests to exercise unexecuted methods. You are required to achieve at least 80% statement coverage. Try to achieve 100% condition coverage (where every conditional predicate is executed on both the true and false paths for all valid paths in a method).
Testing list methods requires special considerations. Make sure those methods work correctly for changes at the front of the list, at the end of the list, and in the middle. Consider how list operations work with empty lists (for example adding the first element to an empty list or removing the only element from a list). In addition, make sure that all list elements are as they should be don’t simply check out only one or two elements. You do not need to test with large amounts of data. Typically lists of four or five elements will suffice.
This project has a list of patrons and lists of books. Note that PatronDB.listAccounts() is helpful for determining what’s in your list of patrons. Lists of books will be based on UniversalList<T>. Since T can be any class type, it’s easiest to use String or Integer or some built in type rather than Book for the actual type parameter in your JUnit tests for this class.
When testing BookDB (or any class that has a BookDB), you will need to pass in a filename. In Eclipse, the project folder is considered the present working directory and is where Eclipse will start looking for files. If you provide just a filename as an argument to BookDB (or other classes), the file should be stored directly under the Eclipse project. If you copy a file in via the file system of the OS, refresh the Eclipse project (right click on project > Refresh) for the files to be seen in Eclipse. The teaching staff recommend that you create book files that contain a few book for unit testing your system. Make sure your smaller file covers the case of an unavailable book.
Functional Testing
As sanity checks, you should start doing functional testing as soon as you have enough code for the GUI to show some results. Use the text file books example.txt for book data, or create your own shorter, simpler file.
There is no text file to initialize patrons. The GUI has a method PackLibraryManagerGUI.populatePatronAccounts() that will create two dummy patrons.
patron1@ncsu.edu/pw1 limit of 3 books checked out patron2@ncsu.edu/pw2 limit of 2 books checked out
Furthermore, the GUI preloads books in reserve and checked out queues for patron1. (See PackLibraryManagerGUI.populatePatronAccounts() for explicit details.) Make sure you are using a book file with at least 4 books in it to avoid exceptions.
To specify booksexample.txt as a commandline argument:
- Put a copy of books-example.txt in the project folder at the top level. (That means books-example.txt will be at the same level as the src and test folders.)
- Select Run > Run Configurations to open the run configurations dialog.
- Create a new Java application run configuration for PackLibraryManagerGUI as the Main class.
- Open the Arguments tab and type books-example.txt in the Program arguments text area.
- Click Apply.
- Click Run to run the application and close the dialog, or click Close simply to close the dialog.
Black box testing
Use the provided black box test plan template to describe your tests. Each test must be repeatable and specific; all input and expected results values must be concrete. All inputs required to complete the test must be specified either in the document or the associated test file must be submitted. Remember to provide instructions for how a tester would set up, start, and run the application for testing (what class from your design contains the main method that starts your program? What are the command line arguments, if any? What do the input files contain?). The instructions should be described at a level where anyone using Eclipse could run your tests.
Follow these steps to complete submission of your black box tests:
1. Run your black box tests on your code and report the results in the Actual Results column of your BBTP document. 2. Save the document as a pdf named BBTP_P2P2.pdf.
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 5/6
2016/7/17 CSC 216: Project 2, Part 2
3. Create a folder named bbtp at the top level in your project and copy the pdf to that folder. 4. Push the folder and contents to your GitHub repository.
Deployment
For this class, deployment means submitting your work for grading. Submitting means pushing your project to NCSU GitHub. Before considering your work complete, make sure:
- Your program satisfies the style guidelines.
- Your program behaves as specified in this document. You should test your code thoroughly. Be sure to know what messages should be displayed for each
major scenario.
- Your program satisfies the gradesheet.
- You generate javadoc documentation on the most recent versions of your project files.
- You push any updated bbtp, doc, and testfiles folders to GitHub.
The electronic submission deadline is precise. Do not be late. You should count on last minute failures (your failures, ISP failures, or NCSU failures). Push early and push often!
https://courses.ncsu.edu/csc216/lec/651/wrap/projects/2016-Summer/project2-part2.html 6/6