Skip to content

Overview#

Modern systems can work with different DB. Jans is also not exception from this rule. Currently it can work with different DB types and also can work in hybrid environment where application can use the strong power of each DB. This part is based on jans-orm layer. It has pluggable architecture which allows to add support for more DB in future.

One of the main target of ORM module is to provide simple lightweight layer to access DB. Also it provides abstractions which hide dependency to specific DB.

Supported DB#

Jans has next persistence modules out-of-the-box:

Configuration#

Type of DB layer is specified in /etc/jans/conf/:

persistence.type=ldap

The list of allowed property values is next: ldap, couchbase, sql, spanner, hybrid. It's defined in this list.

The corresponding list of configuration files for these persistence types are:

  • jans-ldap.properties
  • jans-couchbase.properties
  • jans-spanner.properties
  • jans-sql.properties
  • jans-hybrid.properties

These files contains DB specific properties and format of them is specified in the relevant sections of this documentation.

The applications reloads configuration from these files after start up or on files date time modification after initialization.

Architecture#

Jans ORM has modular architecture. The are few layers in this implementation

  1. jans-orm-core: This is base layer with next functionality:

    • define API methods to work with DB without specific DB dependency

    • provide base implementation with reusable parts needed for DB modules implementation

    • scan beans and work with ORM layer annotations

  2. jans-orm-annotation: Define annotations which instruct ORM about how to work with beans and properties

  3. jans-orm-filter: This module provides Filter API. The syntax is very similar to LDAP filters. The ORM layer converts them at runtime to DB query syntax: SQL/NoSQL/LDAP

  4. jans-orm-cdi: Provides reusable factory which can be used in CDI based projects

  5. jans-orm-standalone: Provides reusable factory for non CDI based application

  6. jans-orm-ldap, jans-orm-couchbase, jans-orm-spanner, jans-orm-sql: These are DB specific implementations.

Sample table and ORM API#

In order to work with DB ORM layer should know which data (attributes/columns) is needed for application. Most part of this information it takes from DB schema at startup but rest of it developer should define in java bean. Here is typical schema with comments:

// Specify that this is Table/objectClass structure
@DataEntry
// Table/objectClass name is `jansPerson`
@ObjectClass(value = "jansPerson")
public class SimpleUser implements Serializable {

    private static final long serialVersionUID = -1634191420188575733L;

    // Define entry primary key. In LDAP terminology it's DN
    @DN
    private String dn;

    // Define text attribute with name in DB `uid`.
    // Consistency attribute instruct ORM that it should send query to DB and
    // specify that it should execute it after table index update.
    // This is used with Couchbase DB
    @AttributeName(name = "uid", consistency = true)
    private String userId;

    // Define date/time attribute with name in DB `updatedAt`
    @AttributeName
    private Date updatedAt;

    // Define date/time attribute with name in DB `jansCreationTimestamp`
    @AttributeName(name = "jansCreationTimestamp")
    private Date createdAt;

    // Define multivalued text attribute with name in DB `jansPersistentJWT`
    @AttributeName(name = "jansPersistentJWT")
    private String[] oxAuthPersistentJwt;


    // All attributes which not defined above ORM should put into the List<CustomObjectAttribute>
    // This is convenient for custom attributes
    @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true)
    protected List<CustomObjectAttribute> customAttributes = new ArrayList<CustomObjectAttribute>();

    // Specify additional objecClass
    // This is needed for LDAP only
    @CustomObjectClass
    private String[] customObjectClasses;

    ...

Main PersistenceEntryManager API methods which applications can use:

    <T> boolean authenticate(String primaryKey, Class<T> entryClass, String password);
    <T> boolean authenticate(String baseDN, Class<T> entryClass, String userName, String password);

    void persist(Object entry);
    void merge(Object entry);

    <T> boolean contains(String primaryKey, Class<T> entryClass);
    <T> boolean contains(String primaryKey, Class<T> entryClass, Filter filter);

    <T> int countEntries(Object entry);
    <T> int countEntries(String primaryKey, Class<T> entryClass, Filter filter);
    <T> int countEntries(String primaryKey, Class<T> entryClass, Filter filter, SearchScope scope);

    <T> T find(Object primaryKey, Class<T> entryClass, String[] ldapReturnAttributes);

    <T> List<T> findEntries(Object entry);
    <T> List<T> findEntries(Object entry, int count);

    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter);
    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter, int count);
    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter, String[] ldapReturnAttributes);
    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter, String[] ldapReturnAttributes, int count);
    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes,
                            int start, int count, int chunkSize);
    <T> List<T> findEntries(String primaryKey, Class<T> entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes,
                            BatchOperation<T> batchOperation, int start, int count, int chunkSize);

    <T> PagedResult<T> findPagedEntries(String primaryKey, Class<T> entryClass, Filter filter, String[] ldapReturnAttributes, String sortBy,
                                        SortOrder sortOrder, int start, int count, int chunkSize);

    void remove(Object entry);

    <T> void removeByDn(String dn, String[] objectClasses);
    <T> void remove(String primaryKey, Class<T> entryClass);

    <T> int remove(String primaryKey, Class<T> entryClass, Filter filter, int count);

    <T> void removeRecursively(String primaryKey, Class<T> entryClass);
    <T> void removeRecursivelyFromDn(String primaryKey, String[] objectClasses);

    boolean hasBranchesSupport(String primaryKey);
    boolean hasExpirationSupport(String primaryKey);

    String getPersistenceType();
    String getPersistenceType(String primaryKey);

    Date decodeTime(String primaryKey, String date);
    String encodeTime(String primaryKey, Date date);

    int getHashCode(Object entry);

    <T> List<AttributeData> exportEntry(String dn, String objectClass);

    <T> void importEntry(String dn, Class<T> entryClass, List<AttributeData> data);

New DB support and integrations#

The ORM developed with perspective to simplify to add new DB support. New ORM implementation requires only few classes/interfaces implementations.

  1. Extend public interface DbOperationService extends PersistenceOperationService interface to define list of CRUD method which DbEntryManager can use.

  2. Implement abstract methods DbEntryManager extends BaseEntryManager<DbOperationService>. This define DB specific methods to work with DB low layer.

  3. Implement public class DbEntryManagerFactory implements PersistenceEntryManagerFactory. This CDI @ApplicationScoped needed to allow integrate new DB module into application.

  4. Put into final jar file /META-INF/beans.xml to allow CDI framework automatically find DbEntryManagerFactory from previous point.

After this it's enough to put new ORM DB module into application war file or follow customization sections to add jar file to custom jetty classpath.

DB Schema#

The DB schema and beans definitions should match each other. During deployment setup generates schema and indexes based on rules in schema file. The data types defined in it setup map to DB SQL types based on default rules.

It's possible to override default generation rules. For this case there is next file.

Default indexes defined in next files: coubase_index.json, spanner_index.json, mysql_index.json, pgsql_index.json


Last update: 2024-01-02
Created: 2022-09-02