openxava / documentation / Chapter 2: Model XML (classic)

1.Introduction XML | 2.Model XML | 3.View XML | 4.Tab XML | 5.Mapping XML | 6.Aspects XML

Table of contents

Chapter 2: Model XML (classic)
Java Implementation
Business Component
Entity and aggregates
Entity
Bean
EJB (2)
Implements (3)
Property (4)
Stereotype
IMAGES_GALLERY stereotype (new in v2.0)
Concurrency and version property (new in v2.2.3)
Valid values
Calculator
Default value calculator
Validator
Default validator (new in v2.0.3)
Calculation (new in v5.7)
Reference (5)
Default value calculator in references
Collection (6)
Method (7)
Finder (8)
Postcreate calculator (9)
Postmodify calculator (11)
Postload and preremove calculator (10, 12)
Validator (13)
Remove validator (14)
Aggregate
Reference to aggregate
Collection of aggregates
Many-to-many relationships
Support for XML components was dropped in v7.0
The model layer in an object oriented application contains the business logic, that is the structure of the data and all calculations, validations and processes associated to this data.
OpenXava is a model oriented framework where the model is the most important, and the rest (e.g. user interface) depends on it.
The way to define the model in OpenXava is using XML and a few of Java. OpenXava generates a complete Java implementation of your model from your definition.

Java Implementation

Currently OpenXava generates code for the next 4 alternatives:
  1. Plain Java Classes (the so-called POJOs) for the model using Hibernate for persistence.
  2. Plain Java Classes for the model using EJB3 JPA (Java Persistence API) for persistence (new in v2.1).
  3. Classic EJB2 EntityBeans for the model and persistence.
  4. POJOs + Hibernate inside an EJB2 container.
The option 2 is the default one (new in v3.0) and the best for the most cases. The option 1 is also good, specially if you need to use Java 1.4. The option 3 is for supporting all the OpenXava applications written using EJB2 (EJB2 was the only option in OpenXava 1.x). The option 4 can be useful in some circumstances. You can see how to configure this in OpenXavaTest/properties/xava.properties.

Business Component

As you have seen the basic unit to create an OpenXava application is the business component. A business component is defined using a XML file. The structure of a business component in OpenXava is:
<?xml version="1.0" encoding="ISO-8859-1"?>
 
<!DOCTYPE component SYSTEM "dtds/component.dtd">
 
<component name="ComponentName">
 
    <!-- Model -->
    <entity>...</entity>
    <aggregate name=”...”>...</aggregate>
    <aggregate name=”...”>...</aggregate>
    ...
 
    <!-- View -->
    <view>...</view>
    <view name="...">...</view>
    <view name="...">...</view>
    ...
 
    <!-- Tabular data -->
    <tab>...</tab>
    <tab name=”...”>...</tab>
    <tab name=”...”>...</tab>
    ...
 
    <!-- Object relational mapping -->
    <entity-mapping table="...">...</entity-mapping>
    <aggregate-mapping aggregate=”...” table="...">...</aggregate-mapping>
    <aggregate-mapping aggregate=”...” table="...">...</aggregate-mapping>
    ...
 
</component>
The first part of the component, the part of entity and aggregates, is used to define the model. In this chapter you will learn the complete syntax of this part.

Entity and aggregates

The definition for entity and aggregate are practically identical. The entity is the main object that represents the business concept, while aggregates are additional object needed to define the business concept but cannot have its own life. For example, when you define an Invoice component, the heading data of invoice are in entity, while for invoice lines you can create an aggregate called InvoiceDetail; the life cycle of an invoice line is attached to the invoice, that is an invoice line without invoice has no meaning, and sharing an invoice line by various invoices is not possible, hence you will model InvoiceDetail as aggregate.
Formally, the relationship between A and B is aggregation, and B can be modeled as an aggregate when:
Sometimes the same concept can be modeled as aggregate or as entity in another component. For example, the address concept. If the address is shared by various persons then you must use a reference to entity, while if each person has his own address maybe an aggregate is a good option.

Entity

The syntax of entity is:
<entity>
    <bean ... />                      <!--  1 -->
    <ejb ... />                       <!--  2 -->
    <implements .../> ...             <!--  3 -->
    <property .../> ...               <!--  4 -->
    <reference .../> ...              <!--  5 -->
    <collection .../> ...             <!--  6 -->
    <method .../> ...                 <!--  7 -->
    <finder .../> ...                 <!--  8 -->
    <postcreate-calculator .../> ...  <!--  9 -->
    <postload-calculator .../> ...    <!-- 10 -->
    <postmodify-calculator .../> ...  <!-- 11 -->
    <preremove-calculator .../> ...   <!-- 12 -->
    <validator .../> ...              <!-- 13 -->
    <remove-validator .../> ...       <!-- 14 -->
</entity>
  1. bean (one, optional): Allows you to use an already existing JavaBean (a simple Java class, the so-called POJO). This applies if you use JPA o Hibernate as persistence engine. In this case the code generation for POJO and Hibernate mapping of this component will not be produced.
  2. ejb (one, optional): Allows you to use an already existing EJB. This only applies if you use EJB CMP2 as persistence engine. In this case code generation for EJB code of this component will not be produced. It does not apply to EJB3.
  3. implements (several, optional): The generated code will implement this interface.
  4. property (several, optional): The properties represent Java properties (with its setters an getters) in the generated code.
  5. reference (several, optional): References to other models, you can reference to the entity of another component or an aggregate of itself.
  6. collection (several, optional): Collection of references. In the generated code it is a property that returns a java.util.Collection.
  7. method (several, optional): Creates a method in the generated code, in this case the method logic is in a calculator (ICalculator).
  8. finder (several, optional): Used to generate finder methods. Finder methods are static method located in the POJO class. In the case of EJB2 generation EJB2 finders are generated.
  9. postcreate-calculator (several, optional): Logic to execute after making an object persistent. In Hibernate in a PreInsertEvent, in EJB2 in the ejbPostCreate method.
  10. postload-calculator (several, optional): Logic to execute just after load the state of an object from persistent storage. In Hibernate in a PostLoadEvent, in EJB2 in the ejbLoad method.
  11. postmodify-calculator (several, optional): Logic to execute after modifying a persistent object and before storing its state in persistent storage. In Hibernate in a PreUpdateEvent, in EJB2 in the ejbStore method.
  12. preremove-calculator (several, optional): Logic to execute just before removing a persistent from persistent storage. In Hibernate in PreDeleteEvent, in EJB2 in the ejbRemove method.
  13. validator (several, optional): Executes a validation at model level. This validator can receive the value of various model properties. To validate a single property it is better to use a property level validator.
  14. remove-validator (several, optional): It's executed before removal, and can deny the object removing.

Bean

With <bean/> you can specify that you want to use your own Java class.
For example:
<entity>
    <bean class="org.openxava.test.model.Family"/>
    ...
In this simple way you can write your own Java code instead of using OpenXava to generate it.
For our example you can write a Family class as follows:
package org.openxava.test.model;
 
import java.io.*;
 
/**
 * @author Javier Paniza
 */
public class Family implements Serializable {
 
    private String oid;
    private int number;
    private String description;
 
    public String getOid() {
        return oid;
    }
    public void setOid(String oid) {
        this.oid = oid;
    }
 
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
 
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
 
}
If you want a reference from the OpenXava generated code to your own handwritten code, then your Java class has to implement an interface (IFamily in this case) that extends IModel (see org.openxava.test.Family in OpenXavaTest/src).
Additionally you have to define the mapping using Hibernate:
<?xml version="1.0"?>
 
<!DOCTYPE hibernate-mapping
    SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping package="org.openxava.test.model">
 
  <class
      name="Family"
      table="XAVATEST@separator@FAMILY">
 
    <id name="oid" column="OID" access="field">
        <generator class="uuid"/>
    </id>
 
    <property name="number" column="NUMBER"/>
    <property name="description" column="DESCRIPTION"/>
 
  </class>
 
</hibernate-mapping>
You can put this file in the hibernate folder of your project. Moreover in this folder you have the hibernate.cfg.xml file that you have to edit in this way:
    ...
    <session-factory>
        ...
        <mapping resource="Family.hbm.xml"/>
        ...
    </session-factory>
    ...
In this easy way you can wrap your existing Java and Hibernate code with OpenXava. Of course, if you are creating a new system it is much better to rely on the OpenXava code generation.

EJB (2)

With <ejb/> you can specify that you want to use your own EJB (1.1 and 2.x version).
For example:
<entity>
    <ejb remote="org.openxava.test.ejb.Family"
        home="org.openxava.test.ejb.FamilyHome"
        primaryKey="org.openxava.test.ejb.FamilyKey"
        jndi="ejb/openxava.test/Family"/>
    ...
In this simple way you can write you own EJB code instead of using code that OpenXava generates.
You can write the EJB code from scratch (only for genuine men), if you are a normal programmer (hence lazy) probably you prefer to use wizards, or better yet XDoclet. If you choose to use XDoclet, then you can put your own XDoclet classes in the package model (or another package of your choice. This depends on the value of the model.package variable in build.xml) in src folder of your project.; and your XDoclet code will be generated with the rest of OpenXava code.
For our example you can write a FamilyBean class in this way:
package org.openxava.test.ejb.xejb;
 
import java.util.*;
import javax.ejb.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @ejb:bean name="Family" type="CMP" view-type="remote"
 *     jndi-name="OpenXavaTest/ejb/openxava.test/Family"
 * @ejb:interface extends="org.openxava.ejbx.EJBReplicable"
 * @ejb:data-object extends="java.lang.Object"
 * @ejb:home extends="javax.ejb.EJBHome"
 * @ejb:pk extends="java.lang.Object"
 *
 * @jboss:table-name "XAVATEST@separator@FAMILY"
 *
 * @author Javier Paniza
 */
abstract public class FamilyBean
    extends org.openxava.ejbx.EJBReplicableBase // 1
    implements javax.ejb.EntityBean {
 
    private UUIDCalculator oidCalculator = new UUIDCalculator();
 
    /**
      * @ejb:interface-method
      * @ejb:pk-field
      * @ejb:persistent-field
      *
      * @jboss:column-name "OID"
      */
    public abstract String getOid();
    public abstract void setOid(String nuevoOid);
 
    /**
      * @ejb:interface-method
      * @ejb:persistent-field
      *
      * @jboss:column-name "NUMBER"
      */
    public abstract int getNumber();
    /**
     * @ejb:interface-method
     */
    public abstract void setNumber(int newNumber);
 
    /**
     * @ejb:interface-method
     * @ejb:persistent-field
     *
     * @jboss:column-name "DESCRIPTION"
     */
    public abstract String getDescription();
    /**
      * @ejb:interface-method
      */
    public abstract void setDescription(String newDescription);
 
    /**
     * @ejb:create-method
     */
    public FamilyKey ejbCreate(Map properties) // 2
        throws
            javax.ejb.CreateException,
            org.openxava.validators.ValidationException,
            java.rmi.RemoteException {
        executeSets(properties);
        try {
            setOid((String)oidCalculator.calculate());
        }
        catch (Exception ex) {
            ex.printStackTrace();
            throw new EJBException(
                "Impossible to create Family because:\n" +
                ex.getLocalizedMessage()
            );
        }
        return null;
    }
 
    public void ejbPostCreate(Map properties) throws javax.ejb.CreateException {
    }
}
On writing your own EJB you must fulfill two little restrictions:
  1. The class must extend from org.openxava.ejbx.EJBReplicableBase
  2. It is required at least a ejbCreate (with its ejbPostCreate) that receives as argument a map and assign its values to the bean, as in the example.
Yes, yes, a little intrusive, but are not the EJB the intrusion culmination?

Implements (3)

With <implements/> you specify a Java interface that will be implemented by the generated code. Let's see it:
<entity>
    <implements interface="org.openxava.test.model.IWithName"/>
    ...
    <property name="name" type="String" required="true"/>
    ...
And you can write your Java interface in this way:
package org.openxava.test.model;
 
import java.rmi.*;
 
/**
 * @author Javier Paniza
 */
public interface IWithName {
 
    String getName() throws RemoteException;
 
}
Beware to make that generated code implements your interface. In this case you have a property named name that generates a method called getName() that implements the interface.
In your generated code you can find an ICustomer interface:
public interface ICustomer extends org.openxava.test.model.IWithName {
    ...
}
In the POJO generated code you can see:
public class Customer implements Serializable, org.openxava.test.model.ICustomer {
    ...
}
In the EJB generated code (if you generate it) you can see the remote interface:
public interface CustomerRemote extends
    org.openxava.ejbx.EJBReplicable,
    org.openxava.test.model.ICustomer
and the EJB bean class is affected too
abstract public class CustomerBean extends EJBReplicableBase
    implements
        org.openxava.test.model.ICustomer,
        EntityBean
This pithy feature makes the polymorphism a privileged guest of OpenXava.
As you can see OpenXava generates an interface for each component. It's good that in your code you use these interfaces instead of POJO classes or EJB2 remote interfaces. All code made in this way can be used with POJO and EJB2 version on same time, or allows you to migrate from a EJB2 to a POJO version with little effort. Although, if you are using POJOs exclusively you may use the POJOs classes directly and ignore the interfaces, as you wish.

Property (4)

An OpenXava property corresponds exactly to a Java property. It represents the state of an object that can be read and in some cases updated. The object does not have the obligation to store physically the property data, it only must return it when required.
The syntax to define a property is:
<property
    name="propertyName"              <!--  1 -->
    label="label"                    <!--  2 -->
    type="type"                      <!--  3 -->
    stereotype="STEREOTYPE"          <!--  4 -->
    size="size"                      <!--  5 -->
    scale="scale"                    <!--  6  new in v2.0.4 -->
    required="true|false             <!--  7 -->
    key="true|false"                 <!--  8 -->
    hidden="true|false"              <!--  9 -->
    search-key="true|false"          <!-- 10  new in v2.2.4 -->
    version="true|false"             <!-- 11  new in v2.2.3 -->
>
    <valid-values .../>              <!-- 12 -->
    <calculator .../>                <!-- 13 -->
    <default-value-calculator .../>  <!-- 14 -->
    <calculation .../>               <!-- 15  new in v5.7 -->
    <validator .../> ....            <!-- 16 -->
</property>
  1. name (required): The property name in Java, therefore it must follow the Java convention for property names, like starting with lower-case. Using underline (_) is not advisable.
  2. label (optional): Label showed to the final user. Is much better use the i18n files.
  3. type (optional): It matches with a Java type. All types valid for a Java property are valid here, this include classes defined by you. You only need to provide a converter to allow saving in database and a editor to render as HTML; thus that things like java.sql.Connection or so can be a little complicated to manage as a property, but not impossible. It's optional, but only if you have specified <bean/> or <ejb/> or this property has a stereotype with a associated type.
  4. stereotype (optional): Allows to specify an special behavior for some properties.
  5. size (optional): Length in characters of property. Useful to generate user interfaces. If you do not specify the size, then a default value is assumed. This default value is associated to the stereotype or type and is obtained from default-size.xml.
  6. scale (optional): (new in v2.0.4) Scale (size of decimal part) of property. Only applies to numeric properties. If you do not specify the scale, then a default value is assumed. This default value is associated to the stereotype or type and is obtained from default-size.xml.
  7. required (optional): Indicates if this property is required. By default this is true for key properties hidden (new in v2.1.3) or without default value calculator on create and false in all other cases. On saving OpenXava verifies if the required properties are present. If this is not the case, then saving is not done and a validation error list is returned. The logic to determine if a property is present or not can be configured by creating a file called validators.xml in your project. You can see the syntax in OpenXava/xava/validators.xml.
  8. key (optional): Indicates that this property is part of the key. At least one property (or reference) must be key. The combination of key properties (and key references) must be mapped to a group of database columns that do not have duplicate values, typically the primary key.
  9. hidden (optional): A hidden property has a meaning for the developer but not for the user. The hidden properties are excluded when the automatic user interface is generated. However at Java code level they are present and fully functional. Even if you put it explicitly into a view the property will be shown in the user interface.
  10. search-key (optional): (new in v2.2.4) The search key properties are used by the user as key for searching objects. They are editable in user interface of references allowing to the user type its value for searching. OpenXava uses the key (key=”true”) properties for searching by default, and if the key (key=”true”) properties are hidden then it uses the first property in the view. With search-key you can choose explicitly the properties for searching.
  11. version (optional): (new in v2.2.3) A version property is used for optimistic concurrency control. If you want control concurrency you only need to have a property marked as version=”true” in your component. Only a single version property should be used per component. The following types are supported for version properties: int, Integer, short, Short, long, Long, Timestamp. The version properties are considered hidden.
  12. valid-values (one, optional): To indicate that this property only can have a limited set of valid values.
  13. calculator (one, optional): Implements the logic for a calculated property. A calculated property only has getter and is not stored in database.
  14. default-value-calculator (one, optional): Implements the logic to calculate the default (initial) value for this property. A property with default-value-calculator has setter and it is persistent.
  15. calculation (one, optional): (new in v5.7) Arithmetic expression to do the calculation for the property. The calculation is done in the user interface when any operand changes.
  16. validator (several, optional): Implements the validation logic to execute on this property before modifying or creating the object that contains it.

Stereotype

A stereotype is the way to determine a specific behavior of a type. For example, a name, a comment, a description, etc. all correspond to the Java type java.lang.String but you surely wish validators, default sizes, visual editors, etc. different in each case and you need to tune finer; you can do this assigning a stereotype to each case. That is, you can have the next sterotypes NAME, MEMO or DESCRIPTION and assign them to your properties.
OpenXava comes with these generic stereotypes:
Now you will learn how to define your own stereotype. You will create one called PERSON_NAME to represent names of persons.
Edit (or create) the file editors.xml in your folder xava. And add:
<editor url="personNameEditor.jsp">
    <for-stereotype stereotype="PERSON_NAME"/>
</editor>
This way you define the editor to render for editing and displaying properties of stereotype PERSON_NAME.
Also you can edit stereotype-type-default.xml and the line:
<for stereotype="PERSON_NAME" type="String"/>
Furthermore it is useful to indicate the default size; you can do this by editing default-size.xml of your project:
<for-stereotype name="PERSON_NAME" size="40"/>
Thus, if you do not put the size in a property of type PERSON_NAME a value of 40 is assumed.
Not so common is changing the validator for required, but if you wish to change it you can do it adding to validators.xml of your project the next definition:
<required-validator>
    <validator-class class="org.openxava.validators.NotBlankCharacterValidator"/>
    <for-stereotype stereotype="PERSON_NAME"/>
</required-validator>
Now everything is ready to define properties of stereotype PERSON_NAME:
<property name="name" stereotype="PERSON_NAME" required="true"/>
In this case a value of 40 is assumed as size, String as type and the NotBlankCharacterValidator validator is executed to verify if it is required.

IMAGES_GALLERY stereotype (new in v2.0)

If you want that a property of your component hold a gallery of images. You only have to declare your property with the IMAGES_GALLERY stereotype, in this way:
<property name="photos" stereotype="IMAGES_GALLERY"/>
Furthermore, in the mapping part you have to map your property to a table column suitable to store a String with a length of 32 characters (VARCHAR(32)).
And everything is done.
In order to support this stereotype you need to setup the system appropriately for your application.
First, create a table in your database to store the images:
CREATE TABLE IMAGES (
    ID VARCHAR(32) NOT NULL PRIMARY KEY,
    GALLERY VARCHAR(32) NOT NULL,
    IMAGE BLOB);
 
CREATE INDEX IMAGES01
    ON IMAGES (GALLERY);
The type of IMAGE column can be a more suitable one for your database to store byte [] (for example LONGVARBINARY) .
The name of the table is arbitrary. You need to specify the table name and schema (new in v2.2.4) name in your configuration file (a .properties file in the root of your OpenXava project). In this way:
images.schema=MYSCHEMA
images.table=IMAGES
If you want to work without schema (new in v3.0.2) you need to put the property image.schema.definition of your configuration to empty string, as following:
images.schema.definition=
And finally you need to define the mapping in your hibernate/hibernate.cfg.xml file, thus:
<hibernate-configuration>
    <session-factory>
        ...
        <mapping resource="GalleryImage.hbm.xml"/>
        ...
    </session-factory>
</hibernate-configuration>
After this you can use the IMAGES_GALLERY stereotype in all components of your application.

Concurrency and version property (new in v2.2.3)

Concurrency is the ability of the application to allow several users to save data at same time without losing data. OpenXava uses an optimistic concurrency schema. Using optimistic concurrency the records are not locked allowing high concurrency without losing data integrity.
For example, if a user A read a record and then a user B read the same record, modify it and save the changes, when the user A try to save the record he receives an error, then he need to refresh the data and retry his modification.
For activating concurrency support for an OpenXava component you only need to declare a property using version=”true”, in this way:
<property name="version" type="int" version="true"/>
This property is for use of persistence engine (Hibernate or JPA), your application or your user must not use this property directly.

Valid values

The element <valid-values/> allows you to define a property that can hold one of the indicated values only. Something like a C (or Java 5) enum.
It's easy to use, let's see this example:
<property name="distance">
    <valid-values>
        <valid-value value="local"/>
        <valid-value value="national"/>
        <valid-value value="international"/>
    </valid-values>
</property>
The distance property only can take the following values: local, national or international, and as you have not put required=”true” the blank value is allowed too. The type is not necessary, int is assumed.
At user interface level the current implementation uses a combo. The label for each value is obtained from the i18n files.
At Java generated code level creates a distance property of type int that can take the values 0 (no value), 1 (local), 2 (national) o 3 (international).
At database level the value is by default saved as an integer, but you can configure easily to use another type and work with no problem with legate databases. See more at object/relational mapping chapter.

Calculator

A calculator implements the logic to execute when the getter method of a calculated property is called. The calculated properties are read only (only have getter) and not persistent (they do not match with any column of database table).
A calculated property is defined in this way:
<property name="unitPriceInPesetas" type="java.math.BigDecimal" size="18">
    <calculator class="org.openxava.test.calculators.EurosToPesetasCalculator">
        <set property="euros" from="unitPrice"/>
    </calculator>
</property>
Now when you (or OpenXava to fill the user interface) call to getUnitPriceInPesetas() the system executes EurosToPesetasCalculator calculator, but before this it sets the value of the property euros of EurosToPesetasCalculator with the value obtained from unitPrice of the current object.
Seeing the calculator code may be instructive:
package org.openxava.test.calculators;
 
import java.math.*;
import org.openxava.calculators.*;
 
/**
 * @author Javier Paniza
 */
public class EurosToPesetasCalculator implements ICalculator { // 1
 
    private BigDecimal euros;
 
    public Object calculate() throws Exception {               // 2
        if (euros == null) return null;
        return euros.multiply(new BigDecimal("166.386")).
            setScale(0, BigDecimal.ROUND_HALF_UP);
    }
 
    public BigDecimal getEuros() {
        return euros;
    }
    public void setEuros(BigDecimal euros) {
        this.euros = euros;
    }
 
}
You can notice two things, first (1) a calculator must implement org.openxava.calculators.ICalculator, and (2) the method calculate() executes the logic to generate the value returned by the property.
According to the above definitions now you can use the generated code in this way:
Product product = ...
product.setUnitPrice(2);
BigDecimal result = product.getUnitPriceInPesetas();
And result will hold 332.772.
You can define a calculator without set from to define values for properties, as shown below:
<property name="detailsCount" type="int" size="3">
    <calculator class="org.openxava.test.calculators.DetailsCountCalculator">
        <set property="year"/>
        <set property="number"/>
    </calculator>
</property>
In this case the property year and number of DetailsCountCalculator calculator are filled from properties of same name from the current object.
The from attribute supports qualified properties, as following:
<aggregate name="Address">
    <property name="street" type="String" size="30" required="true"/>
    <property name="zipCode" type="int" size="5" required="true"/>
    <property name="city" type="String" size="20"    required="true"/>
    <reference name="state" required="true"/>
    <property name="asString" type="String">
        <calculator class="org.openxava.calculators.ConcatCalculator">
            <set property="string1" from="street"/>
            <set property="int2" from="zipCode"/>
            <set property="string3" from="city"/>
            <set property="string4" from="state.name"/>        <!-- 1 -->
            <set property="int5" from="customer.number"/>      <!-- 2 -->
        </calculator>
    </property>
</aggregate>
The property string4 (1) of the calculator is filled using the value of name of the state (that is a reference), this a qualified property (reference.property). In the case of int5 (2) you can see that customer reference is not declared in Address, because it is referenced from the Customer entity, therefore Address has an implicit reference to its container model (its parent) that you can use in from attribute (new in v2.0.4). That is, the int5 property is filled with the number of the customer which has this address.
Also it's possible to assign a constant value to a calculator property:
<property name="fullName" type="String">
    <calculator class="org.openxava.calculators.ConcatCalculator">
        <set property="string1" from="id"/>
        <set property="separator" value=" - "/>
        <set property="string2" from="name"/>
    </calculator>
</property>
In this case the property separator of ConcatCalculator has a constant value.
Another interesting feature of calculator is that you can access from it to the model object (entity or aggregate) that contains the property that is being calculated:
<property name="amountsSum" stereotype="MONEY">
    <calculator class="org.openxava.test.calculators.AmountsSumCalculator"/>
</property>
And the calculator:
package org.openxava.test.calculators;
 
import java.math.*;
import java.rmi.*;
import java.util.*;
 
import javax.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
 
public class AmountsSumCalculator implements IModelCalculator { // 1
 
    private IInvoice invoice;
 
    public Object calculate() throws Exception {
        Iterator itDetails = invoice.getDetails().iterator();
        BigDecimal result = new BigDecimal(0);
        while (itDetails.hasNext()) {
            IInvoiceDetail detail = (IInvoiceDetail) itDetails.next();
            result = result.add(detail.getAmount());
        }
        return result;
    }
 
    public void setModel(Object model) throws RemoteException { // 2
        invoice = (IInvoice) model;
    }
 
}
This calculator implements IModelCalculator (1) (new in v2.0) and to do this it has a method setModel (2), this method is called before calling the calculate() method and thus allows access to the model object (in this case an invoice) that contains the property inside calculate().
Within the code generated by OpenXava you can find an interface for each business concept that is implemented by the POJO class, the EJB2 remote interface and the EJB2 Bean class. That is for Invoice you have a IInvoice interface implemented by Invoice (POJO class), InvoiceRemote (EJB2 remote interface) and InvoiceBean (EJB2 bean class), this last two only if you generate EJB2 code. In the calculator of type IModelCalculator it is advisable to cast to this interface, because in this cases the same calculator works with POJOs, EJB2 remote interface and EJB2 bean class. If you are developing with a POJO only version (maybe the normal case) you can cast directly to the POJO class, in this case Invoice.
This calculator type is less reusable than that which receives simple properties, but sometimes are useful. Why is it less reusable? For example, if you use IInvoice to calculate a discount, this calculator only could be applied to invoices, but if you uses a calculator that receives amount and discountPercentage as simple properties this last calculator could be applied to invoices, deliveries, orders, etc.
From a calculator you have direct access to JDBC connections, here is an example:
<property name="detailsCount" type="int" size="3">
    <calculator class="org.openxava.test.calculators.DetailsCountCalculator">
        <set property="year"/>
        <set property="number"/>
    </calculator>
</property>
And the calculator class:
package org.openxava.test.calculators;
 
import java.sql.*;
 
import org.openxava.calculators.*;
import org.openxava.util.*;
 
/**
 * @author Javier Paniza
 */
public class DetailsCountCalculator implements IJDBCCalculator {       // 1
 
    private IConnectionProvider provider;
    private int year;
    private int number;
 
    public void setConnectionProvider(IConnectionProvider provider) {  // 2
        this.provider = provider;
    }
 
    public Object calculate() throws Exception {
        Connection con = provider.getConnection();
        try {
            PreparedStatement ps = con.prepareStatement(
                "select count(*) from XAVATEST_INVOICEDETAIL “ +
                “where INVOICE_YEAR = ? and INVOICE_NUMBER = ?");
            ps.setInt(1, getYear());
            ps.setInt(2, getNumber());
            ResultSet rs = ps.executeQuery();
            rs.next();
            Integer result = new Integer(rs.getInt(1));
            ps.close();
            return result;
        }
        finally {
            con.close();
        }
    }
 
    public int getYear() {
        return year;
    }
 
    public int getNumber() {
        return number;
    }
 
    public void setYear(int year) {
        this.year = year;
    }
 
    public void setNumber(int number) {
        this.number = number;
    }
 
}
To use JDBC your calculator must implement IJDBCCalculator (1) and then it will receive a IConnectionProvider (2) that you can use within calculate(). Yes, the JDBC code is ugly and awkward, but sometime it can help to solve performance problems.
The calculators allow you to insert your custom logic in a system where all code is generated; and as you see it promotes the creation of reusable code because the calculators nature (simple and configurable) allows you to use them time after time to define calculated properties and methods. This philosophy, simple and configurable classes that can be plugged in several places is the cornerstone that sustains all OpenXava framework.
OpenXava comes with a set of predefined calculators, you can find them in org.openxava.calculators.

Default value calculator

With <default-value-calculator/> you can associate logic to a property, but in this case the property is readable, writable and persistent. This calculator is for calculating its initial value. For example:
<property name="year" type="int" key="true" size="4" required="true">
    <default-value-calculator
        class="org.openxava.calculators.CurrentYearCalculator"/>
</property>
In this case when the user tries to create a new Invoice (for example) he will find that the year field already has a value, that he can change if he wants to do.
You can indicate that the value will be calculated just before creating (inserting into database) an object for the first time; this is done this way:
<property name="oid" type="String" key="true" hidden="true">
    <default-value-calculator
        class="org.openxava.calculators.UUIDCalculator"
        on-create="true"/>
</property>
If you use on-create=”true” then you will obtain that effect.
A typical use of the on-create=”true” is for generating identifiers automatically. In the above example, an unique identifier of type String and 32 characters is generated. Also you can use other generation techniques, for example, a database sequence can be defined in this way:
<property name="id" key="true" type="int" hidden="true">
    <default-value-calculator
        class="org.openxava.calculators.SequenceCalculator" on-create="true">
            <set property="sequence" value="XAVATEST_SIZE_ID_SEQ"/>
    </default-value-calculator>
</property>
Or maybe you want to use an identity (auto increment) column as key:
<property name="id" key="true" type="int" hidden="true">
    <default-value-calculator
        class="org.openxava.calculators.IdentityCalculator" on-create="true"/>
</property>
SequenceCalculator (new in v2.0.1) and IdentityCalculator (new in v2.0.2) do not work with EJB2. They work with Hibernate and EJB3.
If you define a hidden key property with no default calculator with on-create=”true” then it uses identity, sequence or hilo techniques automatically depending upon the capabilities of the underlying database. As this:
<property name="oid" type="int" hidden="true" key="true"/>
Also, this only works with Hibernate and EJB3, not in EJB2.
All others issues about <default-value-calculator/> are as in <calculator/>.

Validator

The validator execute validation logic on the value assigned to the property just before storing. A property may have several validators.
<property name="description" type="String" size="40" required="true">
    <validator class="org.openxava.test.validators.ExcludeStringValidator">
        <set property="string" value="MOTO"/>
    </validator>
    <validator class="org.openxava.test.validators.ExcludeStringValidator"
        only-on-create="true">
        <set property="string" value="COCHE"/>
    </validator>
</property>
The technique to configure the validator (with <set/>) is exactly the same than in calculators. With the attribute only-on-create="true" you can define that the validation will be executed only when the object is created, and not when it is modified.
The validator code is:
package org.openxava.test.validators;
 
import org.openxava.util.*;
import org.openxava.validators.*;
 
/**
 * @author Javier Paniza
 */
 
public class ExcludeStringValidator implements IPropertyValidator { // 1
 
    private String string;
 
    public void validate(
        Messages errors,         // 2
        Object value,            // 3
        String objectName,       // 4
        String propertyName)     // 5
        throws Exception {
        if (value==null) return;
        if (value.toString().indexOf(getString()) >= 0) {
            errors.add("exclude_string", propertyName, objectName, getString());
        }
    }
 
    public String getString() {
        return string==null?"":string;
    }
 
    public void setString(String string) {
        this.string = string;
    }
 
}
A validator has to implement IPropertyValidator (1), this obliges to the calculator to have a validate() method where the validation of property is executed. The arguments of validate() method are:
As you can see when you find a validation error you have to add it (with errors.add()) by sending a message identifier and the arguments. If you want to obtain a significant message you need to add to your i18n file the next entry:
exclude_string={0} cannot contain {2} in {1}
If the identifier sent is not found in the resource file, this identifier is shown as is; but the recommended way is always to use identifiers of resource files.
The validation is successful if no messages are added and fails if messages are added. OpenXava collects all messages of all validators before saving and if there are messages, then it display them and does not save the object.
The package org.openxava.validators contains some common validators.

Default validator (new in v2.0.3)

You can define a default validator for properties depending of its type or stereotype. In order to do it you have to use the file xava/validators.xml of your project to define in it the default validators.
For example, you can define in your xava/validators.xml the following:
<validators>
    <default-validator>
        <validator-class
            class="org.openxava.test.validators.PersonNameValidator"/>
        <for-stereotype stereotype="PERSON_NAME"/>
    </default-validator>
</validators>
In this case you are associating the validator PersonNameValidator to the stereotype PERSON_NAME. Now if you define a property as the next one:
<property name="name" stereotype="PERSON_NAME" required="true"/>
This property will be validated using PersonNameValidator although the property itself does not define any validator. PersonNameValidator is applied to all properties with PERSON_NAME stereotype.
You can also assign a default validator to a type.
In validators.xml files you can also define the validators for determine if a required value is present (executed when you use required="true"). Moreover you can assign names (alias) to validator classes.
You can learn more about validators examining OpenXava/xava/validators.xml and OpenXavaTest/xava/validators.xml.

Calculation (new in v5.7)

With <calculation/> you can define an arithmetic expression to do the calculation for the property. The expression can contain +, -, *, (), numeric values and properties names of the same entity. For example:
<property name="total" type="BigDecimal">
    <calculation>((hours * worker.hourPrice) + tripCost - discount) * (1 + vatPercentage / 100)</calculation>
</property>
Note as worker.hourPrice is used to get the value from the reference.
The calculation is executed and displayed when the user changes any value of the properties used in the expression in the user interface, however the value is not saved until the user clicks on save button.

Reference (5)

A reference allows access from an entity or an aggregate to another entity or aggregate. A reference is translated to Java code as a property (with its getter and its setter) whose type is the referenced model Java type. For example a Customer can have a reference to his Seller, and that allows you to write code like this:
ICustomer customer = ...
customer.getSeller().getName();
to access to the name of the seller of that customer.
The syntax of reference is:
<reference
    name="name"                      <!-- 1 -->
    label="label"                    <!-- 2 -->
    model="model"                    <!-- 3 -->
    required="true|false"            <!-- 4 -->
    key="true|false"                 <!-- 5 -->
    search-key="true|false"          <!-- 6  New in v3.0.2 -->
    role="role"                      <!-- 7 -->
>
    <default-value-calculator .../>  <!-- 8 -->
</reference>
  1. name (optional, required if model is not specified): The name of reference in Java, hence must follow the rules to name members in Java, including start by lower-case. If you do not specify name the model name with the first letter in lower-case is assumed. Using underline (_) is not advisable.
  2. label (optional): Label shown to the final user. It's much better use i18n.
  3. model (optional, required if name is not specified): The model name to reference. It can be the name of another component, in which case it is a reference to entity, or the name of a aggregate of the current component. If you do not specify model the reference name with the first letter in upper-case is assumed.
  4. required (optional): Indicates if the reference is required. When saving OpenXava verifies if the required references are present, if not the saving is aborted and a list of validation errors is returned.
  5. key (optional): Indicates if the reference is part of the key. The combination of key properties and reference properties should map to a group of database columns with unique values, typically the primary key.
  6. search-key (optional): (New in v3.0.2) The search key references are used by the user as key for searching objects. They are editable in user interface of references allowing to the user type its value for searching. OpenXava uses the key (key=”true”) members for searching by default, and if the key (key=”true”) members are hidden then it uses the first property in the view. With search-key you can choose explicitly references for searching.
  7. role (optional): Used only in references within collections. See below.
  8. default-value-calculator (one, optional): Implements the logic for calculating the initial value of the reference. This calculator must return the key value, that can be a simple value (only if the key of referenced object is simple) or key object (a special object that wraps the key and is generated by OpenXava).
A little example of references use:
<reference model="Address" required="true"/>        <!-- 1 -->
<reference name="seller"/>                          <!-- 2 -->
<reference name="alternateSeller" model="Seller"/>  <!-- 3 -->
  1. A reference to an aggregate called Address, the reference name will be address.
  2. A reference to the entity of Seller component. The model is deduced from name.
  3. A reference called alternateSeller to the entity of component Seller.
If you assume that this is in a component named Customer, you could write:
ICustomer customer = ...
Address address = customer.getAddress();
ISeller seller = customer.getSeller();
ISeller alternateSeller = customer.getAlternateSeller();

Default value calculator in references

In a reference <defaut-value-calculator/> works like in a property, only that it has to return the value of the reference key, and on-create="true" is not allowed.
For example, in the case of a reference with simple key, you can write:
<reference name="family" model="Family2" required="true">
    <default-value-calculator class="org.openxava.calculators.IntegerCalculator">
        <set property="value" value="2"/>
    </default-value-calculator>
</reference>
The calculate() method is:
public Object calculate() throws Exception {
    return new Integer(value);
}
As you can see an integer is returned, that is, the default value for family is 2.
In the case of composed key:
<reference name="warehouse" model="Warehouse">
    <default-value-calculator
        class="org.openxava.test.calculators.DefaultWarehouseCalculator"/>
</reference>
And the calculator code:
package org.openxava.test.calculators;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
public class DefaultWarehouseCalculator implements ICalculator {
 
    public Object calculate() throws Exception {
        Warehouse key = new Warehouse();
        key.setNumber(4);
        key.setZoneNumber(4);
        return key; // This works with POJO and EJB2
        // return new WarehouseKey(new Integer(4), 4); // This only work with EJB2
    }
 
}
Returns an object of type Warehouse, (or WarehouseKey if you use only EJB2).

Collection (6)

With <collection/> you define a collection of references to entities or aggregates. This is translated to Java as a property of type java.util.Collection.
Here syntax for collection:
<collection
    name="name"                    <!-- 1 -->
    label="label"                  <!-- 2 -->
    minimum="N"                    <!-- 3 -->
    maximum="N"                    <!-- 4 new v2.0.3 -->
>
    <reference ... />              <!-- 5 -->
    <condition ... />              <!-- 6 -->
    <order ... />                  <!-- 7 -->
    <calculator ... />             <!-- 8 -->
    <postremove-calculator ... />  <!-- 9 -->
</collection>
  1. name (required): The collection name in Java, therefore it must follow the rules for name members in Java, including starting with lower-case. Using underline (_) is not advisable.
  2. label (optional): Label shown to final user. Is much better to use i18n files.
  3. minimum (optional): Minimum number of expected elements. This is validated just before saving.
  4. maximum (optional): (new v2.0.3) Maximum number of expected elements.
  5. reference (required): With the syntax you can see in the previous point.
  6. condition (optional): Restricts the elements that appear in the collection.
  7. order (optional): The elements in collections will be in the indicated order.
  8. calculator (optional): Allows you to define your own logic to generate the collection. If you use this, then you cannot use neither condition nor order.
  9. postremove-calculator (optional): Execute your custom logic just after an element is removed from collection.
Let's have a look at some examples. First a simple one:
<collection name="deliveries">
    <reference model="Delivery"/>
</collection>
If you have this within an Invoice, then you are defining a deliveries collection associated to that Invoice. The details to make the relationship are defined in the object/relational mapping.
Now you can write a code like this:
IInvoice invoice = ...
for (Iterator it = invoice.getDeliveries().iterator(); it.hasNext();) {
    IDelivery delivery = (IDelivery) it.next();
    delivery.doSomething();
}
To do something with all deliveries associated to an invoice.
Let's look at another example a little more complex, but still in Invoice:
<collection name="details" minimum="1">  <!-- 1 -->
    <reference model="InvoiceDetail"/>
    <order>${serviceType} desc</order>   <!-- 2 -->
    <postremove-calculator               <!-- 3 -->
        class="org.openxava.test.calculators.DetailPostremoveCalculator"/>
</collection>
In this case you have a collection of aggregates, the details (or lines) of the invoice. The main difference between collection of entities and collection of aggregates is when you remove the main entity; in the case of a collection of aggregates its elements are deleted too. That is when you delete an invoice its details are deleted too.
  1. The restriction minimum="1" requires at least one detail for the invoice to be valid.
  2. With order you force that the details will be returned ordered by serviceType.
  3. With postremove-calculator you indicate the logic to execute just after a invoice detail is removed.
Let's look at the calculator code:
package org.openxava.test.calculators;
 
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
public class DetailPostremoveCalculator implements IModelCalculator {
 
    private IInvoice invoice;
 
    public Object calculate() throws Exception {
        invoice.setComment(invoice.getComment() + "DETAIL DELETED");
        return null;
    }
 
    public void setEntity(Object model) throws RemoteException {
        this.invoice = (IInvoice) model;
    }
 
}
As you see this is a conventional calculator as it is used in calculated properties. A thing to consider is that the calculator is applied to the container entity (in this case Invoice) and not to the collection element. That is, if your calculator implements IModelCalculator then it receives an Invoice and not an InvoiceDetail. This is consistent because it is executed after the detail is removed and the detail doesn't exist any more.
You have full freedom to define how the collection data is obtained, with condition you can overwrite the default condition generated by OpenXava:
<!-- Others carriers of same warehouse -->
<collection name="fellowCarriers">
    <reference model="Carrier"/>
    <condition>
        ${warehouse.zoneNumber} = ${this.warehouse.zoneNumber} AND
        ${warehouse.number} = ${this.warehouse.number} AND
        NOT (${number} = ${this.number})
    </condition>
</collection>
If you have this collection within Carrier, you can obtain with this collection all carriers of the same warehouse but not himself, that is the list of his fellow workers. As you see you can use this in the condition in order to reference the value of a property of current object.
If with this you have not enough, you can write the logic that returns the collection. The previous example can be written in the following way too:
<!--
The same that 'fellowCarriers' but implemented with a calculator
-->
<collection name="fellowCarriersCalculated">
    <reference model="Carrier"/>
    <calculator class="org.openxava.test.calculators.FellowCarriersCalculator"/>
</collection>
And here the calculator code:
package org.openxava.test.calculators;
 
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
public class FellowCarriersCalculator implements IModelCalculator {
 
    private ICarrier carrier;
 
    public Object calculate() throws Exception {
        // Using Hibernate
        int warehouseZoneNumber = carrier.getWarehouse().getZoneNumber();
        int warehouseNumber = carrier.getWarehouse().getNumber();
        Session session = XHibernate.getSession();
        Query query = session.createQuery("from Carrier as o where " +
                "o.warehouse.zoneNumber = :warehouseZone AND " +
                "o.warehouse.number = :warehouseNumber AND " +
                "NOT (o.number = :number)");
        query.setInteger("warehouseZone", warehouseZoneNumber);
        query.setInteger("warehouseNumber", warehouseNumber);
        query.setInteger("number", carrier.getNumber());
        return query.list();
 
        /* Using EJB3 JPA
        EntityManager manager = XPersistence.getManager();
        Query query = manager.createQuery("from Carrier c where " +
            "c.warehouse.zone = :zone AND " +
            "c.warehouse.number = :warehouseNumber AND " +
            "NOT (c.number = :number) ");
        query.setParameter("zone", getWarehouse().getZone());
        query.setParameter("warehouseNumber", getWarehouse().getNumber());
        query.setParameter("number",  getNumber());
        return query.getResultList();
        */
 
        /* Using EJB2
        return CarrierUtil.getHome().findFellowCarriersOfCarrier(
            carrier.getWarehouseKey().getZoneNumber(),
            carrier.getWarehouseKey().get_Number(),
            new Integer(carrier.getNumber())
        );
        */
    }
 
    public void setModel(Object model) throws RemoteException {
        carrier = (ICarrier) model;
    }
 
}
As you see this is a conventional calculator. Obviously it must return a java.util.Collection whose elements are of type ICarrier.
The references in collections are bidirectional, this means that if in a Seller you have a customers collection, then in Customer you must have a reference to Seller. But if in Customer you have more than one reference to Seller (for example, seller and alternateSeller) OpenXava does not know which to choose, for this case you have the attribute role of reference. You can use it in this way:
<collection name="customers">
    <reference model="Customer" role="seller"/>
</collection>
To indicate that the reference seller and not alternateSeller will be used in this collection.
In the case of a collection of entity references you have to define the reference at the other side, but in the case of a collection of aggregate references this is not necessary, because in the aggregates a reference to this container is automatically generated.

Method (7)

With <method/> you can define a method that will be included in the generated code as a Java method.
The syntax for method is:
<method
    name="name"              <!-- 1 -->
    type="type"              <!-- 2 -->
    arguments="arguments"    <!-- 3 -->
    exceptions="exceptions"  <!-- 4 -->
>
    <calculator ... />       <!-- 5 -->
</method>
  1. name (required): Name of the method in Java, therefore it must follow the Java rules to name members, like beginning with lower-case.
  2. type (optional, by default void): Is the Java type that the method returns. All Java types valid as return type for a Java method are applicable here.
  3. arguments (optional): Argument list of the method in Java format.
  4. exceptions (optional): Exception list that can be thrown by this method, in Java format.
  5. calculator (required): Implements the logic of the method.
Defining a method is easy:
<method name="increasePrice">
    <calculator class="org.openxava.test.calculators.IncreasePriceCalculator"/>
</method>
And the implementation depends on the logic that you want to program. In this case:
package org.openxava.test.calculators;
 
import java.math.*;
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.model.*;
 
/**
 * @author Javier Paniza
 */
public class IncreasePriceCalculator implements IModelCalculator {
 
    private IProduct product;
 
    public Object calculate() throws Exception {
        product.setUnitPrice(    // 1
            product.getUnitPrice().
                multiply(new BigDecimal("1.02")).setScale(2));
        return null;             // 2
    }
 
    public void setModel(Object model) throws RemoteException {
        this.product = (IProduct) model;
    }
 
}
All applicable things for calculators in properties are applicable to methods too, with the next clarifications:
  1. A calculator for a method has moral authority to change the state of the object.
  2. If the return type of the method is void the calculator must return null.
Now you can use the method in the expected way:
IProduct product = ...
product.setUnitPrice(new BigDecimal(100));
product.increasePrice();
BigDecimal newPrice = product.getUnitPrice();
And in newPrice you have 102.
Another example, now a little bit more complex:
<method name="getPrice" type="BigDecimal"
    arguments="String country, BigDecimal tariff"
    exceptions="ProductException, PriceException">
    <calculator class="org.openxava.test.calculators.ExportPriceCalculator">
        <set property="euros" from="unitPrice"/>
    </calculator>
</method>
In this case you can notice that in arguments and exceptions the Java format is used, since what you put there is inserted directly into the generated code.
The calculator:
package org.openxava.test.calculators;
 
import java.math.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
 
public class ExportPriceCalculator implements ICalculator {
 
    private BigDecimal euros;
    private String country;
    private BigDecimal tariff;
 
    public Object calculate() throws Exception {
        if ("España".equals(country) || "Guatemala".equals(country)) {
            return euros.add(tariff);
        }
        else {
            throw new PriceException("Country not registered");
        }
    }
 
    public BigDecimal getEuros() {
        return euros;
    }
    public void setEuros(BigDecimal decimal) {
        euros = decimal;
    }
 
    public BigDecimal getTariff() {
        return tariff;
    }
    public void setTariff(BigDecimal decimal) {
        tariff = decimal;
    }
 
    public String getCountry() {
        return country;
    }
    public void setCountry(String string) {
        country = string;
    }
}
Each argument is assigned to a property of the name in the calculator; that is, the value of the first argument, country, is assigned to country property, and the value of the second one, tariff, to the tariff property. Of course, you can configure values for others calculator properties with <set/> as usual in calculators.
And to use the method:
IProduct product = ...
BigDecimal price = product.getPrice(“España”, new BigDecimal(100)); // works
product.getPrice(“El Puig”, new BigDecimal(100)); // throws PriceException
Methods are the sauce of the objects, without them the object only would be a silly wrapper of data. When possible it is better to put the business logic in methods (model layer) instead of in actions (controller layer).

Finder (8)

A finder is a special method that allows you to find an object or a collection of objects that follow some criteria. In POJO version a finder method is a generated static method in the POJO class. In the EJB2 version a finder matches with a finder in home.
The syntax for finder is:
<finder
    name="name"                <!-- 1 -->
    arguments="arguments"      <!-- 2 -->
    collection="(true|false)"  <!-- 3 -->
>
    <condition ... />          <!-- 4 -->
    <order ... />              <!-- 5 -->
</finder>
  1. name (required): Name of the finder method in Java, hence it must follow the Java rules for member naming, e.g. beginning with lower-case.
  2. arguments (required): Argument list for the method in Java format. It is (most) advisable to use simple data types.
  3. collection (optional, by default false): Indicates if the result will be a single object or a collection.
  4. condition (optional): A condition with SQL/EJBQL syntax where you can use the names of properties inside ${}.
  5. order (optional): An order with SQL/EJBQL syntax where you can use the names of properties inside ${}.
Some examples:
<finder name="byNumber" arguments="int number">
    <condition>${number} = {0}</condition>
</finder>
 
<finder name="byNameLike" arguments="String name" collection="true">
    <condition>${name} like {0}</condition>
    <order>${name} desc</order>
</finder>
 
<finder
    name="byNameLikeAndRelationWithSeller"
    arguments="String name, String relationWithSeller"
    collection="true">
    <condition>${name} like {0} and ${relationWithSeller} = {1}</condition>
    <order>${name} desc</order>
</finder>
 
<finder name="normalOnes" arguments="" collection="true">
    <condition>${type} = 1</condition>
</finder>
 
<finder name="steadyOnes" arguments="" collection="true">
    <condition>${type} = 2</condition>
</finder>
 
<finder name="all" arguments="" collection="true"/>
This generates a set of finder methods available from POJO class and EJB2 home. This methods can be used this way:
// POJO, both JPA and Hibernate
ICustomer customer = Customer.findByNumber(8);
Collection javieres = Customer.findByNameLike(%JAVI%);
 
// EJB2
ICustomer customer = CustomerUtil.getHome().findByNumber(8);
Collection javieres = CustomerUtil.getHome().findByNameLike(%JAVI%);

Postcreate calculator (9)

With <postcreate-calculator/> you can plug in your own logic to execute just after creating the object as persistent object.
Its syntax is:
<postcreate-calculator
    class="class">        <!-- 1 -->
    <set ... /> ...       <!-- 2 -->
</postcreate-calculator>
  1. class (required): Calculator class. This calculator must implement ICalculator or some of its children.
  2. set (several, optional): To set the value of the calculator properties before executing it.
A simple example is:
<postcreate-calculator
    class="org.openxava.test.calculators.DeliveryTypePostcreateCalculator">
    <set property="suffix" value="CREATED"/>
</postcreate-calculator>
And now the calculator class:
package org.openxava.test.calculators;
 
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
public class DeliveryTypePostcreateCalculator implements IModelCalculator {
 
    private IDeliveryType deliveryType;
    private String suffix;
 
    public Object calculate() throws Exception {
        deliveryType.setDescription(deliveryType.getDescription() + " " + suffix);
        return null;
    }
 
    public void setModel(Object model) throws RemoteException {
        deliveryType = (IDeliveryType) model;
    }
 
    public String getSuffix() {
        return suffix;
    }
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
 
}
In this case each time that a DeliveryType is created, just after it, a suffix to description is added.
As you see, this is exactly the same as in other calculators (as calculated properties or method) but is executed just after creation.

Postmodify calculator (11)

With <postmodify-calculator/> you can plug in some logic to execute after the state of the object is changed and just before it is stored in the database, that is, just before executing UPDATE against database.
Its syntax is:
<postmodify-calculator
    class="class">       <!-- 1 -->
    <set ... /> ...      <!-- 2 -->
</postmodify-calculator>
  1. class (required): Calculator class. A calculator that implements ICalculator or some of its children.
  2. set (several, optional): To set the value of the calculator properties before execute it.
A simple example is:
<postmodify-calculator
    class="org.openxava.test.calculators.DeliveryTypePostmodifyCalculator"/>
And now the calculator class:
package org.openxava.test.calculators;
 
import java.rmi.*;
 
import org.openxava.calculators.*;
import org.openxava.test.ejb.*;
 
/**
 * @author Javier Paniza
 */
 
public class DeliveryTypePostmodifyCalculator implements IModelCalculator {
 
    private IDeliveryType deliveryType;
 
    public Object calculate() throws Exception {
        deliveryType.setDescription(deliveryType.getDescription() + " MODIFIED");
        return null;
    }
 
    public void setModel(Object model) throws RemoteException {
        deliveryType = (IDeliveryType) model;
    }
 
}
In this case whenever that a DeliveryType is modified a suffix is added to its description.
As you see, this is exactly the same as in other calculators (as calculated properties or methods), but it is executed just after modifying.

Postload and preremove calculator (10, 12)

The syntax and behavior of postload and preremove calculators are the same of the postcreate and and postmodify ones.

Validator (13)

This validator allows to define a validation at model level. When you need to make a validation on several properties at a time, and that validation does not correspond logically with any of them, then you can use this type of validation.
Its syntax is:
<validator
    class="class"                <!-- 1 -->
    name="name"                  <!-- 2 -->
    only-on-create="true|false"  <!-- 3 -->
>
    <set ... /> ...              <!-- 4 -->
</validator>
  1. class (optional, required if name is not specified): Class that implements the validation logic. It has to be of type IValidator.
  2. name (optional, required if class is not specified): This name is a validator name from xava/validators.xml file of your project or of the OpenXava project.
  3. only-on-create (optional): If true the validator is executed only when creating a new object, not when an existing object is modified. The default value is false.
  4. set (several, optional): To set a value of the validator properties before executing it.
An example:
<validator class="org.openxava.test.validators.CheapProductValidator">
    <set property="limit" value="100"/>
    <set property="description"/>
    <set property="unitPrice"/>
</validator>
And the validator code:
package org.openxava.test.validators;
 
import java.math.*;
 
import org.openxava.util.*;
import org.openxava.validators.*;
 
/**
 * @author Javier Paniza
 */
public class CheapProductValidator implements IValidator {     // 1
 
    private int limit;
    private BigDecimal unitPrice;
    private String description;
 
    public void validate(Messages errors) {                    // 2
        if (getDescription().indexOf("CHEAP") >= 0
            || getDescription().indexOf("BARATO") >= 0            || getDescription().indexOf("BARATA") >= 0) {
            if (getLimitBd().compareTo(getUnitPrice()) < 0) {
                errors.add("cheap_product", getLimitBd());     // 3
            }
        }
    }
 
    public BigDecimal getUnitPrice() {
        return unitPrice;
    }
 
    public void setUnitPrice(BigDecimal decimal) {
        unitPrice = decimal;
    }
 
    public String getDescription() {
        return description==null?"":description;
    }
 
    public void setDescription(String string) {
        description = string;
    }
 
    public int getLimit() {
        return limit;
    }
 
    public void setLimit(int i) {
        limit = i;
    }
 
    private BigDecimal getLimitBd() {
        return new BigDecimal(limit);
    }
 
}
This validator must implement IValidator (1), this forces you to write a validate(Messages messages) (2). In this method you add the error message ids (3) (whose texts are in the i18n files). And if the validation process (that is the execution of all validators) produces some error, then OpenXava does not save the object and displays the errors to the user.
In this case you see how description and unitPrice properties are used to validate, for that reason the validation is at model level and not at individual property level, because the scope of validation is more than one property.

Remove validator (14)

The <remove-validator/> is a level model validator too, but in this case it is executed just before removing an object, and it has the possibility to deny the deletion.
Its syntax is:
<remove-validator
    class="validator"  <!-- 1 -->
    name="name"        <!-- 2 -->
>
    <set ... /> ...    <!-- 3 -->
</remove-validator>
  1. class (optional, required if name is not specified): Class that implements the validation logic. Must implement IRemoveValidator.
  2. name (optional, required if class is not specified): This name is a validator name from the xava/validators.xml file of your project or from the OpenXava project.
  3. set (several, optional): To set the value of the validator properties before executing it.
An example can be:
<remove-validator
    class="org.openxava.test.validators.DeliveryTypeRemoveValidator"/>
 
And the validator:
package org.openxava.test.validators;
 
import java.util.*;
 
import org.openxava.test.ejb.*;
import org.openxava.util.*;
import org.openxava.validators.*;
 
/**
 * @author Javier Paniza
 */
public class DeliveryTypeRemoveValidator implements IRemoveValidator {  // 1
 
    private IDeliveryType deliveryType;
 
    public void setEntity(Object entity) throws Exception {             // 2
        this.deliveryType = (IDeliveryType) entity;
    }
 
    public void validate(Messages errors) throws Exception {
        if (!deliveryType.getDeliveries().isEmpty()) {
            errors.add("not_remove_delivery_type_if_in_deliveries");    // 3
        }
    }
 
}
As you see this validator must implement IRemoveValidator (1) this forces you to write a setEntity() (2) method that receives the object to remove. If validation error is added to the Messages object sent to validate() (3) the validation fails. If after executing all validations there are validation errors, then OpenXava does not remove the object and displays a list of validation messages to the user.
In this case it verifies if there are deliveries that use this delivery type before deleting it.

Aggregate

The aggregate syntax is:
<aggregate name="aggregate">   <!-- 1 -->
    <bean class="beanClass"/>  <!-- 2 -->
    <ejb ... />                <!-- 3 -->
    <implements .../>
    <property .../> ...
    <reference .../> ...
    <collection .../> ...
    <method .../> ...
    <finder .../> ...
    <postcreate-calculator .../> ...
    <postmodify-calculator .../> ...
    <validator .../> ...
    <remove-validator .../> ...
</aggregate>
  1. name (required): Each aggregate must have a unique name. The rules for this name are the same that for class names in Java, that is, to begin with upper-case and each new word starting with upper-case too.
  2. bean (one, optional): Allows to specify a class written by you to implement the aggregate. The class has to be a JavaBean, that is a plain Java class with getters and setters for properties. Usually this is not used because it is much better that OpenXava generates the code for you.
  3. ejb (one, optional): Allows to use existing EJB2 to implement an aggregate. This can be used only in the case of a collection of aggregates. Usually this is not used because it is much better that OpenXava generates the code for you.
An OpenXava component can have whichever aggregates you want. And you can reference it from the main entity or from another aggregate.

Reference to aggregate

The first example is an aggregate Address that is referenced from the main entity.
In the main entity you can write:
<reference name="address" model="Address" required="true"/>
And in the component level you define:
<aggregate name="Address">
    <implements interface="org.openxava.test.ejb.IWithCity"/>            <!.. 1 -->
    <property name="street" type="String" size="30" required="true"/>
    <property name="zipCode" type="int" size="5" required="true"/>
    <property name="city" type="String" size="20"    required="true"/>
    <reference name="state" required="true"/>                            <!-- 2 -->
</aggregate>
As you see an aggregate can implement an interface (1) and contain references (2), among other things, in fact all thing that you can use in <entity/> are supported in an aggregate.
The resulting code can be used this way, for reading:
ICustomer customer = ...
Address address = customer.getAddress();
address.getStreet(); // to obtain the value
Or in this other way to set a new address:
// to set a new address
Address address = new Address(); // it's a JavaBean, never an EJB2
address.setStreet(“My street”);
address.setZipCode(46001);
address.setCity(“Valencia”);
address.setState(state);
customer.setAddress(address);
In this case you have a simple reference (not collection), and the generated code is a simple JavaBean, whose life cycle is associated to its container object, that is, the Address is removed and created through the Customer. An Address never will have its own life and cannot be shared by other Customer.

Collection of aggregates

Now an example of a collection of aggregates. In the main entity (for example Invoice) you can write:
<collection name="details" minimum="1">
    <reference model="InvoiceDetail"/>
</collection>
And define the InvoiceDetail aggregate:
<aggregate name="InvoiceDetail">
    <property name="oid" type="String" key="true" hidden="true">
        <default-value-calculator
            class="org.openxava.test.calculators.InvoiceDetailOidCalculator"
            on-create="true"/>
    </property>
    <property name="serviceType">
        <valid-values>
            <valid-value value="special"/>
            <valid-value value="urgent"/>
        </valid-values>
    </property>
    <property name="quantity" type="int"
        size="4" required="true"/>
    <property name="unitPrice"
        stereotype="MONEY" required="true"/>
    <property name="amount"
        stereotype="MONEY">
        <calculator
            class="org.openxava.test.calculators.DetailAmountCalculator">
            <set property="unitPrice"/>
            <set property="quantity"/>
        </calculator>
    </property>
    <reference model="Product" required="true"/>
    <property name="deliveryDate" type="java.util.Date">
        <default-value-calculator
            class="org.openxava.calculators.CurrentDateCalculator"/>
    </property>
    <reference name="soldBy" model="Seller"/>
    <property name="remarks" stereotype="MEMO"/>
 
    <validator class="org.openxava.test.validators.InvoiceDetailValidator">
        <set property="invoice"/>
        <set property="oid"/>
        <set property="product"/>
        <set property="unitPrice"/>
    </validator>
 
</aggregate>
As you see an aggregate is as complex as an entity, with calculators, validators, references and so on. In the case of an aggregate used in a collection a reference to the container is added automatically, that is, although you have not defined it, InvoiceDetail has a reference to Invoice.
In the generated code you can find an Invoice with a collection of InvoiceDetail. The difference between a collection of references and a collection of aggregates is that when you remove a Invoice its details are removed too (because they are aggregates). Also there are differences at user interface level (you can learn more on this in chapter 4).
(New in v2.1.1 Reference Guide: Explanation of implicit reference) Every aggregate has a implicit reference to its container model. That is, InvoiceDetail has a reference named invoice, even if the reference is not declared (although it can be optionally declared for refining purpose, for example, for making it key). This reference can be used in Java code, as following:
InvoiceDetail detail = ... ;
detail.getInvoice(); // For obtaining the parent
 
Or it can be used in XML code, in this way:
<property name="oid" type="String" key="true" hidden="true">
    <default-value-calculator
        class="org.openxava.test.calculators.InvoiceDetail2OidCalculator"
        on-create="true">
        <set property="invoiceYear" from="invoice.year"/>       <!-- 1 -->
        <set property="invoiceNumber" from="invoice.number"/>   <!-- 1 -->
    </default-value-calculator>
</property>
In this case we use invoice in the from attribute (1) although invoice is not declared in InvoiceDetail. New in v2.1.1: using reference to parent model key properties in a from attribute (that is, from="invoice.year")

Many-to-many relationships

In OpenXava XML components there is no direct concept of a many-to-many relationship, only collections are availables. Nevertheless modeling a many-to-many relationship in OpenXava is easy. You only need to define collections in both sides of the relationship.
For example, if you have customers and states, and a customer can work in several states, and, obviously, in a state several customers can work, then you have a many-to-many (using relational nomenclature) relationship. Suppose that you have a table CUSTOMER (without reference to state), a table STATE (without reference to customer) and a table CUSTOMER_STATE (to link both tables). Then you can model this case in this way:
<component name="Customer">
    <entity>
    ...
        <collection name="states">                  <!-- 1 -->
            <reference model="CustomerState"/>
        </collection>
    ...
    </entity>
 
    <aggregate name="CustomerState">                <!-- 2 -->
        <reference name="customer" key="true"/>     <!-- 3 -->
        <reference name="state" key="true"/>        <!-- 4 -->
    </aggregate>
    ...
</component>
You define in Customer a collection of aggregates (1), each aggregate (CustomerState) (2) contains a reference to a State (4), and, of course, a reference of its container entity (Customer) (3).
Then you map this collection in the usual way:
<component name="Customer">
    ...
    <aggregate-mapping aggregate="CustomerState" table="CUSTOMER_STATE">
        <reference-mapping reference="customer">
            <reference-mapping-detail
                column="CUSTOMER"                            <!-- 1 -->
                referenced-model-property="number"/>
        </reference-mapping>
        <reference-mapping reference="state">
            <reference-mapping-detail
                column="STATE"                               <!-- 2 -->
                referenced-model-property="id"/>
        </reference-mapping>
    </aggregate-mapping>
</component>
CustomerState is mapped to CUSTOMER_STATE, a table that only contains two columns, one to link to CUSTOMER (1) and other to link to STATE (2).
At model and mapping level all is right, but the User Interface generated by default by OpenXava is somewhat cumbersome in this case. Although with the next refinements to the view part your many-to-many collection will be just fine:
<component name="Customer">
    ...
    <view>
        ...
        <collection-view collection="states">
            <list-properties>state.id, state.name</list-properties>  <!-- 1 -->
        </collection-view>
 
        <members>
            ...
            states
            ...
        </members>
 
    </view>
 
    <view model="CustomerState">
        <reference-view reference="state" frame="false"/>            <!-- 2 -->
    </view>
    ...
</component>
In this view you can see how we define explicitly (1) the properties to be shown in list of the collection states. This is needed because we have to show the properties of the State, not the CustomerState ones. Additionally, we define that reference to State in CustomerState view to be showed without frames (2), this is to avoid two ugly nested frames.

By this easy way you can define a collection to map a many-to-many relationship in the database. If you want a bidirectional relationship only need to create a customers collection in State entity, this collection may be of the aggregate type StateCustomer and must be mapped to the table CUSTOMER_STATE. All in analogy to the example here.