Updating value for an existing enum constant on the go in Drools

Viewed 294

I am having the below enum structure for which I have to change the value of the 2nd argument THREAT. The application is almost developed and is much dependant on enum types and the type can't be changed(due to a large number of the enum variables). When the application is restarted, I need the default values there. Is there any way I could change the value of THREAT on the fly?

enum TraceLevel {
   APP_DOS("as", ""),
   APP_DOS1("as", ""),
   APP_DOS2("as", ""),
   APP_DOS3("as", ""),
   APP_DOS4("as", "");
   String NAME;
   String THREAT;

   private TraceLevel(String name, String threat) {
      this.NAME = name;
      this.THREAT = threat;
   }
}

Update 1
depending on the comments, I think I should update the problem a bit more. I am basically working on the drools rule engine where I am having enum constants. The declaration is not really like Java there. So, I am unable to get how do I do that. Here is the drools specific pattern.

declare enum AttackCategory
APP_DOS("as", ""),
APP_DOS1("as", ""),
APP_DOS2("as", ""),
APP_DOS3("as", ""),
APP_DOS4("as", "");
value : String
threat: String

end
1 Answers

As the very many question comments say, you're trying to use an enum in a way that it's not designed or intended for. As with most cases where this happens, you can probably force it to work, but you're going to have additional problems. The correct answer is to go back to the drawing board, as they say, and come up with a solution that isn't trying to force an enum to have class behavior.


The (wrong) Enum way

To change a value on an enum, add setters to your declaration. In Java, this is done like so:

enum TraceLevel {
   APP_DOS("as", ""), ...;
   String NAME;
   String THREAT;

   private TraceLevel(String name, String threat) {
      this.NAME = name;
      this.THREAT = threat;
   }

  public String getThreat() { return this.NAME; }
  public void setThreat(String name) { this.NAME = name; }
}

(Also minor comment -- the variables for 'name' and 'threat' shouldn't be fully capitalized. They should follow the naming conventions for regular variables.)

If, on the other hand, you're using Drools type declarations, you do not create methods on these structures and instead Drools generates getters and setters following bean conventions. As you point out, these conventions do not generate such methods on enums (which kind of should have been a hint that you're trying to use them the wrong way.)

So if you must use enums, you must declare them in Java.


Alternate approach: classes

Your use case appears to just be glorified constants, so why not use that as an alternative approach? Declare a class with three String variables (name, thread, id.) Then, in a rule insert them all into working memory with default values applied. When you do need to use them, you can update them in memory as needed.

declare TraceLevel
  id: String
  name: String
  threat: String
end

rule "Prepare default trace levels"
when
  not( TraceLevel() )
then
  insert( new TraceLevel("APP_DOS", "as", "") ) // equivalent to TraceLevel.APP_DOS
  insert( new TraceLevel("APP_DOS2", "as", "") )
  // etc.
end

rule "Example rule which needs to update a Threat value"
when
  $traceLevel: TraceLevel( id == "APP_DOS" )
then
  modify( $traceLevel ) { threat = "new threat value" }
end

The first rule, "Prepare default trace levels", inserts the defaulted levels into working memory. At this point, working memory contains a set of these objects which are functionally identical to your enum values. Since they're in working memory, they're now available to any subsequently evaluated rules.

Note that the condition of this rule is very simple, and verifies that there are no pre-existing TraceLevel instances in working memory -- this keeps the rule from executing multiple times if for some reason you trigger a full re-evaluation.

The second example rule shows how you'd go about updating the "threat" value using the modify rule action.

In all cases, I've added an "id" field so that you can identify specific TraceLevel instances. These are the equivalents of the TraceLevel enum names (eg. TraceLevel.APP_DOS -> id = "APP_DOS"). The second example shows how you'd leverage this ID to get a specific TraceLevel instance.

Related