With entities we mean Entity Beans or EJB3 JPA2 POJOs, i.e. a persistent class like a Company or Person for example. In the EJB3 cartridge you will not need to worry about the underlying persistence technology, but you will probably want to know that EJB3 POJOs will be generated for the entities you model. The EJB 3.0 container (i.e. JBoss) adopts a suitable configurable persistence technology. (i.e Hibernate)
In order to successfully generate a single entity it is sufficient to simply model a single class and assign it the <<Entity>> stereotype, this stereotype tells the EJB3 cartridge to treat this class as an entity.
Let's start by modeling a package org.andromda.test and putting a class inside that package, give that class the name Car. Now make sure that entity has the <<Entity>> stereotype.
You can now try to generate code from your model and take a look at what is generated. If you don't know how to generate code using AndroMDA then head on over to the getting started guide (specifically the section explaining how to setup your first AndroMDA project).
If everything went well, all code related to this class will have been generated into the core/target/src project subdirectory, no manual implementation will need to be added at this point.
The EJB3 cartridge changes the conventional entity creation hierarchy. Instead of generating an entity base class with an entity implementation class, there are 2 ways the EJB3 cartridge can generate your entity POJOs.
The class we have modeled does not have any properties, however, by default, AndroMDA creates the id attribute of type datatype:Long if no identifier (primary key) attribute has been modeled by the user. It is possible to override these settings in the namespace properties for the AndroMDA maven plugin or the namespace properties for Ant. Click here if you want to know more about the default namespace properties you can set.
Your relational table's name which persists an entity is determined by default from the actual entity name. To change the table name assignment in the @javax.persistence.Table annotation, set the <<Entity>> andromda_persistence_table tag on the entity. The same tag can be modeled on a Many-To-Many association relationship, to name the association table.
To assign an entity's attribute as a primary key, you must assign the <<Identifier>> stereotype to it. If this identifier is not part of a composite primary key, then @javax.persistence.Id annotation is added to the attribute getter method.
An entity identifier attribute's generator type can be modeled via the <<Identifier>> andromda_persistence_generator_type tag on the identifier attribute ONLY. You do not need to configure the andromda_hibernate_generator_class attribute on the Entity stereotype. This is used to model the primary key generation strategy associated with the @javax.persistence.Id annotation for an entity attribute. Currently, the EJB3 cartridge supports generator types:
Natural keys must specify a generator type of NONE, in order to override the default type, and also andromda_persistence_assigned_identifier=true. Generally, any non-numeric identifier will be a natural key, typically a 'name' column. Many legacy databases use natural keys for foreign key columns instead of generated identifier values.
andromda_persistence_generator_name specifies the id generator name. The generator name must be a unique name for a persistence unit, which is referenced by one or more classes to be the generator for an entity bean, or else you will get a JPA validation error. By default, if unspecified, the generator name will be 'Entity_generator'. The name is used both in the @javax.persistence.GeneratedValue(strategy=GenerationType.XXX, generator="Entity_generator") and the @javax.persistence.XXXGenerator(name="Entity_generator") where XXX is the type of generator. This specifies either the table name that stores the generated ids or the sequence name which is the name of the database sequence object used to get the ids.
For sequence generator types, you can specify the initial value of the sequence using <<Identifier>> andromda_persistence_generator_initial_value tag and the allocation size by andromda_persistence_generator_allocation_size tag. The allocation size sets the amount to increment by when allocating id numbers from the sequence generator. All of these settings have default values or are allowed to be empty in the annotations.
For a table generator, you must specify the andromda_persistence_generator_pkcolumn_value tag which defines the primary key value in the generator table to identify the specified generated value from other values.
You can set the column name, size, precision, scale, and DDL definition on entity properties under the <<PersistentProperty>> stereotype. By default the column name is the upperunderscore version of the property name, i.e. firstName is column FIRST_NAME. Associations of multiplicity * are pluralized, so you want to override the default column name. To turn off pluralization, in the andromda.xml default namespace:
<property name="pluralizeAssociationEndNames">false</property>
To change the default naming schema for the relational table column, model the <<PersistentProperty>> andromda_persistence_schema tag on the attribute.
You can set the column length for the relational database table for string based columns by modeling the andromda_persistence_column_length tag on the attribute. String attributes are by default length 20, if unspecified.
If the column is defined as a decimal column (i.e. float or double), you can model the precision and scale of the column by setting andromda_persistence_column_precision tag to set the precision of the decimal column and/or andromda_persistence_column_scale tag to set the scale for a decimal column, on the attribute. A column defined as NUMBER(35, 2) has a precision of 35 (35 significant digits) and a scale of 2 (number of digits to the right (positive) or left (negative) of the decimal point). For example, Oracle DBMS supports precision 1-38 and scale -84 to 127
In order to change the creation DDL for the column in the relational table, you can model andromda_persistence_column_definition tag on the attribute. This adds the @javax.persistence.Column(columnDefinition="") annotation. This DDL is DBMS specific, may not be portable between local test and dev/prod databases.
Length, precision, scale, and lowerBound (nullable) are automatically validated through the JPA validator annotations, so Entities that fail validation will not be persisted and an error message is returned. For the serial column, the additional validations will be:
@javax.persistence.Size(max=15)
It's possible to configure the multiplicity of an entity's property, by setting it to [0..1], meaning the lowerBound is 0 and the property is not required and is allowed to be set to null; setting the multiplicity to a value greater than 0 means the property is required. In the former case the nullable element will be set to true for the @javax.persistence.Column annotation on the property. If not nullable or required, the @javax.persistence.NotNull(message="serial is required") annotation will be added to the property. The following class assigns a multiplicity of [0..1] [lowerBound..upperBound] to the name property which means name can be null.
Some UML tools have a default multiplicity value for attributes when not specified by the user, these default values may differ from tool to tool.
LowerBound (nullable) property is automatically validated through the Hibernate validator utilities, so Entities that fail validation will not be persisted and an error message is returned. The additional validation will be:
@javax.persistence.NotNull(message="serial is required")
If you want an entity's attribute to be unique for all instances of that entity's type, in UML2 mark the attribute as 'Unique'. In UML14, you should assign the <<Unique>> stereotype to it. This will define the corresponding unique element in the @javax.persistence.Column annotation. It will also generate a attribute on the JPA2 @Column(unique=true) annotation, and generate a findByAttribute query, except for identifier properties.
To indicate an attribute as transient (not persisted by the persistence container), you model the <<Transient>> stereotype on the attribute. This adds the @javax.persistence.Transient annotation to the attribute.
To include the mapped column in the SQL insert statement, you set the insertable property on the @javax.persistence.Column annotation which is done by modeling the andromda_persistence_column_insert on the attribute. By default, this is set to true, so it only needs to be specified if you want the column to be initialized using the database default value.
To include the mapped column in the SQL update statement, you set the updatable property on the @javax.persistence.Column annotation which is done by modeling the andromda_persistence_column_update on the attribute. By default, this is set to true, so it only needs to be specified if you want the column to be updated using by the database automatically. The attribute will be read-only from the database.
To specify an attribute as a version attribute, where it becomes the optimistic lock value for an entity, you model the <<Version>> stereotype on this attribute. This can only apply to ONE attribute per class. Attributes with this stereotype will not be updated by the persistent container. The attribute can only of the following types:
To define static constants within an entity POJO (constants that are not resource injections), model a classifier scoped attribute (static in Java). These attributes are defined as static with public visibility. Constants must define a default value in the model. The following entity defines 3 constants for type. Static attributes and operations are shown as underlined in the UML model diagram.
An attribute can be specified as either a BLOB or CLOB field. This is modeled by setting the attribute type to datatype::Blob or datatype::Clob. This will add the @javax.persistence.Lob annotation to the entity attribute. The EJB3 cartridge will assign a default Java type based on the Java mappings specified in AndroMDA. For a Blob, the default is byte[]. For a Clob, the default is String. To override the default types, you can model the <<PersistentAttribute>> andromda_persistence_lob_type tagged value to the fully qualified name of the required type.
For BLOB fields, the attribute type must be modeled as one of:
For CLOB fields, the attribute type must be modeled as one of:
The default fetch type for a LOB typed attribute is lazy. To assign a LOB attribute to be eagerly fetched, model the andromda_persistence_fetch_type tag on the attribute.
This example models the attribute named type as a CLOB where the corresponding column in the table will be of type String and the cartridge will set the fetch type for the attribute to eagerly fetch. The attribute information is defined as a LOB, but it's of type char[].
Hibernate supports mapping date, datetime, and time database types to java.util.Data Java type. The type mapping is done through the <<TemporalElement>> andromda_persistence_temporal_type with options of DATE, TIME, TIMESTAMP, and NONE. This results in @javax.persistence.Temporal(TemporalType.XXX) annotation on the attribute.
Custom hibernate type mappings can be used for Enumerations or other types. For example, if a Java boolean type has an underlying column which uses CHAR(1) Y/N values, the PersistentClass stereotype attribute andromda_hibernate_type="yes_no" can be used, resulting in a JPA annotation @org.hibernate.annotations.Type(type="yes_no"). Note that this is a hibernate-specific extension to JPA.
By default, the EJB3 cartridge and EJB 3.0 spec defines an attribute fetch type as eagerly fetched. To specify an attribute as lazy fetched, we hint to the persistence container by modeling the <<PersistentAssociationEnd>> andromda_persistence_fetch_type tag on the attribute. Under normal circumstances, you do not need to specify this tag.
You may also model operations on an entity, this will generate them as methods in the resulting components. Operations can be classifier scoped (static in Java) where they will be underlined in UML diagrams as shown below. You may also define instance scoped operations if you require.
In general, operations will not be defined in the mapped superclass. They will be defined in the inheriting subclass. This has consequences when dealing with a multi-tier inheritance hierarchy. Refer to the inheritance howto for further information. This also implies that operations are only added to the implementation class on the first run of AndroMDA. Operations defined in the UML model must be manually added to the implementation class afterwards. This shouldn't cause any issues, as the developer would have to define the operation implementation anyway to correspond to the abstract definition in the mapped superclass. The primary purpose for this strategy is to avoid having to annotate the entity operation with @javax.persistence.Transient annotation in both the mapped superclass and the inheriting implementation class.
Classifier scoped operations modeled on entity, marked as query operations (finder methods) are not rendered in the entity components, but instead added to the DAO components.
Entity operations modeled as Query operations are discussed further in the Query Howto. In general entities should NOT contain any business logic. The EJB3 cartridge, like other persistence modeling cartridges, uses the session facade pattern to contain business logic in session bean operations while typical CRUD persistence operations are provided through the DAO layer.
The above example entity models allCarsAreRented() as classifier scoped and isRented() as instance scoped. Both will be added to the entity implementation subclass Car. The bulk of the entity detail, including much of the metadata exists within the CarEmbeddable class. In such cases where non-query operations exists for an entity, the implementation class is generated once only and will not be overridden.
If you want an operation to have a parameter which is allowed to be null then simply set the multiplicity lowerBound to 0 (in UML2). In UML14, assign the <<Nullable>> stereotype to that parameter. By default service operations throw an exception when a null argument has been passed.
It is possible to globally disable checking for null arguments; to do so just specify the
<property name="parameterRequiredCheck">false</property>
In some cases, setting up lifecycle event callbacks for the entity beans can be quite useful. The EJB3 cartridge provides the facility to define these callback methods in the listener class. This class is NOT generated by default. To find out more information, click on Listener Callback.
The following model validations are performed against evey Entity when a model is loaded.
EJB3EntityFacade::entities can only generalize other entities or mapped superclasses
Entity::entities can only specialize other entites
Entity::entity must have at least one primary key
If using a JPA Framework as the ancestor for each entity class, you will want to model the ancestor generalization, include the framework dependency in the core pom.xml, and disable this model validation in andromda.xml through:
<constraints enforceAll="true"> <constraint enforce="false">org::andromda::cartridges::ejb3::metafacades::EJB3EntityFacade::entities can only generalize other entities or mapped superclasses</constraint>
Next we will learn about the DAO components generated for the entities, click here to continue.