Skip to content

Second Tutorial Part 10: Behavior Customization

Laurent Hasson edited this page Dec 4, 2019 · 19 revisions
Previous Main Next
<-- Part 9 Main Part 11 -->

An important part of the Tilda architecture is that it separates the generated classes from the application-level classes that you can customize. Not only can you add new methods in either the Factory or Data classes as we have highlighted in this tutorial, but there are also methods you can override. Based on the object's definition, a variety of methods with empty bodies will be defined in the generated application classes.

🎈 NOTE: Default implementations of required overridable methods will be generated the first time a class is introduced in the system. If an object's definition is changed during the course of development, then the application-class won't be re-generated and a compiler error might occur as a result. For example, you might change the OCC status of a class and suddenly your App class should define its own touch method. Most modern IDEs will flag this and even offer a quick way to add the method to our class which you can then complete with an implementation.

Example

For the purpose of this tutorial, we'll look at a Dummy table in our tutorial defined as such:

  • We'll turn off OCC
  • nameNorm is an AUTO column
  • charCount is a CALCULATED column
    ,{ "name":"Dummy"
      ,"description":"Dummy class for testing purpose"
      ,"occ":false
      ,"columns":[
          { "name":"nameFirst", "type":"STRING" , "size":255, "nullable":false
           ,"description":"A first name"
          }
         ,{ "name":"nameLast" , "type":"STRING" , "size":255, "nullable":false
           ,"description":"A last name"
          }
         ,{ "name":"nameNorm" , "type":"STRING" , "size":255, "nullable":false, "mode":"AUTO"
           ,"description":"A normalized name as upper(nameLast+','+nameFirst)."
          }
         ,{ "name":"charCount", "type":"INTEGER"            , "nullable":true , "mode":"CALCULATED"
           ,"description":"An application-side only count of the character length of nameNorm."
          }
        ]
      ,"primary": { "autogen": true, "keyBatch": 500 }
      ,"indices": [ 
          { "name":"nameNorm", "columns": ["nameNorm"] }
        ]
     }

The generated Java application class will look like:

public class Dummy_Data extends tilda_tutorial.data._Tilda.TILDA__DUMMY
 {
   protected static final Logger LOG = LogManager.getLogger(Dummy_Data.class.getName());

   public Dummy_Data() { }

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//   Implement your customizations, if any, below.
/////////////////////////////////////////////////////////////////////

   @Override
   public int getCharCount()
    {
      // return something
    }

   @Override
   protected boolean beforeWrite(Connection C) throws Exception
     {
       // Do things before writing the object to disk, for example, take care of AUTO fields.
       return true;
     }

   @Override
   protected boolean afterRead(Connection C) throws Exception
     {
       // Do things after an object has just been read, for example, take care of AUTO fields.
       return true;
     }

  @Override
  public boolean touch(Connection C)
  throws Exception
    {
      // Do things here to update your custom life-cycle tracker fields if any.
      // return true for success, or false for failure.
    }
 }

Getters And Setters

Getters and setters are declared as final in the generated Data base class. They are not overridable: this decision was taken lightly: because the behavior of a setter or getter is complex, they shouldn't be overridden in general and introduced too many issues in earlier versions of the framework.

However, if a column is defined as "mode":"CALCULATED", the getter will be declared as abstract in the base class and therefore will need to be concretized in the application-level Data class. defining a column as CALCULATED delegates the column to only exist in the application-space: no column will actually be declared in the database. It is then your responsibility to provide a getter implementation. Of course, no setter will be generated.

🎈 NOTE: The default generated method will cause a compile error and will require immediate attention. A body needs to be provided for an implementation that only you can write.

Additionally, if a column is defined as "mode":"AUTO", the setter will be protected and the field will be expected to be handled in the beforeRead() method, as described below.

OCC (Optimistic Concurrency control)

By default, all objects are OCC-enabled and key life-cycle management columns such as created, lastpdated and deleted are automatically generated. However, if the object is declared with "occ":false, those fields won't be defined and an abstract touch() method will defined.

🎈 NOTE: The default generated method will cause a compile error and will require immediate attention. A body needs to be provided for an implementation that only you can write.

Object Life-Cycle Events

Before an object is written to the database, the beforeWrite() method is called. After an object has been read from the database, the afterRead() method is called.

Typically, logic in there can perform additional validation, logging, keep track of cached values which may be used by AUTO or CALCULATED fields etc...

Previous Main Next
<-- Part 9 Main Part 11 -->
Clone this wiki locally