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. GRAILS
    MULTI-PROJECT
    BUILDS
    &
    MULTI TENANCY
    objectcomputing.com/grails

    View full-size slide

  2. http://sergiodelamo.es
    Sergio del Amo
    @sdelamo

    View full-size slide

  3. objectcomputing.com/grails
    http://groovycalamari.com

    View full-size slide

  4. http://guides.grails.org

    View full-size slide

  5. MULTI-PROJECT
    BUILS

    View full-size slide

  6. objectcomputing.com/grails
    BUILD TOOL

    View full-size slide

  7. A multi-project build in Gradle
    consists of one root project, and
    one or more subprojects that may
    also have subprojects

    View full-size slide

  8. objectcomputing.com/grails
    DEMO
    APP
    PLUGIN
    GROOVY LIBRARY
    ROOT PROJECT

    View full-size slide

  9. 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 ..

    View full-size slide

  10. 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 ..

    View full-size slide

  11. 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 .

    View full-size slide

  12. 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'

    View full-size slide

  13. 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

    View full-size slide

  14. 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

    View full-size slide

  15. 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'
    }

    View full-size slide

  16. objectcomputing.com/grails
    OPEN FOLDER WITH INTELLIJ IDEA

    View full-size slide

  17. objectcomputing.com/grails
    app/build.gradle
    dependencies {

    compile project(':plugin')
    }
    plugin/build.gradle
    dependencies {

    compile project(':groovylib')
    }
    APP
    PLUGIN
    GROOVY
    LIB

    View full-size slide

  18. objectcomputing.com/grails
    app/build.gradle
    dependencies {

    compile project(':plugin')
    }
    grails {
    plugins {
    compile project(':plugin')
    }
    }
    HOT-RELOADING

    View full-size slide

  19. objectcomputing.com/grails
    APP
    PLUGIN
    GROOVY
    LIB
    PersonController.groovy
    RandomPersonService.groovy
    OCI.groovy

    View full-size slide

  20. 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()
    }
    }

    View full-size slide

  21. objectcomputing.com/grails
    plugin/grails-app/services/demo/RandomPersonService.groovy
    package demo
    import groovy.transform.CompileStatic
    @CompileStatic
    class RandomPersonService {
    String randomOciPersonName() {
    List people = OCI.PEOPLE
    Collections.shuffle(people)
    people.first()
    }
    }

    View full-size slide

  22. objectcomputing.com/grails
    groovylib/src/main/groovy/demo/OCI.groovy
    package demo
    import groovy.transform.CompileStatic
    @CompileStatic
    class OCI {
    public static final List PEOPLE = [
    'Ryan',
    'Jeff',
    'Paul',
    'Søren',
    'Sergio'
    ]
    }

    View full-size slide

  23. objectcomputing.com/grails
    KEPP THE BUILD DRY

    View full-size slide

  24. 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

    View full-size slide

  25. 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

    View full-size slide

  26. 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.

    View full-size slide

  27. GORM
    DATA SERVICES

    View full-size slide

  28. 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.

    View full-size slide

  29. MULTI-TENANCY

    View full-size slide

  30. 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.

    View full-size slide

  31. 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

    View full-size slide

  32. objectcomputing.com/grails
    grails-app/conf/application.yml
    grails:
    gorm:
    multiTenancy:
    mode: DATABASE
    tenantResolverClass: org.grails.datastore.mapping.multitenancy.web.SessionTenantResolver
    gradle.properties
    gormVersion=6.1.3.RELEASE

    View full-size slide

  33. 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

    View full-size slide

  34. objectcomputing.com/grails
    grails-app/domain/example/Vehicle.groovy
    package example
    import grails.gorm.MultiTenant
    class Vehicle implements MultiTenant {
    String model
    Integer year
    static constraints = {
    model blank:false
    year min:1980
    }
    }

    View full-size slide

  35. 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

    View full-size slide

  36. 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 list(Map args )
    abstract Integer count()
    @Join('engines')
    abstract Vehicle find(Serializable id)
    }

    View full-size slide

  37. 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, '')
    }

    View full-size slide

  38. objectcomputing.com/grails

    View full-size slide

  39. 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.

    View full-size slide