Part 1 recap: events, parsing, exceptions, serialize & restore
The non-concurrent half: parameterized events, parsing examples*.txt with Scanner + regex, a custom ControllerException, an orderly shutdown that logs to error.log, serializing the whole controller to dump.out, and a Restore that resumes from it via a Fixable factory.
What Part 1 adds to the skeleton
The starter GreenhouseControls hard-codes its schedule. Part 1 turns it into a real, fault-tolerant program by adding six things, each a topic from earlier modules made concrete.
### 1. Parameterized events
The starter Bell rings once. Part 1 makes it ring rings times — and the event files declare it: Event=Bell,time=9000,rings=5 (see examples2.txt). So Bell gains a second constructor argument and a loop in action():
public class Bell extends Event {
private int rings;
public Bell(long delayTime, int rings) {
super(delayTime);
this.rings = rings;
}
public void action() {
for (int i = 0; i < rings; i++) System.out.println("Bing!");
}
}
examples2.txt also introduces FansOn / FansOff — proving the framework extends by *adding an inner Event subclass*, never by editing the controller.
### 2. Parse the event file with Scanner + regex
Each line looks like Event=LightOn,time=2000 (optionally ,rings=5). You read the file with a Scanner and pull the fields with a capturing regex (Module 4): a group for the event name, a group for the time, an optional group for rings. The captured name string is what later (Part 2) feeds reflection.
Pattern p = Pattern.compile("Event=(\\w+),time=(\\d+)(?:,rings=(\\d+))?");
Matcher m = p.matcher(line);
if (m.matches()) {
String name = m.group(1);
long time = Long.parseLong(m.group(2));
// m.group(3) is null when ,rings= is absent
}
### 3. A custom checked exception
A fault — a stuck window, a power cut — is a *recoverable* condition the caller must handle, so it is a checked exception (extends Exception, Module 3):
public class ControllerException extends Exception {
public ControllerException(String why) { super(why); }
}
The new fault events throw it: WindowMalfunction and PowerOut (added in examples3.txt / examples4.txt) throw new ControllerException(...) from action().
### 4. Orderly shutdown that logs
When run() catches a ControllerException, it does not crash — it calls shutdown(), which records the failure to error.log (append mode + a timestamp, Module 8) and then exits cleanly. This is the *fault* half of the project.
### 5. Serialize the whole controller
GreenhouseControls is made Serializable, so on certain faults the program can write its entire object graph — controller, event list, current state — to dump.out with an ObjectOutputStream (Module 8). The clock-related fields are marked transient (absolute times are meaningless after a reload).
### 6. Restore from the dump
Run with -d dump.out and a Restore path deserializes that file with an ObjectInputStream, calls start() on each surviving event to re-base its time onto *now*, and resumes the run() loop — the program picks up where it crashed.
The Fixable factory ties it together
Faults map to fixes through an interface used as a factory (Module 2.3). A Fixable declares fix() and log(); a getFixable(int errorcode) method returns the right Fixable for each error code — so adding a new fault is adding a case, not rewriting the recovery logic:
public interface Fixable {
void fix();
void log();
}