Stateful Entities

We are in the process of seeing how our existing product would be represented in the Cuba platform. Currently a lot of our tables are stateful, meaning that they can have different states such as what you would see in a state machine of sorts (see picture). Different states will drive different permissions/validation, UI changes such as making fields read-only or required, different notifications to go out, etc. Cuba is a very open platform so we could code in different directions and create all of this logic manually. We are planning on having our available states to be in a stand-alone table with inheritance to describe the states for each of the different stateful entities. I will populate a custom datasource of states to represent valid states that can be transitioned to for the UI for each entity. Coded rules and actions will just reside in code in the controller and middleware. What I am asking for is if there are abilities in Cuba I haven’t considered or a best practice for doing this approach or what other users have done. We want to standardize our approach as much as possible. Our current challenges that we are seeing is as follows:

  • Repeating a lot of code in both the GENERIC UI and the MIDDLEWARE to represent our coded business rules, with different behavior because of the different tiers. (e.g. a rule may need the UI to have a field read-only at the same time adding a validator in the Middleware).
  • Our customers can change logic / behavior / design of the business rules. We need smooth options for them to override the business logic. (e.g. customers may want to add an additional state or make other fields read-only).
  • Any suggestions on the business model? Our stateful entities will probably inherit from a mapped superclass, but It looks like I have to add their relationship to the state table manually as each will have their own child class of that table to represent their states. I’m not sure if this gives me anything.
  • External systems that integrate with our system may or may not be subject to certain rules, or may have their own business logic that needs to fire. We generally have a lot of interfaces. These of course will need to be different code in the middleware, any thoughts on how best to manage this though or am I missing something?

Any input on anything above or about stateful entities in the system would be helpful. Thanks!

StateMachineImage

1 Like

Hi Josh,

I cannot suggest any complete solution to your requirements, but I’ll try to comment on some of your concerns.

You are saying about repeating a lot of code in both UI and Middleware. What about encapsulating rules in beans residing in the global module? You can design an interface accepting the entity instance and some kind of “permission type”, and these beans would return “yes/no” or more complex results after evaluating your rules for the given instance. In order to not repeat logic across screens, you can create base controllers which will work with your rules engine. The same is for entity listeners on the middleware, if needed. For example, in a base controller you could write code in ready() which would traverse the components tree and invoke rules engine for every component to disable or hide it. For integration with external systems you can use middleware services exposed as REST endpoints and again invoke your rule engine when needed.

Of course you should cache rules on each tier for acceptable performance.

And about data model: you will certainly benefit from creating a superclass for all your stateful entities, because you will be able to use it in this generic rule engine interface.

Hope this helps. Let me know if you need more details on the points mentioned above.

I will leave this topic “not answered”, maybe we’ll have more suggestions.

I’m interested in this as well so thanks for the response.

Business rule engine aside, do you have a recommended approach for simple status management? i.e. If I’m in the “Ready” status, I only have the option to go to “In Progress” or “Canceled”, but once I’m in “In Progress”, I now have “Complete” available to me as an option. This would be configured per entity of course.

You can use our BPM add-on for configurable status management. A process instance can be associated with an entity instance. ProcActionsFrame is a standard UI element providing options depending on the current process state.

I tried to describe this requirement in another post and did not come across very well. The following psuedo code from the post extends the validation bean to add the ability to encapsulate the business logic for an entity using three events, Validation, Readonly fields and fields changing:


@MyEntityValidator
public class MyEntity {
    @Min(value=1, message="Min value is 1")
    @Max(value=100,  message="Max value is 100")
    @IsReadOnly(name="Field1")
    public int getField1() {

    }

    @Min(value=1, message="Min value is 1")
    @Max(value=100,  message="Max value is 100")
    @IsReadOnly(name="Field2")
    public int getField2() {

    }

    @Changed(name="Field3")
    public String getField3() {

    }
}

public class MyEntityValidator implements ConstraintValidator<MyAnnotation, MyEntity>, IsReadOnly, Changed {
    public void initialize(MyAnnotation annotation) {
    }

    public boolean isValid(MyEntity entity, ConstraintValidatorContext context) {
        if (entity.getField1() > entity.getField2()) {
            return false;
        }

        return true;
    }

    public boolean isReadOnly(MyEntity entity, String fieldName) {
        if("Field3".equals(fieldName)) {
                    // If Field3 == CUSTOMER then make Field2 read only.
            return String.equals(entity.getField3(), "CUSTOMER");
        }
    }

    public void changed(MyEntity entity, String fieldName) {
        if("Field3".equals(fieldName)) {
                    // Field2 will always be 100 if Field1 is a CUSTOMER
            if(entity.getField3().equals("CUSTOMER")) {
                entity.setField2(100);
            }
        }
    }
}

Please note that the code is not fully thought out and is presented purely for discussion. Having a capability like this gets rid of a LOT of boilerplate code and makes systems more reliable IMO.

+1 for the Op’s suggestion.

Thanks again for the reply. My concern with using BPM for this is the following:

If my product ships with a workflow to manage status and I need to build business rules using these statuses, then it’s not exactly easy to allow client modifications to these statuses without also then making large changes to the system business rules.

One potential solution we discussed is to have a more hard-coded set of statuses within the application that we write all our business rules against, and then use the BPM workflow to set these internal statuses at various points in its lifecycle. Is this a suitable approach? Do BPM workflows work with validation rules gracefully? (i.e. user tries to move to In Progress status but business rule prevents them because a date field is required).