Instructions
In this assignment, you will create a class that can be used in other applications to write log messages (for example, progress or error messages) to a specified file and standard out. This class will be implemented using the Singleton pattern, so that the management and access of a specific logger is always conducted via a single instance of the class. Using this pattern, a client application can safely use the Event Logger from different areas of the same application - even on different threads - without danger of corrupting the output files.
The section Lab Submission contains step-by-step instructions you need to follow while doing the lab, so please read at least that far before getting started.
Assignment Overview
The following class diagram illustrates the EventLogger
class you will implement, along with two other classes (EventLoggerClientApp
and ClientUI
) that essentially serve as a test harness. You can download the latter two files from eventloggerfiles.zip. Each contains one or two “TODO” statements where you have to make some modifications to the existing code.
Your implementation of EventLogger must be capable of creating and managing one unique EventLogger
object (instance) for each unique logfile specified in the static getInstance()
method. Note the HashMap (a data structure you studied in CS2852) used as the mechanism to associate a single EventLogger
instance with each specified logfile.
Assignment Details
The following sequence diagram illustrates two ClientUI's making calls to the static getInstance()
methods of EventLogger
. (The actual app creates four ClientUI instances). The order of calls here is arbitrary - the call sequence is entirely dependent upon how you run the test harness.
The point to be taken is this: note that an EventLogger
object is only instantiated on the very first call to getInstance()
for a particular logfile (note that the logfile name should be treated in a case-insensitive fashion). Second (and subsequent) calls to getInstance()
, using the same filename, return the same reference to the already-created EventLogger
instance. Each new logfile specified in the call results in a new instance of EventLogger
that will be associated with that specific file. You (as the implementor) decide whether a new instance of EventLogger
needs to be created within getInstance()
by first determining whether the static HashMap already contains a given EventLogger (value) for the specified file (key) (recall that a Map is a data structure associating key-value pairs).
The logEvent()
method should, in addition to writing the message to the file, print the message to standard out, prefixed by the filename. For example, if logging "Program started" to "warnings.txt", the logEvent
method should also print warnings.txt: Program started
to System.out. You may modify the UML diagram to make it easier to get "warnings.txt" if desired.
Be certain to implement the same thread-safety mechanisms into your implementation of getInstance()
as discussed in lectures on the Singleton pattern, since this method may be called from more than one thread. Also, be sure to access HashMap in a thread-safe manner.
Within the getInstance()
itself, call the logEvent()
method so that you log a message indicating whether you either:
- returned a reference to a new instance of
EventLogger
- returned a reference to a previously-created instance
Finally, note that the logEvent()
method may (will) also be called from multiple threads, so be sure to implement the appropriate code to make it thread-safe as well!!!
Lab Submission
Demonstrations
About 1 hour into the lab, please demonstrate what you have accomplished from the list below. For this lab, the steps below are best performed in order, as each step builds on the one before. You only need to include the code for the final step in your zip, but discuss all the steps in your report.
- Comment out the "TODO" lines and associated code that prevents a compile. You will come back to them later. In ClientUI.actionPerformed(), call EventLogger.getInstance and eventLogger.logEvent instead of creating a thread to run logSomeEvents.
- Write a logger that does not use the singleton pattern. See the section "Without and with Singleton" in the report submission section below. For this step, you may write to a hard-coded log file, ignoring or not taking the path to the log file, so you don't have to handle that yet. Your code should not close the log file. (You may wish to "flush" the file to ensure the log message is written.)
- Implement the Singleton pattern. See the "Without and with Singleton" section again.
- Extend your singleton to include multiple instances, one for each log file. See section "Hashing" in report outline.
- Include all of the TODO's in the code. Run tests with these. See section "Stress testing."
Submission (due Week 5, Wednesday)
Submit your report using this plain-text template. Follow this format:
- (5 pt.) Title & Introduction: Fill in the information at the top of the template. Very briefly describe the lab.
- (25 pt.) Without and with Singleton: Describe the behavior of the program if multiple instances are created. What happens, and why? Include brief snippets of logs produced with and without the Singleton pattern and explain the difference. (You do not need to include the without singleton code in your source zip, only the final version.)
- (25 pt.) Hashing: Describe how you extended the generic singleton pattern to track multiple instances. Include code-snippets as helpful. Give particular attention to how you handle synchronization (if non-trivial).
- (25 pt.) Stress-testing: Describe any bugs you discovered during the stress tests or why you are confident that your code passed the test. In this stage, include the "TODOs" that you commented-out at the beginning. There are some in each of the provided classes.
- (10 pt.) Conclusions: Summarize what you learned in the lab.
- (10 pt.) Source (Remember to include it in your upload)
- (100 pt. Total)
To go from AB to A on this lab, write an excellent report demonstrating clear understanding of the material and remember to provide javadoc for your methods. Spelling, grammar, flow of thought, depth of insight, correctness of ideas, and even visual appearance of the plain-text file all contribute to an excellent report.
When your zip file is unzipped, it should create a folder "eventlogger" containing your source files. Each source file should include your name, the date, and the course name at the top, and a Javadoc comment for each class and method (within reason.) See the files in the starting zip as an example.
Upload your report and zip file using the form below.
Acknowledgement
This lab is based on a lab by MSOE professors on emerald. This page is the official version. The emerald page is just for historical reference.