john
john

Reputation: 11679

Validate the inputs and perform actions accordingly

I have two proceses on which I need to validate on few fields.

Both my processes should pass GenericRecord to Validator class and now depending on whether it is ProcessA or ProcessB, my Validator class should validate those fields.

I am able to make it work for ProcessA but I am confuse how does my Validator class will look like for ProcessB fields validation. Confusion is how does Validator class decide that I need to validate fields for ProcessA or ProcessB as soon as it receives GenericRecord in the constructor. If ProcessA GenericRecord is passed, then do validation on ProcessA fields or If ProcessB GenericRecord is passed, then do validation on ProcessB fields.

ProcessA

try {
  GenericRecordDomainDataDecoder decoder = new GenericRecordDomainDataDecoder(config);
  while (true) {
    ConsumerRecords<byte[], byte[]> records = consumer.poll(1000);
    for (ConsumerRecord<byte[], byte[]> record : records) {
      GenericRecord payload = decoder.decode(record.value());
      String processName = "processA";
      // validation logic
      Validator validation = new Validator(payload);
      if(!validation.isValid())
          continue;

      // some other code
    }
  }
} catch (Exception ex) {
  // logging error
}

ProcessB

try {
  GenericRecordDomainDataDecoder decoder = new GenericRecordDomainDataDecoder(config);
  while (true) {
    ConsumerRecords<byte[], byte[]> records = consumer.poll(1000);
    for (ConsumerRecord<byte[], byte[]> record : records) {
      GenericRecord payload = decoder.decode(record.value());
      String processName = "processB";
      // validation logic
      Validator validation = new Validator(payload);
      if(!validation.isValid())
          continue;

      // some other code
    }
  }
} catch (Exception ex) {
  // logging error
}

Below is my Validator class which only works right now for ProcessA validation. I have added another constructor which I know doesn't work but just wanted to show what I want to do for ProcessB. And then I need to call isValid method that will tell me whether fields for ProcessB are present or not.

public class Validator {
  private String clientId, deviceId, payId;

  // for ProcessA
  public Validator(GenericRecord payload) {
    clientId = (String) DataUtils.parseRecord(payload, "clientId");
    deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
    payId = (String) DataUtils.parseRecord(payload, "payId");
  }

  // for ProcessB, I know this doesn't work - just wanted to show the idea
  public Validator(GenericRecord payload) {
    crossId = (String) DataUtils.parseRecord(payload, "crossId");
    maxId = (String) DataUtils.parseRecord(payload, "maxId");
    minId = (String) DataUtils.parseRecord(payload, "minId");
  }

  // this is what I am calling for ProcessA
  public boolean isValid() {
    return isValidClientIdDeviceId() && isValidPayId();
  }

  private boolean isValidPayId() {
    if (payId == null) {
      logger.log("invalid payId.");
      return false;
    }
    return true;
  }

  private boolean isValidClientIdDeviceId() {
    if (clientId == null && deviceId == null) {
      logger.log("invalid clientId and deviceId.");
      return false;
    }
    return true;
  }

  // getters
}

I can pass another parameter processName which is a String to Validator class. Can we use that to achieve this to validate fields accordingly.

Upvotes: 1

Views: 183

Answers (1)

davidxxx
davidxxx

Reputation: 131346

The first solution I propose to you is acceptable if you have few of type of Process class.

You could have a empty constructor and have a init method by Process you invoke after the constructor.

Just keep the default constructor (don't need to declare that):

  public Validator() {   
  }

  // for ProcessA
  public initProcessA(GenericRecord payload) {
    clientId = (String) DataUtils.parseRecord(payload, "clientId");
    deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
    payId = (String) DataUtils.parseRecord(payload, "payId");
  }

  // for ProcessB, 
  public void initProcessB(GenericRecord payload) {
    crossId = (String) DataUtils.parseRecord(payload, "crossId");
    maxId = (String) DataUtils.parseRecord(payload, "maxId");
    minId = (String) DataUtils.parseRecord(payload, "minId");
  }

In Process A :

   Validator validation = new Validator();
   validation.initProcessA(payload);  

In Process B :

   Validator validation = new Validator();
   validation.initProcessB(payload);

This first solution has its limits.
If you have validation specificities that depends on the Process class, a better solution would be to explode the rules with a distinct validator class for each Process because it would be more maintainable.

You could have for example :

public abstract class Validator<T extends Process>{

   ...
   // common and abstract methods    
   ...
   public abstract boolean isValid();
}

Validator A for Process A :

public class ValidatorA extends Validator<ProcessA>{
   ...
        public ValidatorA(GenericRecord payload){
           clientId = (String) DataUtils.parseRecord(payload, "clientId");
           deviceId = (String) DataUtils.parseRecord(payload, "deviceId");
           payId = (String) DataUtils.parseRecord(payload, "payId");
        }

       public  boolean isValid(){
           // validation rules specific to ProcessA
       }
    ...

}

Validator B for Process B :

public class ValidatorB extends Validator<ProcessB>{
   ...
      public ValidatorB(GenericRecord payload) {
         crossId = (String) DataUtils.parseRecord(payload, "crossId");
         maxId = (String) DataUtils.parseRecord(payload, "maxId");
         minId = (String) DataUtils.parseRecord(payload, "minId");
      }

      public  boolean isValid(){
          // validation rules specific to ProcessB
      }

   ...
}

Upvotes: 1

Related Questions