-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
09ac803
commit b2997a1
Showing
1 changed file
with
97 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,99 @@ | ||
# TOC | ||
|
||
|
||
# grails-multitenant-plugin | ||
This plugin adds multitenant support for grails 3 based on hibernate filters. Tenants are resolved using spring security. It does not support URL based tenant resolver for the time being. | ||
|
||
## Installation | ||
Plugin is not yet published to grails central repo. You can configure it using gradle multiproject setup as done in example found in the above repo. | ||
|
||
Add configClass attribute in application.yml under dataSource section like this: | ||
|
||
``` | ||
configClass: org.grails.plugin.multitenant.HibernateMultitenantConfiguration | ||
``` | ||
|
||
# Architecture | ||
|
||
This plugin uses single database single schema differentiator based technique to identify tenants. | ||
|
||
## Resolving Tenant | ||
|
||
Currently it resolves tenant using spring security. So you have to edit spring security user domain class to implement TenantIdentifier trait like this: | ||
|
||
``` | ||
class User implements Serializable, TenantIdentifier | ||
``` | ||
It add userTenantId property to User domain class and injects two closures dynamically to this domain | ||
|
||
### withTenantId | ||
|
||
This closure executes a particular code inside its scope with a tenantId supplied as parameters even if the logged in user does not belong to that tenant. You can only execute idempotent code inside this block. If your code is query, or some other read only operation, it will execute that with supplied tenantId. If your code is going to change something in database, it will use tenantId of logged in user. Be careful . . | ||
|
||
``` | ||
User.withTenantId(12){ | ||
// Your code goes here | ||
} | ||
``` | ||
|
||
### withoutTenantId | ||
|
||
As the name states, you can bypass tenantId filter temporarily to do operations not specific to any tenant. | ||
|
||
``` | ||
User.withoutTenantId(){ | ||
// You code goes here | ||
``` | ||
|
||
The code in this scope should be read only as is the case with withTenantId method above. | ||
|
||
## Multitenat Domain Classes | ||
|
||
You have to implement Multitenant trait in all domain classes you want to be multitenant. | ||
|
||
``` | ||
class Book implement Multitenant | ||
``` | ||
|
||
This will add a property tenantId to domain class and three methods as below: | ||
|
||
``` | ||
Long tenantId | ||
def beforeInsert() { | ||
if(tenantId == null){ | ||
tenantId = tenantResolverService.resolveTenant() | ||
} | ||
} | ||
def beforeValidate() { | ||
if(tenantId == null){ | ||
tenantId = tenantResolverService.resolveTenant() | ||
} | ||
} | ||
def beforeUpdate() { | ||
if(tenantId == null){ | ||
tenantId = tenantResolverService.resolveTenant() | ||
} | ||
} | ||
``` | ||
So if you want to use these methods in any of multitenant domain class, you have to reproduce above code along with your own implementation as yours will overwrite these methods. | ||
|
||
## TenantResolverService | ||
|
||
This plugin provide TenantResolverService to your application which can be injected anywhere just like normal grails services. It provides only one method resolveTenant which provides tenantId of current user. Multitenant plugin makes extensive use of this service at various places inside the code. Multitenant filter intercepts controller actions only. If you want to do some multitenant stuff inside a service then you should call that service from controller or use withTenantId as below: | ||
|
||
``` | ||
def tenantResolverService | ||
User.withTenantId(tenantResolverService.resolveTenant()){ | ||
// your code here | ||
} | ||
``` | ||
|