Introduction
A small parcel desk needs comparable offers from different shipping rules. For a 500-gram parcel, the prepared rate data describes Town at 600 cents and Steps at 200 cents. You will make those normal offers real, then examine the weight boundary that changes a price.
This lab assumes Java classes, constructors, methods, lists and basic polymorphism. It introduces an interface and an explicit quotation result. The parser and launcher are supplied; you implement the actual eligibility and price decisions. Author-estimated time includes reading and ordinary corrections.
Give a Flat Rule a Public Contract
In this step, you will read an existing Java interface and result object, then implement only the decision inside one rule method. A normal 500-gram parcel should cost 600 cents with Town. You will make that first real offer work before adding the stepped rule.
Open WebIDE. Choose File → Open Folder... in WebIDE, enter /home/labex/project/parcels in the path field and click OK. Wait until EXPLORER shows PARCELS. Choose Terminal → New Terminal to open the integrated terminal panel. This folder is the whole project for this lab. The file tree contains src/, data/, work/ and quote.sh. The editor's file tabs stay inside WebIDE; use its integrated terminal for program commands rather than looking for a separate product Terminal tab.
In the integrated terminal, change to the project directory. cd changes the working directory of this shell; if you create another terminal, repeat it. The JDK and source framework are ready, so there is no build-tool installation.
cd /home/labex/project/parcels
cat displays a file without changing it. Read the small rate table:
cat data/rates.tsv
The file uses TSV: tab-separated fields without a header. A flat row contains type, rule ID, maximum grams and cents. A step row adds step grams before the per-step cents. Town allows up to 2,000 grams for 600 cents. Steps allows up to 5,000 grams and charges 200 cents for each started 500-gram step. Do not change these original records to force a price.
Expand src in the file tree and open ShippingRule.java. An interface defines methods a caller can use without knowing an implementation class. Its two methods promise an ID and a quote for a parcel. Then open Quote.java and compare the two creation methods: priced sets eligibility to true, whereas unavailable sets it to false. The stored zero in an unavailable result is not a free offer.
The public contract is ShippingRule.id() and ShippingRule.quote(Parcel), with Quote.eligible() and Quote.cents(). RuleFactory.flat(String, int, long) and RuleFactory.stepped(String, int, int, long) create rule objects; QuoteEngine.bestRules(Parcel, List<ShippingRule>) returns every winning rule ID. These signatures let the same caller use different implementations. You may organize implementation classes differently, including changing RuleFactory to construct them. Keep these public methods and the supplied command/output format working; class names inside the factory and your editor are not assessed.
Supported parcel weights are integers from 1 through 1,000,000 grams. Rule maximums and step sizes are integers from 1 through 1,000,000; each flat price or step price is an integer from 0 through 1,000,000 cents. A zero-cent eligible offer is valid. It differs from Quote.unavailable(), whose eligible() is false and whose stored cents must not participate in comparison. A long stores calculated cents, so a large valid product does not overflow a 32-bit int. All rates, people and parcel names are synthetic; these are not live carrier prices.
Now open FlatRule.java. The fields and constructor already store the ID, maximum grams and cents. implements ShippingRule means this class supplies the interface's public methods. Calling rule.quote(parcel) selects the implementation of that object at runtime; a caller does not need a cast or a branch for a carrier name. Parcel already provides read-only access to ID, name and grams, so none of its fields need editing.
Before editing, make a source-only backup. cp copies its first path to the second; this copies one Java file into work/, not your parcel or rate data. Make this backup before your first edit, and do not overwrite it with a broken version later.
cp src/FlatRule.java work/FlatRule.java.before-edit
Return to the FlatRule.java editor tab. Click inside the source editor. Press Ctrl+F (Command+F on macOS) to open the editor's Find field. Enter public Quote quote(Parcel parcel) in the Find field. Close Find with its × button and click the source again before selecting or typing; otherwise you may edit search text instead of Java. Its body currently contains a placeholder comment and return Quote.priced(0);. Select only those two lines inside the method. Keep the method signature, its enclosing braces, fields, constructor and id() unchanged.

Only the TODO comment and zero-price return are selected. Keep the method signature and its braces.
Predict the boundary first: should exactly 2,000 grams be allowed? What changes at 2,001? Reject only a weight greater than the configured maximum, then return the configured cents for every remaining parcel. Type this small method body in place of the placeholder:
if (parcel.grams() > maxGrams) return Quote.unavailable();
return Quote.priced(cents);
return immediately ends the method. Therefore an overweight parcel never reaches the priced result, and > leaves the inclusive maximum eligible. Choose File → Save for FlatRule.java and wait until its tab shows the close ×. Auto Save may already be enabled; leave it as it is. Then return to the same integrated terminal. Read the saved disk version before compiling:
cat src/FlatRule.java
Confirm that the two new statements, including their final semicolons, appear inside quote. If the printed source still has the old text, return to the correct file tab, choose File → Save again, wait for the saved state, and repeat this read. Continue only when the disk text contains your intended edit.
./quote.sh runs the provided launcher. It compiles src/*.java with javac -encoding UTF-8 into a temporary directory and starts Java with UTF-8 text encoding. Every run builds the saved sources again; old class files cannot hide an edit that failed to compile.
./quote.sh quote 500
The quote command accepts grams and prints each rule ID with integer cents or UNAVAILABLE. Town should show 600. Steps still shows 0 because its method is intentionally unfinished; that placeholder is not a real free offer. You have made the first usable Town quote through the common interface.
Now test your boundary prediction:
./quote.sh quote 2000
./quote.sh quote 2001
Town must change from 600 to UNAVAILABLE, while the original rate table remains untouched. Check this step before continuing.
If compilation fails, read the named source file and line in the terminal. Open that file in the tree and locate the reported line in the editor. For example, a missing semicolon after a return statement can produce ';' expected. Correct that small edit in the named file tab, choose File → Save, confirm saving has completed, and read cat src/FlatRule.java to check the disk version before rerunning the same launcher command; do not continue interpreting prices from a failed build. If you edited the wrong part of FlatRule, cp work/FlatRule.java.before-edit src/FlatRule.java restores only that source file to its initial unfinished form. Reopen it, repeat the local method edit, save and run again. This does not restore or overwrite data/, and rerunning setup is not a recovery method. An incorrect command path is fixed by repeating the documented cd and checking the filename.
Charge for Every Started Weight Step
In this step, you will reuse the same interface and edit only the stepped rule's quotation method. Your working FlatRule remains in place; do not replace its class again.
Continue in WebIDE, with its integrated terminal in /home/labex/project/parcels. Open StepRule.java from the file tree. Read the existing fields and constructor: the maximum weight, step grams and cents per step are parameters of this object. This is different data behind the same ShippingRule interface, not a reason to add carrier-specific conditions to the caller.
Predict prices before editing. Every started 500-gram step costs 200 cents: 1–500 grams needs one step, 501–1,000 needs two, and 1,001–1,500 needs three. Thus 500 grams should cost 200 cents and 501 should cost 400. Ordinary integer division truncates: 501 / 500 is 1 and would undercharge. For positive grams, (grams + stepGrams - 1L) / stepGrams rounds the number of steps upward. The L makes that arithmetic use long; multiplying the count by stepCents also uses long.
Make a backup of this source before its first edit:
cp src/StepRule.java work/StepRule.java.before-edit
Use the same editor Find and save workflow taught in the first step. Find public Quote quote(Parcel parcel) in StepRule.java. Replace only its placeholder comment and zero-price return inside the method; keep all other code. Check the maximum first, then calculate a whole number of started steps and multiply by the per-step cents:
if (parcel.grams() > maxGrams) return Quote.unavailable();
long steps = (parcel.grams() + stepGrams - 1L) / stepGrams;
return Quote.priced(steps * stepCents);
Save the file and run a normal quote in the integrated terminal:
./quote.sh quote 500
Expected output, with tab-separated columns:
Town 600
Steps 200
Both rules now return genuine offers through the same contract. Check the step boundary and then the eligibility boundary:
./quote.sh quote 501
./quote.sh quote 5001
At 501 grams Steps must show 400, matching your prediction. At 5,001 both rules show UNAVAILABLE. This is a valid weight with no offer, not an invalid parcel. The qualification check prevents a misleading price outside the service limit.
Try zero grams deliberately. Do not redirect this expected failure over a useful output file:
./quote.sh quote 0
It intentionally reports INVALID_WEIGHT SAMPLE and exits with status 2, without changing your source or original rate records. Recover by supplying a valid weight:
./quote.sh quote 1500
Both rules now show 600: a real tie for the next lab to handle. Eligibility and pricing belong to replaceable rule objects, while the caller only needs the interface. If you make a source error, use the compiler filename/line, correct and save the method, then rerun. To restart only this source edit, cp work/StepRule.java.before-edit src/StepRule.java restores the initial StepRule; it leaves FlatRule and every data record intact. Complete the method again before checking the step.
Summary
You implemented two rules behind one Java interface, kept eligibility separate from integer cents, and exercised exact limits and started-step rounding. The same caller can now obtain meaningful prices without knowing which implementation supplies them.



