Target Audience: this guided project is geared toward the beginning Java programmer who has some experience with using Eclipse.
A paradigm of good design is to reduce redundancy. You want to have code in one location (it’s easier to maintain) and reuse that code as much as possible. In Guided Project 1, you explored the composition relationship. You could encapsulate code in a single class (e.g., Course) providing an abstraction that could be used by other classes (e.g., WolfScheduler). The container class WolfScheduler could then delegate to the contained class Course.
Composition is one type of relationship in object-oriented programs. The other relationship is inheritance. Inheritance is when one class extends or specialized another class. The common code goes in the parent and the extension goes in the child.
After completing this Guided Project, students will be able to…
Implement and test a multi-class software system from a given set of requirements and design.
Use inheritance, abstract classes, and interfaces to implement an object hierarchy in an OO system.
Use software engineering best practices like test-driven development, code coverage, static analysis, version control, continuous integration, and documentation with supporting tooling to implement and test object-oriented systems.
WolfScheduler System
You will implement and test PART of the WolfScheduler system. The WolfScheduler system provides a way for a student to determine which course schedule may be best for them in an upcoming semester.
You will develop the WolfScheduler project over the course of the three guided projects. The WolfScheduler requirements describe the fully implemented system. Guided Project 2 will complete the requirements except for checking for conflicts between events and courses.
You will complete the functionality for handling schedule conflicts in Guided Project 3. There are expectations from the Guided Projects that you must follow. Do NOT attempt to implement any functionality before a Guided Project tells you to do so!
As part of the Guided Project, you are expected to run the provided JUnit tests and acceptance tests to ensure that your implementation meets the requirements and design of the system.
Double check your implementation to ensure that you're meeting all expectations.
Total Estimated Time*:
7 hours 20 minutes
* Times are only estimates. It may take you less time or more time depending on how much debugging effort is required for your specific implementation. Use the relative numbers to help guide you: for example, a task labeled as "5 minutes" should not require as much effort as a task labeled "20 minutes", regardless of how much time it takes to actually complete the task.
Guided Task: Guided Project 2 GitHub Repository
You will be assigned a separate GitHub repository for each Guided Project and each major Project. This is to ensure that your work on each is distinct and that any work on a new project doesn’t get recorded as late work on an old project. However, you will continue with the same WolfScheduler project for GP2. You need to share the project to your GP2 repository.
Learning Outcomes
Disconnect a project from a GitHub repository
Share a project with a new GitHub repository
Push changes to a new remote GitHub repository
Best Practice: Version Control
A project may belong to only a single local repository. That is because a Git repository is represented as a folder on a file system with a special .git/ folder that stores Git metadata. The same project cannot be in two locations on the file system at once. The process outlined below will let you share an existing Eclipse project with a new repository and then retain a copy of your Guided Project 1 submission in a local copy of your Guided Project 1 repository.
Complete the following steps to push WolfScheduler to your GP2 repository.
Clone your GP2 repository provided by the teaching staff. The pattern will be csc216-XXX-GP2-YYY, where XXX is your section number and YYY is your repository number.
Stage your WolfScheduler to your GP2 repository by right clicking on the project and selecting Team > Share Project.
In the Configure Git Repository pop-up, uncheck the option Use or create repository in parent folder of project. Then select your new repository from the drop down and check your project.
Now that your project is staged for the GP2 repository, add the files to the index by right clicking on the WolfScheduler project and selecting Team > Add to index. Then Commit and Push the project to start GP2! Use a commit message like “[Skeleton] Starting GP2 with GP1 WolfScheduler”.
Reset your GP1 WolfScheduler
When you shared the WolfScheduler project with your new GP2 repo, that removed the WolfScheduler directory from your local GP1 repo directory. If you want to keep a copy of your GP1 WolfScheduler, you should reset your local GP1 repository to the last commit in the remote. Then your local GP1 repository will have a copy of your final GP1 WolfScheduler submission. You can use that as a backup as you’re working on GP2!
Choose to do the reset in either Eclipse or Git Bash!
In Eclipse, do the following:
Right click on your GP1 repository in the Git Repositories view and select Reset.
Make sure the last commit is selected and select the option for a Reset type of Hard (HEAD, index, and working tree updated). Click Reset.
You will receive a warning about overwriting your local changes. This is what we want since we want to bring a copy of the project back into our local GP1 repository and erase all of your uncommitted local changes (which in this case is all the deleted WolfScheduler files). Click Reset.
Check that WolfScheduler is now in the Working Tree/ directory of your GP1 repository.
In Git Bash, do the following:
Change directory to your repository location.
Enter the command git reset --hard HEAD. This will reset the local repository to the same information as the remote and erase all of your uncommitted local changes (which in this case is all the deleted WolfScheduler files).
Caution: Resetting a Repo
In this case, resetting the repo is useful, but the reset command can lead to major problems. Use the power of the reset command carefully!
Check Your Submission
You should ALWAYS verify that your pushed changes are on the remote repository. You can do this by going to your repository on the GitHub website and making sure that your WolfScheduler project has been pushed to your GP2 repository.
Select the appropriate organization and repository.
Verify that your latest commit message is listed and that all pushed files are in the repository.
Verify that your Guided Project 2 Jenkins job is pulling your WolfScheduler from your GP2 repository (this job will start with GP2-. If Jenkins does not recognize your project, please notify the teaching staff via Piazza or the sup list as early as possible to ensure that your project is set up correctly for auto grading.
Caution: Red Ball on Jenkins is OK (at this point)
At this point, your Jenkins build will be a red ball. That is expected because there are several things that we have to do in Guided Project 2 before our code will even compile. The important thing is that the job runs and gives you a red ball!
Make sure that all fields, methods, and constructors are commented.
Resolve all static analysis notifications.
Fix test failures.
Commit and push your code changes with a meaningful commit message. Label your commit with “[Skeleton]” for future you!
Guided Task: Design a Hierarchy
The focus for GP2 is to add Events to the WolfScheduler program. That way users can put items like meals, club meetings, exercise, and other non-course activities on their schedules. For Guided Project 2, you do not need to worry about checking for conflicting activities.
Learning Outcomes
Identify design decisions and trade-offs
Best Practices: Inheritance
There are two main relationships between classes: composition and inheritance. Composition is a has-a relationship where one object has an instance (or collection) of another object. Inheritance is an is-a relationship where one class is an extension or specialization of another class. When two objects have a common set of fields with some specializations, those objects are candidates for an inheritance hierarchy. You can create a parent class that contains the common fields and each child class can then specialize.
Identifying Common Elements
Use Case 6 and Use Case 7 describes a new type of item that can go on a student’s schedule: Events. Both Course and Event have a common set of attributes: title, meetingDays, startTime, and endTime. These common elements can be stored in a parent class, Activity, and Course and Event can specialize as appropriate for their classes.
By providing a common parent class, you can maintain the user’s schedule as an ArrayList of Activity objects so the schedule can hold both Courses and Events!
UML diagram notations
UML uses standard conventions for display of data, methods, and relationships. Many are illustrated in the UML diagram above. Here are some things you should note:
- OR a red square (empty or solid) in front of a class member means private.
+ OR a green circle (empty or solid) in front of a class member means public.
Static members (data or methods) are underlined. They also have a small S notation on the left icon.
Final members (data or methods) have a small F notation on the left icon and the value is typically provided.
Methods embellished with C are constructors.
Methods that are declared but not defined (abstract methods or those declared in interfaces) are in italics.
The names of abstract classes are in italics and there is a small A notation on the class icon.
Dotted arrows with triangular heads point to interfaces from the classes that implement them.
Solid arrows with triangular heads go from concrete classes to their parents.
Solid arrows with simple heads indicate has-a relationships (composition). The containing class is at the tail of the arrow and the class that is contained is at the head. The arrow is decorated with the name and access of the member in the containing class. The arrow is also decorated with the “multiplicity” of the relationship, where 0..1 means there is 1 instance of the member in the containing class and 0..* means there are many (usually indicating a collection such as an array or ArrayList).
A circle containing an X or cross that sits on the border of a class that contains an inner or nested class, with a line connecting it to the inner class.
You can read this UML class diagram and see the names and types of all the classes and class members that you must create. The method signatures in your program must match the above diagram and provided interfaces exactly for the teaching staff tests to run.
Design Changes and Refactoring
In CSC 216, you’ll have the opportunity to explore creating designs. But for programming projects you will be provided with a teaching staff design that you’re expected to implement. However, in the Guided Projects, you can model design changes and decisions that are made while implementing the WolfScheduler system. These changes are common in practice because of additional understanding and knowledge about a solution as it is implemented.
As you consider design changes, you want to make those changes in slow controlled steps and ensure that you don’t break any old functionality before adding new functionality to the system. You can use refactoring to support making small structural changes to the program that provides a better design and allows for extension and modification of a program while not changing the functionality. You can then ensure that your changes do not alter the functionality by running your unit tests!
In the next section you will walk through using one of Eclipse’s built in refactoring tools that will support the extraction of a super class, Activity, as a first step to the inheritance hierarchy shown in the Figure above.
Guided Task: Extract a Super Class
With the new hierarchy design, now you need to move toward implementation. The common elements are already implemented in Course. You can extract those elements into the parent class. Attempting this extraction manually can be messy and can lead to breaking the code. Luckily, Eclipse provides a refactoring tool that helps with extracting a super class, because developers frequently need to make these types of changes in their code.
Learning Outcomes
Use the Eclipse refactoring tool to create a super class
Use automated testing to ensure no regression of functionality
Extract the Super Class
To extract the Activity super class, do the following:
Open Course in the editor.
Right click in the Course class in the editor and select Refactor > Extract Superclass. Make sure you are in the curly braces (e.g., {}) that define Course, otherwise the option to Extract Superclass won’t be available!
Give the superclass the name Activity.
Select the checkboxes next to the following members of Course
UPPER_HOUR
UPPER_MIN
title
meetingDays
startTime
endTime
getTitle()
setTitle()
getMeetingDays()
getMeetingString()
getStartTime()
getEndTime()
setMeetingDaysAndTime()
Any private helper methods that you wrote to support the implementation of the above methods (the teaching staff solution has a helper method getTimeString())
Click Next and verify that you have all the items you need.
Click Next. Eclipse will provide a warning that the visibility of the method getTimeString() will change due to the refactoring. Since the method is used in Course, the method will need to be public so Course can access it. Warnings like this should be noted for review after the refactoring.
Click Next again. You’ll see a list of the changes that will be performed as part of the refactoring. This change will modify most of the classes in the project!
Click Finish.
Check Compilation
Your project should continue to compile after the refactoring is complete. If your code does not compile, you can use Ctrl+Z (Cmd+Z) to undo the refactoring and try again!
Run Tests
Run all of your unit tests on the refactored code. Ensure there are no regressions in functionality.
Update Activity and Course
Now that we have extracted the Activity class, we have a few changes that we need to make to ensure encapsulation of Activity information and provide the additional functionality that Activity needs. Complete the following steps.
Make Activity Abstract
Since Activity is a super class of Course and will soon be the super class of Event, there is no need for Activity to be a concrete class. Instead, Activity should be abstract - that means you cannot directly construct Activity objects. Additionally, we’ll be creating some abstract behavior that we Course and Event will define for their contexts.
Add the abstract keyword to the Activity class header.
publicabstractclassActivity{...}
Make Activity’s Fields Private
When creating the super class, Eclipse set the fields of Activity to protected level access. This means that any sub-class can access the fields directly. However, it also means that another class in the same package can also access the fields directly. To protect your fields, make them private.
Resolve Course Compilation Errors
There will be several compilation errors in Course after you make the fields in Activity private in the hashCode(), equals(), and toString() methods. Do the following to resolve:
Remove hashCode() and equals(). Now that there is a super class, you should regenerate hashCode() and equals() to use the super class. DO NOT do generate a new equals() and hashCode() yet!
In toString(), change direct references to Activity fields to use the associated getter methods.
Run your tests. The tests for Course.hashCode() and Course.equals() will fail. The WolfSchedulerTest.testGetCourseFromCatalog() will also fail because Course.equals() is not yet reimplemented. You’ll fix those shortly!
Create Activity’s Constructor
Activity doesn’t automatically have a constructor. You want to continue to use the one path of construction paradigm. That means you need a way to construct Activity and its fields.
Replace the default Activity constructor with one that requires all of the fields. The parameters MUST be in the order of title, meetingDays, startTime, and endTime. Additionally, update the body of the constructor to use the appropriate setter methods for the fields since all of the error checking is completed there.
After you add a parameterized constructor to Activity, Course no longer compiles. Now, Course needs to call the parameterized Activity constructor.
Update Course’s non-compiling constructor to use Activity’s new constructor. Remember, Activity is the parent of Course. To interact with the parent class, you need to use the super reference.
publicCourse(Stringname,Stringtitle,Stringsection,intcredits,StringinstructorId,StringmeetingDays,intstartTime,intendTime){super(title,meetingDays,startTime,endTime);setName(name);//setTitle(title); <-- DELETE THIS, called in supersetSection(section);setCredits(credits);setInstructorId(instructorId);//setMeetingDaysAndTime(meetingDays, startTime, endTime); <-- DELETE THIS, called in super}
Run your unit tests to make sure that everything is still passing (except for the failures discussed above).
Do the following to add back the hashCode() and equals() functionality in both Activity and Course. Note that you want to generated Activity’s method first since Course’s method will rely on Activity’s.
Use Eclipse’s source generation tools to generate hashCode() and equals() in Activity.
Then use Eclipse’s source generation tools to generate hashCode() and equals() in Course.
Run your unit tests. They should all be passing again!
Add Abstract Functionality to Activity
Adding events will complicate the display of information in the GUI. There will be some items that Course has that Event will not and vice versa. Creating the array of Strings for display in the GUI should instead be delegated to classes in the Activity hierarchy. You will add two abstract methods that will provide a short and a long version of the array of information to provide to the GUI.
Add the statement public abstract String[] getShortDisplayArray(); to Activity.
Add the statement public abstract String[] getLongDisplayArray(); to Activity.
Implement Abstract Functionality in Course
After you add these statements, Course will no longer compile. Select the compiler error on the Course class header and use the Quick Fix to add implementations of these two methods to Course.
Implement the methods in Course as follows:
getShortDisplayArray() returns an array of length 4 containing the Coursename, section, title, and meeting string.
getLongDisplayArray() returns an array of length 7 containing the Coursename, section, title, credits, instructorId, meeting string, empty string (for a field that Event will have that Course does not).
Comment Activity and Course and Fix Static Analysis Notifications
Update all your Javadoc for Activity and Course. Make sure you update all references to Course in the comments for Activity.
Overridden methods much also be commented to describe the specifics in the overridden implementation.
Now is a great time to make sure that CheckStyle, PMD, and SpotBugs are all active on your project. Right click on the WolfScheduler project and select Properties. You can select each tool and make sure it is turned on. Resolve all the notifications.
Create a new Java class called Event in the edu.ncsu.csc216.wolf_scheduler.course package of the WolfScheduler project. Select the following options:
Browse for Activity as the Superclass
Check the option to creating stubs for “Inherited abstract methods”.
Check the option to “Generate comments”.
Implement Event State
The Event class will not yet compile because we do not yet call Activity’s constructor. Before creating a constructor for Event, we want to implement the fields. This way we can integrated the fields when generating our constructor.
Event knows about two other items in addition to those provided by Activity:
an integer called weeklyRepeat
a String called eventDetails.
The fields should be private.
Generate getters and setters for the fields.
Implement Event() Constructor
Generate an Event() Constructor using Event’s fields.
The constructor should have six parameters (title, meetingDays, startTime, endTime, weeklyRepeat, and eventDetails). This is because the Event constructor also needs the parameters to construct the parent Activity. Update the lines that set the fields to call the corresponding setter methods as a common path of error checking.
The setWeeklyRepeat() method should throw an IllegalArgumentException if the weeklyRepeat parameter is less than 1 or greater than 4. The IllegalArgumentException message should be “Invalid weekly repeat”.
Create private constants to represent the minimum and maximum values for the weekly repeats.
Implement Event.setEventDetails()
The setEventDetails() method should throw an IllegalArgumentException if the eventDetails parameter is null. Since eventDetails are optional, the field may contain an empty string. The IllegalArgumentException message should be “Invalid event details”.
Implement Event.getShortDisplayArray()
The getShortDisplayArray() should return a String array of length four. The first two values should be empty strings since Event doesn’t have a name or section. The last two values should be the title and the meeting string.
Implement Event.getLongDisplayArray()
The getLongDisplayArray() should return a String array of length seven. The first two values should be empty strings since Event doesn’t have a name or section. The third value is the title followed by two values with empty strings. The last two are the meeting string and eventDetails.
Override getMeetingString() and toString()
Right click in the editor and select Source > Override/Implement Methods. Check the boxes to getMeetingString() and toString() (which is under Object).
ForgetMeetingString(), append the following to Activity’s getMeetingString(): " (every X weeks)" where X is the value stored in weeklyRepeat. Remember, you can call the parent class’ methods by using super.methodName().
Implement toString() to produce a comma separated string that meets the description in [UC 10].
Overriding Other Methods?
You don’t need to override the equals() and hashCode(). An Event should be considered the same if the title and the meeting information is the same; the number of weeks between meetings and the details aren’t needed for equality. Therefore, you don’t need to override these methods.
Oh no! The test testSetMeetingDaysAndTime() is failing! You will eventually correct the code causing that error in the Debugging section, which comes next.
All of your other tests should pass now, however. If they do not, you will need to debug those tests. It may be helpful to hold on fixing them until after we discuss the debugger.
Comment Event and Fix Static Analysis Notifications
Complete the following tasks:
Update all your Javadoc for Event. Overridden methods much also be commented to describe the specifics in the overridden implementation.
Complete the following tasks before pushing your work to GitHub.
Make sure that all fields, methods, and constructors are commented.
Resolve all static analysis notifications.
Fix test failures.
Commit and push your code changes with a meaningful commit message. Label your commit with “[Implementation]” for future you!
Guided Task: Run the Debugger
You have a failing test case! The test is considering invalid paths of the setMeetingDaysAndTime() functionality for an Event. As defined in [UC6], an Event’s meetingDays are valid for Sunday through Saturday. You’ll represent Sunday with a U and Saturday with an S. That means the meetingDays value of “A” is not valid for Event. The test is failing because you CAN set the meetingDays to “A”. It’s time to use the debugger to find where you need to fix your code.
The debugger is a tool that steps through your program a statement at a time. You can follow the flow of control into a called method. Additionally, the debugger provides a view into the values of variables as the code is executing. It’s a very helpful tool for finding and fixing faults in your code.
Learning Outcomes
Use the debugger to fix a failing test.
Set a Breakpoint
When you debug code, you need to stop the execution so you can then step through the program. A breakpoint pauses the execution of the program. Then you can view information about the program’s state.
When a test fails, you should put a breakpoint at the line of the code under test that you think is causing the failure. For the failure at line 134 in EventTest.testSetMeetingDaysAndTime(), the call to the code under test that you want to investigate is at line 133: event.setMeetingDaysAndTime("A", 0, 0); Double click in the left blue gutter bar to place a breakpoint.
Run the Program through the Debugger
Running the debugger is similar to running a program: right click on EventTest in the Package Explorer and select Debug As > JUnit Test. (Alternative way: There is also a debug button the top level tool bar. Select Debug. In the resulting dialog, select JUnit Test and then the New icon along the top left of the menu. Select your test class, package, or source folder.)
You may get a message about switching perspectives - this is okay. If you check the “Remember my decision,” you will not see this dialog again.
The Debug Perspective provides several views to help you with the task of debugging your code.
Debug shows the live stack trace of methods. The figure illustrates the stack trace in execution of EventTest.testSetMeetingDaysAndTime(). If other programs were running at the same time, you would see them here.
Stepping Buttons are in the top tool bar. The provide the ability to restart execution, stop execution, and step through the code. We’ll cover this in more detail shortly.
Variables shows the values of all the variables that have been declared. If your breakpoint stops before a variable’s declaration, that variable will not appear in the list.
Breakpoints shows the locations of all your breakpoints in the code (you can have many breakpoints).
EventTest.java shows where you are in the code at the time of the breakpoint. The arrow and highlighted text let you know where you are in the code.
Debugger Controls
The main Eclipse toolbar provides buttons for working with the debugger. There are 7 buttons in the toolbar:
Resume: resumes the current execution from the given program point
Suspend: pauses an execution
Stop: stops the debugging execution. Always stop your debugging executions or you’ll use up a lot of system memory!
Disconnect: disconnects the debugger
Step Into: steps into a method call
Step Over: steps over a method call without going into the details of the method
Step Return: finishes execution of the current method and returns to the caller
Step Through a Program
You can use the debugger to determine what is happening in a program and find an underlying bug. By exploring the program, you are likely to have a better understanding of the flow of control and identify where an implementation doesn’t meet the requirements.
Since the breakpoint is at line 133 in EventTest with the program statement event.setMeetingDaysAndTime("A", 0, 0);, you now want to step into the method call in order to understand how “A” is being set to the meetingDays field.
Click the Step Into button to transfer the flow of control to the first line of Activity.setMeetingDaysAndTime().
Continue stepping through the method with the Step Over button. You reach the end of the method for the assignment to the meetingDays field without throwing an exception!
At this point you can either Resume or Stop the test run. You know there’s a problem in Activity.setMeetingDaysAndTime().
Debug the Program
The implementation of setMeetingDaysAndTime() in Activity is the implementation extracted from Course. There isn’t an implementation of setMeetingDaysAndTime() that supports Event specifics! You need to make a decision about how to best handle the differences between Course and Event for setMeetingDaysAndTime(). A common implementation in Activity will not work.
The solution is to have Course and Event override the setMeetingDaysAndTime() method. Course and Activity will handle their own checks on meetingDays appropriate for their requirements. Then they will pass meetingDays, startTime, and endTime to Activity.setMeetingDaysAndTime() for the common time checks and assignment of the fields.
Override setMeetingDaysAndTime() in Course and ensure that [UC1] is satisfied.
Override setMeetingDaysAndTime() in Event and ensure that [UC6] is satisfied. Note that for the meetingDays, string “U” represents Sunday and “S” represents Saturday. The other days of week characters are the same as Course. Any other character, including “A”, is invalid
Run Tests
Run your tests! If any are still failing, use the debugger to help you find the problem.
Comment Event and Fix Static Analysis Notifications
Complete the following tasks:
Update all your Javadoc for Course and Event. Overridden methods much also be commented to describe the specifics in the overridden implementation.
Resolve all static analysis notifications.
Additional Resources on the Debugger
This was a very brief overview of using the debugger. If you would like more information, please see the Eclipse Debugger Tutorial.
Complete the following tasks before pushing your work to GitHub.
Make sure that all fields, methods, and constructors are commented.
Resolve all static analysis notifications.
Fix test failures.
Commit and push your code changes with a meaningful commit message. Label your commit with “[Debug]” for future you!
Guided Task: Create ActivityRecordIO
CourseRecordIO handles reading course records from a file to create a course catalog and writing Courses to a file. Now that you have Events that should also be written to an output file (as per [UC10], you need to create a new IO class to handle writing Activity objects.
Create a new Java class called ActivityRecordIO in the edu.ncsu.csc216.wolf_scheduler.io package of the WolfScheduler project. Do not create the constructor or any methods in ActivityRecordIO.
Move writeCourseRecords() to ActivityRecordIO
Complete the following steps to move writeCourseRecords() from CourseRecordIO to ActivityRecordIO.
Open CourseRecordIO in the editor.
Select the writeCourseRecords method name in the editor. You only want to select the method name.
Right click on the writeCourseRecords method name and select Refactor > Move.
Browse for ActivityRecordIO. Uncheck the options to keep original member as delegate to moved member.
The method is now in ActivityRecordIO. WolfScheduler and CourseRecordIOTest have been udpated with the change.
Refactor the method name in ActivityRecordIO. Select the method name, right click on the method and select Refactor > Rename. Enter writeActivityRecords and click Enter.
Update the generic parameter of the ArrayList to be Activity instead of Course.
Update the local variables in the for loop. You can use the keyboard short cut of Alt + Shift + R to do the rename refactoring.
Change c to a
Change courses to activities
Delete the import for Course since it is no longer needed.
At this point, there will be a compilation error in WolfScheduler.exportSchedule(). That’s ok. We’ll fix it later.
The complication error in CourseRecordIOTest we’ll fix after you check that ActivityRecordIO is complete.
After you are done, ActivityRecordIO should look like the following:
packageedu.ncsu.csc216.wolf_scheduler.io;importjava.io.File;importjava.io.IOException;importjava.io.PrintStream;importjava.util.ArrayList;importedu.ncsu.csc216.wolf_scheduler.course.Activity;/**
* Writes activities to file.
* @author Sarah Heckman
*/publicclassActivityRecordIO{/**
* Writes the given list of Courses to
* @param fileName file to save to
* @param activities list of course to save
* @throws IOException if the file cannot be written
*/publicstaticvoidwriteActivityRecords(StringfileName,ArrayList<Activity>activities)throwsIOException{PrintStreamfileWriter=newPrintStream(newFile(fileName));for(Activitya:activities){fileWriter.println(a.toString());}fileWriter.close();}}
Update CourseRecordIOTest
There is a call to ActivityRecordIO in CourseRecordIOTest that is not compiling. This is because we changed the parameter type from an ArrayList of Courses to an ArrayList of Activitys. We’ll need to update the ArrayList generic type in our test.
Update the first line of the test method to ArrayList<Activity> courses = new ArrayList<Activity>();. You’ll need to import Activity for the test to compile.
Run Tests
Run your tests! You’ll get a warning because WolfScheduler is not compiling, but you can run anyway to make sure that CourseRecordIOTest passes. If any are still failing in the course or io packages, use the debugger to help you find the problem. For now, the WolfScheduler tests may fail due to compilation errors.
However, your suite of tests is not sufficient to evaluate if events are correctly written to file. Create a class ActivityRecordIOTest the edu.ncsu.csc216.wolf_scheduler.io package of the test/ folder in the WolfScheduler project. Copy in the provided ActivityRecordIOTest code into ActivityRecordIOTest. Create a new text file in the test-file/ directory called expected_activity_records.txt and copy the provided expected_activity_records.txt. Run the tests. Ensure they all pass!
Comment ActivityRecordIO and Fix Static Analysis Notifications
Complete the following tasks before pushing your work to GitHub.
Make sure that all fields, methods, and constructors are commented.
Resolve all static analysis notifications.
Fix test failures.
Commit and push your code changes with a meaningful commit message. Label your commit with “[Implementation]” for future you!
Independent Task: Update WolfScheduler
There are several updates required for WolfScheduler to work with the Activity hierarchy.
Learning Outcomes
Refactor WolfScheduler to use Activity polymorphically.
Update WolfSchedulerTest
Download the updated WolfSchedulerTest. You can use the tests to help you drive your development. The details of the changes are outlined in the following steps.
Update WolfScheduler
There are several tasks that you will need to complete to update WolfScheduler to pass the provided tests.
Update schedule Field
The first change is to update the generic type of the scheduleArrayList. A schedule can now contain Events. Update the generic type to Activity so you can store both Courses and Events in the schedule. Update the field reference and the construction of schedule in WolfScheduler.WolfScheduler().
There will be additional compilation issues that you will resolve in the next steps.
Update addCourseToSchedule()
Since schedule’s type is now Activity rather than Course, the reference returned from a call to .get() cannot be assigned to a Course reference without a cast. Casting should be avoided when it makes the class less cohesive. In this case, that means WolfScheduler should focus on adding Activity objects rather than casting to figure out if an object is a duplicate or not. To avoid casting in WolfScheduler, we’ll create a new abstract method in Activity that will be implemented in Course to check for duplicate Courses and in Event to check for duplicate Events.
The check that is done at this portion of the code is to see if the Course to be added is a duplicate of a Course already in the schedule – see [UC4]. [UC6] describes a similar situation for Event. The idea of duplicate Courses and Events is different from the definition of equality in the equals() methods. Keeping a full comparison is beneficial for testing and may be useful in other situations. So now add a new abstract method to Activity that both Course and Event can implement. The method will check if some other Course or Event is a duplicate.
Add the abstract method public abstract boolean isDuplicate(Activity activity); to Activity.
Implement the methods in Course and Event.
You will need to check if the parameter is an instance of Course and cast to check Course’s fields. But this is similar to how the equals() method works and fits the Course abstraction of identifying a duplicate of itself. You should also cast Event so that you can ensure the object is an Event. An Event and Course can have the same title, but two Events and two Coursess cannot!
Update WolfScheduler.addCourseToSchedule() to use the new isDuplicate() method.
Comment all your updates!
Update removeCourseFromSchedule()
removeCourseFromSchedule() requires a larger refactoring. The remove functionality is the same for both Courses and Events. However, the current removeCourseFromSchedule() method has parameter specific to Course. By updating the method signature, you can update the method to handle any object in the Activity hierarchy.
Select the removeCourseFromSchedule method name. Right click and select Refactor > Change Method Signature.
In the resulting dialog, remove the two existing parameters and add a new parameter of type int called idx. The default value (used for replacement of the parameters in the refactoring) should be -1. Make sure the “Keep original method as delegate to change method” is unchecked. Click OK.
The dialog will warn of compilation errors due to the change. We’ll fix those in a moment. Click Continue.
Rename removeCourseFromSchedule() to removeActivityFromSchedule(). Use Alt+Shift+R for the keyboard shortcut.
Fix the compilation errors so that the removeActivityFromSchedule() method compiles. The parameter idx is the index of the Activity you want to remove from the schedule. Note that the fix can be completed by removing the for loop and delegating to the ArrayList’s remove(idx) method. You’ll want to catch any IndexOutOfBoundsExceptions and return false.
Update resetSchedule()
Fix the resetSchedule() method so that the method compiles and passes its test case.
Update getCourseCatalog(), getScheduledCourses() and getFullScheduledCourses()
Update getCourseCatalog() to include a forth column that provides the meeting string information.
You created abstract methods in Activity that support returning an array for Courses and Events. Refactor getScheduledCourses() and getFullScheduledCourses() to use the Activity.getShortDisplayArray() and Activity.getLongDisplayArray() methods. Note that instead of assigning the cells individually, you can use the Activity.get*DisplayArray() method to assign the result at row i.
Additionally, rename the methods to getScheduledActivities() and getFullScheduledActivities().
Implement addEventToSchedule()
The functionality for adding a Course is separate from adding an Event. Implement the addEventToSchedule() method that is called in the WolfSchedulerTest class. The method headers should be:
If the new Event is a duplicate of an existing Event in the schedule, an IllegalArgumentException should be thrown with the message “You have already created an event called [event title]”.
Run Tests
Run your tests! If any are still failing, use the debugger to help you find the problem.
Comment WolfScheduler and Fix Static Analysis Notifications
Run WolfSchedulerGUI and ensure that you pass the new and updated suite of system tests for the WolfScheduler project. As part of running your tests, you must report the actual results of execution. Download the document as a Word document by select File > Download > Microsoft Word in Google Drive. Create a new folder in your WolfScheduler project called project_docs by right clicking on WolfScheduler and selecting New > Folder. Save your black box test plan as a Word document (*.doc or *.docx) in the project_docs folder. As you run each test, report the results of execution in the black box test plan in the actual results column. DO NOT record, “Passed” or “Failed.” Instead, describe the results, similar to the provided Expected Results.
Make sure all your black box tests pass! However, if you run out of time, report the actual results of execution - EVEN IF THEY ARE FAILING! You’ll earn some points on the system test portion of the grading rubric for reporting actual, failing results.
Run WolfSchedulerGUI and ensure that you pass the extended suite of system tests for the WolfScheduler project.
The Black Box Test Plan is stored on Google Drive. As part of running your tests, you must report the actual results of execution. Download the document as a Word document by select File > Download > Microsoft Word in Google Drive. Create a new folder in your WolfScheduler project called project_docs by right clicking on WolfScheduler and selecting New > Folder. Save your black box test plan as a Word document (*.doc or *.docx) in the project_docs folder. As you run each test, report the results of execution in the black box test plan in the actual results column. DO NOT record, “Passed” or “Failed.” Instead, describe the results, similar to the provided Expected Results.
Make sure all your black box tests pass! However, if you run out of time, report the actual results of execution - EVEN IF THEY ARE FAILING! You’ll earn some points on the system test portion of the grading rubric for reporting actual, failing results.
If you haven’t been commenting your code all along, go back and comment your code with Javadoc. All classes, methods, and fields should be commented. If you have been commenting as you have implemented the Activity hierarchy, go back and double check that the comments are up to date for the implemented functionality.
Make sure you include comments for overridden method that describe why the override was important.
Generate Javadoc for WolfScheduler. You may want to delete the existing doc/ folder before generating a new one to ensure that all Javadoc is updated. Double check that everything was generated!
Make sure that all code is pushed to GitHub by the assignment deadline. There are deductions for any late work up to 48 hours.
Grading Rubric
Your Wolf Scheduler Guided Project 2 will be evaluated on the following items:
Overall Rubric
Phase
Grade Item
Points
Details
Total Points
0
Deductions
Grade Item
Points
Details
Misnamed file or incorrect project structure
-5
Incorrect names of files or incorrect project structure. This can include problems when importing the project to Eclipse for acceptance testing, incorrect location of the system test file, incorrect file extension, etc.
Other deductions
-5
If the project has to be manually graded due, you will receive a 5 point deduction. Make sure that your project builds on Jenkins!
Complete the following tasks before pushing your work to GitHub.
Make sure that all fields, methods, and constructors are commented.
Resolve all static analysis notifications.
Fix test failures.
Commit and push your code changes with a meaningful commit message. Label your commit with [Test], [Static Analysis], [Fix], [GUI], [Documentation] as appropriate for the change and for future you!
Check Jenkins results for a green ball! Fix any Jenkins issues.
Grading Rubric
Your Wolf Scheduler Guided Project 2 will be evaluated on the following items:
Overall Rubric
Phase
Grade Item
Points
Details
Total Points
0
Deductions
Grade Item
Points
Details
Misnamed file or incorrect project structure
-5
Incorrect names of files or incorrect project structure. This can include problems when importing the project to Eclipse for acceptance testing, incorrect location of the system test file, incorrect file extension, etc.
Other deductions
-5
If the project has to be manually graded due, you will receive a 5 point deduction. Make sure that your project builds on Jenkins!
Javadoc Rubric
Item
Strong - 3 points
Adequate - 2 points
Inadequate - 1 point
Jenkins Server
We are using the Jenkins Continuous Integration system to automatically evaluate your work and provide feedback on your submission. Go to the [Guided Project and Project Jenkins Server by using https://csc216-jenkins.csc.ncsu.edu. NOTE: The Jenkins servers for CSC216 are self signed and are maintained by the CSC216 teaching staff and CSC IT. Please select the option to accept the signed certificate. Usually, there’s a link for Advanced that will display an option to trust the certificate.