View Javadoc
1   package com.guinetik.hexafun.examples.counter;
2   
3   import com.guinetik.hexafun.HexaApp;
4   import com.guinetik.hexafun.HexaFun;
5   import com.guinetik.hexafun.fun.Result;
6   import com.guinetik.hexafun.examples.counter.CounterInputs.*;
7   
8   import static com.guinetik.hexafun.examples.counter.CounterUseCases.*;
9   import static com.guinetik.hexafun.examples.counter.CounterValidators.*;
10  
11  /**
12   * Counter application demonstrating the improved HexaFun DSL.
13   *
14   * <p>Key improvements showcased:
15   * <ul>
16   *   <li>Type-safe keys (UseCaseKey) instead of strings</li>
17   *   <li>Cleaner syntax: validate/handle instead of from/to</li>
18   *   <li>Implicit closure: no .and() chaining needed</li>
19   *   <li>Validator chaining: multiple .validate() calls</li>
20   * </ul>
21   */
22  public class CounterApp {
23  
24      private final HexaApp app;
25  
26      public CounterApp() {
27          this.app = HexaFun.dsl()
28  
29              // Increment: single validator
30              .useCase(INCREMENT)
31                  .validate(CounterValidators::validateIncrement)
32                  .handle(input -> Result.ok(input.counter().increment()))
33  
34              // Decrement: single validator
35              .useCase(DECREMENT)
36                  .validate(CounterValidators::validateDecrement)
37                  .handle(input -> Result.ok(input.counter().decrement()))
38  
39              // Add: chained validators (counter not null + amount in range)
40              .useCase(ADD)
41                  .validate(CounterValidators::validateAddCounter)
42                  .validate(CounterValidators::validateAddAmount)
43                  .handle(input -> Result.ok(input.counter().add(input.amount())))
44  
45              .build();
46      }
47  
48      /**
49       * Increment a counter.
50       */
51      public Result<Counter> increment(Counter counter) {
52          return app.invoke(INCREMENT, new IncrementInput(counter));
53      }
54  
55      /**
56       * Decrement a counter.
57       */
58      public Result<Counter> decrement(Counter counter) {
59          return app.invoke(DECREMENT, new DecrementInput(counter));
60      }
61  
62      /**
63       * Add amount to a counter.
64       */
65      public Result<Counter> add(Counter counter, int amount) {
66          return app.invoke(ADD, new AddInput(counter, amount));
67      }
68  
69      /**
70       * Get the underlying HexaApp for testing.
71       */
72      public HexaApp getApp() {
73          return app;
74      }
75  
76      // ----- Demo -----
77  
78      public static void main(String[] args) {
79          CounterApp app = new CounterApp();
80          Counter counter = Counter.zero();
81  
82          System.out.println("Starting: " + counter);
83  
84          // Increment
85          Result<Counter> r1 = app.increment(counter);
86          System.out.println("After increment: " + r1.get());
87  
88          // Add 10
89          Result<Counter> r2 = app.add(r1.get(), 10);
90          System.out.println("After add(10): " + r2.get());
91  
92          // Try invalid add (amount too large)
93          Result<Counter> r3 = app.add(r2.get(), 500);
94          System.out.println("After add(500): " + (r3.isSuccess() ? r3.get() : "FAILED: " + r3.error()));
95  
96          // Decrement
97          Result<Counter> r4 = app.decrement(r2.get());
98          System.out.println("After decrement: " + r4.get());
99  
100         // Try null counter
101         Result<Counter> r5 = app.increment(null);
102         System.out.println("Increment null: " + (r5.isSuccess() ? r5.get() : "FAILED: " + r5.error()));
103     }
104 }