Validation Packs

In this Lesson

You will learn about validation packs and the special services they provide to protect the information in a database table.

Concepts

It is good to install data validation rules as close to the data as possible. This ensures that information is well-protected regardless of the consumer process that is accessing the data. The way to do this in Soiree is to use a validation pack.

Each datasource that provides insert or update capability also provides a validation pack. The validation pack allows you to embed data validation rules into your datasource. The validation pack is used to test the information in the datasource prior to each insert or update. If a validation rules is violated then the insert or update is not performed and the error messages are returned to the consumer [ more on that in a minute ].

Each validation pack provides two opportunities for data validation

  1. Column level validations
    These check the validity of a single column. For example, is the column’s value in the list of values defined in a code list?
  2. Row level validations
    These check the validity of two or more columns that are dependent on each other. For example, is the party end time greater than the party start time?
Execution Order
Row validations are always performed after the column validations. This allows you to bypass cross-column validation if any of the columns used in the cross-column validation contains invalid content.

Competing Forces

Consider this apparently simple, yet interestingly non-trivial question: What happens when you discover invalid data?

The simple answer is: You complain

Yes, but: How loudly do you complain and who do you complain to?
[ hey, that’s a ya-buttal. Ya, but… ]

The data access team just wants to prevent invalid data from entering the database. So, they would likely stuff their complaint into an Exception and throw it at you.

The engineering team would say they need enough detailed information to understand which piece of data is invalid.

The designer team would insist that the complaint should be displayed on the element in the scene that contains the offending content. To which the data access person would say, what is a scene and why should I care?

Remember
A datasource may be used by many different processes – some of which involve a user interface [ scene ] and others that do not.

So, we have competing forces at work

  1. User experience teams want the validation close to the visuals so that the complaint can be tossed into the proper visual element.
  2. Data access teams want the validation close to the data so they can ensure the data is protected – regardless of who is using it.
  3. Engineers are somewhere in the middle. For example, if they have a nightly process updating many different tables they will probably want to describe the error in some log, report, or alert that is later resolved by someone.

So, at which of the three layers should data validation take place?

Sadly, all too often the answer is ‘in the user interface layer’ or ‘in all three layers’.

Leakage

These competing forces unleash a brutal attack on your development efforts called Leakage

Leakage occurs when the separation of responsibilities is violated. [ ok, i was thinking leakage was something else… ]

Let’s review the separation that is desired and the implications of violating it

  1. The designer role is responsible for how information is presented.
  2. The engineering role is responsible for what is done with the information.
  3. The data access role is responsible for data integrity.

When data validation is moved to the presentation layer you need to write the logic more than once. Once for each type of visual platform (desktop, mobile device, etc), and again for any non-visual process that may need to manipulate the data. This complicates the initial development of the product as well as its on-going maintenance.

Exploit everyone’s strengths instead of relying on their weakest skill. We are better together.
The worst damage is inflicted on your team’s human fabric. Data validation often involves programming. This means the need for technical disciplines has been sprayed into the presentation space. Programming skills are then needed to create the visual layer and the engineering team ends up doing the design work or you attempt to turn designers into programmers. Either way you may be relying on someone in their area of weakness instead of exploiting everyone’s strengths. You are no longer able to use a rich mixture of multi-disciplinary skills to build your masterpiece and you will likely end up with a lesser product at a higher cost. Everything gets more complex and fragile.

Leakage stinks. [ yep, that’s exactly what I was thinking when you introduced the idea… ]

And it all started with a simple little question: What happens when you discover invalid data?

A Leakage Sealant

The Soiree validation packs are a sealant against leakage. [ and there are other sealants to be discussed later ]

Validation packs give you the best of both worlds. You may embed data validation in the data access layer and have them behave as though they are in the visual layer. This is accomplished by introducing a Message Owner and some specially seasoned sauce.
[ you are making me hungry again ]

A MessageOwner is a Java class that is notified when a message is assigned to a value. These messages are generally an ERROR message resulting from a value failing to pass a validation rule, however, informational or warning message may also be assigned to a value and the MessageOwner will see those too.

  • You can assign a separate message owner to each value individually
  • You can assign the same message owner to all values
  • You can assign separate message owners to some values and a single message owner to all other values.
Tip
MessageOwners allow the data consumer to handle the messages the way they prefer. This is exactly how Soiree gets validation pack messages attached to an element in a Scene.

You may also use a datasource without any message owners, in fact, this is how datasources are normally used. When the validation process produces one or more ERROR messages for which a message owner is not available the validation process will throw a ValidationException. [ if nobody was listening before they will now! ] If the validation produced multiple ERROR messages then only the first ValidationException is thrown to let the consumer know there was at least one error. The consumer should then ask the datasource for all of the ValidationExceptions that may have been produced.

The datasource can provide a list of all the ValidationExceptions produced in the validation process. Each ValidationException contains the ERROR message and the name of the value associated with the message. The datasource can also provide a list of all the messages that were produced. The messages could be of type ERROR, INFO, or WARN.

You will get to see all of this in action in the lesson that follows this one. But, before you can see validations in action you must first create a few.

Let’s go validate some data.

Add column validations to the Party Validation Pack

In this exercise you will use the Party’s validation pack to install some validation rules in the Party datasource.

  1. Open the PartyValidationPack class



  2. This class is a subclass of the Soiree provided validation pack and exists to provide a place to install customizations without losing them when the datasource is rebuilt.



  3. Override the validation method for party_name, party_time_start, and party_time_end
    • Position the editor cursor at the bottom of the class



    • Right click and select Source … Override/Implement Methods…



    • Select the three methods and press OK


  4. Copy and paste this code into the end of checkPartyName() method ( after the super.checkPartyName(isInsert, partyName); statement )
    if (isEmpty(partyName)){
    	setPartyNameMessage(error("A party name must be provided"));
    }
    
    

    The method should now look like this. Notice the methods that are being used.



    Always call the superclass method because it may contain validations generated by Soiree. Soiree did generate a validation for the party name to ensure the value does not exceed the length of the column in the database.



  5. Notice
    The first ERROR message assigned to a value will remain in effect. So, if multiple validations attempt to set an error message the first error message will be the one people see. In this example, if both the Soiree validation and the custom validation failed we would then see the Soiree validation message because it is called before the custom validation.
  6. Copy and paste this code into the end of checkPartyTimeStart() method ( after the super.checkPartyTimeStart(isInsert, partyTimeStart); statement )
    if (!getPartyTimes().containsCode(partyTimeStart)){
    	setPartyTimeStartMessage(error("The party start time is not allowed"));
    }
    
    

    Ignore the error that appears for getPartyTimes. You will fix this later.

  7. Copy and paste this into the end of checkPartyTimeEnd() method (after the super.checkPartyTimeEnd(isInsert, partyTimeEnd); statement )
    if (!getPartyTimes().containsCode(partyTimeEnd)){
    	setPartyTimeStartMessage(error("The party end time is not allowed"));
    }
    
    

    Ignore the error that appears for getPartyTimes. You will fix this later.
    [ just act like you didn’t notice this method is setting the error message on the wrong value. We want this error to be there. ]

  8. Copy and paste this method as the last method in the class.
    /** Obtain the com.example.party.codelist.PartyTimes code list
     * @return A CodeListRes containing the PartyTimes
     * @throws BrokerException If the item list cannot be located
     */
    private CodeListRes getPartyTimes() throws BrokerException{
    	try{
    		//Obtain the code list from the resource broker
    		return CodeListBroker.getCodeList(PartyTimesCodes.CODE_LIST_ID, getDBConnectionProvider().getUserInfo().getTenant());
    	}catch (BrokerException be){
    		//This is a configuration issue: log the issue
    		logger.error("Unable to locate the party times code list", be );
    		throw be; // throw it at the fan
    	}
    }
    
    
  9. You should now have a class that contains the following methods, some of which contain errors as shown here



  10. Correct the CodeListRes error as shown here



  11. Correct the BrokerException, CodeListBroker, and PartyTimesCodes errors the same way



  12. Remove the //TODO comments from the overridden methods



  13. The methods should now be free of errors and look like this



Add a row validation to the Party Validation Pack

In this exercise you will create a validation that involves two values. You will ensure the party end time is at least one hour greater than the start time.

  1. Override the rowValidations() method. Your validation pack class should now contain this method



  2. Copy and paste this into the end of the rowValidations() method.
    //Check to see if either column validation produced an error
    //No sense comparing them if they are wonky
    if (!isErrorPartyTimeStart() && !isErrorPartyTimeEnd()){
    
    	//convert the times to a number
    	//no need to check for valid numerics in each field. Column validation ensures they are numbers.
    	int startHour = Integer.parseInt(ds.getPartyTimeStart());
    	int endHour = Integer.parseInt(ds.getPartyTimeEnd());
    
    	//Ensure the start time is less than the end time
    	if (startHour >= endHour){
    		setPartyTimeStartMessage(error("The party start time must be at least one hour before the end time"));
    		setPartyTimeEndMessage(error("The party end time must be at least one hour after the start time"));
    	}
    }
    
    
  3. Remove the //TODO comments from the overridden methods



  4. Your rowValidations() method should now look like this



  5. Save and close the Java class

Congratulations! You have customized your first datasource.

You will test this datasource in the next lesson.