class="java" name="code"> @StateMachine public static interface InvoiceStateMachineMeta { @StateSet static interface States { @Initial @Function(transition = InvoiceStateMachineMeta.Transitions.Post.class, value = { InvoiceStateMachineMeta.States.Posted.class }) static interface Draft {} @Functions({ @Function(transition = InvoiceStateMachineMeta.Transitions.Pay.class, value = { States.PartialPaid.class, InvoiceStateMachineMeta.States.PaidOff.class }) }) static interface Posted {} @Function(transition = InvoiceStateMachineMeta.Transitions.Pay.class, value = { States.PartialPaid.class, InvoiceStateMachineMeta.States.PaidOff.class }) static interface PartialPaid {} @End static interface PaidOff {} } @TransitionSet static interface Transitions { static interface Post {} @Conditional(condition = Payable.class, judger = PayableJudger.class, postEval = true) static interface Pay {} } @ConditionSet static interface Conditions { static interface Payable { BigDecimal getTotalAmount(); BigDecimal getPayedAmount(); } } public static class Utilities { public static class PayableJudger implements ConditionalTransition<Payable> { @Override public Class<?> doConditionJudge(Payable t) { if ( 0 < t.getPayedAmount().compareTo(BigDecimal.ZERO) && 0 < t.getTotalAmount().compareTo(t.getPayedAmount()) ) { return PartialPaid.class; } else if ( 0 >= t.getTotalAmount().compareTo(t.getPayedAmount()) ) { return PaidOff.class; } else { throw new IllegalStateException(); } } } } } @StateMachine public static interface InvoiceItemStateMachineMeta { @StateSet static interface States { @Initial @Function(transition = InvoiceItemStateMachineMeta.Transitions.Pay.class, value = { InvoiceItemStateMachineMeta.States.Paid.class }) static interface Unpaid {} @End @InboundWhile(on = { InvoiceStateMachineMeta.States.Posted.class, InvoiceStateMachineMeta.States.PartialPaid.class }, relation = InvoiceItemStateMachineMeta.Relations.ParentInvoice.class) static interface Paid {} } @TransitionSet static interface Transitions { static interface Pay {} } @RelationSet static interface Relations { @RelateTo(InvoiceStateMachineMeta.class) static interface ParentInvoice {} } }
?
@LifecycleMeta(InvoiceStateMachineMeta.class) public static class Invoice extends ReactiveObject implements InvoiceStateMachineMeta.Conditions.Payable { private final BigDecimal totalAmount;; private BigDecimal payedAmount = new BigDecimal(0D); private final List<InvoiceItem> items = new ArrayList<>(); public Invoice(final BigDecimal totalAmount) { initialState(InvoiceStateMachineMeta.States.Draft.class.getSimpleName()); this.totalAmount = totalAmount; } @Condition(InvoiceStateMachineMeta.Conditions.Payable.class) public InvoiceStateMachineMeta.Conditions.Payable getPayable() { return this; } @Override public BigDecimal getTotalAmount() { return totalAmount; } @Override public synchronized BigDecimal getPayedAmount() { return payedAmount; } @Transition public void post() {} @Transition(InvoiceStateMachineMeta.Transitions.Pay.class) @PostStateChange(to = InvoiceItemStateMachineMeta.States.Paid.class, observableName = "items", mappedBy = "parent") public synchronized void onItemPaied(LifecycleContext<InvoiceItem, String> context) { payedAmount = payedAmount.add(context.getTarget().getPayedAmount()); } public void addItem(InvoiceItem invoiceItem) { if ( !items.contains(invoiceItem) ) { items.add(invoiceItem); } } public List<InvoiceItem> getItems() { return Collections.unmodifiableList(items); } } @LifecycleMeta(InvoiceItemStateMachineMeta.class) public static class InvoiceItem extends ReactiveObject { private int seq; private BigDecimal amount; private BigDecimal payedAmount; private final Invoice parent; public InvoiceItem(Invoice parent, BigDecimal amount) { initialState(InvoiceItemStateMachineMeta.States.Unpaid.class.getSimpleName()); this.amount = amount; this.parent = parent; this.seq = this.parent.getItems().size() + 1; this.parent.addItem(this); } @Transition public void pay(final BigDecimal amount) { if ( 0 < this.amount.compareTo(amount) ) { throw new IllegalArgumentException("paying amount is not enough to pay this item."); } this.payedAmount = amount; } public BigDecimal getPayedAmount() { return payedAmount; } @Relation(InvoiceItemStateMachineMeta.Relations.ParentInvoice.class) public Invoice getParent() { return this.parent; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ( ( parent == null ) ? 0 : parent.hashCode() ); result = prime * result + seq; return result; } @Override public boolean equals(Object obj) { if ( this == obj ) return true; if ( obj == null ) return false; if ( getClass() != obj.getClass() ) return false; InvoiceItem other = (InvoiceItem) obj; if ( parent == null ) { if ( other.parent != null ) return false; } else if ( !parent.equals(other.parent) ) return false; if ( seq != other.seq ) return false; return true; } }
?
@Test public void test_relational_callback_post_state_change() { final Invoice invoice = new Invoice(new BigDecimal(10000.0D)); final InvoiceItem itemOne = new InvoiceItem(invoice, new BigDecimal(4000.0D)); final InvoiceItem itemTwo = new InvoiceItem(invoice, new BigDecimal(4000.0D)); final InvoiceItem itemThree = new InvoiceItem(invoice, new BigDecimal(2000.0D)); invoice.post(); assertState(InvoiceStateMachineMeta.States.Posted.class, invoice); assertState(InvoiceItemStateMachineMeta.States.Unpaid.class, itemOne); itemOne.pay(new BigDecimal(4000.0D)); assertState(InvoiceItemStateMachineMeta.States.Paid.class, itemOne); assertState(InvoiceStateMachineMeta.States.PartialPaid.class, invoice); itemTwo.pay(new BigDecimal(4000.0D)); assertState(InvoiceItemStateMachineMeta.States.Paid.class, itemTwo); assertState(InvoiceStateMachineMeta.States.PartialPaid.class, invoice); itemThree.pay(new BigDecimal(2000.0D)); assertState(InvoiceItemStateMachineMeta.States.Paid.class, itemThree); assertState(InvoiceStateMachineMeta.States.PaidOff.class, invoice); }
?