Access to add and change pages is restricted. See: https://cwiki.apache.org/confluence/display/OFBIZ/Wiki+access

Multitenancy support and how to use it

This tutorial document is meant for explaining the OFBiz multitenancy functionnality. It will help to configure and use it

Important!

This tutorial is intended to be used with SVN revisions greater than 927271. It will not work with Release 4 or 9.04. Note also that some multi-tenants related commits have been applied since r927271...

Introduction

Multi-tenancy has been introduced in OFBiz at rev 927271. Multi-tenancy is the ability to run separate data instances (tenants) from a single copy of OFBiz. Each data instance is kept in a separate database. A user logs into a data instance (or tenant) by specifying the tenant ID in the login form. Note that a default database is still used.

If you want to use OFBiz with only one database (ie you don't want to use multi-tenants), there is nothing to change in what you were doing before.

The advantage with multi-tenant is that the tenant doesn't need access to load data using something like "ant run-install ..." or anything else on the command line. You could have hundreds of people active in other tenant instances so you don't want to stop and start the server to do anything like this, and hopefully you can avoid having an admin work with the tenant to get custom data loaded. You want things to be self-service, and that is the point of making it database driven (with a UI so the user can get stuff into the relevant portions of the database).

Tenant Databases

The datasources (= database references) are defined in the TenantDataSouces Entity not in the entityengine.xml (cf. description below).

Of course, if you are using a DBMS which does not support the ";create=true" syntax used OOTB with Derby (eg Postgres, MySql, etc.) you need to create the tenant(s) DB(s) and credentials before running the tenant(s) data installation.

Configuring for MultiTenant

The configuration files that need to be touched are the following:

  • OFBIZ-HOME/framework/entity/data/<yourTenantConfig>.xml
  • OFBIZ-HOME/framework/entity/config/entityengine.xml
  • OFBIZ-HOME/framework/entity/ofbiz-component.xml

yourTenantConfig.xml

Per Tenant add the following:

<Tenant tenantId="TENANT" tenantName="Tenant Name"/>
<TenantDataSource tenantId="TENANT" entityGroupName="org.apache.ofbiz" jdbcUri="jdbc:postgresql://host:port/DEMO1_db" jdbcUsername="username" jdbcPassword="password"/>
<TenantDataSource tenantId="TENANT" entityGroupName="org.apache.ofbiz.olap" jdbcUri="jdbc:derby:ofbizolap_TENANT; create=true" jdbcUsername="username" jdbcPassword="password"/>

The JDBC URIs follow the naming convention for JDBC connection strings. Credentials as you please. Of course you can add any data source to any of the two entity groups. Do not specify a datasource for entity group 'org.apache.ofbiz.tenant' here!

This information will be stored on the database that you specify underneath the org.apache.ofbiz.tenant entity group on entityengine.xml.

ofbiz-component.xml

Add a row to load your own config file above OR alter the row pointing to the DemoTenantData.xml

Make sure you understand at which load-level (with which reader) this file is going to be loaded. The data in the file needs to be loaded before OFBiz will be able to address any tenant data source!

This means: If you decide to assign this file load to the reader="ext", you need to execute the following data read sequence before you can access the tenant databases:

$ java -Xmx512m -XX:MaxPermSize=128m -jar ofbiz.jar -install -readers=seed -delegator=default
$ java -Xmx512m -XX:MaxPermSize=128m -jar ofbiz.jar -install -readers=seed-initial -delegator=default
$ java -Xmx512m -XX:MaxPermSize=128m -jar ofbiz.jar -install -readers=ext -delegator=default

Of course you can group this all into a single data loader run:

$ java -Xmx512m -XX:MaxPermSize=128m -jar ofbiz.jar -install -readers=seed,seed-initial,ext -delegator=default

It is not a good idea to assign this file-load to readers="seed", because seed and seed-initial level data will be loaded to every tenant database as well.

entityengine.xml

Add a dedicated datasource entry for persistence of the tenant data sources as follows:

Datasource reference on delegator

Add the datasource reference to your delegator element

<delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
(...)
<group-map group-name="org.apache.ofbiz.tenant" datasource-name="localpostnewtenants"/>
(...)
</delegator>

Only a single datasource is required for entity group 'org'ofbiz.tenant'. All tenant-specific data source info will be persisted there and will be read to generate the tenant's delegators.

Datasource configuration

Add a datasource configuration element with the respective name ('localpostnewtenant' in this example). Just copy the existing entry for your database technology and change name, connection string etc accordingly.

Loading Tenant.

To load the multi-tenant demo, run ant run-install-multitenant OR ant load-demo-multitenant.

To set up the databases for multi-tenancy and load the seed data only, do the following:

All of the following commands must be executed in sequence.

$ svn co [https://svn.apache.org/repos/asf/ofbiz/ofbiz-framework/trunk] ofbiz
$ ant
$ java \-Xmx512m \-XX:MaxPermSize=128m \-jar ofbiz.jar \-install \-readers=seed \-delegator=default
$ java \-Xmx512m \-XX:MaxPermSize=128m \-jar ofbiz.jar \-install \-readers=seed \-delegator=default#DEMO1
$ java \-Xmx512m \-XX:MaxPermSize=128m \-jar ofbiz.jar \-install \-readers=seed \-delegator=default#DEMO2
$ ant run

Note that the long java lines instead of something like "ant run-install" are used in order to be able to specify a delegatorName.

Starting with revision New Revision: 1172989 two new ant command are added which will load all seed/demo data of components which are not connected to a tenant or connected with this specific tenant, or load all tenants this way.

In order to know which component are connected to which tenant, 2 entities were added:
1. Component (is automatically loaded by ant run-install)
2. TenantComponent

With the following xml file lines these entities can be connected with a tenant
<TenantComponent tenantId="tn1" componentName="cpn1"/>

Available command detail:
1. By using: "ant run-install-tenant" (load specify component data filter with tenantId)
1.1 "ant run-install-tenant" will install all tenant data (reader=tenant)
1.2 "ant run-install-tenant -DtenantId=<tenantId>" will install all tenant data and then run install all default OFBiz components and only components related to tenant (all readers).
1.3 "ant run-install-tenant -DtenantId=<tenantId> -Ddata-readers=seed,seed-initial,..." will install all tenant data and then run install all default OFBiz components and only components related to tenant (specify readers).
1.4 "ant run-install-tenant -DtenantId=<tenantId> -Dcomponent=<componentName>" will install all tenant data and then run install all default OFBiz components and and only one component.

2. By using: "ant run-install-all-tenants" (load all tenant and all data)
2.1 "ant run-install-all-tenants" will install all tenant data and then install all data (separate data by each tenant).
2.2 "ant run-install-all-tenants -Ddata-readers=seed,seed-initial,..." will install all tenant data and then load specify reader (seperate data by each tenant).

Practical hint on entity readers

It may make sense to define new readers per tenant in order to avoid tenant-specific data to be loadad on each tenant database. This is of special interest if you are planning to segragate tenants later on, i.e. using the tenant database with a dedicated tenant OFBiz instance.
In order to do this: Define more readers in entityengine.xml and use them in the ofbiz-component.xml to mark exclusive files for a certain tenant.

Delegator naming convention

In order to address data for be loaded only for a specific tenant, the tenant's delegator needs to be specified. the naming convention is as follows:

  • delegatorname (from entityengine.xml; in most cases this equals 'default', but you may have renamed your delegator ....)
  • #
  • tenantId (is has become a practice to use UPPPERCASE for this Id; it is the same Id that you use to authenticate for a certain tenant as per the next section)

Displaying the tenant Id field for connection

in framework/common/config/general.properties, change the multitenant option to Y
This will show the TenantID for login.
For Demo purposes use the DEMO1 and DEMO2

Setting the ecommerce app. to use a specific Tenant Database

You can determine the tenant used in the ecommerce app. setting the paramenter entityDelegatorName in the web.xml file of the web application, as follows:

...
<context-param>
    <param-name>entityDelegatorName</param-name>
    <param-value>default#tenantId</param-value>
    <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
</context-param>
...

where tenantId is the Tenant ID of your ecommerce app. For example, for the Tenant DEMO1 the code will be:

...
<context-param>
    <param-name>entityDelegatorName</param-name>
    <param-value>default#DEMO1</param-value>
    <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
</context-param>
...

Then, ensure that exists a "ProductStore" related with the "WebSite" settled in the parameter webSiteId of the previous web.xml file. You can load a demo product store (related with the websiteId "WebStore") doing this:

$OFBIZ_HOME> java -Xmx512m -XX:MaxPermSize=128m -jar ofbiz.jar -install -readers=seed,demo -delegator=default#tenantId

For more info you can check https://issues.apache.org/jira/browse/OFBIZ-3579 and the patch attached there.

Setting the initial path according to domain name

You can determine a initial path used in the tenant

<Tenant tenantId="TENANT" tenantName="Tenant Name" domainName="domain.name" initialPath="/initial"/>

If a user enter any domain names (without mount point) which be specified in the Tenant entity then the system would redirect to the initial path.
If the system doesn't has any web application with root mount but a user would like to use the tenant feature with redirecting to the initial path, the user have to create a new web application for the root mount.
If the system already has a web application with root mount and don't want it redirect to the other path, just don't put the domain that was using in the Tenant entity.

The incoming domain name sets the tenantId, so the changes in web.xml of the ecommerce is not required.

1 Comment

  1. Loading seed data only will not work if you use the commands as is as DEMO1 and DEMO2 tenant do not exist in the database. Therefore, you will need to create the tenant in the Tenant entity and relevant data in TenantDataSource entity and then replace the DEMO1 and DEMO2 with your tenant IDs