SlideShare a Scribd company logo
1 of 56
Download to read offline
Grails: How To Plug In

Burt Beckwith
SpringSource




                                                       CONFIDENTIAL
                         © 2010 SpringSource, A division of VMware. All rights reserved
Agenda

 What Is A Plugin?
 Implementation Details
 Testing
 Source Control and Release Management
 Best Practices and Tips



                            CONFIDENTIAL   2
My Plugins
 Acegi                                       Flex Scaffold (major rework, not yet released)
 App Info
                                              SpringMVC
 BlazeDS
                                              Spring Security Core
 Cloud Foundry
                                              Spring Security ACL
 Cloud Foundry UI
                                              Spring Security App Info
 CodeNarc
                                              Spring Security Kerberos
 Console
 Database Reverse Engineering                Spring Security LDAP
 Database Migrations                         Spring Security Open ID
 Datasources                                 Spring Security CAS
 Dynamic Controller                          Spring Security UI
 Dynamic Domain Class (core code)            Twitter
 FamFamFam                                   UI Performance
 Flex

                                     CONFIDENTIAL                                               3
What Is A Plugin?




      CONFIDENTIAL   4
What Is A Plugin?




       “  A set of software components that
          adds specific abilities to a larger
          software application
          https://secure.wikimedia.org/wikipedia/en/wiki/Plug-in_(computing)




                                  CONFIDENTIAL                                 5
What Is A Plugin?


 Very similar to a Grails application project
 Plus a *GrailsPlugin.groovy plugin descriptor file
 Use grails create­plugin to create one
 Often adds artifacts, resources, scripts
 Good for code reuse
 Modular development




                            CONFIDENTIAL               6
What Is A Plugin?




 http://blog.springsource.com/2010/06/01/whats-a-plugin-oriented-architecture/


                                     CONFIDENTIAL                                7
Application Directory Structure




           CONFIDENTIAL           8
Plugin Directory Structure




           CONFIDENTIAL      9
The Background


 Grails is designed to wire
  different libraries together and
  make them easy to use

 Can be seen as “platform for
  runtime configuration”

 Without well defined system, de-
  coupling those components was
  hard

                         CONFIDENTIAL   10
Extension Points


 The Build System
 Spring Application Context
 Dynamic method registration
 Auto Reloading
 Container Config (web.xml)
 Adding new Artefact Types




                          CONFIDENTIAL   11
Types of Plugin

 New functionality
  • Datasources, UI Performance, etc.
 Wrapper
  • Spring Security, Searchable, Quartz, etc.
  • Often have many scripts, e.g. Cloud Foundry, Database
  Migration
 UI
 Bug fix
 • http://grails.org/plugin/error-pages-fix, http://grails.org/plugin/aop-reloading-fix
 Resource-only
  • famfamfam

                                         CONFIDENTIAL                                     12
Plugin Architecture




                      CONFIDENTIAL   13
Plugin Goals


   Convention-based approaches
   DRY (Don't Repeat Yourself)
   Required extension points satisfied
   Easy to distribute & install
    • Without additional configuration




                             CONFIDENTIAL   14
What Can A Plugin Do?


 Enhance classes at runtime
 • Add methods, constructors, properties, etc.

 Perform runtime Spring configuration
 Modify web.xml on the fly
 Add new controllers, tag libraries, etc.




                              CONFIDENTIAL       15
A Basic Plugin



    class LoggingGrailsPlugin {
        def version = "0.1”
        def grailsVersion = "1.3 > *"
        def doWithDynamicMethods = {
          for (c in application.allClasses) {
             c.metaClass.getLog = {->
                LogFactory.getLog(c)
             }
          }
        }
    }




                                   CONFIDENTIAL   16
DEMO




CONFIDENTIAL   17
Implementation Details




         CONFIDENTIAL    18
Application Object

 'GrailsApplication' object
 • available with the 'application' variable
 • holds convention information
 Useful methods like:
 • get*Classes
   • Retrieve all GrailsClass instances for particular artifact, e.g.
    getControllerClasses()
 • add*Class(Class clazz)
   • Adds new GrailsClass for specified class,
    e.g. addControllerClass(myClass)
 • get*Class(String name)
   • Retrieves GrailsClass for given name,
    e.g. getControllerClass(name)


                                        CONFIDENTIAL                    19
Grails Artifacts


 Some resource that fulfills a convention
 • controllers, services, etc.

 Represented by the GrailsClass interface
 • http://grails.org/doc/latest/api/org/codehaus/groovy/grails/
  commons/package-summary.html for API of all artifacts

 Add new artifacts via the Artifact API
 • http://grails.org/Developer+-+Artefact+API




                                      CONFIDENTIAL                20
Grails Artifacts


 Design decision: include or generate artifacts?
  • Include is more automatic, no explicit step
  • Including requires workflow to override
  • Generate requires extra step but is more customizable
  • Generation is static – old files can get out of date
 Overriding domain classes?
  • Really only an issue with create-drop and update, not with migrations
 Overriding controllers?
  • “un-map” with UrlMappings
  "/admin/console/$action?/$id?"(controller: "console")
  "/console/$action?/$id?"(controller: "errors", action: "urlMapping")



                                        CONFIDENTIAL                        21
The GrailsClass Interface

 Implemented by Grails artifacts written in Groovy
 • getPropertyValue(String name)
 • newInstance()
 • getName()                ← logical name

 • getFullName()            ← class name including package

 • getShortName()           ← class name without package

 • getPropertyName()        ← class name as property name

 • getClazz()               ← actual java.lang.Class


                              CONFIDENTIAL                   22
Plugin Descriptor

 Metadata
 • version, grailsVersion range, pluginExcludes, dependsOn, etc.

 Lifecycle Closures
                                  ← Modify XML generated for web.xml at
 doWithWebDescriptor              runtime

 doWithSpring                     ← Participate in Spring configuration
                                  ← Post ApplicationContext initialization
 doWithApplicationContext         activities

 doWithDynamicMethods             ← Add methods to MetaClasses

 onChange                         ← Participate in reload events


                              CONFIDENTIAL                                   23
Configuring Spring




  class JcrGrailsPlugin {
    def version = 0.1               Bean name is method name,
    def dependsOn = [core:0.4]      first argument is bean class
      def doWithSpring = {
        jcrRepository(RepositoryFactoryBean) {
           configuration = "classpath:repository.xml"
           homeDir = "/repo"
        }
      }                              Set properties on the bean
  }




                                   CONFIDENTIAL                    24
Advantages Of Spring DSL


 Just Groovy code, so can contain complex logic
 dependent on:

 • environment
 • project conventions
 • anything!

 Easy to specify complex bean definitions
 • thanks to Groovy's neat lists and maps syntax


                            CONFIDENTIAL           25
Overriding Spring Beans


 Use loadAfter to define plugin load order; your beans
 override other plugins' and Grails'

 resources.groovy loads last, so applications can
 redefine beans there
  Import com.mycompany.myapp.MyUserDetailsService
  beans = {
    userDetailsService(MyUserDetailsService) {
      grailsApplication = ref('grailsApplication')
      foo = 'bar'
    }
  }


 BeanPostProcessor/BeanFactoryPostProcessor
                                 CONFIDENTIAL             26
Plugging In Dynamic Methods


                                                  Taken from Grails core, this
 def doWithDynamicMethods = { ctx ->              plugin finds all classes ending
   application                                    with “Codec” and dynamically
      .allClasses                                 creates “encodeAsFoo” methods!
      .findAll { it.name.endsWith("Codec") }
      .each {clz ->
         Object
            .metaClass
            ."encodeAs${clz.name-'Codec'}" = {
               clz.newInstance().encode(delegate)
            }
         }
                                               The “delegate” variable
      }
                                               is equivalent to “this” in
 }
                                               regular methods



                                   CONFIDENTIAL                                27
Reload Events


  Grails apps must be reloadable during
  development

  • Can mean many things
  • Plugin's responsibility

  Plugins can define
  watchedResources
  firing onChange events
  when modified


                              CONFIDENTIAL   28
Example Reloading Plugin



class I18nGrailsPlugin {                           Defines set of files to watch
  def version = "0.4.2"                            using Spring Resource pattern
  def watchedResources =
    "file:../grails-app/i18n/*.properties"
    def onChange = { event ->
      def messageSource =
         event.ctx.getBean("messageSource")
        messageSource?.clearCache()
    }
}
                                                       When one changes, event
                                                       is fired and plugin responds
                                                       by clearing message cache




                                    CONFIDENTIAL                                   29
The Event Object


   event.source
    • Source of the change – either a Spring Resource or a
     java.lang.Class if the class was reloaded
   event.ctx
    • the Spring ApplicationContext
   event.application
    • the GrailsApplication
   event.manager
    • the GrailsPluginManager



                              CONFIDENTIAL                   30
Adding Elements to web.xml

    def doWithWebDescriptor = { xml →

        def contextParam = xml.'context-param'
        contextParam[contextParam.size() - 1] + {
          'filter' {
              'filter-name'('springSecurityFilterChain')
              'filter-class'(DelegatingFilterProxy.name)
          }
        }

        def filterMapping = xml.'filter-mapping'
        filterMapping[filterMapping.size() - 1] + {
           'listener' {
              'listener-class'(HttpSessionEventPublisher.name)
           }
        }
    }

                                     CONFIDENTIAL                31
Dependency Management


   Jar files
   • Prefer BuildConfig.groovy → Maven repos
   • lib directory is ok if unavailable otherwise

   Other plugins
   • def dependsOn = [springSecurityCore: '1.1 > *']

   • def loadAfter = ['controllers']

   Grails
   • def grailsVersion = '1.2.3 > *'


                          CONFIDENTIAL                 32
BuildConfig.groovy

 grails.project.dependency.resolution = {
   inherits 'global'
   log 'warn'

  repositories {
    grailsPlugins()
    grailsHome()
    grailsCentral()

      flatDir name:'myRepo', dirs:'/path/to/repo'

      mavenCentral()
      mavenRepo 'http://download.java.net/maven/2/'
      mavenRepo 'http://my.cool.repo.net/maven/'
  }




                                    CONFIDENTIAL      33
BuildConfig.groovy

    dependencies {
      runtime 'mysql:mysql-connector-java:5.1.13'
      compile group: 'commons-httpclient',
                name: 'commons-httpclient',
                version: '3.1'
      build('net.sf.ezmorph:ezmorph:1.0.4', 'net.sf.ehcache:ehcache:1.6.1') {
        transitive = false
      }
      test('com.h2database:h2:1.2.144') {
        export = false
      }
      runtime('org.liquibase:liquibase-core:2.0.1',
               'org.hibernate:hibernate-annotations:3.4.0.GA') {
        excludes 'xml-apis', 'commons-logging'
      }
    }
}


                                    CONFIDENTIAL                                34
Troubleshooting Dependency Management


   Run grails dependency­report
   • See http://burtbeckwith.com/blog/?p=624 for
    visualization tips

   Increase logging level
   • log 'warn' → 'info', 'verbose', or 'debug'




                         CONFIDENTIAL              35
Scripts


   Gant: http://gant.codehaus.org/
   Groovy + Ant - XML
   Can be used in apps but more common in plugins
   Put in plugin's (or app's) scripts directory
   _Install.groovy
    • runs when you run grails install­plugin or
     when it's transitively installed - don't overwrite!
     might be reinstall or plugin upgrade



                           CONFIDENTIAL                    36
Scripts


   _Uninstall.groovy
    • runs when you run grails uninstall­plugin so
     you can do cleanup, but don't delete user-
     created/edited stuff

   _Upgrade.groovy
    • runs when you run grails upgrade (not when
     you upgrade a plugin)



                            CONFIDENTIAL             37
Scripts

                      eventCreateWarStart = { name, stagingDir →
   _Events.groovy    …
                      }
    • Respond to
                      eventGenerateWebXmlEnd = {
     build events     …
                      }



   Naming convention
    • Prefix with '_' → don't show in grails help
    • Suffix with '_' → 'global' script, i.e. doesn't need
     to run in a project dir (e.g. create­app)

                            CONFIDENTIAL                           38
Scripts


   Reuse existing scripts with includeTargets
    • includeTargets << grailsScript("_GrailsWar")

   Include common code in _*Common.groovy
    • includeTargets << new 
     File("$cloudFoundryPluginDir/scripts/ 
     _CfCommon.groovy")




                          CONFIDENTIAL               39
Testing Scripts


   Put tests in test/cli
   Extend grails.test.AbstractCliTestCase
   stdout and stderr will be in target/cli-output
   http://www.cacoethes.co.uk/blog/groovyandgrails/t
    esting-your-grails-scripts

   Run with the rest with grails test­app or alone
    with grails test­app ­­other



                            CONFIDENTIAL                40
Scripts

                             Typical Structure
  includeTargets << new File(
          "$cloudFoundryPluginDir/scripts/_CfCommon.groovy")

  USAGE = '''
  grails cf-list-files [path] [--appname] [--instance]
  '''

  target(cfListFiles: 'Display a directory listing') {
    depends cfInit

      // implementation of script
  }

  def someHelperMethod() { … }

  setDefaultTarget cfListFiles

                                      CONFIDENTIAL             41
Custom Artifacts


   ControllerMixinArtefactHandler extends
   ArtefactHandlerAdapter

   interface ControllerMixinGrailsClass extends
   InjectableGrailsClass

   DefaultControllerMixinGrailsClass extends
   AbstractInjectableGrailsClass implements
   ControllerMixinGrailsClass




                            CONFIDENTIAL           42
Custom Artifacts



  class MyGrailsPlugin {

      def watchedResources = [
        'file:./grails-app/controllerMixins/**/*ControllerMixin.groovy',
        'file:./plugins/*/grails-app/controllerMixins/**/*ControllerMixin.groovy'
      ]

      def artefacts = [ControllerMixinArtefactHandler]

      def onChange = { event →
        ...
      }
  }




                                      CONFIDENTIAL                                  43
Testing




 CONFIDENTIAL   44
Testing

   Write regular unit and integration tests in test/unit
   and test/integration

   'Install' using inline mechanism in
   BuildConfig.groovy
   • grails.plugin.location.'my­plugin' = '../my­plugin'

   Test scripts as described earlier
   Create test apps programmatically – all of the
   Spring Security plugins do this with bash scripts


                           CONFIDENTIAL                     45
Testing

   Use build.xml or Gradle to create single target that
   tests and builds plugin
   <target name='package' description='Package the plugin'
           depends='test, doPackage, post-package-cleanup'/>

   Use inline plugin or install from zip
   grails install-plugin /path/to/plugin/grails-myplugin-0.1.zip




                                   CONFIDENTIAL                    46
Source Control and Release Management




                CONFIDENTIAL            47
Becoming A Plugin Developer


   Signup at Codehaus xircles
   • http://xircles.codehaus.org/signup &
     http://xircles.codehaus.org/projects/grails-plugins/members
   Talk about your idea on the mailing list
   • http://grails.org/Mailing+lists
   • Summarize your contribution and ask on the dev list
     for your request to be processed - include your xircles
     user name in the request
   Build (and test!) your plugin and run:
    • grails publish-plugin
   Done!

                              CONFIDENTIAL                         48
Source Control and Release Management

   Internal server for jars & plugins is easy with Artifactory or
    Nexus
  repositories {
    grailsPlugins()
    grailsHome()
    mavenRepo "http://yourserver:8081/artifactory/libs-releases-local/"
    mavenRepo "http://yourserver:8081/artifactory/plugins-releases-local/"
    grailsCentral()
  }

   Release with grails publish­plugin ­­repository=repo_name
  grails.project.dependency.distribution = {
    remoteRepository(
        id: "repo_name",
        url: "http://yourserver:8081/artifactory/plugins-snapshots-local/") {
      authentication username: "admin", password: "password"
    }
  }
                                      CONFIDENTIAL                              49
Source Control and Release Management

   Use “release” plugin http://grails.org/plugin/release
   • Will be default in 1.4+, publish-plugin replaces release-plugin
   • Sends tweet from @grailsplugins and email to plugin forum
     http://grails-plugins.847840.n3.nabble.com/
   • Will check code into SVN for you
     • disable with ­­noScm or grails.release.scm.enabled = false




                                     CONFIDENTIAL                      50
Best Practices and Tips




         CONFIDENTIAL     51
Best Practices and Tips


   Delete anything auto-generated that you don't use
    • grails-app/views/error.gsp
    • _Uninstall.groovy and other generated scripts
    • Empty descriptor callbacks

   Exclude files used in development or testing
    • Use def pluginExcludes = [...]
    • src/docs
    • Test artifacts
   Use Ivy + Maven repos in BuildConfig.groovy, not lib dir


                             CONFIDENTIAL                      52
Best Practices and Tips


   Write tests
   Run them often
   Run tests before commit and especially before
    release (use build.xml)

   Create test apps (ideally programmatically)
   Programmatically build inline plugin location:
   def customerName = System.getProperty("customer.name")
   grails.plugin.location."$customerName" = "customer-plugins/$customerName"


                                   CONFIDENTIAL                                53
Best Practices and Tips


   Get to 1.0
    • Initial version 0.1 is just a suggestion
    • People trust 1.0+ more
   Start using source control early
    • Easy to run git init locally and later → github
   Support your plugin!




                          CONFIDENTIAL                  54
Best Practices and Tips


   http://grails.org/doc/latest/guide/12.%20Plug-ins.html
   http://grails.org/doc/latest/guide/4.%20The
    %20Command%20Line.html#4.3%20Hooking%20into
    %20Events

   http://www.grails.org/The+Plug-in+Developers+Guide
   http://blog.springsource.com/2010/05/18/managing-
    plugins-with-grails-1-3/




                               CONFIDENTIAL                  55
Hackergarten




Signup for hackergarten here:

http://bit.ly/gr8_hackergarten



               CONFIDENTIAL      56

More Related Content

What's hot

Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012
Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012
Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012kennethaliu
 
Using Magnolia in a Microservices Architecture
Using Magnolia in a Microservices ArchitectureUsing Magnolia in a Microservices Architecture
Using Magnolia in a Microservices ArchitectureMagnolia
 
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...VMware Tanzu
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuVMware Tanzu
 
Developing modern java web applications with java ee 7 and angular js
Developing modern java web applications with java ee 7 and angular jsDeveloping modern java web applications with java ee 7 and angular js
Developing modern java web applications with java ee 7 and angular jsShekhar Gulati
 
Grails 3.0 Preview
Grails 3.0 PreviewGrails 3.0 Preview
Grails 3.0 Previewgraemerocher
 
Dropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackDropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackJacek Furmankiewicz
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new buildIgor Khotin
 
Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Zachary Klein
 
Enabling White-Box Reuse in a Pure Composition Language
Enabling White-Box Reuse in a Pure Composition LanguageEnabling White-Box Reuse in a Pure Composition Language
Enabling White-Box Reuse in a Pure Composition Languageelliando dias
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and FriendsYun Zhi Lin
 
Modular Java applications with OSGi on Apache Karaf
Modular Java applications with OSGi on Apache KarafModular Java applications with OSGi on Apache Karaf
Modular Java applications with OSGi on Apache KarafIoan Eugen Stan
 
Step by step guide to create theme for liferay dxp 7
Step by step guide to create theme for liferay dxp 7Step by step guide to create theme for liferay dxp 7
Step by step guide to create theme for liferay dxp 7Azilen Technologies Pvt. Ltd.
 
Getting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautGetting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautZachary Klein
 
Developing Plug-Ins for NetBeans
Developing Plug-Ins for NetBeansDeveloping Plug-Ins for NetBeans
Developing Plug-Ins for NetBeanselliando dias
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with GradleRyan Cuprak
 
Spring Boot on Amazon Web Services with Spring Cloud AWS
Spring Boot on Amazon Web Services with Spring Cloud AWSSpring Boot on Amazon Web Services with Spring Cloud AWS
Spring Boot on Amazon Web Services with Spring Cloud AWSVMware Tanzu
 

What's hot (20)

Micronaut Launchpad
Micronaut LaunchpadMicronaut Launchpad
Micronaut Launchpad
 
Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012
Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012
Modularizing your Grails Application with Private Plugins - SpringOne 2GX 2012
 
Java 9 Modularity in Action
Java 9 Modularity in ActionJava 9 Modularity in Action
Java 9 Modularity in Action
 
Using Magnolia in a Microservices Architecture
Using Magnolia in a Microservices ArchitectureUsing Magnolia in a Microservices Architecture
Using Magnolia in a Microservices Architecture
 
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...
The Making of the Oracle R2DBC Driver and How to Take Your Code from Synchron...
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
Developing modern java web applications with java ee 7 and angular js
Developing modern java web applications with java ee 7 and angular jsDeveloping modern java web applications with java ee 7 and angular js
Developing modern java web applications with java ee 7 and angular js
 
Grails 3.0 Preview
Grails 3.0 PreviewGrails 3.0 Preview
Grails 3.0 Preview
 
Dropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stackDropwizard Spring - the perfect Java REST server stack
Dropwizard Spring - the perfect Java REST server stack
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new build
 
Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!Grails 4: Upgrade your Game!
Grails 4: Upgrade your Game!
 
Enabling White-Box Reuse in a Pure Composition Language
Enabling White-Box Reuse in a Pure Composition LanguageEnabling White-Box Reuse in a Pure Composition Language
Enabling White-Box Reuse in a Pure Composition Language
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and Friends
 
Modular Java applications with OSGi on Apache Karaf
Modular Java applications with OSGi on Apache KarafModular Java applications with OSGi on Apache Karaf
Modular Java applications with OSGi on Apache Karaf
 
Step by step guide to create theme for liferay dxp 7
Step by step guide to create theme for liferay dxp 7Step by step guide to create theme for liferay dxp 7
Step by step guide to create theme for liferay dxp 7
 
Getting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and MicronautGetting Groovy with JHipster and Micronaut
Getting Groovy with JHipster and Micronaut
 
Developing Plug-Ins for NetBeans
Developing Plug-Ins for NetBeansDeveloping Plug-Ins for NetBeans
Developing Plug-Ins for NetBeans
 
From JavaEE to AngularJS
From JavaEE to AngularJSFrom JavaEE to AngularJS
From JavaEE to AngularJS
 
Faster Java EE Builds with Gradle
Faster Java EE Builds with GradleFaster Java EE Builds with Gradle
Faster Java EE Builds with Gradle
 
Spring Boot on Amazon Web Services with Spring Cloud AWS
Spring Boot on Amazon Web Services with Spring Cloud AWSSpring Boot on Amazon Web Services with Spring Cloud AWS
Spring Boot on Amazon Web Services with Spring Cloud AWS
 

Viewers also liked

GR8Conf 2009: Groovy in Fiance Case Study by Jonathan Felch
GR8Conf 2009: Groovy in Fiance Case Study by Jonathan FelchGR8Conf 2009: Groovy in Fiance Case Study by Jonathan Felch
GR8Conf 2009: Groovy in Fiance Case Study by Jonathan FelchGR8Conf
 
GR8Conf 2011: CodeNarc and GMetrics
GR8Conf 2011: CodeNarc and GMetricsGR8Conf 2011: CodeNarc and GMetrics
GR8Conf 2011: CodeNarc and GMetricsGR8Conf
 
Idiomatic spock
Idiomatic spockIdiomatic spock
Idiomatic spockGR8Conf
 
GR8Conf 2011: Grails 1.4 Update by Peter Ledbrook
GR8Conf 2011: Grails 1.4 Update by Peter LedbrookGR8Conf 2011: Grails 1.4 Update by Peter Ledbrook
GR8Conf 2011: Grails 1.4 Update by Peter LedbrookGR8Conf
 
Mum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developerMum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developerGR8Conf
 
Metaprogramming with Groovy
Metaprogramming with GroovyMetaprogramming with Groovy
Metaprogramming with GroovyGR8Conf
 
Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle GR8Conf
 

Viewers also liked (7)

GR8Conf 2009: Groovy in Fiance Case Study by Jonathan Felch
GR8Conf 2009: Groovy in Fiance Case Study by Jonathan FelchGR8Conf 2009: Groovy in Fiance Case Study by Jonathan Felch
GR8Conf 2009: Groovy in Fiance Case Study by Jonathan Felch
 
GR8Conf 2011: CodeNarc and GMetrics
GR8Conf 2011: CodeNarc and GMetricsGR8Conf 2011: CodeNarc and GMetrics
GR8Conf 2011: CodeNarc and GMetrics
 
Idiomatic spock
Idiomatic spockIdiomatic spock
Idiomatic spock
 
GR8Conf 2011: Grails 1.4 Update by Peter Ledbrook
GR8Conf 2011: Grails 1.4 Update by Peter LedbrookGR8Conf 2011: Grails 1.4 Update by Peter Ledbrook
GR8Conf 2011: Grails 1.4 Update by Peter Ledbrook
 
Mum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developerMum, I want to be a Groovy full-stack developer
Mum, I want to be a Groovy full-stack developer
 
Metaprogramming with Groovy
Metaprogramming with GroovyMetaprogramming with Groovy
Metaprogramming with Groovy
 
Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle Creating and testing REST contracts with Accurest Gradle
Creating and testing REST contracts with Accurest Gradle
 

Similar to GR8Conf 2011: Grails, how to plug in

Build12 factorappusingmp
Build12 factorappusingmpBuild12 factorappusingmp
Build12 factorappusingmpEmily Jiang
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugToshiaki Maki
 
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexusMicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexusEmily Jiang
 
Simplify Cloud Applications using Spring Cloud
Simplify Cloud Applications using Spring CloudSimplify Cloud Applications using Spring Cloud
Simplify Cloud Applications using Spring CloudRamnivas Laddad
 
Grails plugin development
Grails plugin developmentGrails plugin development
Grails plugin developmentMohd Farid
 
Cloud Foundry for Spring Developers
Cloud Foundry for Spring DevelopersCloud Foundry for Spring Developers
Cloud Foundry for Spring DevelopersGunnar Hillert
 
Building 12-factor Cloud Native Microservices
Building 12-factor Cloud Native MicroservicesBuilding 12-factor Cloud Native Microservices
Building 12-factor Cloud Native MicroservicesJakarta_EE
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedToru Wonyoung Choi
 
Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3Velocidex Enterprises
 
Cloud nativemicroservices jax-london2020
Cloud nativemicroservices   jax-london2020Cloud nativemicroservices   jax-london2020
Cloud nativemicroservices jax-london2020Emily Jiang
 
Cloud nativemicroservices jax-london2020
Cloud nativemicroservices   jax-london2020Cloud nativemicroservices   jax-london2020
Cloud nativemicroservices jax-london2020Emily Jiang
 
04_Azure Kubernetes Service: Basic Practices for Developers_GAB2019
04_Azure Kubernetes Service: Basic Practices for Developers_GAB201904_Azure Kubernetes Service: Basic Practices for Developers_GAB2019
04_Azure Kubernetes Service: Basic Practices for Developers_GAB2019Kumton Suttiraksiri
 
CICD With GitHub, Travis, SonarCloud and Docker Hub
CICD With GitHub, Travis, SonarCloud and Docker HubCICD With GitHub, Travis, SonarCloud and Docker Hub
CICD With GitHub, Travis, SonarCloud and Docker HubCarlos Cavero Barca
 
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...Oleg Shalygin
 
Live Coding 12 Factor App
Live Coding 12 Factor AppLive Coding 12 Factor App
Live Coding 12 Factor AppEmily Jiang
 
Arquillian & Citrus
Arquillian & CitrusArquillian & Citrus
Arquillian & Citruschristophd
 
AWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAmazon Web Services
 

Similar to GR8Conf 2011: Grails, how to plug in (20)

Build12 factorappusingmp
Build12 factorappusingmpBuild12 factorappusingmp
Build12 factorappusingmp
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsug
 
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexusMicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
MicroProfile, Docker, Kubernetes, Istio and Open Shift lab @dev nexus
 
Simplify Cloud Applications using Spring Cloud
Simplify Cloud Applications using Spring CloudSimplify Cloud Applications using Spring Cloud
Simplify Cloud Applications using Spring Cloud
 
Grails plugin development
Grails plugin developmentGrails plugin development
Grails plugin development
 
Cloud Foundry for Spring Developers
Cloud Foundry for Spring DevelopersCloud Foundry for Spring Developers
Cloud Foundry for Spring Developers
 
Building 12-factor Cloud Native Microservices
Building 12-factor Cloud Native MicroservicesBuilding 12-factor Cloud Native Microservices
Building 12-factor Cloud Native Microservices
 
GradleFX
GradleFXGradleFX
GradleFX
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO Extended
 
Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3Digital Forensics and Incident Response in The Cloud Part 3
Digital Forensics and Incident Response in The Cloud Part 3
 
Cloud nativemicroservices jax-london2020
Cloud nativemicroservices   jax-london2020Cloud nativemicroservices   jax-london2020
Cloud nativemicroservices jax-london2020
 
Cloud nativemicroservices jax-london2020
Cloud nativemicroservices   jax-london2020Cloud nativemicroservices   jax-london2020
Cloud nativemicroservices jax-london2020
 
Gradle
GradleGradle
Gradle
 
04_Azure Kubernetes Service: Basic Practices for Developers_GAB2019
04_Azure Kubernetes Service: Basic Practices for Developers_GAB201904_Azure Kubernetes Service: Basic Practices for Developers_GAB2019
04_Azure Kubernetes Service: Basic Practices for Developers_GAB2019
 
CICD With GitHub, Travis, SonarCloud and Docker Hub
CICD With GitHub, Travis, SonarCloud and Docker HubCICD With GitHub, Travis, SonarCloud and Docker Hub
CICD With GitHub, Travis, SonarCloud and Docker Hub
 
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...
GCP - Continuous Integration and Delivery into Kubernetes with GitHub, Travis...
 
Live Coding 12 Factor App
Live Coding 12 Factor AppLive Coding 12 Factor App
Live Coding 12 Factor App
 
Arquillian & Citrus
Arquillian & CitrusArquillian & Citrus
Arquillian & Citrus
 
Introduction To Grails
Introduction To GrailsIntroduction To Grails
Introduction To Grails
 
AWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for GovernmentAWS Webcast - Build Agile Applications in AWS Cloud for Government
AWS Webcast - Build Agile Applications in AWS Cloud for Government
 

More from GR8Conf

DevOps Enabling Your Team
DevOps Enabling Your TeamDevOps Enabling Your Team
DevOps Enabling Your TeamGR8Conf
 
Scraping with Geb
Scraping with GebScraping with Geb
Scraping with GebGR8Conf
 
How to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and AndroidHow to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and AndroidGR8Conf
 
Ratpack On the Docks
Ratpack On the DocksRatpack On the Docks
Ratpack On the DocksGR8Conf
 
Groovy Powered Clean Code
Groovy Powered Clean CodeGroovy Powered Clean Code
Groovy Powered Clean CodeGR8Conf
 
Cut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature pluginsCut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature pluginsGR8Conf
 
Performance tuning Grails applications
 Performance tuning Grails applications Performance tuning Grails applications
Performance tuning Grails applicationsGR8Conf
 
Ratpack and Grails 3
 Ratpack and Grails 3 Ratpack and Grails 3
Ratpack and Grails 3GR8Conf
 
Grails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloudGrails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloudGR8Conf
 
Functional testing your Grails app with GEB
Functional testing your Grails app with GEBFunctional testing your Grails app with GEB
Functional testing your Grails app with GEBGR8Conf
 
Deploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPCDeploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPCGR8Conf
 
The Grails introduction workshop
The Grails introduction workshopThe Grails introduction workshop
The Grails introduction workshopGR8Conf
 
The Groovy Ecosystem Revisited
The Groovy Ecosystem RevisitedThe Groovy Ecosystem Revisited
The Groovy Ecosystem RevisitedGR8Conf
 
Groovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examplesGroovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examplesGR8Conf
 
Integration using Apache Camel and Groovy
Integration using Apache Camel and GroovyIntegration using Apache Camel and Groovy
Integration using Apache Camel and GroovyGR8Conf
 
CRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineCRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineGR8Conf
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8confGR8Conf
 
CRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineCRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineGR8Conf
 
Jan reher may 2013
Jan reher may 2013Jan reher may 2013
Jan reher may 2013GR8Conf
 
Good Form - complex web forms made Groovy
Good Form - complex web forms made GroovyGood Form - complex web forms made Groovy
Good Form - complex web forms made GroovyGR8Conf
 

More from GR8Conf (20)

DevOps Enabling Your Team
DevOps Enabling Your TeamDevOps Enabling Your Team
DevOps Enabling Your Team
 
Scraping with Geb
Scraping with GebScraping with Geb
Scraping with Geb
 
How to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and AndroidHow to create a conference android app with Groovy and Android
How to create a conference android app with Groovy and Android
 
Ratpack On the Docks
Ratpack On the DocksRatpack On the Docks
Ratpack On the Docks
 
Groovy Powered Clean Code
Groovy Powered Clean CodeGroovy Powered Clean Code
Groovy Powered Clean Code
 
Cut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature pluginsCut your Grails application to pieces - build feature plugins
Cut your Grails application to pieces - build feature plugins
 
Performance tuning Grails applications
 Performance tuning Grails applications Performance tuning Grails applications
Performance tuning Grails applications
 
Ratpack and Grails 3
 Ratpack and Grails 3 Ratpack and Grails 3
Ratpack and Grails 3
 
Grails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloudGrails & DevOps: continuous integration and delivery in the cloud
Grails & DevOps: continuous integration and delivery in the cloud
 
Functional testing your Grails app with GEB
Functional testing your Grails app with GEBFunctional testing your Grails app with GEB
Functional testing your Grails app with GEB
 
Deploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPCDeploying, Scaling, and Running Grails on AWS and VPC
Deploying, Scaling, and Running Grails on AWS and VPC
 
The Grails introduction workshop
The Grails introduction workshopThe Grails introduction workshop
The Grails introduction workshop
 
The Groovy Ecosystem Revisited
The Groovy Ecosystem RevisitedThe Groovy Ecosystem Revisited
The Groovy Ecosystem Revisited
 
Groovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examplesGroovy 3 and the new Groovy Meta Object Protocol in examples
Groovy 3 and the new Groovy Meta Object Protocol in examples
 
Integration using Apache Camel and Groovy
Integration using Apache Camel and GroovyIntegration using Apache Camel and Groovy
Integration using Apache Camel and Groovy
 
CRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineCRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual Machine
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
 
CRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual MachineCRaSH the shell for the Java Virtual Machine
CRaSH the shell for the Java Virtual Machine
 
Jan reher may 2013
Jan reher may 2013Jan reher may 2013
Jan reher may 2013
 
Good Form - complex web forms made Groovy
Good Form - complex web forms made GroovyGood Form - complex web forms made Groovy
Good Form - complex web forms made Groovy
 

Recently uploaded

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraDeakin University
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 

Recently uploaded (20)

Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Artificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning eraArtificial intelligence in the post-deep learning era
Artificial intelligence in the post-deep learning era
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 

GR8Conf 2011: Grails, how to plug in

  • 1. Grails: How To Plug In Burt Beckwith SpringSource CONFIDENTIAL © 2010 SpringSource, A division of VMware. All rights reserved
  • 2. Agenda  What Is A Plugin?  Implementation Details  Testing  Source Control and Release Management  Best Practices and Tips CONFIDENTIAL 2
  • 3. My Plugins  Acegi  Flex Scaffold (major rework, not yet released)  App Info  SpringMVC  BlazeDS  Spring Security Core  Cloud Foundry  Spring Security ACL  Cloud Foundry UI  Spring Security App Info  CodeNarc  Spring Security Kerberos  Console  Database Reverse Engineering  Spring Security LDAP  Database Migrations  Spring Security Open ID  Datasources  Spring Security CAS  Dynamic Controller  Spring Security UI  Dynamic Domain Class (core code)  Twitter  FamFamFam  UI Performance  Flex CONFIDENTIAL 3
  • 4. What Is A Plugin? CONFIDENTIAL 4
  • 5. What Is A Plugin? “ A set of software components that adds specific abilities to a larger software application https://secure.wikimedia.org/wikipedia/en/wiki/Plug-in_(computing) CONFIDENTIAL 5
  • 6. What Is A Plugin?  Very similar to a Grails application project  Plus a *GrailsPlugin.groovy plugin descriptor file  Use grails create­plugin to create one  Often adds artifacts, resources, scripts  Good for code reuse  Modular development CONFIDENTIAL 6
  • 7. What Is A Plugin? http://blog.springsource.com/2010/06/01/whats-a-plugin-oriented-architecture/ CONFIDENTIAL 7
  • 9. Plugin Directory Structure CONFIDENTIAL 9
  • 10. The Background  Grails is designed to wire different libraries together and make them easy to use  Can be seen as “platform for runtime configuration”  Without well defined system, de- coupling those components was hard CONFIDENTIAL 10
  • 11. Extension Points  The Build System  Spring Application Context  Dynamic method registration  Auto Reloading  Container Config (web.xml)  Adding new Artefact Types CONFIDENTIAL 11
  • 12. Types of Plugin  New functionality • Datasources, UI Performance, etc.  Wrapper • Spring Security, Searchable, Quartz, etc. • Often have many scripts, e.g. Cloud Foundry, Database Migration  UI  Bug fix • http://grails.org/plugin/error-pages-fix, http://grails.org/plugin/aop-reloading-fix  Resource-only • famfamfam CONFIDENTIAL 12
  • 13. Plugin Architecture CONFIDENTIAL 13
  • 14. Plugin Goals  Convention-based approaches  DRY (Don't Repeat Yourself)  Required extension points satisfied  Easy to distribute & install • Without additional configuration CONFIDENTIAL 14
  • 15. What Can A Plugin Do?  Enhance classes at runtime • Add methods, constructors, properties, etc.  Perform runtime Spring configuration  Modify web.xml on the fly  Add new controllers, tag libraries, etc. CONFIDENTIAL 15
  • 16. A Basic Plugin class LoggingGrailsPlugin { def version = "0.1” def grailsVersion = "1.3 > *" def doWithDynamicMethods = { for (c in application.allClasses) { c.metaClass.getLog = {-> LogFactory.getLog(c) } } } } CONFIDENTIAL 16
  • 18. Implementation Details CONFIDENTIAL 18
  • 19. Application Object  'GrailsApplication' object • available with the 'application' variable • holds convention information  Useful methods like: • get*Classes • Retrieve all GrailsClass instances for particular artifact, e.g. getControllerClasses() • add*Class(Class clazz) • Adds new GrailsClass for specified class, e.g. addControllerClass(myClass) • get*Class(String name) • Retrieves GrailsClass for given name, e.g. getControllerClass(name) CONFIDENTIAL 19
  • 20. Grails Artifacts  Some resource that fulfills a convention • controllers, services, etc.  Represented by the GrailsClass interface • http://grails.org/doc/latest/api/org/codehaus/groovy/grails/ commons/package-summary.html for API of all artifacts  Add new artifacts via the Artifact API • http://grails.org/Developer+-+Artefact+API CONFIDENTIAL 20
  • 21. Grails Artifacts  Design decision: include or generate artifacts? • Include is more automatic, no explicit step • Including requires workflow to override • Generate requires extra step but is more customizable • Generation is static – old files can get out of date  Overriding domain classes? • Really only an issue with create-drop and update, not with migrations  Overriding controllers? • “un-map” with UrlMappings "/admin/console/$action?/$id?"(controller: "console") "/console/$action?/$id?"(controller: "errors", action: "urlMapping") CONFIDENTIAL 21
  • 22. The GrailsClass Interface  Implemented by Grails artifacts written in Groovy • getPropertyValue(String name) • newInstance() • getName() ← logical name • getFullName() ← class name including package • getShortName() ← class name without package • getPropertyName() ← class name as property name • getClazz() ← actual java.lang.Class CONFIDENTIAL 22
  • 23. Plugin Descriptor  Metadata • version, grailsVersion range, pluginExcludes, dependsOn, etc.  Lifecycle Closures ← Modify XML generated for web.xml at doWithWebDescriptor runtime doWithSpring ← Participate in Spring configuration ← Post ApplicationContext initialization doWithApplicationContext activities doWithDynamicMethods ← Add methods to MetaClasses onChange ← Participate in reload events CONFIDENTIAL 23
  • 24. Configuring Spring class JcrGrailsPlugin { def version = 0.1 Bean name is method name, def dependsOn = [core:0.4] first argument is bean class def doWithSpring = { jcrRepository(RepositoryFactoryBean) { configuration = "classpath:repository.xml" homeDir = "/repo" } } Set properties on the bean } CONFIDENTIAL 24
  • 25. Advantages Of Spring DSL  Just Groovy code, so can contain complex logic dependent on: • environment • project conventions • anything!  Easy to specify complex bean definitions • thanks to Groovy's neat lists and maps syntax CONFIDENTIAL 25
  • 26. Overriding Spring Beans  Use loadAfter to define plugin load order; your beans override other plugins' and Grails'  resources.groovy loads last, so applications can redefine beans there Import com.mycompany.myapp.MyUserDetailsService beans = { userDetailsService(MyUserDetailsService) { grailsApplication = ref('grailsApplication') foo = 'bar' } }  BeanPostProcessor/BeanFactoryPostProcessor CONFIDENTIAL 26
  • 27. Plugging In Dynamic Methods Taken from Grails core, this def doWithDynamicMethods = { ctx -> plugin finds all classes ending application with “Codec” and dynamically .allClasses creates “encodeAsFoo” methods! .findAll { it.name.endsWith("Codec") } .each {clz -> Object .metaClass ."encodeAs${clz.name-'Codec'}" = { clz.newInstance().encode(delegate) } } The “delegate” variable } is equivalent to “this” in } regular methods CONFIDENTIAL 27
  • 28. Reload Events  Grails apps must be reloadable during development • Can mean many things • Plugin's responsibility  Plugins can define watchedResources firing onChange events when modified CONFIDENTIAL 28
  • 29. Example Reloading Plugin class I18nGrailsPlugin { Defines set of files to watch def version = "0.4.2" using Spring Resource pattern def watchedResources = "file:../grails-app/i18n/*.properties" def onChange = { event -> def messageSource = event.ctx.getBean("messageSource") messageSource?.clearCache() } } When one changes, event is fired and plugin responds by clearing message cache CONFIDENTIAL 29
  • 30. The Event Object  event.source • Source of the change – either a Spring Resource or a java.lang.Class if the class was reloaded  event.ctx • the Spring ApplicationContext  event.application • the GrailsApplication  event.manager • the GrailsPluginManager CONFIDENTIAL 30
  • 31. Adding Elements to web.xml def doWithWebDescriptor = { xml → def contextParam = xml.'context-param' contextParam[contextParam.size() - 1] + { 'filter' { 'filter-name'('springSecurityFilterChain') 'filter-class'(DelegatingFilterProxy.name) } } def filterMapping = xml.'filter-mapping' filterMapping[filterMapping.size() - 1] + { 'listener' { 'listener-class'(HttpSessionEventPublisher.name) } } } CONFIDENTIAL 31
  • 32. Dependency Management  Jar files • Prefer BuildConfig.groovy → Maven repos • lib directory is ok if unavailable otherwise  Other plugins • def dependsOn = [springSecurityCore: '1.1 > *'] • def loadAfter = ['controllers']  Grails • def grailsVersion = '1.2.3 > *' CONFIDENTIAL 32
  • 33. BuildConfig.groovy grails.project.dependency.resolution = { inherits 'global' log 'warn' repositories { grailsPlugins() grailsHome() grailsCentral() flatDir name:'myRepo', dirs:'/path/to/repo' mavenCentral() mavenRepo 'http://download.java.net/maven/2/' mavenRepo 'http://my.cool.repo.net/maven/' } CONFIDENTIAL 33
  • 34. BuildConfig.groovy dependencies { runtime 'mysql:mysql-connector-java:5.1.13' compile group: 'commons-httpclient', name: 'commons-httpclient', version: '3.1' build('net.sf.ezmorph:ezmorph:1.0.4', 'net.sf.ehcache:ehcache:1.6.1') { transitive = false } test('com.h2database:h2:1.2.144') { export = false } runtime('org.liquibase:liquibase-core:2.0.1', 'org.hibernate:hibernate-annotations:3.4.0.GA') { excludes 'xml-apis', 'commons-logging' } } } CONFIDENTIAL 34
  • 35. Troubleshooting Dependency Management  Run grails dependency­report • See http://burtbeckwith.com/blog/?p=624 for visualization tips  Increase logging level • log 'warn' → 'info', 'verbose', or 'debug' CONFIDENTIAL 35
  • 36. Scripts  Gant: http://gant.codehaus.org/  Groovy + Ant - XML  Can be used in apps but more common in plugins  Put in plugin's (or app's) scripts directory  _Install.groovy • runs when you run grails install­plugin or when it's transitively installed - don't overwrite! might be reinstall or plugin upgrade CONFIDENTIAL 36
  • 37. Scripts  _Uninstall.groovy • runs when you run grails uninstall­plugin so you can do cleanup, but don't delete user- created/edited stuff  _Upgrade.groovy • runs when you run grails upgrade (not when you upgrade a plugin) CONFIDENTIAL 37
  • 38. Scripts eventCreateWarStart = { name, stagingDir →  _Events.groovy … } • Respond to eventGenerateWebXmlEnd = { build events … }  Naming convention • Prefix with '_' → don't show in grails help • Suffix with '_' → 'global' script, i.e. doesn't need to run in a project dir (e.g. create­app) CONFIDENTIAL 38
  • 39. Scripts  Reuse existing scripts with includeTargets • includeTargets << grailsScript("_GrailsWar")  Include common code in _*Common.groovy • includeTargets << new  File("$cloudFoundryPluginDir/scripts/  _CfCommon.groovy") CONFIDENTIAL 39
  • 40. Testing Scripts  Put tests in test/cli  Extend grails.test.AbstractCliTestCase  stdout and stderr will be in target/cli-output  http://www.cacoethes.co.uk/blog/groovyandgrails/t esting-your-grails-scripts  Run with the rest with grails test­app or alone with grails test­app ­­other CONFIDENTIAL 40
  • 41. Scripts Typical Structure includeTargets << new File( "$cloudFoundryPluginDir/scripts/_CfCommon.groovy") USAGE = ''' grails cf-list-files [path] [--appname] [--instance] ''' target(cfListFiles: 'Display a directory listing') { depends cfInit // implementation of script } def someHelperMethod() { … } setDefaultTarget cfListFiles CONFIDENTIAL 41
  • 42. Custom Artifacts  ControllerMixinArtefactHandler extends ArtefactHandlerAdapter  interface ControllerMixinGrailsClass extends InjectableGrailsClass  DefaultControllerMixinGrailsClass extends AbstractInjectableGrailsClass implements ControllerMixinGrailsClass CONFIDENTIAL 42
  • 43. Custom Artifacts class MyGrailsPlugin { def watchedResources = [ 'file:./grails-app/controllerMixins/**/*ControllerMixin.groovy', 'file:./plugins/*/grails-app/controllerMixins/**/*ControllerMixin.groovy' ] def artefacts = [ControllerMixinArtefactHandler] def onChange = { event → ... } } CONFIDENTIAL 43
  • 45. Testing  Write regular unit and integration tests in test/unit and test/integration  'Install' using inline mechanism in BuildConfig.groovy • grails.plugin.location.'my­plugin' = '../my­plugin'  Test scripts as described earlier  Create test apps programmatically – all of the Spring Security plugins do this with bash scripts CONFIDENTIAL 45
  • 46. Testing  Use build.xml or Gradle to create single target that tests and builds plugin <target name='package' description='Package the plugin' depends='test, doPackage, post-package-cleanup'/>  Use inline plugin or install from zip grails install-plugin /path/to/plugin/grails-myplugin-0.1.zip CONFIDENTIAL 46
  • 47. Source Control and Release Management CONFIDENTIAL 47
  • 48. Becoming A Plugin Developer  Signup at Codehaus xircles • http://xircles.codehaus.org/signup & http://xircles.codehaus.org/projects/grails-plugins/members  Talk about your idea on the mailing list • http://grails.org/Mailing+lists • Summarize your contribution and ask on the dev list for your request to be processed - include your xircles user name in the request  Build (and test!) your plugin and run: • grails publish-plugin  Done! CONFIDENTIAL 48
  • 49. Source Control and Release Management  Internal server for jars & plugins is easy with Artifactory or Nexus repositories { grailsPlugins() grailsHome() mavenRepo "http://yourserver:8081/artifactory/libs-releases-local/" mavenRepo "http://yourserver:8081/artifactory/plugins-releases-local/" grailsCentral() }  Release with grails publish­plugin ­­repository=repo_name grails.project.dependency.distribution = { remoteRepository( id: "repo_name", url: "http://yourserver:8081/artifactory/plugins-snapshots-local/") { authentication username: "admin", password: "password" } } CONFIDENTIAL 49
  • 50. Source Control and Release Management  Use “release” plugin http://grails.org/plugin/release • Will be default in 1.4+, publish-plugin replaces release-plugin • Sends tweet from @grailsplugins and email to plugin forum http://grails-plugins.847840.n3.nabble.com/ • Will check code into SVN for you • disable with ­­noScm or grails.release.scm.enabled = false CONFIDENTIAL 50
  • 51. Best Practices and Tips CONFIDENTIAL 51
  • 52. Best Practices and Tips  Delete anything auto-generated that you don't use • grails-app/views/error.gsp • _Uninstall.groovy and other generated scripts • Empty descriptor callbacks  Exclude files used in development or testing • Use def pluginExcludes = [...] • src/docs • Test artifacts  Use Ivy + Maven repos in BuildConfig.groovy, not lib dir CONFIDENTIAL 52
  • 53. Best Practices and Tips  Write tests  Run them often  Run tests before commit and especially before release (use build.xml)  Create test apps (ideally programmatically)  Programmatically build inline plugin location: def customerName = System.getProperty("customer.name") grails.plugin.location."$customerName" = "customer-plugins/$customerName" CONFIDENTIAL 53
  • 54. Best Practices and Tips  Get to 1.0 • Initial version 0.1 is just a suggestion • People trust 1.0+ more  Start using source control early • Easy to run git init locally and later → github  Support your plugin! CONFIDENTIAL 54
  • 55. Best Practices and Tips  http://grails.org/doc/latest/guide/12.%20Plug-ins.html  http://grails.org/doc/latest/guide/4.%20The %20Command%20Line.html#4.3%20Hooking%20into %20Events  http://www.grails.org/The+Plug-in+Developers+Guide  http://blog.springsource.com/2010/05/18/managing- plugins-with-grails-1-3/ CONFIDENTIAL 55
  • 56. Hackergarten Signup for hackergarten here: http://bit.ly/gr8_hackergarten CONFIDENTIAL 56