Skip to content

Commit 4e6ee9d

Browse files
committed
Move all classes to new package names and remove domain object generation scripts
1 parent a8f7ce2 commit 4e6ee9d

File tree

62 files changed

+911
-1068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+911
-1068
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.iml
2+
plugin.xml
3+
.idea
4+
*.zip
5+
target
6+
test
+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import grails.plugin.multitenant.core.CurrentTenantThreadLocal
2+
import grails.plugin.multitenant.core.DomainNameDatabaseTenantResolver
3+
import grails.plugin.multitenant.core.DomainNamePropertyTenantResolver
4+
import grails.plugin.multitenant.core.datasource.PropertyDataSourceUrlResolver
5+
import grails.plugin.multitenant.core.datasource.TenantDataSourcePostProcessor
6+
import grails.plugin.multitenant.core.hibernate.TenantEventHandler
7+
import grails.plugin.multitenant.core.spring.TenantBeanContainer
8+
import grails.plugin.multitenant.core.MultiTenantFilter
9+
import grails.plugin.multitenant.core.spring.TenantBeanFactoryPostProcessor
10+
import grails.plugin.multitenant.core.util.TenantUtils
11+
import com.infusion.util.domain.event.hibernate.CriteriaContext
12+
import grails.plugin.multitenant.core.util.log.log.MultiTenantLogLayout
13+
import org.apache.log4j.Appender
14+
import org.apache.log4j.Logger
15+
import org.codehaus.groovy.grails.commons.ConfigurationHolder
16+
import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
17+
import org.codehaus.groovy.grails.commons.spring.GrailsApplicationContext
18+
import org.codehaus.groovy.grails.validation.ConstrainedProperty
19+
import org.hibernate.Query
20+
import org.hibernate.criterion.Expression
21+
import org.hibernate.type.IntegerType
22+
import grails.plugin.multitenant.core.datasource.DatabaseDatasourceUrlResolver
23+
import util.ConfigHelper
24+
import org.codehaus.groovy.grails.plugins.GrailsPlugin
25+
import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
26+
import grails.plugin.multitenant.core.DomainNameDatabaseTenantResolver
27+
import grails.plugin.multitenant.core.DomainNamePropertyTenantResolver
28+
import grails.plugin.multitenant.core.CurrentTenantThreadLocal
29+
30+
class GrailsMultiTenantCoreGrailsPlugin {
31+
def version = "1.0.0"
32+
def grailsVersion = "1.3.0 > *"
33+
def dependsOn = [falconeUtil: "1.0"]
34+
def author = "Eric Martineau, Scott Ryan"
35+
36+
def title = "Multi-Tenant Plugin"
37+
def description = ''' Allows for managing data for mutiple 'tenants' in a single database by using a tenantId column
38+
for each domain object. Also handles the proxying of spring beans for a multi-tenant environment. '''
39+
// URL to the plugin's documentation
40+
def documentation = "http://grails.org/MultiTenant+Plugin"
41+
def doWithSpring = {
42+
//Utility class that contains tenant resolver
43+
tenantUtils(TenantUtils) {
44+
currentTenant = ref("currentTenant")
45+
}
46+
if (ConfigurationHolder.config.tenant.mode == "singleTenant") {
47+
48+
//Put switching datasource here
49+
tenantDataSourcePostProcessor(TenantDataSourcePostProcessor)
50+
if (
51+
ConfigurationHolder.config.tenant.datasourceResolver.type == "config" ||
52+
ConfigurationHolder.config.tenant.datasourceResolver.type.size() == 0
53+
) {
54+
55+
dataSourceUrlResolver(PropertyDataSourceUrlResolver)
56+
57+
} else {
58+
59+
dataSourceUrlResolver(DatabaseDatasourceUrlResolver) {
60+
eventBroker = ref("eventBroker")
61+
}
62+
}
63+
64+
} else {
65+
66+
//This registers hibernate events that force filtering on domain classes
67+
//In single tenant mode, the records are automatically filtered by different
68+
//data sources.
69+
tenantEventHandler(TenantEventHandler) {
70+
sessionFactory = ref("sessionFactory")
71+
currentTenant = ref("currentTenant")
72+
}
73+
}
74+
//Bean container for all multi-tenant beans
75+
tenantBeanContainer(TenantBeanContainer) {
76+
currentTenant = ref("currentTenant")
77+
}
78+
79+
//The post-processor does bean modification for multi-tenant beans
80+
tenantBeanFactoryPostProcessor(TenantBeanFactoryPostProcessor)
81+
82+
def resolverType = ConfigHelper.get("request") {it.tenant.resolver.type}
83+
if (resolverType == "request") {
84+
//This implementation
85+
currentTenant(CurrentTenantThreadLocal) {
86+
eventBroker = ref("eventBroker")
87+
}
88+
89+
def requestResolverType = ConfigHelper.get("config") {it.tenant.resolver.request.dns.type}
90+
if (requestResolverType == "config") {
91+
//Default tenant resolver is a property file. This can be easily overridden
92+
tenantResolver(DomainNamePropertyTenantResolver)
93+
} else if (ConfigurationHolder.config.tenant.resolver.request.dns.type == "db") {
94+
tenantResolver(DomainNameDatabaseTenantResolver) {
95+
eventBroker = ref("eventBroker")
96+
}
97+
}
98+
}
99+
100+
//This bean adds the current tenantId to all logs
101+
multiTenantLogLayout(MultiTenantLogLayout) {
102+
currentTenant = ref("currentTenant")
103+
}
104+
}
105+
106+
def doWithEvents = {
107+
ctx ->
108+
if (ConfigurationHolder.config.tenant.mode != "singleTenant") {
109+
110+
//Listen for criteria created events
111+
hibernate.criteriaCreated("tenantFilter") {
112+
CriteriaContext context ->
113+
boolean hasAnnotation = TenantUtils.isAnnotated(context.entityClass)
114+
if (context.entityClass == null || hasAnnotation) {
115+
final Integer tenant = ctx.currentTenant.get();
116+
context.criteria.add(Expression.eq("tenantId", tenant));
117+
}
118+
}
119+
120+
//Listen for query created events
121+
hibernate.queryCreated("tenantFilter") {
122+
Query query ->
123+
for (String param: query.getNamedParameters()) {
124+
if ("tenantId".equals(param)) {
125+
query.setParameter("tenantId", ctx.currentTenant.get(), new IntegerType());
126+
}
127+
}
128+
}
129+
}
130+
}
131+
132+
def doWithApplicationContext = {GrailsApplicationContext applicationContext ->
133+
def logValue = ConfigHelper.get(true) {it.tenant.log}
134+
if (logValue) {
135+
log.info "Setting up multi-tenant logging format"
136+
Enumeration<Appender> appenders = Logger.getRootLogger().getAllAppenders()
137+
if (appenders != null) {
138+
while (appenders.hasMoreElements()) {
139+
appenders.nextElement().setLayout(applicationContext.multiTenantLogLayout)
140+
}
141+
}
142+
}
143+
}
144+
145+
def doWithWebDescriptor = {xml ->
146+
def resolverFromConfig = ConfigHelper.get("request") {it.tenant.resolver.type}
147+
if (resolverFromConfig == "request") {
148+
149+
//Add filter definition to web.xml
150+
def filterElements = xml.'filter'[0]
151+
filterElements + {
152+
'filter' {
153+
'filter-name'("MultiTenantFilter")
154+
'filter-class'(MultiTenantFilter.class.getName())
155+
}
156+
}
157+
158+
//This is what we'll be adding filter mappings to
159+
def filterMappingElements = xml.'filter-mapping'[0]
160+
161+
//Look in plugins for urls patterns
162+
DefaultGrailsPluginManager grailsManager = (DefaultGrailsPluginManager) manager;
163+
grailsManager.getAllPlugins().each {
164+
GrailsPlugin plugin ->
165+
if (plugin.getInstance().getProperties().containsKey("multiTenantFilterUrls")) {
166+
List urls = plugin.getInstance().multiTenantFilterUrls
167+
urls.each {url ->
168+
log.info "Adding ${url} to multitenant request filter mappings from ${plugin}"
169+
filterMappingElements + {
170+
'filter-mapping' {
171+
'filter-name'("MultiTenantFilter")
172+
'url-pattern'("${url}")
173+
}
174+
}
175+
}
176+
}
177+
}
178+
179+
def urls = ConfigHelper.get(null) {it.tenant.filterUrls}
180+
urls?.each {url ->
181+
log.info "Adding ${url} to multitenant request mappings from Config.groovy"
182+
filterMappingElements + {
183+
'filter-mapping' {
184+
'filter-name'("MultiTenantFilter")
185+
'url-pattern'("${url}")
186+
}
187+
}
188+
}
189+
190+
log.info "Finished mapping filter urls"
191+
}
192+
}
193+
194+
def doWithDynamicMethods = {ctx ->
195+
196+
if (ConfigurationHolder.config.tenant.mode != "singleTenant") {
197+
//Add a nullable contraint for tenantId.
198+
application.domainClasses.each {DefaultGrailsDomainClass domainClass ->
199+
domainClass.constraints?.get("tenantId")?.applyConstraint(ConstrainedProperty.NULLABLE_CONSTRAINT, true);
200+
domainClass.clazz.metaClass.beforeInsert = {
201+
if (tenantId == null) tenantId = 0
202+
}
203+
}
204+
}
205+
206+
TenantUtils.ready = true
207+
}
208+
209+
210+
}

0 commit comments

Comments
 (0)