OFBiz
  1. OFBiz
  2. OFBIZ-4659 Umbrella task for jackrabbit integration
  3. OFBIZ-4836

Jackrabbit (jcr) doesn't work nice with multi-tenancy aspect of OFBiz

    Details

    • Type: Sub-task Sub-task
    • Status: Closed
    • Priority: Blocker Blocker
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: framework
    • Labels:
      None

      Description

      When having multiple tenants and one of the users (of a tenant) creates (uploads) a file to JCR then this file is visible to all users of all tenants

      1. jcr-config.xml
        3 kB
        Sascha Rodekamp
      2. OFBIZ-4836_JCR_MultiTenancy.patch
        44 kB
        Sascha Rodekamp
      3. OFBIZ-4836_JCR_MultiTenancy .patch
        40 kB
        Sascha Rodekamp
      4. OFBIZ-4836-jcr-entity.patch
        2 kB
        Pierre Smits

        Activity

        Hide
        Sascha Rodekamp added a comment -

        Issue fixed in jackrabbit20120501 branch @ Rev 1347578

        Show
        Sascha Rodekamp added a comment - Issue fixed in jackrabbit20120501 branch @ Rev 1347578
        Hide
        Sascha Rodekamp added a comment -

        Hi,

        now we have different repositories for each tenant.

        We have to make sure, that the JcrDataSource is filled for the tenant user. If there is no entry in the entity for a certain tenant defined, i create a default repository path: "/data/jcr/<tenantId>"

        Show
        Sascha Rodekamp added a comment - Hi, now we have different repositories for each tenant. We have to make sure, that the JcrDataSource is filled for the tenant user. If there is no entry in the entity for a certain tenant defined, i create a default repository path: "/data/jcr/<tenantId>"
        Hide
        Sascha Rodekamp added a comment -

        Hi Pierre,
        nope. I think I did something wrong with my tenant setup. I will try to reproduce your issue.

        Btw. I use now the new jackrabbit branch for development.

        Regards,
        Sascha

        Show
        Sascha Rodekamp added a comment - Hi Pierre, nope. I think I did something wrong with my tenant setup. I will try to reproduce your issue. Btw. I use now the new jackrabbit branch for development. Regards, Sascha
        Hide
        Pierre Smits added a comment -

        Hi Sascha,

        Thanks for providing the patch to test the functionality.
        After having applied it to a clean trunk checkout, doing a clean build and install the demo-data and a modification to the 'ant create-tenant' target (and process) to have it create the jcr settings in the database of the main delegator in accordance with following example:

        <JcrDataSource tenantId="@tenantId@" jcrMinRecordLength="0" jcrRepHighlighting="1" jcrRepId="@tenantId@" jcrRepPath="runtime/data/jcr/@tenantId@/"/>

        I created a new tenant and saw the data in the JcrDataSource.

        After subsequently restarting OFBiz and:

        • logging in the main environment as admin I created a new entry in the Jackrabbit section of the example application (that worked). I also uploaded the patch into the repository successfully.
        • having logged out and logged in again (but now as the tenant-admin in the tenant environment I tried the same, but with no succes. It generated a NPE.

        Looking thru the file/folder structure of OFBiz I didn't saw a jcr repository created in location 'runtime/data/jcr/' for the tenant.

        Did I miss a step?

        Regards,

        Pierre

        Show
        Pierre Smits added a comment - Hi Sascha, Thanks for providing the patch to test the functionality. After having applied it to a clean trunk checkout, doing a clean build and install the demo-data and a modification to the 'ant create-tenant' target (and process) to have it create the jcr settings in the database of the main delegator in accordance with following example: <JcrDataSource tenantId="@tenantId@" jcrMinRecordLength="0" jcrRepHighlighting="1" jcrRepId="@tenantId@" jcrRepPath="runtime/data/jcr/@tenantId@/"/> I created a new tenant and saw the data in the JcrDataSource. After subsequently restarting OFBiz and: logging in the main environment as admin I created a new entry in the Jackrabbit section of the example application (that worked). I also uploaded the patch into the repository successfully. having logged out and logged in again (but now as the tenant-admin in the tenant environment I tried the same, but with no succes. It generated a NPE. Looking thru the file/folder structure of OFBiz I didn't saw a jcr repository created in location 'runtime/data/jcr/' for the tenant. Did I miss a step? Regards, Pierre
        Hide
        Sascha Rodekamp added a comment -

        Hi Pierre, here is a first suggestions for multi tenancy and jackrabbit.

        In this version each tenant gets is own repository.

        Show
        Sascha Rodekamp added a comment - Hi Pierre, here is a first suggestions for multi tenancy and jackrabbit. In this version each tenant gets is own repository.
        Hide
        Pierre Smits added a comment -

        THis is an example of the entity for jcr

        Show
        Pierre Smits added a comment - THis is an example of the entity for jcr
        Hide
        Pierre Smits added a comment -

        A entry in TenantDataSource could be:

        for Derby:
        <TenantDataSource tenantId="DEMO1" entityGroupName="jcr.ofbiz" jdbcPassword="ofbiz" jdbcUri="dbc:derby:DEMO1/version/db;create=true" jdbcUsername="ofbiz"/>

        for PostgreSQL:
        <TenantDataSource tenantId="DEMO2"entityGroupName="jcr.ofbiz" jdbcPassword="ofbiz" jdbcUri="jdbc:postgresql://<IP address>/ofbiz_DEMO2" jdbcUsername="ofbiz"/>

        Show
        Pierre Smits added a comment - A entry in TenantDataSource could be: for Derby: <TenantDataSource tenantId="DEMO1" entityGroupName="jcr.ofbiz" jdbcPassword="ofbiz" jdbcUri="dbc:derby:DEMO1/version/db;create=true" jdbcUsername="ofbiz"/> for PostgreSQL: <TenantDataSource tenantId="DEMO2"entityGroupName="jcr.ofbiz" jdbcPassword="ofbiz" jdbcUri="jdbc:postgresql://<IP address>/ofbiz_DEMO2" jdbcUsername="ofbiz"/>
        Hide
        Pierre Smits added a comment -

        Tenant independent (or rather delegator independent) would be the best approach from a scalability point of view. Store as much of the parameters as possible in OFBiz (Tenant)DataSource and load on startup (caching the lot).

        Think of:
        <!-- jcr home directory -> <- from jcr-config.xml
        <home-dir path="runtime/data/jcr/" />
        <!-- jcr workspace credentials -> <- from jcr-config.xml
        <jcr-credentials username="system" password="ofbiz" />

        From jackrabbit.xml the params:
        $

        {rep.home}
        ${wsp.name}
        ${minRecordLength}
        ${rep.supportHighlighting}
        ${wsp.supportHighlighting}

        See below.


        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
        <param name="path" value="${rep.home}

        /repository"/>
        </FileSystem>
        <DataStore class="org.apache.jackrabbit.core.data.FileDataStore" >
        <param name="path" value="$

        {rep.home}/repository/datastore"/>
        <param name="minRecordLength" value="0"/>
        </DataStore>
        <Workspaces rootPath="${rep.home}

        /workspaces" defaultWorkspace="default"/>
        <Workspace name="$

        {wsp.name}">
        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
        <param name="path" value="${wsp.home}"/>
        </FileSystem>
        <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.DerbyPersistenceManager">
        <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
        <param name="schemaObjectPrefix" value="${wsp.name}

        _"/>
        </PersistenceManager>
        <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
        <param name="path" value="$

        {wsp.home}

        /index"/>
        <param name="supportHighlighting" value="true"/>
        </SearchIndex>
        </Workspace>
        <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
        <param name="path" value="$

        {rep.home}

        /repository/index"/>
        <param name="supportHighlighting" value="true"/>
        </SearchIndex>
        -->

        Show
        Pierre Smits added a comment - Tenant independent (or rather delegator independent) would be the best approach from a scalability point of view. Store as much of the parameters as possible in OFBiz (Tenant)DataSource and load on startup (caching the lot). Think of: <!-- jcr home directory - > < - from jcr-config.xml <home-dir path="runtime/data/jcr/" /> <!-- jcr workspace credentials - > < - from jcr-config.xml <jcr-credentials username="system" password="ofbiz" /> From jackrabbit.xml the params: $ {rep.home} ${wsp.name} ${minRecordLength} ${rep.supportHighlighting} ${wsp.supportHighlighting} See below. <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem"> <param name="path" value="${rep.home} /repository"/> </FileSystem> <DataStore class="org.apache.jackrabbit.core.data.FileDataStore" > <param name="path" value="$ {rep.home}/repository/datastore"/> <param name="minRecordLength" value="0"/> </DataStore> <Workspaces rootPath="${rep.home} /workspaces" defaultWorkspace="default"/> <Workspace name="$ {wsp.name}"> <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem"> <param name="path" value="${wsp.home}"/> </FileSystem> <PersistenceManager class="org.apache.jackrabbit.core.persistence.pool.DerbyPersistenceManager"> <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/> <param name="schemaObjectPrefix" value="${wsp.name} _"/> </PersistenceManager> <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex"> <param name="path" value="$ {wsp.home} /index"/> <param name="supportHighlighting" value="true"/> </SearchIndex> </Workspace> <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex"> <param name="path" value="$ {rep.home} /repository/index"/> <param name="supportHighlighting" value="true"/> </SearchIndex> -->
        Hide
        Sascha Rodekamp added a comment -

        Ah ok Pierre i got it. Maybe this will work also for the repository. I will try a few things and come back to you.

        Best Regards
        Sascha

        Show
        Sascha Rodekamp added a comment - Ah ok Pierre i got it. Maybe this will work also for the repository. I will try a few things and come back to you. Best Regards Sascha
        Hide
        Sascha Rodekamp added a comment - - edited

        Maybe it's better to extend the whole config not only the home dir (see jcr-config.xml file). That gives us the possibility to use a tenant independent JCR implementation.
        What do you think?

        Show
        Sascha Rodekamp added a comment - - edited Maybe it's better to extend the whole config not only the home dir (see jcr-config.xml file). That gives us the possibility to use a tenant independent JCR implementation. What do you think?
        Hide
        Pierre Smits added a comment -

        Hi Sascha,

        References to tenants are stored in entity Tenant. See https://demo-trunk.ofbiz.apache.org:8443/webtools/control/FindGeneric?entityName=Tenant&find=true

        The tenantId is used as the delegator to persist the OFBiz data in the TenantDataSouce.

        Each tenant has its own OFBiz data storage and that is defined in TenantDataSource. See https://demo-trunk.ofbiz.apache.org:8443/webtools/control/FindGeneric?entityName=TenantDataSource&find=true

        If we can reuse that data then a JCR repository could be like: <home-dir path="runtime/data/jcr/<tenantId>/" />

        While keeping in mind that the first part of the home-dir path (runtime/data/jcr) is set through jcr-config.xml.

        Regards,

        Pierre

        Show
        Pierre Smits added a comment - Hi Sascha, References to tenants are stored in entity Tenant. See https://demo-trunk.ofbiz.apache.org:8443/webtools/control/FindGeneric?entityName=Tenant&find=true The tenantId is used as the delegator to persist the OFBiz data in the TenantDataSouce. Each tenant has its own OFBiz data storage and that is defined in TenantDataSource. See https://demo-trunk.ofbiz.apache.org:8443/webtools/control/FindGeneric?entityName=TenantDataSource&find=true If we can reuse that data then a JCR repository could be like: <home-dir path="runtime/data/jcr/<tenantId>/" /> While keeping in mind that the first part of the home-dir path (runtime/data/jcr) is set through jcr-config.xml. Regards, Pierre
        Hide
        Sascha Rodekamp added a comment -

        Hi Pierre,
        not sure if i understand you right. Why we have to inject the delegator in the homedir?

        I'm looking for a way to configure different homedirs in the jcr-config.xml.

        Somthing like:

            <!-- jcr home directory -->
            <home-dirs>
        	    <home-dir path="runtime/data/jcr_1/" />
        	    <home-dir path="runtime/data/jcr_2/" />
            </home-dirs>
        

        Than i'm able to load a repository instance for each tenant. But I'm not sure where to store the reference between the tenant and his repository instance, do you have an idea?

        Show
        Sascha Rodekamp added a comment - Hi Pierre, not sure if i understand you right. Why we have to inject the delegator in the homedir? I'm looking for a way to configure different homedirs in the jcr-config.xml. Somthing like: <!-- jcr home directory --> <home-dirs> <home-dir path= "runtime/data/jcr_1/" /> <home-dir path= "runtime/data/jcr_2/" /> </home-dirs> Than i'm able to load a repository instance for each tenant. But I'm not sure where to store the reference between the tenant and his repository instance, do you have an idea?
        Hide
        Pierre Smits added a comment -

        Hi Sascha,

        In JCRFactoryImpl.java we have:
        homeDir = UtilXml.childElementAttribute(configRootElement, "home-dir", "path", "runtime/data/jcr/")

        Which is then retrieved by:
        repository = new TransientRepository(jackrabbitConfigFile, homeDir)

        What if we inject the delegator in the homedir? That would work out, wouldn't?

        Regards,

        Pierre

        Show
        Pierre Smits added a comment - Hi Sascha, In JCRFactoryImpl.java we have: homeDir = UtilXml.childElementAttribute(configRootElement, "home-dir", "path", "runtime/data/jcr/") Which is then retrieved by: repository = new TransientRepository(jackrabbitConfigFile, homeDir) What if we inject the delegator in the homedir? That would work out, wouldn't? Regards, Pierre
        Hide
        Sascha Rodekamp added a comment -

        Hi Pierre,
        yes i would also go this way. A separate repository for each tenant. Having "tenant nodes" would be a high effort and a lot of code. A lot of code means many potential security issues

        Show
        Sascha Rodekamp added a comment - Hi Pierre, yes i would also go this way. A separate repository for each tenant. Having "tenant nodes" would be a high effort and a lot of code. A lot of code means many potential security issues
        Hide
        Pierre Smits added a comment -

        Hi Sascha,

        I am not that well experienced with Jackrabbit, but I would say that the best solution would be similar to multi-tenancy in OFBiz. There we set up for each tenant a different set of databases. For that we use the tenantID as the delegator. And the security is fairly straight-forward. Only tenant users (in accordance with the security schema for him/her) have access to their own tenant data, and perform actions/functions accordingly.

        That should also work with JCR, i think. But I might be mistaken.

        Wouldn't creating tenants as nodes introduce the issue (risk?) of a user of a higher node having access to data in lower nodes? That would be hard to sell to (potential) customers.

        What if there was a repository for each tenant? Is that feasible?

        Regards,

        Pierre

        Show
        Pierre Smits added a comment - Hi Sascha, I am not that well experienced with Jackrabbit, but I would say that the best solution would be similar to multi-tenancy in OFBiz. There we set up for each tenant a different set of databases. For that we use the tenantID as the delegator. And the security is fairly straight-forward. Only tenant users (in accordance with the security schema for him/her) have access to their own tenant data, and perform actions/functions accordingly. That should also work with JCR, i think. But I might be mistaken. Wouldn't creating tenants as nodes introduce the issue (risk?) of a user of a higher node having access to data in lower nodes? That would be hard to sell to (potential) customers. What if there was a repository for each tenant? Is that feasible? Regards, Pierre
        Hide
        Sascha Rodekamp added a comment -

        Hi Pierre,
        yes that's possible. A multi-tenancy support isn't implemented yet.
        You welcome to provide a patch.

        Which information do we need in a content node to provide multi-tenancy?

        Show
        Sascha Rodekamp added a comment - Hi Pierre, yes that's possible. A multi-tenancy support isn't implemented yet. You welcome to provide a patch. Which information do we need in a content node to provide multi-tenancy?

          People

          • Assignee:
            Sascha Rodekamp
            Reporter:
            Pierre Smits
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development