Build predicates from user input - java

I have an application server written in java that must use different machine learning models based on the request context. For example my request context looks like
class RequestContext {
String clientId;
String experimentId;
String sessionId;
...
}
Currently I have a delegation logic:
if(requestContext.experimentId == "experiment1"
&& requestContext.clientId == "client1"
){
// use model #1
} else if(requestContext.experimentId == "experiment2"
&& requestContext.clientId == "client1"){
// use model #2
} ...
I could use guava's predicates to express these rules and upon match, delegate to the appropriate model. As a second step, I would like to move these out of the server code to an external configuration store and have the server periodically read from it. This would enable me to not have to deploy server code each time I change the delegation rule. Moreover, I could write a UI that would let the business users define the conditions and the model to use.
My idea is to first specify a list of conditions that are available (in this case, clientId, experimentId, and sessionId) and allow the user to write a simple java-like script to create the conditions, for example one would write
clientId == "client1" && (sessionId != "session1" || experimentId == "experiment1")
then specify a model to use for when this condition is met. What library/techniques will help me parse a user specified predicate logic into a guava predicate-like object?

final Pattern client_pattern = Pattern.compile("clientId\\s+==\\s+\"(.*?)\"");
Function<String, RequestContext> = new Function<String, RequestContext>() {
public RequestContext apply(String s) {
Matcher client_matcher = client_pattern.matcher(s);
String client_id = client_matcher.find() ? client_matcher.group(1) : null;
// similarly for experiment id and session id
return new RequestContext(client_id, exp_id, session_id);
}
};
That does the parsing. Now that you have the request context, the guava predicates are simple:
Predicate<RequestContext> pred_1 = new Predicate<RequestContext>() {
public boolean apply(RequestContext rc) {
return rc.clientId.equals("client1") && rc.experimentId.equals("experiment1");
}
};
You could also write simpler atomic predicates and then use Predicates#and to combine them.

Related

Prevent coding multiple if/else statements with two changing expressions

I'm a beginner APEX developer (language based off of Java) and I was wondering if there is an efficient way to write conditional statements where two conditions change while the rest remains static.
For instance, in my code below, Countryy__c will change to say UK, US and Canada (besides France) and for each of these countries the Industry will change from Accounting to Medicine to Legal. Meanwhile, lead type and status will always remain as outbound and open respectively. Moreover each Country and Industry combination has a unique 'Owner ID'.
So in other words, there will be a total of 12 if/else statements with 12 different OwnerIds. Given that the code will be messy to maintain in the future if the number of countries and industries grow, is there a better way of coding this?
public static void changeOwnerToQueue(List<String> DeactivatedUserIds){
List<Lead> leadList = new List<Lead>();
List<lead> updatedQueue = new List<Lead>();
leadList = [SELECT Id, OwnerId, Countryy__c, Industry__c, Lead_Type__c, Status from lead
where OwnerId IN :DeactivatedUserIds];
for(Lead l : leadList){
if(l.Countryy__c == 'France' && l.Industry__c == 'Accounting' && l.Lead_Type__c == 'Outbound' && l.Status == 'Open'){
l.OwnerId = '00G5J000000pX41';
updatedQueue.add(l);
}
}
The most maintainable pattern for this kind of mapping in Apex is to use Custom Metadata. You'd create some Custom Metadata Type (MyOwnerMap__mdt), with fields for Country__c, Industry__c, and Owner__c. You'd create Custom Metadata records to represent all of your mappings. Then, in your code, you'd pull that data to create a Map, using a custom class as a key to represent the unique mapping of Country + Industry -> Owner:
class OwnerMapKey {
public String industry;
public String country;
public OwnerMapKey(String ind, String ctry) {
this.industry = ind;
this.country = ctry;
}
public Boolean equals(Object other) {
if (other instanceof OwnerMapKey) {
OwnerMapKey o = (OwnerMapKey)other;
return this.industry == o.industry && this.country == o.country;
}
return false;
}
public Integer hashCode() {
return (this.industry + this.country).hashCode();
}
}
List<MyOwnerMap__mdt> ownerMapValues = MyOwnerMap__mdt.getAll().values();
Map<OwnerMapKey, Id> ownerMap = new Map<OwnerMapKey, Id>();
for (MyOwnerMap__mdt eachOwnerMap: ownerMapValues) {
ownerMap.put(new OwnerMapKey(eachOwnerMap.Industry__c, eachOwnerMap.Country__c), eachOwnerMap.Owner__c);
}
Then, you can easily access the desired Owner value for any combination of Industry and Country. Note that you'll probably want to have a fallback if that entry is missing from your Custom Metadata.
someRecord.OwnerId = ownerMap.get(new OwnerMapKey(SOME_INDUSTRY, SOME_COUNTRY)) || defaultOwner;
(Disclaimer: above code written directly in Stack Overflow and untested).
The reason this pattern is valuable is that your solution then becomes admin-maintainable: you can change the mapping with no code changes and no deployment, just by altering the Custom Metadata records.

How do I validate multiple inputs for a function?

I have a "Validator" class which allows us to set values of its member variables (mostly boolean) - mv1, mv2, mv3 etc. with setter methods. Lets call all these variables "settings". All the setter methods return this Validator instead of the usual void. A Validator is setup and then used by automation test methods to validate the json/string response body of an api call made in the test method.
The Validator has a validate(Input input) method which takes an "Input" object (actually an api response) and validates it based on the values of settings of Validator. There are some dependencies between the various settings. For example, if mv1 = true, then mv3 cannot be true etc. Also, I cannot always use enums to restrict the values of the settings !
I validate all the settings with validateSettings(). The validate(Input input) calls it before doing the validation. I want to find out all the invalid inputs, display them all at once and then prevent the validation until the inputs are fixed. What is the best way to do this in Java ?
What did I try ?
Using plain Java -
I used a string to store all the invalid settings and with reasons why they are invalid. Then, throw an IllegalArgumentException if one or more settings were found to be invalid and pass it the string. I want to avoid writing custom code if possible. I also don't want to use Java's assert because it can be disabled at run time.
Using TestNg library-
I use a SoftAssert to validate the member variables. The code inspects some of the the member variables, asserts that the variables have valid values and finally does softAssert.assertAll() to list all the wrong values at once. But, I wonder if Java has any in-built features to do this.
class Validator {
// Validator settings
boolean mv1;
boolean mv2;
boolean mv3;
boolean mv4;
boolean mv5;
//MyEnum mv6;//...etc.
// Setters - One example.
public Validator setMv1(boolean mv1) {
this.mv1 = mv1;
return this;
}
// Validation logic
public void validate(Input input) {
validateSettings();
// Now, validate the input.
}
// Validate the settings of this Validator - using TestNg library
private void validateSettings() {
SoftAssert assertz = new SoftAssert();
// No need to validate all settings ! Only some needed.
if (mv1 == true) {
assertz.assertFalse(mv3, "Meaningful error message");
assertz.assertTrue(mv5, "Meaningful error message");
}
// Assert other things.
assertz.assertAll();
}
// Validate the settings of this Validator - using plain Java.
private void validateSettingsV1() {
String errors = "These are the invalid settings - ";
boolean areSettingsInvalid = false;
if (mv1 == true) {
if (mv3 == true) {
errors += "mv3 can't be true when...blah";
areSettingsInvalid = true;
}
if (mv5 == false) {
errors += "mv5 can't be false when...blah";
areSettingsInvalid = true;
}
// Repeat above logic for all invalid settings.
if (areSettingsInvalid == true) {
throw new IllegalArgumentException(errors);
}
}
}
}

How can I avoid repetitive if-else when validating fields in a DTO?

StudentDTO class having around 20 string attributes and each need to validate whether mandatory or not based on the logic given below in comments. This will make update method lengthy with too many if else's. Exception message should change based on the property evaluating. This code use Java 11.
// all fields except lastUpdated are string
public Student populateStudent(final StudentDTO studentDTO) {
Student student = new Student();
boolean dataUpdated = false;
/*
If mandatory parameter is:
1.) null : parameter is not updating
2.) empty : validate and throw an exception
3.) blank : validate and throw an exception
*/
if (isEmptyOrBlank(studentDTO.getName())) {
handleBadParam("Bad student name");
} else {
if (studentDTO.getName() != null) {
student.setName(studentDTO.getName());
dataUpdated = true;
}
}
if (isEmptyOrBlank(studentDTO.getBirthday())) {
handleBadParam("Bad student birthday");
} else {
if (studentDTO.getBirthday() != null) {
student.setBirthday(studentDTO.getBirthday());
dataUpdated = true;
}
}
// .... 20 other similar if-else statements later ....
// if atleast one parameter updated then date should update
if (dataUpdated) {
student.setLastUpdated(new Date());
}
return student;
}
private boolean isEmptyOrBlank(String name) {
return name != null && (name.isEmpty() || isBlank(name));
}
private void handleBadParam(String messgae) {
throw new IllegalArgumentException(messgae);
}
private boolean isBlank(String name) {
return (name.trim().length() == 0);
}
It seems you are validating your object.
I will not share any code example, I will just share an design opinion. By the way while designing your application, you should follow a design principle. So SOLID design principles is the commonly accepted, and you can apply these principles to your app while designing it.
You may create a class like StudentValidator so it's job must be only validating the Student object. So you realize first principle of solid's single responsibility.
And also that StudentValidator class will have methods which validations you need. And after all that implementations, you can cover in a method for each validation or you may call them when needed line.
Also there are many design patterns to avoid if-else statements via implementing patterns. Like command pattern, using enums etc.
I would strongly recommend to use the Java environment JSR 303 Bean Validation.The javax.validation packages provide developers with a standardized way of doing so. Fields that have to fulfill certain criteria receive the corresponding annotations, e.g. #NotNull, and these are then evaluated by the framework. Naturally, for checking more specific conditions, there is the possibility of creating custom annotations and validators.
You could refer to this https://dzone.com/articles/bean-validation-made-simple.

Business logic validation patterns & advices

I have two layers of validation in my application. First is entity validation performed by bean validation API (e.g. required fields).
The second level is business logic validation. For example, user has a post. User can delete a post only if he is a creator of this post and post rating < 50. So I have to do something like this:
if (post.getCreator().equals(session.getUser())) {
if (post.getRating() < 50) {
postRepository.delete(post);
} else errors.add(400, "Cant delete post with rating 50 or higher")
} else errors add (400, "You should be owner of the post")
I don't like this way as this conditionals are reused and I have to duplicate code. Moreover, if number of conditionals is greater than 5 or so it becomes unreal to read and understand the code.
Moreover, standard Spring Validator won't be very helpful as I have to maker different validation for one entity on different actions (delete and update for example)
So I'm looking for a way to do this in a smarter way (pattern maybe) and I would be very grateful if someone could give me a hint.
Thank in advance!
You can use the strategy pattern.
Each condition can be modelled as a function that takes a post and a session context and might return an error:
Post -> Session -> Optional<String>
You could represent this with an interface:
#FunctionalInterface
public interface ValidationCondition {
Optional<String> validate(final Post post, final Session session);
}
So for example:
public class CreatorValidation implements ValidationCondition {
public Optional<String> validate(final Post post, final Session session) {
if (post.getCreator().equals(session.getUser()) {
return Optional.empty();
}
return Optional.of("You should be the owner of the post");
}
}
You can then store every validation in a list:
final List<ValidationCondition> conditions = new ArrayList<>();
conditions.add(new CreatorValidation());
conditions.add(new ScoreValidation());
// etc.
Using the list, validations can be applied in bulk:
final List<String> errors = new ArrayList<>();
for (final ValidationCondition condition : conditions) {
final Optional<String> error = condition.validate(post, session);
if (error.isPresent()) {
errors.add(error.get());
}
}
Using Java 8 lambdas, you could declare these inline:
final ValidationCondition condition = (post, session) -> {
// Custom logic
});
Strategy pattern is the solution in my opinion.
I will give you a very simple example. Lets say we have two kinds of credit cards, Visa and Mastercard. The logic to perform payment operation is the same for both cards, but card number validation is different. So, by passing VisaStrategy object through a workflow does the same logic and operations as we would pass MastercardStrategy, except one thing - card number validation, which is done inside each defined Strategy class, so you do not have any "if else" stuff in your code at all. Each Strategy class is now responsible for one and only one type of card validation.
If you look for flexible and easy to maintain code structure - use Strategy design pattern.

Servlet request processing

Greetings,
I have a servlet which pulls an "action" parameter from a querystring. Based on this string I perform the required action.
What is the best way to check the value of the "action" parameter. Currently my code is a long if, else if, else if, else if...when I'd rather have some kind of mapping from string to method where I didn't have so many branch conditions.
Regards,
Ken
Populate a Map<String, Action> where String represents the condition for which you would like to grab the action and Action is the interface which you've definied for your actions.
E.g.
Action action = actions.get(request.getMethod() + request.getPathInfo());
if (action != null) {
action.execute(request, response);
}
You can find a detailed example in this answer.
One possible way is to keep them in a file (XML file or Properties file).
Load them into the memory. It can be stored in some Map.
Based the key, the operation(value) can be decided.
Maybe using a helper class with an enum type might help:
public class ActionHelper {
public enum ServletAction {
ActionEdit,
ActionOpen,
ActionDelete,
ActionUndefined
}
public static ServletAction getAction(String action)
{
action = action != null ? action : "";
if (action.equalsIgnoreCase("edit"))
return ServletAction.ActionEdit;
else if (action.equalsIgnoreCase("open"))
return ServletAction.ActionOpen;
else if (action.equalsIgnoreCase("delete"))
return ServletAction.ActionDelete;
return ServletAction.ActionUndefined;
}
}
Then, your servlet will have something short and simple like:
ServletAction sa = ActionHelper.getAction(request.getParameter("action"));
switch (sa) {
case ServletAction.ActionEdit:
//
break;
// ... more cases
}

Categories

Resources