Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Grails Multi-Project Builds - Multitenancy

Grails Multi-Project Builds - Multitenancy

Slides Deck of GR8Conf EU 2017 by Sergio del Amo

Sergio del Amo

June 01, 2017
Tweet

More Decks by Sergio del Amo

Other Decks in Programming

Transcript

  1. A multi-project build in Gradle consists of one root project,

    and one or more subprojects that may also have subprojects
  2. objectcomputing.com/grails DEMO multiproject$ mkdir app multiproject$ cd app multiproject/app$ grails

    grails> create-app --profile web --inplace | Application created at multiproject/app | Resolving Dependencies. Please wait… CONFIGURE SUCCESSFUL Total time: 12.262 secs grails> exit multiproject/app$ cd ..
  3. objectcomputing.com/grails DEMO multiproject$ mkdir plugin multiproject$ cd plugin multiproject/plugin$ grails

    grails> create-app --profile plugin --inplace | Application created at multiproject/plugin | Resolving Dependencies. Please wait… CONFIGURE SUCCESSFUL Total time: 12.262 secs grails> exit multiproject/plugin$ cd ..
  4. objectcomputing.com/grails DEMO - MOVING GRADLE FILES TO ROOT multiproject$ mv

    app/gradlew . multiproject$ mv app/gradlew.bat . multiproject$ mv app/gradle.properties . multiproject$ mv app/gradle .
  5. objectcomputing.com/grails DEMO - SETUP SETTINGS.GRADLE multiproject$ touch settings.gradle multiproject$ echo

    "include 'app'" >> settings.gradle multiproject$ echo "include 'plugin'" >> settings.gradle multiproject$ echo "include 'groovylib'" >> settings.gradle multiproject$ cat settings.gradle include ‘app' include ‘plugin' include 'groovylib'
  6. objectcomputing.com/grails DEMO - CLEAN-UP plugin FOLDER multiproject$ rm plugin/gradlew multiproject$

    rm plugin/gradlew.bat multiproject$ rm plugin/grailsw.bat multiproject$ rm plugin/grailsw multiproject$ rm plugin/grailsw.bat multiproject$ rm plugin/grails-wrapper.jar multiproject$ rm plugin/settings.gradle multiproject$ rm plugin/gradle.properties multiproject$ rm -rf plugin/gradle
  7. objectcomputing.com/grails DEMO - CLEAN-UP app FOLDER multiproject$ rm app/grailsw multiproject$

    rm app/grailsw.bat multiproject$ rm app/grails-wrapper.jar multiproject$ rm app/settings.gradle multiproject$ rm app/.gitignore
  8. objectcomputing.com/grails DEMO - PLAIN GROOVY PROJECT multiproject$ mkdir groovylib multiproject$

    cd groovylib multiproject/groovylib$ touch build.gradle apply plugin: 'groovy' repositories { jcenter() } dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.11' }
  9. objectcomputing.com/grails app/grails-app/controllers/app/PersonController.groovy package app import demo.RandomPersonService import groovy.transform.CompileStatic @CompileStatic class

    PersonController { RandomPersonService randomPersonService def index() { render randomPersonService.randomOciPersonName() } }
  10. buildscript { repositories { mavenLocal() maven { url "https://repo.grails.org/grails/core" }

    } dependencies { classpath "org.grails:grails-gradle-plugin:$grailsVersion" classpath "org.grails.plugins:hibernate5:${gormVersion-".RELEASE"}" classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.2" } } ext { grailsApps = ['app'] grailsPlugins = ['plugin'] } subprojects { project -> boolean isGrailsApp = grailsApps.contains(project.name) boolean isGrailsPlugin = grailsPlugins.contains(project.name) boolean isGrailsProject = isGrailsApp || isGrailsPlugin if ( isGrailsProject ) { apply plugin:"eclipse" apply plugin:"idea" if ( isGrailsApp ) { apply plugin:"war" apply plugin:"org.grails.grails-web" apply plugin:"asset-pipeline" apply plugin:"org.grails.grails-gsp" } if ( isGrailsPlugin ) { apply plugin:"org.grails.grails-plugin" apply plugin:"org.grails.grails-plugin-publish" } repositories { mavenLocal() maven { url "https://repo.grails.org/grails/core" } } dependencies { objectcomputing.com/grails multiproject/build.gradle version "0.1" group "app" grails { plugins { compile project(':plugin') } } multiproject/app/build.gradle version "0.1" group "plugin" dependencies { compile project(':groovylib') } multiproject/plugin/build.gradle
  11. FEATURES AS GRADLE FILES objectcomputing.com/grails gradle/geb.gradle project.ext.seleniumVersion = '2.53.1' project.ext.htmlUnitVersion

    = '2.18' project.ext.htmlUnitDriverVersion = '2.47.1' project.ext.phantomJsDriverVersion = '1.3.0' dependencies { testCompile 'org.grails.plugins:geb' testRuntime "net.sourceforge.htmlunit:htmlunit:$htmlUnitVersion" testRuntime "org.seleniumhq.selenium:selenium-support:$seleniumVersion" testCompile "org.seleniumhq.selenium:selenium-htmlunit-driver:$htmlUnitDriverVersion" testCompile "com.codeborne:phantomjsdriver:$phantomJsDriverVersion" testCompile "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion" testCompile "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion" } apply from: "${rootProject.projectDir}/gradle/geb.gradle" build.gradle
  12. objectcomputing.com/grails APP PLUGIN SPRING SECURITY CORE APP PLUGIN SPRING SECURITY

    CORE loadBefore property to specify one ore more plugins that your plugin should load before loadAfter property to specify one ore more plugins that your plugin should load after UNDERSTANDING PLUGIN ORDER dependsOn dependencies will be loaded before the plugin and if all dependencies do not load, then the plugin will not load.
  13. Introduced in GORM 6.1, Data Services take the work out

    of implemented service layer logic by adding the ability to automatically implement abstract classes or interfaces using GORM logic.
  14. Multi-Tenancy, as it relates to software developments, is when a

    single instance of an application is used to service multiple clients (tenants) in a way that each tenants' data is isolated from the other.
  15. MULTI-TENANCY MODE • DATABASE - Use a distinct database connection

    per tenant • SCHEMA - Use a single database, but different physical schemas per tenant • DISCRIMINATOR - Use a single database, but partition the data using a discriminator column
  16. objectcomputing.com/grails Type DESCRIPTION SessionTenantResolver Resolves the tenant id from the

    HTTP session using an attribute called gorm.tenantId CookieTenantResolver Resolves the tenant id form the HTTP cookie using an attribute called gorm.tenantId SubDomainTenantResolver Resolves the tenant id from the current subdomain. For example if the subdomain is foo.mycompany.com the tenant id would be foo SystemPropertyTenantResolver Resolves the tenant id form a System Property called gorm.tenantId. Mainly useful for testing TENANT RESOLVER
  17. objectcomputing.com/grails Type DESCRIPTION CurrentTenant Resolves the current tenant and binds

    a Hibernate session for the scope of the method Tenant Resolves a specific tenant and binds a Hibernate session for the scope of the method WithoutTenant Execute some logic within a method without a tenant present MULTI-TENANCY TRANSFORMATION
  18. objectcomputing.com/grails grails-app/services/example/VehicleService.groovy import grails.gorm.multitenancy.CurrentTenant import grails.gorm.services.Join import grails.gorm.services.Service import grails.gorm.transactions.Transactional

    import groovy.transform.CompileStatic @Service(Vehicle) @CurrentTenant @CompileStatic abstract class VehicleService { @Join('engines') abstract List<Vehicle> list(Map args ) abstract Integer count() @Join('engines') abstract Vehicle find(Serializable id) }
  19. objectcomputing.com/grails grails-app/controllers/example/VehicleController.groovy @TestFor(VehicleController) class VehicleControllerSpec extends HibernateSpec { @Override Map

    getConfiguration() { [(Settings.SETTING_MULTI_TENANT_RESOLVER_CLASS): SystemPropertyTenantResolver] } VehicleService vehicleService def setup() { System.setProperty(SystemPropertyTenantResolver.PROPERTY_NAME, 'audi') vehicleService = hibernateDatastore.getService(VehicleService) controller.vehicleService = vehicleService } def cleanup() { System.setProperty(SystemPropertyTenantResolver.PROPERTY_NAME, '') }
  20. ?

  21. OCI 12140 Woodcrest Exec. Dr., Ste. 250 Saint Louis, MO

    63141 USA © 2017, All Rights Reserved. No part of this publication may be photocopied or reproduced in any form without written permission from OCI. Nor shall the OCI logo or copyright information be removed from this publication. No part of this publication may be stored in a retrieval system, transmitted by any means, recorded or otherwise, without written permission from OCI. While every precaution has been taken in preparing this material, including research, development and testing, OCI assumes no responsibility for errors or omissions. No liability is assumed by OCI for any damages resulting from the use of this information.