COSC1284 Programming Techniques Semester 2 Assignment 2
Assignment Objective
This assignment requires you to implement a “Library Management System (LMS)”.
(Note that the requirements and constraints described below are intentionally simplistic/artificial, being designed to provide a suitably sized assignment, and assess your understanding of various aspects of (good) object oriented programming. )
Specifically, the emphasis of this assessment is on adhering to a specification rather than developing a complete commercial grade library management product with realistic business rules.
The method signatures have been provided and must be implemented exactly as below. This will allow appropriate interfaces to be added to the program at a later stage and ensure that any test classes written to test your application will work correctly.
What you need to do
Your task is to write a simple “Library Management System (LMS)” as specified in this document.
Your design will consist of a collection of interacting classes/interfaces to store information about:
- The library and its collection
- The holdings contained in the library collection
- The members who can borrow/return available holdings
The system will need to be modelled as a number of object oriented classes/interfaces. The main classes involved in the system, and their behaviours, are detailed below.
- Your first task should be to download the startup project from Blackboard.
- Import it into Eclipse.
- Rename it to: [your_student_number]_A2
Any questions regarding this assignment or any of the requirements discussed in the specification should be directed to the assignment 2 forum in blackboard.
Part A – Write the class hierarchies indicated below to satisfy the functional requirements (5 marks)
For this part of the assignment you must design and implement the class heirarchies for both the holdings and the members.
You must also write a class that contains sample code for testing your class heirarchies are working correctly.
It is important the you complete this part of the assignment before moving onto Parts B & C.
You should not start implementing the menu system until you have completed and fully tested your classes.
The functional requirements for the two class heirarchies are specified below.
Holding - Functional Requirements
The system needs to cater for two distinct types of Holdings: Books and Videos. You should create an Abstract class called ‘Holding’ and two sub-classes called ‘Book’, and ‘Video’. Additional types of holding may be added later with each type of holding having a unique calculation of late fees.
Each holding has a:
- A unique seven-digit alpha-numeric code prefixed with ‘b’ for a book and ‘v’ for a video (e.g. b000010 or v000010);
- title (e.g. “Introduction to Java Programming”) which must be at least one character in length and cannot be set to null;
- predefined loan fee ($ value);
- maximum loan period (defined in terms of the number of days);
- late penalty fee ($ value) calculated on a per late day basis.
- an attribute which indicates if the holding has been made ‘inactive’ i.e. temporarily removed from the system.
- A holding may be made ‘inactive’ essentially preventing the item from being borrowed. The conditions that make a holding inactive are:
- If a holding is in an invalid state such as having an invalid ID or title, it should be marked as ‘inactive’.
- If a holding is damaged, then the administrator of the system can mark the item as ‘inactive’ until the item can be repaired and placed back on the shelves.
- A holding should not be allowed to have its status changed to inactive, if it is currently on loan.
Books:
- Books have a fixed standard loan fee of $10, and a fixed maximum loan period of 28 days.
- Books: late fee = number of late days x fixed daily rate of $2. e.g. if a given book was returned 3 days late, the late fee will be $6 (3 days x $2).
Videos:
- Videos have a variable loan fee of either $4 or $6.50 (determined at the time the item is created in the system, and a fixed maximum loan period of 7 days.
- Videos: late fee = number of late days x 50% of the standard loan fee. e.g. if a given video with a standard loan fee of $6.50 was returned 3 days late, the late fee will be $9.75 (3 days x 50% of $6.50).
- Videos should also have an attribute indicating the running time of the movie.
The specifications for the holding classesare specified below.
Attributes
You should use appropriate variables and constants. You will need to decide where in the hierarchy these attributes belong, what are the most appropriate data types and scope for these attributes.
Getters and or Setters should not be written arbitrarily for all variables. Only write a getter and/or setter if you use it within your program.
NOTE: The DateTime class provided has multiple constructors to create a date based on the current date, a date specified by day, month, and year, and a date based on the number of days from the current date.
These constructors enable the creation of a specific date without having to change the system clock or having to wait for the specified number of days before fines are incurred.
DateTime todaysDate = new DateTime();
DateTime nextWeeksDate = new DateTime(7);
DateTime specificDate = new DateTime(14, 4, 2016);
This method will return the number of days between two dates.
todaysDate.diffDays(nextWeeksDate);
To get a date formatted in the Australian date format you can call the following method:
todaysDate.getFormattedDate();
Constructors
The constructor for the holding class must take the following arguments ‘holdingId’ and ‘title’.
public Holding(String holdingId, String title)
public Book(String holdingId, String title, int numPages)
public Video(String holdingId, String title, double loanFee, double runningTime)
Methods
The classes should have appropriate getters, setters and other methods to represent the functions as specified in the functional requirements section.
The method signatures have been provided and must be implemented exactly as below. This will allow appropriate interfaces to be added to the program at a later stage and ensure that any test classes written to test your application will work correctly.
You also need to consider which of the methods below should be abstract methods and modify your implementation accordingly.
Additional methods may be used if required but attention must be paid to ensure proper use of scope, return types and parameters. You should also ensure that you are not duplicating the functions already present as detailed below.
public double calculateLateFee(DateTime dateReturned)
The method can be used to calculate the late fee as part of the returning process, but it can also be used by the user of the system to find out what the late fee will be if returned on the specified date. The specific calculation will depend on the type of holding please see the functional requirements above. Note: the calcuation must be performed at the time this method is called (i.e polymorphically), you should not modify the value of the underlying attributes at the time of contructing the object to meet this requirement. Also note that it must return a double, so if no late fee will be applied, it should return zero.
public boolean borrowHolding()
A holding can only be borrowed if:
- it is currently active in the system
- it is not already on loan
If an item is borrowed, then it must have it’s borrowDate set to the current date
public boolean returnHolding(DateTime dateReturned)
A holding can only be returned if:
- it is currently active in the system
- it is already on loan
- the return date is on or after the date on which the item was borrowed
If an item is returned, then it must have it’s borrowDate set to null
public String print()
The print method should return a string that represents the current state of the object in a user friendly format designed for display on the console. This method should not ‘do’ the actual printing, but give the data back to the calling method. The Menu will be responsible for printing it to the console.
Example String Output:
Book
Not on loan: ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: System Status: |
b000001 The Lion King 248 10.0 28 No Active |
On loan: ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: Date of Loan: |
b000001 The Lion King 248 10.0 28 Yes 23/08/2016 |
System Status: |
Active |
Video
Not on loan: ID: Title: Running Time: Loan Fee: Max Loan Period: On Loan: System Status: |
v000001 Intro to Java 1.37 6.5 7 No Active |
On loan: ID: Title: Running Time: Loan Fee: Max Loan Period: On Loan: Date of Loan: |
v000001 Intro to Java 1.37 6.5 7 Yes 23/08/2016 |
System Status: |
Active |
public String toString()
The Holding classes should override the toString() method to provide a pre-determined string representation of the holding. The format for the holding representation separates each attribute via the use of a colon ‘:’. This method will be used later when implementing your file reading and writing operations.
Book id:title:number_of_pages:loan_date:standard_loan_fee:max_loan_period:active
Video
id:title:runningTime:loan_date:standard_loan_fee:max_loan_period:active
e.g. b000001:Intro to Java Programming:248:12/09/2016:10:28:active v000001:Intro to Java Programming:1.37:null:4:7:active
public boolean activate()
public boolean deactivate()
Member - Functional Requirements
The system needs to cater for two distinct types of Members: Standard and Premium. These members can borrow and return holdings. You should create an Abstract class called ‘Member’ and two sub-classes called ‘StandardMember’, and ‘PremiumMember’.
The member has:
- a unique seven-digit alpha-numeric code prefixed with ‘s’ for a standard member and ‘p’ for a premium member (e.g. s000010 or p000010);
- full name (e.g. “John Smith”) which must be at least one character in length
- maximum borrowing credit ($ value) which is predefined according to the specific membership type
- Each member should have their credit set to the maximum available credit limit for that type of member when the member is created.
- collection of currently borrowed holdings
- Standard members have a fixed maximum borrowing credit of $30
- Premium members have a fixed maximum borrowing credit of $45.
- The holding’s standard loan fee should be deducted from member’s borrowing credit at the time he/she borrows a holding.
- The member must have sufficient credit available to borrow a given holding.
- The holding return procedure differs based on a specific member type:
- Standard members are not allowed to return a (late) book if their current balance will become negative after paying the late penalty fee. In such cases, the current credit of a member should first be restored to the initial maximum value.
- Premium members can return a holding even if this will result in a negative current balance. However, they won’t be able to borrow any new holdings until their current credit is restored to a positive value.
The requirements for the member classesare specified below.
Attributes
You are should use appropriate variables and constants. You will need to decide where in the hierarchy these attributes belong, what are the most appropriate data types and scope for these attributes.
Constructors
The constructor for the Member class must take the following arguments ‘memberId’, ‘fullName’ and
‘credit’.
public Member(String memberID, String fullName, int credit)
public StandardMember(String standardMemberId, String standardMemberName)
public PremiumMember(String premimumMemberId, String premiumMemberName)
Methods
The classes should have appropriate getters, setters and other methods to represent the functions as specified in the functional requirements section.
The method signatures have been provided and must be implemented exactly as below. This will allow appropriate interfaces to be added to the program at a later stage and ensure that any test classes written to test your application will work correctly.
You also need to consider which of the methods below should be abstract methods and modify your implementation accordingly.
Additional methods may be used if required but attention must be paid to ensure proper use of scope, return types and parameters. You should also ensure that you are not duplicating the functions already present as detailed below.
public boolean borrowHolding(Holding holding)
A member can only be borrow a holding if:
- They are currently active in the system
- They have enough credit to pay the initial loan fee
public boolean returnHolding(Holding holding, DateTime returnDate)
The conditions for returning a holding are different depending on the type of member, please see the functional requirements section above.
public boolean resetCredit()
This is just a convienience method that will set the member’s credit back to its maximumValue.
public boolean deactivate()
This allows you to set a flag that inidicates that the member should be made inactive in the system. This flag is used when implementing some of the business rules.
public boolean activate()
This allows you to set a flag that inidicates that the member should be made active again in the system.
public String print()
This method should return a string that can be printed by the ‘client’ (your menu system) that represents the current state of the member including the holdings they currently have onloan. This should be displayed in a ‘human friendly’ format such as the example below.
Member
ID: s000001 Title: Simba Remaining Credit: 30.0 |
One Item on Loan: ID: s000001 Title: Simba Remaining Credit: 20.0 Current holdings on loan: b000001 Two or more items on loan: ID: s000001 Title: Simba Remaining Credit: 13.5 Current holdings on loan: b000001:v000001 |
public String toString()
The member class and its sub-classes should override the toString() method to provide a pre-determined string representation of the member. The format for the member representation separates each attribute via the use of a colon ‘:’.
The basic output of this method may be modified (i.e. add additional attributes) to facilitate maintaining state when writing and reading to text files.
member_id:full_name:remaining_credit e.g. p00001:Joe Bloggs:25
Part B – Write a menu driven program to demonstrate and test the classes you have implemented in the previous section. (5 marks)
You are required to implement a simple application which tests the functionality of the Holding and Member class hierarchies you have just developed. This application should demonstrate the processes of creating, manipulating and displaying the details of a collection of Holding and Member objects according to the requirements set out below.
IMPORTANT: A ‘façade’ class has been provided in your startup project. Your menu system must only have a reference to this class and should only make calls to this class. The Menu system should not directly access the main classes in your system such as the class heirarchies that you created in Part A of the assignment.
The ‘façade’ should have a reference to a Library class that is responsible for managing the collections of members and holdings. Note: The diagram below is a basic representation, you will have several classes in your system, not shown in the diagram, this is intended to get you started.
Write a menu driven program to perform the operations outlined below.
The Menu should handle all the input/output. It then gives the information to the façade that passes it to the Library. Any response is passed from the Library, back to the façade that gives it to the menu for display.
You may modify your menu as you see fit by adding / removing menu items, provided that the system allows you to perform all of the functions below. If you choose to modify the menu system you should make sure that it is user friendly and intutitive and does not unnecessarily prompt the user for input.
- Declare two arrays named holdings and members that can store the references for up to 15 objects each. This should be done in your Library class.
- Create the 8 Holding objects and 4 Member objects shown at the bottom of this section to automatically populate the library when the program starts so there is sample data for testing.
- Additionally, allow the user of the program to add additional holdings and members at runtime. If the maximum number (15) of holdings or members is exceeded, a message should be displayed indicating that the operation cannot be performed.
- Store references to these objects in their respective arrays (remember this should be done in your ‘Library’ class
- Allow a user to perform both borrowing and return operations on any of the Holding objects stored in the array. Based on the returned value of these methods give appropriate feedback on the success or failure of operation.
For example when a book is borrowed you should display something like:
Your current balance is now: 20.0
You successfully borrowed:
ID: b000001
Title: The Lion King
Number of Pages: 248
Loan Fee: 10.0
Max Loan Period: 28
On Loan: Yes
Date of Loan: 24/08/2016
System Status: Active
Press any key to return to the menu
For example when a video is returned display any fine incurred.
You incurred a late penalty of :9.75 You current balance is now: 3.75
You successfully returned:
ID: v000001
Title: The Lion King
Running Time: 1.37
Loan Fee: 6.5
Max Loan Period: 7
On Loan: No
System Status: Active
Press any key to return to the menu
- Display the current state of the objects stored in each of the arrays.
- Allow the user to search for an object by providing an ‘ID’ at runtime and print only that object. If
the ‘ID’ supplied does not exist in the collection, the user should be informed and re-prompted to enter a valid ‘ID’. They should also be able to type ‘exit’ or ‘e’ to cancel the operation if they choose.
- Allow user to borrow and return books repeatedly through the use of a loop. The loop should be repeated, as long as a user responds positively to the prompt, “Any more transactions?”
- Add an Interface to your program called ‘SystemOperations’. This should contain two methods:
public boolean activate();
public boolean deactivate();
You should then have both your class hierarchies implement this interface. Write a single method in your main program (for each of the methods in your interface) that you can call which is able to take objects from either hierarchy as a parameter.
You will need to add this function to your menu.
Holding Sample Data (for pre-loading your system):
ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: System Status: ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: System Status: ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: System Status: ID: Title: Number of Pages: Loan Fee: Max Loan Period: On Loan: System Status: |
b000001 Intro to Java 200 10.0 28 Yes Active b000002 Learning UML 124 10.0 28 No Active b000003 Design Patterns 345 10.0 28 No Active b000004 Advanced Java 287 10.0 28 No Active |
ID: v000001 Running Time: 1.37 Title: Java 1 Loan Fee: 4 Max Loan Period: 7 On Loan: No System Status: Active ID: v000002 Title: Java 2 Running Time: 1.28 Loan Fee:6.50 Max Loan Period: 7 On Loan: No System Status: Active ID: v000003 Title: UML 1 Running Time: 1.47 Loan Fee: 6.50 Max Loan Period: 7 On Loan: No System Status: Active ID: v000004 Title: UML 2 Running Time: 1.12 Loan Fee: 4 Max Loan Period: 7 On Loan: No System Status: Active |
Member Sample Data (for pre-loading your system):
ID: Title: Remaining Credit: ID: Title: Remaining Credit: |
s000001 Joe Bloggs 30 p000001 Fred Bloggs 45 |
ID: Title: Remaining Credit: ID: Title: Remaining Credit: |
s000002 Jane Smith 30 p00002 Fred Smith 45 |
Part C – Add File reading and writing functions to your program. (5 marks)
Finally, extend the application writing all objects (both book and member objects) to the files holdings.txt and members.txt.
You will need to add exception handling mechanism as part of your File operations.
When saving your data you should save to two files for each of the holdings and members:
holdings.txt holdings_backup.txt members.txt members_backup.txt
These files should be saved into your project directory using a relative path so it will work on any system when being assessed. Do not hard code the path to a directory on your own hard drive.
Part of your exception handling must include:
If the main data file is not found, it should automatically revert to using the backup file, so that this is handled without the user being aware.
When saving you always need to save to both files. The system will look first for the main file when loading the data, then and only if this file is not found it will restore from the backup file. Upon exiting the system again both files should be saved to the hard drive.
The data saved to the files should enable the full restoration of the state of the object at the time that it was written to the file was written. To restore the link between the which members have which holdings onloan, you can choose to augment the files above or choose to write out a separate file that maps these two together.
Updated (12/09) : for
clarification on persistence
***Important*** and restoration requirement.
You are not permitted to use serialisation for the implementation of the file reading and writing.
You must write your own classes for writing these objects to file on exit, and restoring them on program start up.
Submission Requirements
Your solution must use Java 1.7 or above and be compatible with the environment supplied in the computer laboratories.
You can use your own computers to develop your assignment, but you must make sure that your assignment can be compiled and run on the computers in the RMIT laboratories.
Assessment
The assignment is designed to test multiple competencies required for successful software development. The assessment evaluates all skills required not just the code itself. You will be assessed on your ability to comply with requirements as set out in this document.
The assessment will include competencies in:
- Business Requirements: such as adherence to a style guide, documentation of your program and compliance with processes such as submission of your work prior to assessment.
- Java Programming: in Java demonstrating a mastery of the language and the accepted conventions for developing applications.
- Software Development Lifecycle: practices such as an iterative approach to development that includes thorough testing of your solution.
- Algorithm Development: that demonstrates that you have a clear idea of the logic required to complete the necessary tasks.
The code should closely resemble your logical solution as demonstrated in your documented algorithm.