Make Borrowing Rules Part of the Object

JavaBeginner
Practice Now

Introduction

A community tool desk lends physical tools to registered members. Two drills can have the same name while belonging to different loans. A tool under maintenance must stay unavailable, and only the recorded borrower can return a borrowed tool.

You will make these rules part of a Java object, then use a small prepared command loop. This first lab keeps changes in memory; the next lab teaches saving. You should already know Java classes, methods, private fields, lists and basic exceptions. Estimated reading and practice time: 45 minutes.

Borrow One Tool Without Losing Its Identity

In this step, you will run a normal loan, read the prepared object, and add the small rule that protects it from a second loan.

Open the Terminal tab. cd selects the project folder; every later shell command in this lab starts there. If a mistyped line has not run, press Ctrl+U to clear it and retype. For “file not found,” run this cd again rather than resetting the environment.

cd /home/labex/project/tool-library

The prepared application already compiles. javac is the Java compiler, -encoding UTF-8 selects the source encoding, -d out puts compiled classes in out, and *.java selects the Java source files in this folder.

javac -encoding UTF-8 -d out *.java

Successful compilation prints nothing. Compile successfully before every launch after editing; otherwise Java could run old classes. java starts the program, -Dfile.encoding=UTF-8 selects its text encoding, -cp out selects the compiled classes, and Desk is the entry class. desk.tsv supplies the records; --memory disables saving for this lab.

java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv --memory

You are inside the desk program, not the shell. Type each line and press Enter:

borrow A11 M01
list
quit

Expect Accepted: A11 BORROWED M01. A12 is another Drill but stays AVAILABLE: the ID identifies a physical tool, while its name may repeat. quit returns to the shell. This normal loan works before repair, but the code does not yet protect it from being borrowed again. Because this run used --memory, the original file is unchanged and the next run starts afresh.

Read the prepared source with cat, which displays a file without editing it:

cat Tool.java

A tool stores a stable id, display name, state, borrower and note. An enum has a fixed set of named values: AVAILABLE means nobody holds the tool, BORROWED means a member holds it, and MAINTENANCE blocks borrowing. The dash - means no borrower. The private fields can change only through methods. Read borrow: it currently assigns BORROWED and a new member without checking the old state. Predict what a second loan would overwrite. The constructor, getters and enum are already complete; keep them.

The command framework is also prepared:

cat Desk.java

Find the call found.borrow(c[2]) and its surrounding try/catch. The loop checks whether a member ID exists, but a Tool must protect its own state. An IllegalArgumentException becomes Rejected: ... and the loop stays open. The state check must happen before either assignment; throwing after mutation would leave a refused loan partly applied.

Before editing, make a source-only backup. mkdir -p creates a folder if needed; cp copies a file. These are your own backup files, not completed answers. Do not copy or reset the desk/member data.

mkdir -p work
cp Tool.java work/Tool-before-borrow.java.txt

Open the existing file in nano, a terminal text editor:

nano Tool.java

In nano, ^ in the shortcut bar means Ctrl. Hold Ctrl while pressing the other key; do not type the caret. Press Ctrl+W, type state = State.BORROWED;, and press Enter to find the assignment inside borrow. Press Ctrl+A to move to the beginning of that line. Use arrow keys to position the cursor and Backspace to correct characters. Insert this guard above the assignment, leaving the two existing assignments and the rest of the class in place:

        if (state != State.AVAILABLE) {
            throw new IllegalArgumentException("Tool is not available");
        }

Here != means “is not equal to.” The condition refuses both an existing loan and maintenance; it does not change identity, name or note. Write the branch into your existing method rather than replacing the class. Check the braces and semicolon.

Press Ctrl+O to save, Enter to confirm the existing filename, then Ctrl+X to exit. To abandon an unsaved mistake instead, press Ctrl+X and answer N at the save prompt. Reopen the file to try again. At the shell, nano Tool.java opens it again; Ctrl+W finds the same anchor. For a compiler error, read its filename and line, repair that location in nano, save and recompile. Do not launch after a failed compile.

If you need to undo all of this step's source edits, the following recovery command restores only your earlier Tool.java backup. It loses those edits, so use it only when you intend to start this source edit again; it never resets data. This is a recovery option, not a normal next step:

cp work/Tool-before-borrow.java.txt Tool.java

After saving the guard (or redoing it after recovery), compile and launch:

javac -encoding UTF-8 -d out *.java
java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv --memory

Type these desk commands in order:

borrow A11 M01
list
borrow A11 M02
borrow A13 M01
borrow TYPO M01
borrow A12 M02
list
quit

The first loan is accepted. The duplicate loan and maintenance loan are intentionally refused with Rejected: Tool is not available. TYPO produces an unknown-ID refusal; correct the ID on the next line without resetting. A12 can still be borrowed independently by M02. The final list must retain A11 → M01 and A13's maintenance state and note. quit returns to the shell; desk.tsv remains unchanged. The return method is still incomplete and is the next step's work.

Allow Only the Recorded Borrower to Return a Tool

In this step, you will complete the reverse transition while preserving other loans.

Start in the same Terminal tab, at the shell prompt. Returning is legal only from BORROWED, and only when the supplied member matches borrower. For Java strings, .equals() compares their contents; ! negates that comparison. Once both checks pass, set the state to AVAILABLE and clear the borrower to -. Throwing first prevents a failed return from partly changing the object.

Keep your borrowing guard. Before the next edit, make a new source-only backup so recovery will retain the completed borrow method:

cp Tool.java work/Tool-before-return.java.txt
nano Tool.java

Press Ctrl+W, search for state = State.AVAILABLE;, and press Enter. This is the first assignment inside giveBack. Press Ctrl+A to start that line. Insert the two checks below before it; keep the existing state assignment and borrower = "-"; after both checks. Do not replace the class or remove the borrow guard.

        if (state != State.BORROWED) {
            throw new IllegalArgumentException("Tool is not borrowed");
        }
        if (!borrower.equals(member)) {
            throw new IllegalArgumentException("Borrower does not match");
        }

The first branch rejects an available or maintenance tool. Only a borrowed tool reaches the identity check. Compare the member with the recorded borrower, not with a display name. Check the braces, then Ctrl+O, Enter, Ctrl+X to save and exit. For an unsaved mistake, Ctrl+X, N abandons it. Correct compiler errors by reopening and searching the relevant method; compile successfully before launching. To deliberately discard this step's edits while keeping the borrow guard, use cp work/Tool-before-return.java.txt Tool.java, then redo only the return edit. Do not restore the older before-borrow backup.

Compile again so the running program will use your current source, then open a new in-memory desk. Each run starts from the original file in this lab.

javac -encoding UTF-8 -d out *.java
java -Dfile.encoding=UTF-8 -cp out Desk desk.tsv --memory

Type these desk commands in order:

list
return A14 M01
return A13 M03
return A14 M03
borrow A14 M02
list
quit

The first list shows the existing loan A14 → M03. The wrong borrower gets Rejected: Borrower does not match. Returning the maintenance tool gets Rejected: Tool is not borrowed. Neither refusal changes the object. The correct return produces Accepted: A14 AVAILABLE -, and M02 can then borrow it. A13 stays under maintenance; A11 and A12 keep separate IDs and notes.

You have expressed two allowed arrows: AVAILABLE → BORROWED and BORROWED → AVAILABLE. There is no return arrow from MAINTENANCE, and this application does not provide a maintenance-management command. A refusal is a normal business result; it does not end the command loop. You can run the program again to practise. Changes deliberately disappear after quit in this lab; keep your source, and continue to the independent persistence lab to learn why.

Summary

You used an enum and private object state to protect tool loans. Same-name tools kept separate IDs, invalid actions preserved the object, and a valid return made a tool available for another member. Saving across runs is the next learning goal.