change to english nach Deutsch wechseln

Good and evil

Intro

This page will become a unrelated bunch of tips, what and how to DO with SRJRCFrames and what NOT to do.

... one "Don't" is so important, that I'd like to start with it:

Factories

The most important reason for use of SRJRCFrames, among others, is the flexibility and extensibility. But it does not fit with these goals at all, if factories with "public static" methods convert a groovy application into a big and unmanageable moloch.

The ApplicationContext takes care about those factories and the best of all, they can be changed at runtime. So each factory is an applicationservice wich can be accessed by the public services interface (one of the sparse exceptions to this rule), the ApplicationServiceProvider.

That also works great for applications, that get loaded dynamically and which offer an application service and other applications like to use that service. See below a sample from the RecordingManager of VdrAssistant:

SelectionPopupFactory spf = (SelectionPopupFactory)
                            ApplicationServiceProvider.getService(
                                      SelectionPopupFactory.class);

spf.registerSelectionPopupProvider(BonusItem.class, 
                                   new RecSelectionPopupService());
   

The SelectionPopupFactory is a factory, that offers a popup to select and attach entities of given type. The RecordingManager offers such a popup to select recordings and the JobManager, another loadable application uses it.
To achieve this, the ApplicationServiceProvider is asked for the factory and that factory is than extended with the new service.

Entities

Entities are javabeans, that get stored in a SQL-database. Creating a GUI application it is very commen, that entities are presented with an editor to the user, to change some properties of the Entity. This is where JGoodies comes into play, so I decided to use the JGoody Model-class as a basis for the entities.

public class Person extends AbstractEntity {
   public static final String FLD_NAME = "name";
   private String name;

   public String getName() {
      return name;
   }


   public void setName(String name) {
      this.name = name;
   }
} 

The above is the well known pattern of a java bean - each property has a read- and write method. The superclass AbstractEntity will add some properties for internal management - you don't need to care about those properties, only if you like controlling and statistics. The bean from above needs to get extended, so that it works with an editor:

public void setName(String name) {
   String ov = this.name
   this.name = name;
   if (ov != null) {
      if (name == null || ov.compareTo(name) != 0) setDirty(true);
   } else if (ov != name) setDirty(true);
   PropertyChangeEvent pce = new PropertyChangeEvent(this,
                                                     "name",
                                                     ov,
                                                     name);
   firePropertyChangeEvent(pce);
} 

Only the tossing of an event enables the "black magic" of JGoodies bindings and so is fundamental for SRJRCFrames too. In the codesnippet I anticipated a pattern from SRJRCFrames. The framework heavily uses caching, so an entity will only be stored, if it has been changed. That's what the propery dirty is for.

Internal properties

IMPORTANT: the internal properties should be considered readonly!

dirty
is a virtual property, which means, that it will not be stored. Its use is the distinction of changed and unchanged entities.
id
Each Entity needs a number for identification, which makes an instance unique. This is comparable to java Integers, where there are no different instances that have the same value.
uCreated
The userid of the user, that created that data entry. This property is null for transient entities. The value will be created a storage time.
uModified
The userid of the user, that stored the last modification.
dtCreated
Timestamp of creation
dtModified
Timestamp of last modification
cModified
modification counter

database-access

The database access is fully transparent to the application, so the application code does not reflect, whether a database is envolved or not. The application only uses operations like Read or Save. The rest is internal of the framework.

Most important interface to persistence is the class Transaction and those instances will be created by an applicationservice: the TransactionFactory.

if (taFactory == null)
    taFactory = (TransactionFactory) 
                ApplicationServiceProvider.getService(
                             TransactionFactory.class);

Transaction ta = taFactory.createTransaction();

A Transaction consists of one or more operations, the TransactionOperations. These can be added without restriction. On creation time of an operation or at attaching it to a Transaction nothing will happen. The TransactionOperation is only a recipe on what to do. The operations will be executed, when the whole Transaction gets executed.

A Person could be saved like this:

Person instance = new Person();   
Transaction ta = taFactory.createTransaction();

instance.setName("Brown");
ta.add(new TOSave<Person>(instance));
ta.execute(); 

The reading of Person instances is as easy ...

Transaction ta = taFactory.createTransaction();
TORead<Person> tor = new TORead<Person>(Person.class);

ta.add(tor);
ta.setRollbackOnly();
ta.execute();

List<Person> persons = tor.getResult();   

To find a Person with known name, ...

Transaction ta = taFactory.createTransaction();
ConditionElement ceName = new EqualConditionElement(Person.FLD_NAME, 
                                                    "Brown");
TORead<Person> tor = new TORead<Person>(Person.class,
                                        ceName);

ta.add(tor);
ta.setRollbackOnly();
ta.execute();

List<Person> persons = tor.getResult();    

See the apidocs for further variants of operations. SRJRCFrames supports partially read entities as well as updating a single property.