LSPS documentation logo
LSPS Documentation
Persisting Data using Records

To persist business data from Model instances, define the respective records as shared. These will have their values persisted in the database.

Each record and the relevant relationships are reflected in a database table. When you create a new instance of the record or relationship, a new entry is added to the respective table. The mapping of shared records to tables makes use of Hibernate as its ORM library.

Mapping of shared records to database occurs in accordance with the following rules:

  • Every shared record is stored in its own table.
  • If there are relationship between two records the mapping is realized as follows:
    • If the relationship is 1:1, then the foreign key of the source record is placed in the table of the target record.
    • On the side without the foreign key, fetching is always eager.
    • If the relationship is 1:N, then the foreign key of the source record is placed in the table of the target record.
    • If the relationship is N:N, then the join table with the target-source-record primary keys is created.

Fetching of record instances is governed by Hibernate's principles with the transactions of the LSPS Server.

Customizing Entity Auditing

The revision history of shared Records, or auditing, relies on the Revision Entity that holds the revision ID and its timestamps: When an instance of an audited shared record changes, the Revision Entity calls the Revision Listener implemented by the LspsRevisionListener class. The listener creates a new revision instance with the revision data.

Important: Information on how to set up and use auditing and the related database schema is available in the Modeling guide.

Hence if you want to record custom revision information, you need to do the following:

  1. Expand the Revision Entity shared record by adding a Field or creating a related shared Record.
  2. Implement a custom RevisionListener that extends LspsRevisionListener that will get the data for the field or related shared record.

Important: On WebSphere, it is not possible to implement a custom RevisionListener.

Adding a Field to the Revision Entity

To create a custom Revision Entity with additional field so as to store additional revision information, do the following:

  1. Add the field to the Entity Revision shared Record.
    customrevisionentityfield.png
    Revision entity record with the custom field
  2. Implement the custom RevisionListener:
    1. In the ejb package of your application, create a class that extends the LspsRevisionListener class and implements EJBRevisionListener.
    2. Override the newRevision(Object revisionEntity) method of the your RevisionListener class:

      • Call the newRevision() method of LspsRevisionListener on the input Revision Entity: super.newRevision(revisionEntity);
      • Set the value of the field on the Revision Entity object. ((MapSharedRecordEntity) revisionEntity).set("USER", securityService.getPrincipalName());

      An example implementation is here.

      Important: Including complex logic in your Revision Listener class, such as, contacting an external system to acquire data, might result in performance issues.

  3. Register the ejb.
  4. Open the Properties view of the Revision Entity record.
  5. Open the Auditing tab and insert the class name of your RevisionListener into the Revision Listener class property.
  6. Deploy the application and the Module with the RevisionEntity data model.

Adding a Related Record to the Revision Entity

To create a custom Revision Entity with a related share Record so as to add complex custom information to the revisions, do the following:

  1. Create the related shared Record.

    customrevisionentityrecord.png
    Revision entity record with the custom field and a related record
  2. Deploy the Module with your Revision records to the server to create their Hibernate entities.
  3. Implement the custom RevisionListener:
    1. In the ejb package of your application, create a class that extends LspsRevisionListener class and implements EJBRevisionListener.
    2. Override the newRevision(Object revisionEntity) method in your RevisionListener class:
      • Call the newRevision() method of LspsRevisionListener on the input Revision Entity: super.newRevision(revisionEntity);
        1. Obtain the Hibernate entity of your Revision Entity Record, for example:
          SharedRecordContext sharedRecordContext =
            SharedRecordContextProvider.INSTANCE.getSharedRecordContextByJndi("");
          SharedRecordNamingInfo recordNamingInfo =
            sharedRecordContext.getNamingInfoForEntityName(((ExternalRecordEntity) revisionEntity).getEntityName());
          
        2. Obtain the entity name of the property of the Revision record from Hibernate.java; for example: recordNamingInfo = sharedRecordContext.getNamingInfoForTableName("<YOUR_RECORD_NAME>");
        3. Once you have the hibernate name of the property you need to set, open a hibernate session and set the value of the property:
          Session session = SharedRecordUtils.getSessionFactory(null).getCurrentSession();
          MapSharedRecordEntity entity = new MapSharedRecordEntity("CustomRevisionData");
          entity.set("NAME", "my custom value");
          session.persist(entity);
          ((MapSharedRecordEntity) revisionEntity).set("S_CUSTOM_REVISION_ENTITY_CUSTOMREVISIONDATA", entity);

          Important: Including complex logic in your Revision Listener class, such as, contacting an external system to acquire data, might result in performance issues.

  4. Register the ejb.
  5. In your data model, adjust the Entity Revision shared record to use your implementation and upload the resources.

    revisionentityimplementationclass.png
    Revision Entity shared Record implemented by a custom RevisionListener class

Example Implementation of a Custom Revision Listener

Custom implementation of the RevisionListener must extend the LspsRevisionListener and implement EJBRevisionListener. Once you created your RevisionListener implementation make sure to register it in the ComponentServiceBean:

Example of a custom RevisionListener for a RevisionEntity record with a custom field user

import java.io.Serializable;
 
import javax.annotation.security.PermitAll;
import javax.ejb.EJB;
import javax.ejb.Stateless;
 
import org.hibernate.Session;
import org.hibernate.envers.RevisionType;
 
import com.whitestein.lsps.common.ejb.SecurityManagerServiceLocal;
import com.whitestein.lsps.common.hibernate.SharedRecordContext;
import com.whitestein.lsps.common.hibernate.SharedRecordContextProvider;
import com.whitestein.lsps.common.hibernate.SharedRecordNamingInfo;
import com.whitestein.lsps.common.hibernate.SharedRecordUtils;
import com.whitestein.lsps.hibernate.envers.EJBRevisionListener;
import com.whitestein.lsps.hibernate.envers.LspsRevisionListener;
import com.whitestein.lsps.model.sharedrecord.ExternalRecordEntity;
import com.whitestein.lsps.model.sharedrecord.MapSharedRecordEntity;
 
@Stateless
@PermitAll
public class CustomRevisionListener extends LspsRevisionListener implements EJBRevisionListener {
    //injects the security service (for the user field):
    @EJB
    private SecurityManagerServiceLocal securityService;
 
    @Override
    public void newRevision(Object revisionEntity) {
        super.newRevision(revisionEntity);
 
        //persisting into a custom field in the Revision Entity record:
        ((MapSharedRecordEntity) revisionEntity).set("USER", securityService.getPrincipalName());
    }
}

Example of a custom RevisionListener for a RevisionEntity record with the related record CustomRevisionData

import java.io.Serializable;
 
import javax.annotation.security.PermitAll;
import javax.ejb.EJB;
import javax.ejb.Stateless;
 
import org.hibernate.Session;
import org.hibernate.envers.RevisionType;
 
import com.whitestein.lsps.common.ejb.SecurityManagerServiceLocal;
import com.whitestein.lsps.common.hibernate.SharedRecordContext;
import com.whitestein.lsps.common.hibernate.SharedRecordContextProvider;
import com.whitestein.lsps.common.hibernate.SharedRecordNamingInfo;
import com.whitestein.lsps.common.hibernate.SharedRecordUtils;
import com.whitestein.lsps.hibernate.envers.EJBRevisionListener;
import com.whitestein.lsps.hibernate.envers.LspsRevisionListener;
import com.whitestein.lsps.model.sharedrecord.ExternalRecordEntity;
import com.whitestein.lsps.model.sharedrecord.MapSharedRecordEntity;
 
@Stateless
@PermitAll
public class CustomRevisionListener extends LspsRevisionListener implements EJBRevisionListener {
    //injects the security service (for the user field):
    @EJB
    private SecurityManagerServiceLocal securityService;
 
    @Override
    public void newRevision(Object revisionEntity) {
        super.newRevision(revisionEntity);
 
        //persisting into a record related to the Revision Entity record:
       
        //obtain the names of the for properties in the hibernate entity:
        //SharedRecordContext sharedRecordContext = SharedRecordContextProvider.INSTANCE.getSharedRecordContextByJndi("");
        //SharedRecordNamingInfo recordNamingInfo = sharedRecordContext.getNamingInfoForEntityName(((ExternalRecordEntity) revisionEntity).getEntityName());    
        //obtain the name of the hibernate entity for your table:
        //recordNamingInfo = sharedRecordContext.getNamingInfoForTableName("CustomRevisionData");
 
        MapSharedRecordEntity entity = new MapSharedRecordEntity("CustomRevisionData");
        entity.set("NAME", "xxx");
       
        Session session = SharedRecordUtils.getSessionFactory(null).getCurrentSession();
        session.persist(entity);
       
        ((MapSharedRecordEntity) revisionEntity).set("S_CUSTOM_REVISION_ENTITY_CUSTOMREVISIONDATA", entity);
    }
}

Example EJB registration

@EJB(beanName = "CustomRevisionListener")
    private EJBRevisionListener customRevisionListener;
 
    @Override
    protected void registerCustomComponents() {
        register(customRevisionListener, CustomRevisionListener.class);
    }