CounterApp.java
package com.guinetik.hexafun.examples.counter;
import com.guinetik.hexafun.HexaApp;
import com.guinetik.hexafun.HexaFun;
import com.guinetik.hexafun.fun.Result;
import com.guinetik.hexafun.examples.counter.CounterInputs.*;
import static com.guinetik.hexafun.examples.counter.CounterUseCases.*;
import static com.guinetik.hexafun.examples.counter.CounterValidators.*;
/**
* Counter application demonstrating the improved HexaFun DSL.
*
* <p>Key improvements showcased:
* <ul>
* <li>Type-safe keys (UseCaseKey) instead of strings</li>
* <li>Cleaner syntax: validate/handle instead of from/to</li>
* <li>Implicit closure: no .and() chaining needed</li>
* <li>Validator chaining: multiple .validate() calls</li>
* </ul>
*/
public class CounterApp {
private final HexaApp app;
public CounterApp() {
this.app = HexaFun.dsl()
// Increment: single validator
.useCase(INCREMENT)
.validate(CounterValidators::validateIncrement)
.handle(input -> Result.ok(input.counter().increment()))
// Decrement: single validator
.useCase(DECREMENT)
.validate(CounterValidators::validateDecrement)
.handle(input -> Result.ok(input.counter().decrement()))
// Add: chained validators (counter not null + amount in range)
.useCase(ADD)
.validate(CounterValidators::validateAddCounter)
.validate(CounterValidators::validateAddAmount)
.handle(input -> Result.ok(input.counter().add(input.amount())))
.build();
}
/**
* Increment a counter.
*/
public Result<Counter> increment(Counter counter) {
return app.invoke(INCREMENT, new IncrementInput(counter));
}
/**
* Decrement a counter.
*/
public Result<Counter> decrement(Counter counter) {
return app.invoke(DECREMENT, new DecrementInput(counter));
}
/**
* Add amount to a counter.
*/
public Result<Counter> add(Counter counter, int amount) {
return app.invoke(ADD, new AddInput(counter, amount));
}
/**
* Get the underlying HexaApp for testing.
*/
public HexaApp getApp() {
return app;
}
// ----- Demo -----
public static void main(String[] args) {
CounterApp app = new CounterApp();
Counter counter = Counter.zero();
System.out.println("Starting: " + counter);
// Increment
Result<Counter> r1 = app.increment(counter);
System.out.println("After increment: " + r1.get());
// Add 10
Result<Counter> r2 = app.add(r1.get(), 10);
System.out.println("After add(10): " + r2.get());
// Try invalid add (amount too large)
Result<Counter> r3 = app.add(r2.get(), 500);
System.out.println("After add(500): " + (r3.isSuccess() ? r3.get() : "FAILED: " + r3.error()));
// Decrement
Result<Counter> r4 = app.decrement(r2.get());
System.out.println("After decrement: " + r4.get());
// Try null counter
Result<Counter> r5 = app.increment(null);
System.out.println("Increment null: " + (r5.isSuccess() ? r5.get() : "FAILED: " + r5.error()));
}
}