Description
Specifications – Use arrays in this project; ArrayLists are not allowed!
Overview: This project is the second of three that will involve the cost and reporting for marketing
campaigns. In Part 1 you developed Java classes that represent categories of marketing campaigns
including direct marketing and indirect marketing (both search engine and social media).
In Part 2,
you will implement four additional classes: (1) CampaignCostComparator that implements the
Comparator interface for MarketingCampaign, (2) ROIComparator that implements the Comparator
interface for MarketingCampaign, (3) MarketingCampaignList that represents a list of
MarketingCampaign objects and includes several specialized methods, and (4)
MarketingCampaignPart2 which contains the main method for the program.
Note that the main
method in MarketingCampaignPart2 should create a MarketingCampaignList object and then call the
readFile method on the MarketingCampaignList object, which will add MarketingCampaign objects
to the list as the data is read in from a file.
You can use MarketingCampaignPart2 in conjunction
with interactions by running the program in a jGRASP canvas (or debugger with a breakpoint) and
single stepping until the variables of interest are created. You can then enter interactions in the usual
way.
In addition to the source files, you may create an optional JUnit test file for each class and write
one or more test methods to ensure the classes and methods meet the specifications. You should
create a jGRASP project upfront and then add the new source and optional test files as they are
created. All of your files should be in a single folder.
• MarketingCampaign.java
Requirements and Design: In addition to the specifications in Part 1, the MarketingCampaign
class should implement the Comparable interface for MarketingCampaign, which means the
following method must be implemented in MarketingCampaign.
o compareTo: Takes a MarketingCampaign object as a parameter and returns an int
indicating the results of comparing the MarketingCampaign object upon which this
method was invoked with the MarketingCampaign object referenced by the parameter
based on their respective name fields ignoring case.
• DirectMC, IndirectMC, SearchEngineMC, and SocialMediaMC
Requirements and Design: No changes from the specifications in Part 1.
• MarketingCampaignList.java
Requirements: The MarketingCampaignList class provides methods for reading in the data file
and generating reports.
Design: The MarketingCampaignList class has fields, a constructor, and methods as outlined
below.
(1) Fields: (1) An array of MarketingCampaign objects and (2) an array of String elements to
hold invalid records read from the data file. [The second array will be used in Part 3.] Note
that there are no fields for the number elements in each array. In this project, the size of the
array should be the same as the number of MarketingCampaign objects in the array. These
two fields should be private.
(2) Constructor: The constructor has no parameters and initializes the MarketingCampaign
array and String array in the fields to arrays of length 0.
(3) Methods: Usually a class provides methods to access and modify each of its instance
variables (i.e., getters and setters) along with any other required methods. The methods for
MarketingCampaignList are described below.
o getMarketingCampaignArray returns an array of type MarketingCampaign
representing the MarketingCampaign array field.
o getInvalidRecordsArray returns an array of type String representing the invalid
records array field.
o addMarketingCampaign has no return value, accepts a MarketingCampaign object,
increases the capacity of the MarketingCampaign array by one, and adds the
MarketingCampaign object in the last position of the MarketingCampaign array. See
hints on last page.
o addInvalidRecord has no return value, accepts a String, increases the capacity of
the invalidRecords array by one, and adds the String in the last position of the
invalidRecords array. This method will be used in the next project, but it still needs to be
tested in this project. See hints on last page.
o readFile has no return value, accepts the data file name as a String, and throws
FileNotFoundException. This method creates a Scanner object to read in the file one line
at a time. When a line is read, a separate Scanner object on the line should be created to
read the values in that line.
The data in each line is separated by a comma so the
delimiter should be set to comma by invoking the useDelimiter(“,”) method on
the Scanner object for the line. For each line read in, the appropriate MarketingCampaign
object is created and added to the MarketingCampaign array field, or if not a valid
category code, the line should be ignored.
The data file has comma-delimited text
records as follows: category, name, and revenue, followed by one or more fields specific
to the category. Remember, DirectMC, IndirectMC, SearchEngineMC, and
SocialMediaMC objects are all MarketingCampaign objects. The category codes are D
for DirectMC, I for IndirectMC, S for SearchEngineMC, and M for SocialMediaMC.
Any other category code is invalid. Below are examples data records in the
marketing_campaign_data_1.csv file that can be downloaded.
M,Web Ads 3,35000.0,3.0,8000
D,Ad Mailing,10000.00,3.00,2000
Z,Web Ads X,30500.0,2.75,6500
I,Web Ads 4,5000.0,2.25,1000
I,Web Ads 1,15000.0,2.0,3500
S,Web Ads 2,27500.0,2.50,5000
o generateReport processes the MarketingCampaign array using the original order
from the file to produce the Marketing Campaign Report and then returns the report as
String. See example result in output for MarketingCampaignPart2 beginning on page 6.
o generateReportByName sorts the MarketingCampaign array by its natural ordering,
and then processes the MarketingCampaign array to produce the Marketing Campaign
Report (by Name), then returns the report as a String. See example result in output for
MarketingCampaignPart2 beginning on page 6.
o generateReportByCampaignCost sorts the MarketingCampaign array by
campaign cost (lowest first), and then processes the MarketingCampaign array to produce
the Marketing Campaign Report (by Campaign Cost) and then returns the report as String.
See example result in output for MarketingCampaignPart2 beginning on page 6.
o generateReportByROI sorts the MarketingCampaign array by ROI (highest first),
and then processes the MarketingCampaign array to produce the Marketing Campaign
Report (by ROI) and then returns the report as String. See example result in output for
MarketingCampaignPart2 beginning on page 6.
Code and Test: See examples of file reading and sorting (using Arrays.sort) in the class notes.
The natural sorting order is based on a MarketingCampaign object’s name and is determined by
the compareTo method when the Comparable interface is implemented for MarketingCampaign.
The following call to Arrays.sort can be used to sort the MarketingCampaign array in
generateReportByName above.
Arrays.sort(getMarketingCampaignsArray());
The sorting order based on a campaign cost is determined by the CampaignCostComparator class
which implements the Comparator interface (described below).
Arrays.sort(getMarketingCampaignArray(), new CampaignCostComparator());
The sorting order based on ROI is determined by the ROIComparator class which implements the
Comparator interface (described below).
Arrays.sort(getMarketingCampaignArray(), new ROIComparator());
If you have an optional test file with test methods for the generate reports methods above, you
may want to use the following assertion to avoid having to match the return result exactly (where
the expected_result is part of what you think it should contain and the actual_result is the result of
the method call.
Assert.assertTrue(actual_result.contains(expected_result));
• CampaignCostComparator.java
Requirements and Design: The CampaignCostComparator class implements the Comparator
interface for MarketingCampaign objects. Hence, it implements the method
compare(MarketingCampaign c1, MarketingCampaign c2)
that defines the ordering from lowest to highest based on the campaign cost. See examples in
class notes.
• ROIComparator.java
Requirements and Design: The ROIComparator class implements the Comparator interface for
MarketingCampaign objects. Hence, it implements the method
compare(MarketingCampaign c1, MarketingCampaign c2)
that defines the ordering from highest to lowest based on the ROI. Hint – the calcROI method
will be invoked as appropriate in this method. See examples in class notes.
• MarketingCampaignPart2.java
Requirements: The MarketingCampaignPart2 class contains the main method for running the
program.
Design: The MarketingCampaignPart2 class is the driver class and has a main method described
below.
o main accepts a file name as a command line argument, creates a
MarketingCampaignList object, and then invokes its methods to read the file and process
the marketing campaign records and then to generate and print the four reports as shown
in the example output beginning on page 6. If no command line argument is provided,
the program should indicate this and end as shown in the first example output on page 6.
An example data file can be downloaded from the assignment page in Canvas.
Code and Test: If you have an optional test file for the MarketingCampaignPart2 class, you
should have at least two test methods for the main method. One test method should invoke
MarketingCampaignPart2.main(args) where args is an empty String array, and the other test
method should invoke MarketingCampaignPart2.main(args) where args[0] is the String
representing the data file name.
Depending on how you implemented the main method, these two
methods should cover the code in main. As for the assertion in the test method, since
BASE_COST is a public class variable in IndirectMC, you could assert that
IndirectMC.BASE_COST equals 1500.0 in each test method.
In the first test method, you can invoke main with no command line argument as follows:
// If you are checking for args.length == 0
// in MarketingCampaignPart2, the following should exercise
// the code for true.
String[] args1 = {}; // an empty String[]
MarketingCampaignPart2.main(args1);
In the second test method, you can invoke main as follows with the file name as the first (and only)
command line argument:
String[] args2 = {” marketing_campaign_data_1.csv”};
// args2[0] is the file name
MarketingCampaignPart2.main(args2);
If Web-CAT complains the default constructor for MarketingCampaignPart2 has not been
covered, you may want to include the following line of code in one of your test methods to exercise
the constructor.
// to exercise the default constructor
MarketingCampaignPart2 app = new MarketingCampaignPart2();
Notes:
1. Passing in command line arguments in jGRASP – On the top menu, click “Build” then turn on
“Run Arguments” by clicking the associated checkbox. Now you can enter the arguments (e.g.,
the filename) in the Run Arguments text box at the top of the edit window containing the main
method. Finally, run or debug the program in the usual way.
2. To run the program with no command line argument, either delete the text entered above.
Alternatively, click “Build” then turn off “Run Arguments” by clicking the associated checkbox.
Then run or debug the program in the usual way.
3. You can also test your program using your own data files.
Example Output when file name is missing as command line argument
MM«M —-jGRASP exec: java MarketingCampaignPart2
MM§MFile name expected as command line argument.
MM§MProgram ending.
MM§M
MM©M —-jGRASP: operation complete.
Example Output for marketing_campaign_data_1.csv
MM«M —-jGRASP exec: java MarketingCampaignPart2 marketing_campaign_data_1.csv
MM§M——————————-
MM§MMarketing Campaign Report
MM§M——————————-
MM§M
MM§MWeb Ads 3 (class SocialMediaMC)
MM§MRevenue: $35,000.00 Campaign Cost: $27,000.00 ROI: 29.63%
MM§M Base Cost: $3,000.00
MM§M Ad Cost: $24,000.00 = $3.00 per ad * 8000 ads
MM§M
MM§MAd Mailing (class DirectMC)
MM§MRevenue: $10,000.00 Campaign Cost: $7,000.00 ROI: 42.86%
MM§M Base Cost: $1,000.00
MM§M Mail Cost: $6,000.00 = $3.00 per mail piece * 2000 mail pieces
MM§M
MM§MWeb Ads 4 (class IndirectMC)
MM§MRevenue: $5,000.00 Campaign Cost: $3,750.00 ROI: 33.33%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $2,250.00 = $2.25 per ad * 1000 ads
MM§M
MM§MWeb Ads 1 (class IndirectMC)
MM§MRevenue: $15,000.00 Campaign Cost: $8,500.00 ROI: 76.47%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $7,000.00 = $2.00 per ad * 3500 ads
MM§M
MM§MWeb Ads 2 (class SearchEngineMC)
MM§MRevenue: $27,500.00 Campaign Cost: $14,500.00 ROI: 89.66%
MM§M Base Cost: $2,000.00
MM§M Ad Cost: $12,500.00 = $2.50 per ad * 5000 ads
MM§M
MM§M—————————————–
MM§MMarketing Campaign Report (by Name)
MM§M—————————————–
MM§M
MM§ Ad Mailing (class DirectMC)
MM§MRevenue: $10,000.00 Campaign Cost: $7,000.00 ROI: 42.86%
MM§M Base Cost: $1,000.00
MM§M Mail Cost: $6,000.00 = $3.00 per mail piece * 2000 mail pieces
MM§M
MM§MWeb Ads 1 (class IndirectMC)
MM§MRevenue: $15,000.00 Campaign Cost: $8,500.00 ROI: 76.47%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $7,000.00 = $2.00 per ad * 3500 ads
MM§M
MM§MWeb Ads 2 (class SearchEngineMC)
MM§MRevenue: $27,500.00 Campaign Cost: $14,500.00 ROI: 89.66%
MM§M Base Cost: $2,000.00
MM§M Ad Cost: $12,500.00 = $2.50 per ad * 5000 ads
MM§M
MM§MWeb Ads 3 (class SocialMediaMC)
MM§MRevenue: $35,000.00 Campaign Cost: $27,000.00 ROI: 29.63%
MM§M Base Cost: $3,000.00
MM§M Ad Cost: $24,000.00 = $3.00 per ad * 8000 ads
M§M
MM§MWeb Ads 4 (class IndirectMC)
MM§MRevenue: $5,000.00 Campaign Cost: $3,750.00 ROI: 33.33%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $2,250.00 = $2.25 per ad * 1000 ads
MM§M
MM§M————————————————-
MM§MMarketing Campaign Report (by Lowest Campaign Cost)
MM§M————————————————-
MM§M
MM§MWeb Ads 4 (class IndirectMC)
MM§MRevenue: $5,000.00 Campaign Cost: $3,750.00 ROI: 33.33%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $2,250.00 = $2.25 per ad * 1000 ads
MM§M
MM§MAd Mailing (class DirectMC)
MM§MRevenue: $10,000.00 Campaign Cost: $7,000.00 ROI: 42.86%
MM§M Base Cost: $1,000.00
MM§M Mail Cost: $6,000.00 = $3.00 per mail piece * 2000 mail pieces
MM§M
MM§MWeb Ads 1 (class IndirectMC)
MM§MRevenue: $15,000.00 Campaign Cost: $8,500.00 ROI: 76.47%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $7,000.00 = $2.00 per ad * 3500 ads
MM§M
MM§MWeb Ads 2 (class SearchEngineMC)
MM§MRevenue: $27,500.00 Campaign Cost: $14,500.00 ROI: 89.66%
MM§M Base Cost: $2,000.00
MM§M Ad Cost: $12,500.00 = $2.50 per ad * 5000 ads
MM§M
MM§MWeb Ads 3 (class SocialMediaMC)
MM§MRevenue: $35,000.00 Campaign Cost: $27,000.00 ROI: 29.63%
MM§M Base Cost: $3,000.00
MM§M Ad Cost: $24,000.00 = $3.00 per ad * 8000 ads
MM§M
MM§M————————————————-
MM§MMarketing Campaign Report (by Highest ROI)
MM§M————————————————-
MM§M
MM§MWeb Ads 2 (class SearchEngineMC)
MM§MRevenue: $27,500.00 Campaign Cost: $14,500.00 ROI: 89.66%
MM§M Base Cost: $2,000.00
MM§M Ad Cost: $12,500.00 = $2.50 per ad * 5000 ads
MM§M
MM§MWeb Ads 1 (class IndirectMC)
MM§MRevenue: $15,000.00 Campaign Cost: $8,500.00 ROI: 76.47%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $7,000.00 = $2.00 per ad * 3500 ads
MM§M
MM§MAd Mailing (class DirectMC)
MM§MRevenue: $10,000.00 Campaign Cost: $7,000.00 ROI: 42.86%
MM§M Base Cost: $1,000.00
MM§M Mail Cost: $6,000.00 = $3.00 per mail piece * 2000 mail pieces
MM§M
MM§MWeb Ads 4 (class IndirectMC)
MM§MRevenue: $5,000.00 Campaign Cost: $3,750.00 ROI: 33.33%
MM§M Base Cost: $1,500.00
MM§M Ad Cost: $2,250.00 = $2.25 per ad * 1000 ads
MM§M
MM§MWeb Ads 3 (class SocialMediaMC)
MM§MRevenue: $35,000.00 Campaign Cost: $27,000.00 ROI: 29.63%
MM§M Base Cost: $3,000.00
MM§M Ad Cost: $24,000.00 = $3.00 per ad * 8000 ads
MM§M
MM§M
MM©M —-jGRASP: operation complete.
Hints
1. Adding an element to a full array in your addMarketingCampaign and addInvalidRecord
methods – Consider the example below where MyType[] myArray is an instance field and
addElement is an instance method that adds newElement to myArray, which is full.
Since the
length of an array cannot be changed after it has been created, myArray must be replaced
with one that has a length of myArray.length + 1 and then elements from the original array
must be copied to the new array.
This copy operation could be done using a loop. However,
Java.util.Arrays provides a copyOf method, which creates the new array and performs the
copy in a single statement as shown in the first statement in the method below.
The second
statement adds newElement as the last element in the array.
public void addElement(MyType newElement) {
myArray = Arrays.copyOf(myArray, myArray.length + 1);
myArray[myArray.length – 1] = newElement;
}
2. The advantage to keeping the array full is that it allows the use of for-each loops with the
array.
for (MyType mt : myArray)
{
// do something with each mt
}
3. In the readFile method, if you use a switch statement to determine the category, you should
use type char for the switch expression rather than String; that is, each of the case labels
should be of type char (e.g., case ‘D’: rather than type String (e.g., case “D”:).
When the switch type is String, the code coverage tool used by Web-CAT fails to detect that
the default case is covered. If category is the reference to the String that contains the
category code, then the following statement returns the category code as type char.
category.charAt(0)