Question
In this project you will complete the implementation of a Java program that helps a user maintain a library of their favorite songs. The library
In this project you will complete the implementation of a Java program that helps a user maintain a library of their favorite songs. The library is in the form of a list of songs. The program stores this list in a text file so that it is saved after the program closes. That means that if a user modifies the list by adding or removing songs, the changes are saved if the application is closed and re-loaded. An example of a list of songs in a library could be: Your songs: 1 XO Tour Llif3, Luv Is Rage 2, Lil Uzi Vert, 3.02 2 Man's not hot, , Big Shaq, 3.06 3 Bodak Yellow (Money Moves), , Cardi B, 3.36 4 What About Us, Beautiful Trauma, P!nk, 4.31 5 DNA, DAMN., Kendrick Lamar, 3.06 Each song is represented by the following data fields: title, album, artist, playing time (minutes) Note that title, artist, and playing time are required. Album is optional, and is represented by a space in the above print out. OBJECTIVES: 1. Use inheritance to utilize superclass functionality. 2. Work with file I/O. 3. Gain experience processing data from a comma-delimited text file. 4. Work with a multiple-class program. 5. Gain experience implementing "skeleton" code. 6. Develop code that makes use of a data structure. 7. Be able to write a class definition that works according to a specification. 8. Gain experience developing code in an incremental fashion. 9. Gain experience with testing code by using JUnit tests.
PROJECT CODE
The project consists of these Java source code files:
LibraryMain.java
FileAccessor.java
SongFileAccessor.java
SongList.java
Song.java
Two of these files, SongFileAccessor.java and SongList.java , contain code in skeleton form. Your task is to finish writing the code for these two classes so the application works correctly.
You will be submitting ONLY the SongFileAccessor and SongList code.
NOTE : The rest of the code is provided for you and we suggest that you not modify it.
Additionally, we provide two Junit test files:
SongFileAccessorTest.java
SongListTest.java
We strongly recommend that you run these tests while you develop your c ode. It would also be helpful to use the debugger.
Specification for the SongFileAccessor class.
This class inherits from the abstract class FileAccessor . It does this to leverage the functionality provided by its superclass: opening a text file, reading the lines of text, and writing to a text file. Since SongFileAccessor specializes FileAccessor, you only need to write the methods that:
parse the song data from the file.
create Song objects from each line.
put those objects on a SongList.
You will also write methods that support the functionality of writing the song list to the text file. Note that the songs are stored in a comma - delimi ted format, or CSV, a common data format for text files. You will need to parse the data from this format when reading in the lines of the file, and encode the songs into the CSV format before writing it to the file.
You may add additional attributes and private methods if you wish, as long as your code conforms to the following specification.
1. This class should have a SongList as a member variable.
2. You will write the following methods (the method descriptions also appear in the skeleton code):
- A constructor that matches the signature of its superclass. It also initializes the SongList member variable.
- processLine . This method must be implemented since it is an abstract method in the superclass. It takes a String which is a line in the text file an d represents a song in the form: title,album,artist,playingTime
You can see this by opening the text file songs.txt provided. This file is the song library database.
The processLine method parses or tokenizes a line into individual data fields us ing the comma character as a field separator, or delimiter. Use the String class split method to do this. The split method will return an array of Strings. Note that you may have to convert a field to the proper data type that the Song class needs.
The a lbum field may not be present in a line of text. That means some of the lines will may have one token t h a t d o e s n o t h a v e a n y c h a r a c t e r s . You will need to check the s e c o n d t o k e n , w h i c h r e p r e s e n t s t h e a l b u m f i e l d , so you know which Song constructor to call.
Once you have the tokens, cre ate a new instance of the Song class using the data tokens - they are the title, album(optional), artist, playing time. Once you have done this, add the new Song to the member SongList instance (that was initialized in the constructor).
After each line has been processed, the SongList will contain all of the songs in the file in the form of Song objects.
Note: because you are extending FileAccessor, you will not have any of the code that deals with opening and reading the lines of the fi le in your SongFileAccessor class.
- getSongList . This method takes no parameters. It simply returns the SongList instance to the caller.
- getSongsAsCSV. This method takes a SongList object as a parameter. It assembles a CSV - formatted String for all of the songs in the SongList and returns that String. For example, one song in CSV looks like this:
XO Tour Llif3,Luv Is Rage 2,Lil Uzi Vert,3.02
Each of these CSV Strings ends with a line break, which is the \ n String. We suggest you use the StringBuilder class for this. It would also be useful to write a private method that takes a Song object and returns the CSV formatted String for that object.
- writeSongsToFile . This method takes a SongList as a parameter. It makes use of the superclass method writeToFile to handle the file I/O. You will call the getSongsAsCSV method that you are writing to convert the song list into one CSV string to be written to the file. The file name is available to you directly because it is declared as protected . That means it is available only to subclasses of FileAccessor.
Specification for the SongList class.
This class maintains the list of Song objects. It provides the functionality called for by the application regarding the song list. You may choose to implement the list as either an array OR an ArrayList from the java.util package. Both store objects of type Song.
This class has a member var iable that is the songList.
You will write the following methods:
- A constructor that takes no parameters. It initializes the songList member variable.
- addSong . This method takes a Song object as a parameter and does not return a value. It adds the param eter to the songList.
- isEmpty . Takes no parameters. Returns true if there are no songs on the list, false otherwise.
- getSize . Takes no parameters. It returns an integer which is the number of songs on the list.
- clearSongList . Takes no parameters and doe s not return a value. It removes all of the songs from the song list.
- removeSongByTitle . Takes a String parameter which is the title of a song on the list. It returns true if that title matched a song on the list and that song was removed from the list. I t returns false if the title was not found in the song list. It returns false if the song list is empty.
- getSongListAsArray . This method takes no parameters and returns an array of type S ong , where each member of the array is the string representation of a Song object on the song list. If the list is empty, an array of length 0 is returned. Note that there are no null values on the array returned.
- getSongListAsString . This method takes no parameters. It returns a String, which is the concatenation of each Song on the song lists String representation (its toString method). The line break character (or String) is inserted between each song. The number of each song is p repended to the song string. The numbers start at 1, not 0.
This is an example of the String returned by this method as it would look when printed:
1 XO Tour Llif3, Luv Is Rage 2, Lil Uzi Vert, 3.02 2 Man's not hot, , Big Shaq, 3.06 3 Bodak Yellow (Money Moves), , Cardi B, 3.36
4 What About Us, Beautiful Trauma, P!nk, 4.31 5 DNA, DAMN., Kendrick Lamar, 3.06
If the song list is empty, the String no songs is returned.
REQUIREMENTS :
1. You must submit in OWL a class defi nition named SongList and a class definition named SongFileAccessor exactly . You will receive zero points if you do not meet this requirement.
2. Your code in addition to the code provided must compile to receive more than zero points.
3. You may add variables and any private methods you want to the two classes you are writing.
4. You may not add any public methods to the two classes you are writing.
5. Your code must be your own work. Any code that is copied from another student or outside sou rce is considered plagiarism and if detected you will receive zero points and other action will be taken (see syllabus for details).
6. You must use either an array or an ArrayList from the java.util package to implement the songList.
7. Your SongList and SongFi leAccessor code must conform to the specifications written above.
8. The String returned from your getSongListAsString method must conform to the format specified in the above section. If no songs are on the list the String returned must be: " no songs ". Each song is on one line, position number first followed by one blank, followed by the songs String. See the specification for the getSongListAsString method above.
Note: do not use the format method to produce this output. We suggest you use the StringBuilder class (see the API and previous lecture notes).
9. Your SongFileAccessor inherits from FileAccessor. There should not be any methods or other code from the superclass in your subclass that is not part of the subclasss tasks. For example, you wo uld not have a Scanner in your subclass, but you do define the processLine method in your subclass. You also can directly use the fileName in your subclass when writing to the file.
FileAccessor.java
1 import java.util.Scanner; 2 import java.io.*; 3 4 /** 5 * This abstract class contains the functionality of reading lines from a text file 6 * and writing a String to a text file. Its abstract method, processLine, is intended to 7 * be implemented by subclasses so they can process each line in their specialized manner. 8 * This class utilizes a Scanner member variable to read from a text file. The file name is 9 * a protected member variable and is available directly to its subclasses. A PrintWriter is used 10 * in the writeToFile method to write a String to the file. 11 */ 12 public abstract class FileAccessor{ 13 protected String fileName; 14 Scanner scan; 15 16 /* Constructor that initializes the Scanner and opens the file. 17 * An IOException is thrown if the file cannot be opened or is not found. 18 */ 19 public FileAccessor(String fName) throws IOException{ 20 fileName = fName; 21 scan = new Scanner(new FileReader(fileName)); 22 } 23 24 /* Assumes the Scanner instance contains the lines of text from the file. 25 * The lines are read from the scanner, and processLine is called in each line. 26 */ 27 public void processFile() { 28 while(scan.hasNext()){ 29 processLine(scan.nextLine()); 30 } 31 scan.close(); 32 } 33 34 /* This method must be implemented by any subclass. This allows the 35 * subclass to handle the line of text in its own specialized manner. 36 */ 37 public abstract void processLine(String line); 38 39 /* This method utilizes a PrintWriter to write a String to a text file. 40 * An IOException is thrown if the file cannot be opened or found. 41 */ 42 public void writeToFile(String data, String fileName) throws IOException{ 43 PrintWriter pw = new PrintWriter(fileName); 44 pw.print(data); 45 pw.close(); 46 } 47 48 } 49
LibraryMain.java
1 import java.util.Scanner; 2 /* This application manages a collection of songs for a user. The songs 3 * are representeed by Song objects. The songs are managed by a SongList object. 4 * The songs are stored in a comma-delimited text file. 5 * A user has several options that are displayed in a menu format. 6 * This class runs a console interface between a user and the SongList 7 */ 8 import java.io.*; 9 10 public class LibraryMain { 11 12 public static void main(String[] args) throws IOException{ 13 String dataFile = "songs.txt"; 14 System.out.println("Song Library"); 15 Scanner scan = new Scanner(System.in); 16 // Load any songs that were saved in the dataFile. 17 SongFileAccessor sfa = new SongFileAccessor(dataFile); 18 sfa.processFile(); 19 SongList songs = sfa.getSongList(); 20 21 boolean keepGoing = true; 22 String userStr = ""; 23 int position; 24 25 while(keepGoing) { 26 System.out.println("Main Menu:"); 27 System.out.println("Enter A to add a song."); 28 System.out.println("Enter R to remove a song."); 29 System.out.println("Enter P to view all songs."); 30 System.out.println("Enter S to save all songs."); 31 System.out.println("Enter C to clear all songs."); 32 System.out.println("Enter X to quit."); 33 System.out.println(""); 34 userStr = scan.nextLine(); 35 36 if (userStr.equals("A")){ 37 System.out.println("Enter the title: "); 38 String title = scan.nextLine(); 39 System.out.println("Enter the album, press the return button if none: "); 40 String album = scan.nextLine(); 41 System.out.println("Enter the artist: "); 42 String artist = scan.nextLine(); 43 System.out.println("Enter the playing time: "); 44 String playTime = scan.nextLine(); 45 songs.addSong(new Song(title, album, artist, Double.parseDouble(playTime))); 46 } 47 else if (userStr.equals("R")){ 48 System.out.println("Enter the title of the song to be removed:"); 49 String title = scan.nextLine(); 50 if(songs.removeSongByTitle(title)) 51 System.out.println("Song "+title+" removed."); 52 else 53 System.out.println("Could not find "+title+" in the list."); 54 } 55 else if (userStr.equals("S")){ 56 System.out.println("Your songs have been saved."); 57 sfa.writeSongsToFile(songs); 58 } 59 else if (userStr.equals("P")){ 60 System.out.println("Your songs: "); 61 System.out.println(songs.getSongListAsString()); 62 } 63 else if (userStr.equals("C")){ 64 songs.clearSongList(); 65 System.out.println("Songs cleared."); 66 } 67 else if(userStr.equalsIgnoreCase("X")) 68 keepGoing = false; 69 else 70 System.out.println("Unrecognized input."); 71 } 72 System.out.println("Bye for now."); 73 scan.close(); 74 } 75 }
Song.java
1 /** 2 * This class encapsulates the data required to represent a song in a song collection. 3 * The attributes of a song are: title, album, artist, and playing time. 4 * The title, artist, and playing time are required fields. The album field is optional. 5 * The playing time is represented by a double value. For example, a playing time of 6 * five minutes and thirty-five seconds would be the number 5.35. 7 **/ 8 public class Song { 9 10 private String title; 11 private String album; 12 private String artist; 13 private double playTime; 14 15 /* Constructor when the album field is not present. 16 */ 17 public Song(String title, String artist, double playTime){ 18 this.title = title; 19 this.album = ""; 20 this.artist = artist; 21 this.playTime = playTime; 22 } 23 24 /* Constructor when all fileds are present. 25 */ 26 public Song(String title, String album, String artist, double playTime){ 27 this.title = title; 28 this.album = album; 29 this.artist = artist; 30 this.playTime = playTime; 31 } 32 33 public String getTitle(){ 34 return title; 35 } 36 37 public String getAlbum(){ 38 return album; 39 } 40 41 public String getArtist(){ 42 return artist; 43 } 44 45 public double getPlayTime(){ 46 return playTime; 47 } 48 49 public String toString(){ 50 return title+", "+album+", "+artist+", "+playTime; 51 } 52 }
SongFileAccessor.java
1 import java.io.*; 2 /** 3 * This class extends FileAccessor to process the song data in a text file. 4 * The songs are stored in the file in comma-delimited(CSV) format. Each 5 * line in the file reporesents one song. Each line in the file is processed 6 * into a new Song object, which is placed on the SongList member variable "songs". 7 * Another method, writeSongsToFile, takes a SongList, converts its songs to a single 8 * CSV formatted String and writes it to the text file. 9 **/ 10 public class SongFileAccessor extends FileAccessor { 11 12 // a SongList member variable 13 14 15 /* After the call to the superclass constructor, initialize the member variable "songs" 16 to a new SongList. 17 */ 18 public SongFileAccessor(String f) throws IOException{ 19 super(f); 20 } 21 22 /* This method implements the abstract method processLine in the FileAccessor class. 23 It uses the String class method split to parse the line into individual Strings. 24 The split method is passed "," as a parameter since the comma is the delimeter. 25 26 Each line of the file has this format: 27 title,album,artist,playTime 28 Where title, artist and playTime are required, and album is optional. An example of 29 a line with no album: 30 title,,artist,playTime 31 32 You may assume that the title, artist and playTime fields will always be present. After 33 the line has been tokenized, the array returned by split contains the data needed to create a 34 new Song object. 35 You have to check the length of the second token to determine if the album field is present and based 36 on that length which Song constructor to call. 37 */ 38 public void processLine(String line){ 39 String[] tokens = line.split(","); 40 41 } 42 43 /* Returns the SongList member variable "songs". 44 */ 45 public SongList getSongList(){ 46 return null; 47 } 48 49 /* This method writes the data in a SongList object to the text file. 50 The songs on the list must first be converted into a String in CSV 51 format. Then this method calls the writeToFile method, passing it the 52 CSV String and the fileName. 53 */ 54 public void writeSongsToFile(SongList songs) throws IOException{ 55 } 56 57 /* This method returns a String of all songs in the song list 58 in CSV format. Each song must be put into CSV format, and 59 a line break inserted between songs. 60 */ 61 public String getSongsAsCSV(SongList songList){ 62 return null; 63 } 64 }
SongList.java
1 import java.util.ArrayList; 2 /* This class encapsulates a list of songs in a user's collection and several 3 * operations that can be performed on that list. A song is represented 4 * by an instance of the Song class. Each song has the following fields: 5 * a title, an (optional) album, an artist, and a playing time. 6 */ 7 public class SongList { 8 //Class member variable declaration(s): 9 10 11 12 /* Constructor that initializes the list and any other 13 * variables. 14 */ 15 public SongList(){ 16 } 17 18 /* Add the song passed in to the end of the list. 19 * For example, if the list contained: song1, song2, 20 * the next song added, song3, would result in this list: 21 * song1, song2, song3. 22 */ 23 public void addSong(Song newSong){ 24 } 25 26 /* Remove the song in the songList with the targetTitle. 27 * First, the method searches for a song in the list with a title that 28 * matches the targetTitle. If it is found, that song is removed from 29 * the list. If the targetTitle is not matched, the list remains the same and false is returned. 30 * Note that there should not be any null values between songs in the list. 31 * For example, if the list contained: song1, song2, song3, 32 * and the title of song2 was "MyTitle", this call: 33 * removeSongByTitle("MyTitle"); 34 * would result in this list: song1, song3. 35 * This method returns true if the targetTitle matches the title of a song in the list, 36 * false otherwise. 37 */ 38 public boolean removeSongByTitle(String targetTitle){ 39 return true; 40 } 41 42 /* Return the song list as an array of Song objects. 43 * Note that the array should contain only the songs 44 * on the list in the correct order and no empty cells (null values). 45 * This method returns an array of length 0 if the song list is empty. 46 */ 47 public Song[] getSongListAsArray(){ 48 return null; 49 } 50 51 /* Remove all songs from the list, resulting in an empty list. 52 */ 53 public void clearSongList(){ 54 } 55 56 /* Returns the number of songs stored in the song list. 57 */ 58 public int getSize(){ 59 return 0; 60 } 61 62 /* Returns true if the song list contains no songs, false otherwise. 63 */ 64 public boolean isEmpty(){ 65 return true; 66 } 67 68 /* This method returns a String which consists of the String 69 * representation of each song in the list. A line break is 70 * inserted between each song String. 71 * If the song list is empty, the String "no songs" is returned. 72 */ 73 public String getSongListAsString(){ 74 return null; 75 } 76 }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started