SlideShare a Scribd company logo
1 of 61
Download to read offline
Burt Beckwith
SpringSource
Grails Plugin Best Practices
2CONFIDENTIAL 2CONFIDENTIAL
My Plugins
 Acegi
 App Info
 App Info Hibernate
 AspectJ (in-progress)
 Atomikos
 Binary Artifacts
 BlazeDS (reworked)
 Cache
 Cache-Ehcache
 Cache-Redis
 Cache-Gemfire
 Cloud Foundry
 Cloud Foundry UI
 Cloud Support
 CodeNarc
 Console (rework, current owner)
 Database Reverse Engineering
 Database Sessions
 Database Migration
 Database Migration JAXB
 Datasources
 Dumbster
 Dynamic Controller
 Dynamic Domain Class (core code)
 EJB (in-progress)
 EJB Glassfish (in-progress)
 FamFamFam
 Flex (reworked, current owner)
 Flex Scaffold (major rework, not yet released)
 HDIV (in-progress)
3CONFIDENTIAL 3CONFIDENTIAL
My Plugins
 Heroku
 Hibernate Filter (rework, current owner)
 Jbossas
 jdbc-pool (rework, current owner)
 JMX
 LazyLob
 Logback
 Memcached
 P6Spy UI
 Ratpack
 Remoting (reworked, current owner)
 SpringMVC
 Spring Security Core
 Spring Security ACL
 Spring Security App Info
 Spring Security CAS
 Spring Security Kerberos
 Spring Security LDAP
 Spring Security OAuth Consumer (in-progress)
 Spring Security OAuth Provider (in-progress)
 Spring Security Open ID
 Spring Security Shiro
 Spring Security UI
 Standalone
 standalone-tomcat-memcached
 standalone-tomcat-redis
 tcpmon
 Twitter
 UI Performance
 Webxml (rework, current owner)
4CONFIDENTIAL 4CONFIDENTIAL
What Is A Plugin?
5CONFIDENTIAL 5CONFIDENTIAL
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)
“
6CONFIDENTIAL 6CONFIDENTIAL
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
7CONFIDENTIAL 7CONFIDENTIAL
Application Directory Structure
8CONFIDENTIAL 8CONFIDENTIAL
Plugin Directory Structure
9CONFIDENTIAL 9CONFIDENTIAL
Extension Points
 The Build System
 Spring Application Context
 Dynamic method registration
 Auto Reloading
 Container Config (web.xml)
 Adding new Artefact Types
10CONFIDENTIAL 10CONFIDENTIAL
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
11CONFIDENTIAL 11CONFIDENTIAL
Plugin Goals
 Convention-based approaches
 DRY (Don't Repeat Yourself)
 Required extension points satisfied
 Easy to distribute & install
• Without additional configuration
12CONFIDENTIAL 12CONFIDENTIAL
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.
13CONFIDENTIAL 13CONFIDENTIAL
A Basic Plugin
class LoggingGrailsPlugin {
def version = "0.1”
def grailsVersion = "2.0 > *"
def doWithDynamicMethods = {
for (c in application.allClasses) {
c.metaClass.getLog = {->
LogFactory.getLog(c)
}
}
}
}
14CONFIDENTIAL 14CONFIDENTIAL
Application Object
 'GrailsApplication' object
• available with the application variable in the plugin descriptor, and
the grailsApplication Spring bean
• holds convention information
• Convenient access to the config: grailsApplication.config
(since the holders are deprecated)
15CONFIDENTIAL 15CONFIDENTIAL
Application Object
 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)
16CONFIDENTIAL 16CONFIDENTIAL
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
17CONFIDENTIAL 17CONFIDENTIAL
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")
18CONFIDENTIAL 18CONFIDENTIAL
Plugin Descriptor
 Metadata
• version, grailsVersion range, pluginExcludes, dependsOn, etc.
 Lifecycle Closures
doWithWebDescriptor
← Modify XML generated for web.xml at
runtime
doWithSpring ← Participate in Spring configuration
doWithApplicationContext
← Post ApplicationContext initialization
activities
doWithDynamicMethods ← Add methods to MetaClasses
onChange ← Participate in reload events
19CONFIDENTIAL 19CONFIDENTIAL
Configuring Spring
class JcrGrailsPlugin {
def version = 0.1
def dependsOn = [core:0.4]
def doWithSpring = {
jcrRepository(RepositoryFactoryBean) {
configuration = "classpath:repository.xml"
homeDir = "/repo"
}
}
}
Bean name is method name,
first argument is bean class
Set properties on the bean
20CONFIDENTIAL 20CONFIDENTIAL
Planning for Customization
21CONFIDENTIAL 21CONFIDENTIAL
Planning for Customization
 Plugins are compiled first, then the app; this means that
everything can be overridden
 Prefer Spring beans to using new
 Prefer dynamic instantiation (to allow class name override) to
using new
 Use protected, not private and avoid static
 Move logic from plugin descriptor to classes
22CONFIDENTIAL 22CONFIDENTIAL
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'
}
}
23CONFIDENTIAL 23CONFIDENTIAL
Overriding Spring Beans
 For more advanced configuration, use a
BeanPostProcessor, BeanFactoryPostProcessor, or
a BeanDefinitionRegistryPostProcessor
24CONFIDENTIAL 24CONFIDENTIAL
Plugging In Dynamic Methods
def doWithDynamicMethods = { ctx ->
application
.allClasses
.findAll { it.name.endsWith("Codec") }
.each {clz ->
Object
.metaClass
."encodeAs${clz.name-'Codec'}" = {
clz.newInstance().encode(delegate)
}
}
}
}
Taken from Grails core, this
plugin finds all classes ending
with “Codec” and dynamically
creates “encodeAsFoo” methods!
The “delegate” variable
is equivalent to “this” in
regular methods
25CONFIDENTIAL 25CONFIDENTIAL
Example Reloading Plugin
class I18nGrailsPlugin {
def version = "0.4.2"
def watchedResources =
"file:../grails-app/i18n/*.properties"
def onChange = { event ->
def messageSource =
event.ctx.getBean("messageSource")
messageSource?.clearCache()
}
}
Defines set of files to watch
using Spring Resource pattern
When one changes, event
is fired and plugin responds
by clearing message cache
26CONFIDENTIAL 26CONFIDENTIAL
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
27CONFIDENTIAL 27CONFIDENTIAL
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)
}
}
}
28CONFIDENTIAL 28CONFIDENTIAL
Dependency Management
 Jar files
• Prefer BuildConfig.groovy Maven repos→
• lib directory is ok if unavailable otherwise
 Other plugins
• def loadAfter = ['controllers']
• Declare dependencies in BuildConfig.groovy
 Grails
• def grailsVersion = '2.0 > *'
29CONFIDENTIAL 29CONFIDENTIAL
BuildConfig.groovy
grails.project.dependency.resolution = {
inherits 'global'
log 'warn'
repositories {
grailsCentral()
flatDir name:'myRepo', dirs:'/path/to/repo'
mavenLocal()
mavenCentral()
mavenRepo 'http://download.java.net/maven/2/'
mavenRepo 'http://my.cool.repo.net/maven/'
}
30CONFIDENTIAL 30CONFIDENTIAL
BuildConfig.groovy
dependencies {
runtime 'mysql:mysql-connector-java:5.1.22'
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'
}
}
31CONFIDENTIAL 31CONFIDENTIAL
BuildConfig.groovy
plugins {
runtime ":hibernate:$grailsVersion", {
export = false
}
runtime ':jquery:1.8.3'
compile ':spring-security-core:1.2.7.3'
runtime ':console:1.2'
build ':release:2.2.1', ':rest-client-builder:1.0.3', {
export = false
}
}
}
32CONFIDENTIAL 32CONFIDENTIAL
Troubleshooting Dependency Management
 Run grails dependency­report
• See http://burtbeckwith.com/blog/?p=624 for
visualization tips
 Increase BuildConfig.groovy logging level
• log 'warn' → 'info', 'verbose', or 'debug'
33CONFIDENTIAL 33CONFIDENTIAL
Scripts
 Gant: http://gant.codehaus.org/
 Groovy + Ant - XML
 Can be used in apps but more common in plugins
 Put in the 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
34CONFIDENTIAL 34CONFIDENTIAL
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)
35CONFIDENTIAL 35CONFIDENTIAL
Scripts
 _Events.groovy
• Respond to
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)
eventCreateWarStart = { name, stagingDir →
…
}
eventGenerateWebXmlEnd = {
…
}
36CONFIDENTIAL 36CONFIDENTIAL
Scripts
 Reuse existing scripts with includeTargets
• includeTargets << grailsScript("_GrailsWar")
 Include common code in _*Common.groovy
• includeTargets << new File(               
  cloudFoundryPluginDir,                  
  "scripts/CfCommon.groovy")
37CONFIDENTIAL 37CONFIDENTIAL
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
/testing-your-grails-scripts
 Run with the rest with grails test­app or alone
with grails test­app ­­other
38CONFIDENTIAL 38CONFIDENTIAL
Scripts
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
Typical Structure
39CONFIDENTIAL 39CONFIDENTIAL
Custom Artifacts
 ControllerMixinArtefactHandler extends
ArtefactHandlerAdapter
 interface ControllerMixinGrailsClass extends
InjectableGrailsClass
 DefaultControllerMixinGrailsClass extends
AbstractInjectableGrailsClass implements
ControllerMixinGrailsClass
40CONFIDENTIAL 40CONFIDENTIAL
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 →
...
}
}
41CONFIDENTIAL 41CONFIDENTIAL
Testing
42CONFIDENTIAL 42CONFIDENTIAL
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
43CONFIDENTIAL 43CONFIDENTIAL
Testing
 Use build.xml or Gradle to create single target that
tests and builds plugin
 Use inline plugin or install from zip
 Zip install is deprecated, so better to use the
maven-install script
• Will resolve as a BuildConfig dependency (using
mavenLocal())
<target name='package' description='Package the plugin'
depends='test, doPackage, post-package-cleanup'/>
grails install-plugin /path/to/plugin/grails-myplugin-0.1.zip
44CONFIDENTIAL 44CONFIDENTIAL
Testing
 Use CI, e.g. CloudBees BuildHive:
• https://fbflex.wordpress.com/2012/07/12/using-cl
oudbees-buildhive-to-test-grails-plugins/
• https://buildhive.cloudbees.com/job/burtbeckwith
/job/grails-database-session/
45CONFIDENTIAL 45CONFIDENTIAL
Source Control and Release Management
46CONFIDENTIAL 46CONFIDENTIAL
Becoming A Plugin Developer
 Create an account at grails.org
 Discuss your idea on the User mailing list
• http://grails.org/Mailing+lists
 Submit a request at http://grails.org/plugins/submitPlugin
• Monitor the submission for questions and comments
 Build (and test!) your plugin and run:
• grails publish-plugin --stacktrace
 Profit!
47CONFIDENTIAL 47CONFIDENTIAL
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()
}
48CONFIDENTIAL 48CONFIDENTIAL
Source Control and Release Management
 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"
}
}
49CONFIDENTIAL 49CONFIDENTIAL
Source Control and Release Management
 Use “release” plugin http://grails.org/plugin/release
• Sends tweet from @grailsplugins and email to plugin forum
http://grails-plugins.847840.n3.nabble.com/
• Will not check code into SVN for you
plugins {
build ':release:2.2.1', ':rest-client-builder:1.0.3', {
export = false
}
}
50CONFIDENTIAL 50CONFIDENTIAL
Best Practices and Tips
51CONFIDENTIAL 51CONFIDENTIAL
Best Practices and Tips
 Delete anything auto-generated that you don't use
• grails-app/views/error.gsp
• Empty grails-app/i18n/messages.properties
• _Uninstall.groovy and other generated scripts
• web-app files
• grails-app/conf/UrlMappings.groovy
• Empty descriptor callbacks
52CONFIDENTIAL 52CONFIDENTIAL
Best Practices and Tips
 Exclude files used in development or testing
• Use def pluginExcludes = [...]
• src/docs
• Test artifacts
 Create .gitignore (manually or with
integrate-with –git)
 Open every file, decide that you own it or not
53CONFIDENTIAL 53CONFIDENTIAL
Best Practices and Tips
 Use dependency management in
BuildConfig.groovy, not lib dir
 Change the minimum Grails version to 2.0 or the lowest
version you're comfortable supporting:
• def grailsVersion = '2.0 > *'
54CONFIDENTIAL 54CONFIDENTIAL
Best Practices and Tips
 Write tests
 Run them often
 Run tests before commit and especially before
release (use build.xml or Gradle)
 Create test apps (ideally programmatically)
 Programmatically build inline plugin location:
def customerName = System.getProperty("customer.name")
grails.plugin.location."$customerName" = "customer-plugins/$customerName"
55CONFIDENTIAL 55CONFIDENTIAL
Best Practices and Tips
 Prefer Java to Groovy (or @CompileStatic) for
performance if applicable
 Instead of using inline plugins, install into a test
app and use Meld or another diff tool to keep in
sync
 Before you release, run package-plugin and open
the ZIP, look at what's there
56CONFIDENTIAL 56CONFIDENTIAL
Best Practices and Tips
 Use a sensible naming convention, e.g.
grails.plugin.<pluginname>
 Most plugin metadata is not optional:
• Fix grailsVersion
• Update description and documentation
• Set value for license, issueManagement, scm (and
organization, developers if applicable)
57CONFIDENTIAL 57CONFIDENTIAL
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!
58CONFIDENTIAL 58CONFIDENTIAL
Best Practices and Tips
 http://grails.org/Creating+Plugins
 http://grails.org/The+Plug-in+Developers+Guide
 http://blog.springsource.com/2010/05/18/managing-plu
gins-with-grails-1-3/
 http://grails.org/doc/latest/guide/plugins.html
59CONFIDENTIAL 59CONFIDENTIAL
Want To Learn More?
61CONFIDENTIAL 61CONFIDENTIAL
Thanks!

More Related Content

What's hot

Grails 3.0 Preview
Grails 3.0 PreviewGrails 3.0 Preview
Grails 3.0 Previewgraemerocher
 
A year in the life of a Grails startup
A year in the life of a Grails startupA year in the life of a Grails startup
A year in the life of a Grails startuptomaslin
 
Faster java ee builds with gradle [con4921]
Faster java ee builds with gradle [con4921]Faster java ee builds with gradle [con4921]
Faster java ee builds with gradle [con4921]Ryan Cuprak
 
Gradle - Build system evolved
Gradle - Build system evolvedGradle - Build system evolved
Gradle - Build system evolvedBhagwat Kumar
 
Migrating from Grails 2 to Grails 3
Migrating from Grails 2 to Grails 3Migrating from Grails 2 to Grails 3
Migrating from Grails 2 to Grails 3Michael Plöd
 
Why jakarta ee matters (ConFoo 2021)
Why jakarta ee matters (ConFoo 2021)Why jakarta ee matters (ConFoo 2021)
Why jakarta ee matters (ConFoo 2021)Ryan Cuprak
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureZachary Klein
 
Android gradle-build-system-overview
Android gradle-build-system-overviewAndroid gradle-build-system-overview
Android gradle-build-system-overviewKevin He
 
GR8Conf 2011: Adopting Grails
GR8Conf 2011: Adopting GrailsGR8Conf 2011: Adopting Grails
GR8Conf 2011: Adopting GrailsGR8Conf
 
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...DynamicInfraDays
 
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
 
Micronaut For Single Page Apps
Micronaut For Single Page AppsMicronaut For Single Page Apps
Micronaut For Single Page AppsZachary Klein
 
Java(ee) mongo db applications in the cloud
Java(ee) mongo db applications in the cloud Java(ee) mongo db applications in the cloud
Java(ee) mongo db applications in the cloud Shekhar Gulati
 
Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Jared Burrows
 
4 JVM Web Frameworks
4 JVM Web Frameworks4 JVM Web Frameworks
4 JVM Web FrameworksJoe Kutner
 
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
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and FriendsYun Zhi Lin
 

What's hot (20)

Grails 3.0 Preview
Grails 3.0 PreviewGrails 3.0 Preview
Grails 3.0 Preview
 
Gradle
GradleGradle
Gradle
 
A year in the life of a Grails startup
A year in the life of a Grails startupA year in the life of a Grails startup
A year in the life of a Grails startup
 
Apache Lucene for Java EE Developers
Apache Lucene for Java EE DevelopersApache Lucene for Java EE Developers
Apache Lucene for Java EE Developers
 
Faster java ee builds with gradle [con4921]
Faster java ee builds with gradle [con4921]Faster java ee builds with gradle [con4921]
Faster java ee builds with gradle [con4921]
 
Gradle - Build system evolved
Gradle - Build system evolvedGradle - Build system evolved
Gradle - Build system evolved
 
Migrating from Grails 2 to Grails 3
Migrating from Grails 2 to Grails 3Migrating from Grails 2 to Grails 3
Migrating from Grails 2 to Grails 3
 
Why jakarta ee matters (ConFoo 2021)
Why jakarta ee matters (ConFoo 2021)Why jakarta ee matters (ConFoo 2021)
Why jakarta ee matters (ConFoo 2021)
 
Micronaut: Changing the Micro Future
Micronaut: Changing the Micro FutureMicronaut: Changing the Micro Future
Micronaut: Changing the Micro Future
 
Android gradle-build-system-overview
Android gradle-build-system-overviewAndroid gradle-build-system-overview
Android gradle-build-system-overview
 
GR8Conf 2011: Adopting Grails
GR8Conf 2011: Adopting GrailsGR8Conf 2011: Adopting Grails
GR8Conf 2011: Adopting Grails
 
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
ContainerDays NYC 2016: "OpenWhisk: A Serverless Computing Platform" (Rodric ...
 
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...
 
Micronaut For Single Page Apps
Micronaut For Single Page AppsMicronaut For Single Page Apps
Micronaut For Single Page Apps
 
Java(ee) mongo db applications in the cloud
Java(ee) mongo db applications in the cloud Java(ee) mongo db applications in the cloud
Java(ee) mongo db applications in the cloud
 
Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)Make Your Build Great Again (DroidConSF 2017)
Make Your Build Great Again (DroidConSF 2017)
 
Angular beans
Angular beansAngular beans
Angular beans
 
4 JVM Web Frameworks
4 JVM Web Frameworks4 JVM Web Frameworks
4 JVM Web Frameworks
 
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
 
Dropwizard and Friends
Dropwizard and FriendsDropwizard and Friends
Dropwizard and Friends
 

Viewers also liked

Pope Francis: from the heart of the gospel (cont.)
Pope Francis: from the heart of the gospel (cont.)Pope Francis: from the heart of the gospel (cont.)
Pope Francis: from the heart of the gospel (cont.)MargaretObrovac
 
Conferences i/o 3 Minute Getting Started Guide - V2
Conferences i/o 3 Minute Getting Started Guide - V2Conferences i/o 3 Minute Getting Started Guide - V2
Conferences i/o 3 Minute Getting Started Guide - V2John Pytel
 
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...Nathan Varma
 
High Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootHigh Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootDaniel Woods
 
Global Services Location Index 2016 | A.T. Kearney
Global Services Location Index 2016  | A.T. KearneyGlobal Services Location Index 2016  | A.T. Kearney
Global Services Location Index 2016 | A.T. KearneyKearney
 
Cálculo de circuitos mixtos
Cálculo de circuitos mixtosCálculo de circuitos mixtos
Cálculo de circuitos mixtosGabriel Diaz
 
Aprendizaje social de Albert Bandura
Aprendizaje social de Albert BanduraAprendizaje social de Albert Bandura
Aprendizaje social de Albert BanduraSoniiMuua
 
Sistema economico capitalista
Sistema economico capitalistaSistema economico capitalista
Sistema economico capitalistaFrancisco Zapata
 
Circuitos serie-y-paralelo-ejercicios
Circuitos serie-y-paralelo-ejerciciosCircuitos serie-y-paralelo-ejercicios
Circuitos serie-y-paralelo-ejerciciosCristian Garcia
 
Herramientas 2.0 para todos los públicos
Herramientas 2.0 para todos los públicosHerramientas 2.0 para todos los públicos
Herramientas 2.0 para todos los públicosmariajesusmusica
 
El Blog, punto de encuentro lector
El Blog, punto de encuentro lectorEl Blog, punto de encuentro lector
El Blog, punto de encuentro lectormariajesusmusica
 
¿Qué aprendemos en clase de música?
¿Qué aprendemos en clase de música?¿Qué aprendemos en clase de música?
¿Qué aprendemos en clase de música?mariajesusmusica
 

Viewers also liked (20)

Pope Francis: from the heart of the gospel (cont.)
Pope Francis: from the heart of the gospel (cont.)Pope Francis: from the heart of the gospel (cont.)
Pope Francis: from the heart of the gospel (cont.)
 
Smile n write ied.by najma adam
Smile n write ied.by najma adamSmile n write ied.by najma adam
Smile n write ied.by najma adam
 
Conferences i/o 3 Minute Getting Started Guide - V2
Conferences i/o 3 Minute Getting Started Guide - V2Conferences i/o 3 Minute Getting Started Guide - V2
Conferences i/o 3 Minute Getting Started Guide - V2
 
Pope Francis I
Pope Francis IPope Francis I
Pope Francis I
 
Peradaban Mesir Kuno
Peradaban Mesir KunoPeradaban Mesir Kuno
Peradaban Mesir Kuno
 
10 frases sobre publicidad
10 frases sobre publicidad10 frases sobre publicidad
10 frases sobre publicidad
 
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...
OT for Kids - Assessing and Improving Handwriting for Occupational Therapists...
 
High Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring BootHigh Performance Microservices with Ratpack and Spring Boot
High Performance Microservices with Ratpack and Spring Boot
 
Global Services Location Index 2016 | A.T. Kearney
Global Services Location Index 2016  | A.T. KearneyGlobal Services Location Index 2016  | A.T. Kearney
Global Services Location Index 2016 | A.T. Kearney
 
Cálculo de circuitos mixtos
Cálculo de circuitos mixtosCálculo de circuitos mixtos
Cálculo de circuitos mixtos
 
Aprendizaje social de Albert Bandura
Aprendizaje social de Albert BanduraAprendizaje social de Albert Bandura
Aprendizaje social de Albert Bandura
 
Sistema economico capitalista
Sistema economico capitalistaSistema economico capitalista
Sistema economico capitalista
 
Teoría Aprendizaje Social
Teoría Aprendizaje SocialTeoría Aprendizaje Social
Teoría Aprendizaje Social
 
Circuitos serie-y-paralelo-ejercicios
Circuitos serie-y-paralelo-ejerciciosCircuitos serie-y-paralelo-ejercicios
Circuitos serie-y-paralelo-ejercicios
 
Prensa digital
Prensa digitalPrensa digital
Prensa digital
 
Herramientas 2.0 para todos los públicos
Herramientas 2.0 para todos los públicosHerramientas 2.0 para todos los públicos
Herramientas 2.0 para todos los públicos
 
El Blog, punto de encuentro lector
El Blog, punto de encuentro lectorEl Blog, punto de encuentro lector
El Blog, punto de encuentro lector
 
Clase música20
Clase música20Clase música20
Clase música20
 
Aprendizaje musical TIC
Aprendizaje musical TICAprendizaje musical TIC
Aprendizaje musical TIC
 
¿Qué aprendemos en clase de música?
¿Qué aprendemos en clase de música?¿Qué aprendemos en clase de música?
¿Qué aprendemos en clase de música?
 

Similar to Grails Plugin Best Practices

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
 
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...Gaetano Giunta
 
Docker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionDocker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionBrennan Saeta
 
What to expect from Java 9
What to expect from Java 9What to expect from Java 9
What to expect from Java 9Ivan Krylov
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetesBen Hall
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Enginecatherinewall
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO DevsWO Community
 
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
 
Spring5 New Features
Spring5 New FeaturesSpring5 New Features
Spring5 New FeaturesJay Lee
 
Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Roberto Franchini
 
UKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUlrich Krause
 
Camel on Cloud by Christina Lin
Camel on Cloud by Christina LinCamel on Cloud by Christina Lin
Camel on Cloud by Christina LinTadayoshi Sato
 
Spring Performance Gains
Spring Performance GainsSpring Performance Gains
Spring Performance GainsVMware Tanzu
 

Similar to Grails Plugin Best Practices (20)

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
 
Gradle
GradleGradle
Gradle
 
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
Symfony HTTP Kernel for refactoring legacy apps: the eZ Publish case study - ...
 
Docker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline ExecutionDocker & ECS: Secure Nearline Execution
Docker & ECS: Secure Nearline Execution
 
GradleFX
GradleFXGradleFX
GradleFX
 
What to expect from Java 9
What to expect from Java 9What to expect from Java 9
What to expect from Java 9
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetes
 
Js tacktalk team dev js testing performance
Js tacktalk team dev js testing performanceJs tacktalk team dev js testing performance
Js tacktalk team dev js testing performance
 
What's new in the July 2017 Update for Dynamics 365 - Developer features
What's new in the July 2017 Update for Dynamics 365 - Developer featuresWhat's new in the July 2017 Update for Dynamics 365 - Developer features
What's new in the July 2017 Update for Dynamics 365 - Developer features
 
Cannibalising The Google App Engine
Cannibalising The  Google  App  EngineCannibalising The  Google  App  Engine
Cannibalising The Google App Engine
 
Grails 101
Grails 101Grails 101
Grails 101
 
ITB2017 - Keynote
ITB2017 - KeynoteITB2017 - Keynote
ITB2017 - Keynote
 
Apache Cayenne for WO Devs
Apache Cayenne for WO DevsApache Cayenne for WO Devs
Apache Cayenne for WO Devs
 
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
 
Spring5 New Features
Spring5 New FeaturesSpring5 New Features
Spring5 New Features
 
Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!Integration tests: use the containers, Luke!
Integration tests: use the containers, Luke!
 
UKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basics
 
Camel on Cloud by Christina Lin
Camel on Cloud by Christina LinCamel on Cloud by Christina Lin
Camel on Cloud by Christina Lin
 
Iac d.damyanov 4.pptx
Iac d.damyanov 4.pptxIac d.damyanov 4.pptx
Iac d.damyanov 4.pptx
 
Spring Performance Gains
Spring Performance GainsSpring Performance Gains
Spring Performance Gains
 

More from Burt Beckwith

Advanced GORM - Performance, Customization and Monitoring
Advanced GORM - Performance, Customization and MonitoringAdvanced GORM - Performance, Customization and Monitoring
Advanced GORM - Performance, Customization and MonitoringBurt Beckwith
 
Fun With Spring Security
Fun With Spring SecurityFun With Spring Security
Fun With Spring SecurityBurt Beckwith
 
Little Did He Know ...
Little Did He Know ...Little Did He Know ...
Little Did He Know ...Burt Beckwith
 
Hacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginHacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginBurt Beckwith
 
What's New in spring-security-core 2.0
What's New in spring-security-core 2.0What's New in spring-security-core 2.0
What's New in spring-security-core 2.0Burt Beckwith
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst PracticesBurt Beckwith
 
Testing the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsTesting the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsBurt Beckwith
 
Securing Grails Applications
Securing Grails ApplicationsSecuring Grails Applications
Securing Grails ApplicationsBurt Beckwith
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsBurt Beckwith
 

More from Burt Beckwith (10)

Advanced GORM - Performance, Customization and Monitoring
Advanced GORM - Performance, Customization and MonitoringAdvanced GORM - Performance, Customization and Monitoring
Advanced GORM - Performance, Customization and Monitoring
 
Fun With Spring Security
Fun With Spring SecurityFun With Spring Security
Fun With Spring Security
 
Little Did He Know ...
Little Did He Know ...Little Did He Know ...
Little Did He Know ...
 
Hacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginHacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 Plugin
 
What's New in spring-security-core 2.0
What's New in spring-security-core 2.0What's New in spring-security-core 2.0
What's New in spring-security-core 2.0
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst Practices
 
Grails Transactions
Grails TransactionsGrails Transactions
Grails Transactions
 
Testing the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsTesting the Grails Spring Security Plugins
Testing the Grails Spring Security Plugins
 
Securing Grails Applications
Securing Grails ApplicationsSecuring Grails Applications
Securing Grails Applications
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 

Recently uploaded

2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observabilityitnewsafrica
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...itnewsafrica
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Kaya Weers
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructureitnewsafrica
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 

Recently uploaded (20)

2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security ObservabilityGlenn Lazarus- Why Your Observability Strategy Needs Security Observability
Glenn Lazarus- Why Your Observability Strategy Needs Security Observability
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...Abdul Kader Baba- Managing Cybersecurity Risks  and Compliance Requirements i...
Abdul Kader Baba- Managing Cybersecurity Risks and Compliance Requirements i...
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)Design pattern talk by Kaya Weers - 2024 (v2)
Design pattern talk by Kaya Weers - 2024 (v2)
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical InfrastructureVarsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
Varsha Sewlal- Cyber Attacks on Critical Critical Infrastructure
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 

Grails Plugin Best Practices

  • 2. 2CONFIDENTIAL 2CONFIDENTIAL My Plugins  Acegi  App Info  App Info Hibernate  AspectJ (in-progress)  Atomikos  Binary Artifacts  BlazeDS (reworked)  Cache  Cache-Ehcache  Cache-Redis  Cache-Gemfire  Cloud Foundry  Cloud Foundry UI  Cloud Support  CodeNarc  Console (rework, current owner)  Database Reverse Engineering  Database Sessions  Database Migration  Database Migration JAXB  Datasources  Dumbster  Dynamic Controller  Dynamic Domain Class (core code)  EJB (in-progress)  EJB Glassfish (in-progress)  FamFamFam  Flex (reworked, current owner)  Flex Scaffold (major rework, not yet released)  HDIV (in-progress)
  • 3. 3CONFIDENTIAL 3CONFIDENTIAL My Plugins  Heroku  Hibernate Filter (rework, current owner)  Jbossas  jdbc-pool (rework, current owner)  JMX  LazyLob  Logback  Memcached  P6Spy UI  Ratpack  Remoting (reworked, current owner)  SpringMVC  Spring Security Core  Spring Security ACL  Spring Security App Info  Spring Security CAS  Spring Security Kerberos  Spring Security LDAP  Spring Security OAuth Consumer (in-progress)  Spring Security OAuth Provider (in-progress)  Spring Security Open ID  Spring Security Shiro  Spring Security UI  Standalone  standalone-tomcat-memcached  standalone-tomcat-redis  tcpmon  Twitter  UI Performance  Webxml (rework, current owner)
  • 5. 5CONFIDENTIAL 5CONFIDENTIAL 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) “
  • 6. 6CONFIDENTIAL 6CONFIDENTIAL 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
  • 9. 9CONFIDENTIAL 9CONFIDENTIAL Extension Points  The Build System  Spring Application Context  Dynamic method registration  Auto Reloading  Container Config (web.xml)  Adding new Artefact Types
  • 10. 10CONFIDENTIAL 10CONFIDENTIAL 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
  • 11. 11CONFIDENTIAL 11CONFIDENTIAL Plugin Goals  Convention-based approaches  DRY (Don't Repeat Yourself)  Required extension points satisfied  Easy to distribute & install • Without additional configuration
  • 12. 12CONFIDENTIAL 12CONFIDENTIAL 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.
  • 13. 13CONFIDENTIAL 13CONFIDENTIAL A Basic Plugin class LoggingGrailsPlugin { def version = "0.1” def grailsVersion = "2.0 > *" def doWithDynamicMethods = { for (c in application.allClasses) { c.metaClass.getLog = {-> LogFactory.getLog(c) } } } }
  • 14. 14CONFIDENTIAL 14CONFIDENTIAL Application Object  'GrailsApplication' object • available with the application variable in the plugin descriptor, and the grailsApplication Spring bean • holds convention information • Convenient access to the config: grailsApplication.config (since the holders are deprecated)
  • 15. 15CONFIDENTIAL 15CONFIDENTIAL Application Object  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)
  • 16. 16CONFIDENTIAL 16CONFIDENTIAL 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
  • 17. 17CONFIDENTIAL 17CONFIDENTIAL 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")
  • 18. 18CONFIDENTIAL 18CONFIDENTIAL Plugin Descriptor  Metadata • version, grailsVersion range, pluginExcludes, dependsOn, etc.  Lifecycle Closures doWithWebDescriptor ← Modify XML generated for web.xml at runtime doWithSpring ← Participate in Spring configuration doWithApplicationContext ← Post ApplicationContext initialization activities doWithDynamicMethods ← Add methods to MetaClasses onChange ← Participate in reload events
  • 19. 19CONFIDENTIAL 19CONFIDENTIAL Configuring Spring class JcrGrailsPlugin { def version = 0.1 def dependsOn = [core:0.4] def doWithSpring = { jcrRepository(RepositoryFactoryBean) { configuration = "classpath:repository.xml" homeDir = "/repo" } } } Bean name is method name, first argument is bean class Set properties on the bean
  • 21. 21CONFIDENTIAL 21CONFIDENTIAL Planning for Customization  Plugins are compiled first, then the app; this means that everything can be overridden  Prefer Spring beans to using new  Prefer dynamic instantiation (to allow class name override) to using new  Use protected, not private and avoid static  Move logic from plugin descriptor to classes
  • 22. 22CONFIDENTIAL 22CONFIDENTIAL 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' } }
  • 23. 23CONFIDENTIAL 23CONFIDENTIAL Overriding Spring Beans  For more advanced configuration, use a BeanPostProcessor, BeanFactoryPostProcessor, or a BeanDefinitionRegistryPostProcessor
  • 24. 24CONFIDENTIAL 24CONFIDENTIAL Plugging In Dynamic Methods def doWithDynamicMethods = { ctx -> application .allClasses .findAll { it.name.endsWith("Codec") } .each {clz -> Object .metaClass ."encodeAs${clz.name-'Codec'}" = { clz.newInstance().encode(delegate) } } } } Taken from Grails core, this plugin finds all classes ending with “Codec” and dynamically creates “encodeAsFoo” methods! The “delegate” variable is equivalent to “this” in regular methods
  • 25. 25CONFIDENTIAL 25CONFIDENTIAL Example Reloading Plugin class I18nGrailsPlugin { def version = "0.4.2" def watchedResources = "file:../grails-app/i18n/*.properties" def onChange = { event -> def messageSource = event.ctx.getBean("messageSource") messageSource?.clearCache() } } Defines set of files to watch using Spring Resource pattern When one changes, event is fired and plugin responds by clearing message cache
  • 26. 26CONFIDENTIAL 26CONFIDENTIAL 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
  • 27. 27CONFIDENTIAL 27CONFIDENTIAL 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) } } }
  • 28. 28CONFIDENTIAL 28CONFIDENTIAL Dependency Management  Jar files • Prefer BuildConfig.groovy Maven repos→ • lib directory is ok if unavailable otherwise  Other plugins • def loadAfter = ['controllers'] • Declare dependencies in BuildConfig.groovy  Grails • def grailsVersion = '2.0 > *'
  • 29. 29CONFIDENTIAL 29CONFIDENTIAL BuildConfig.groovy grails.project.dependency.resolution = { inherits 'global' log 'warn' repositories { grailsCentral() flatDir name:'myRepo', dirs:'/path/to/repo' mavenLocal() mavenCentral() mavenRepo 'http://download.java.net/maven/2/' mavenRepo 'http://my.cool.repo.net/maven/' }
  • 30. 30CONFIDENTIAL 30CONFIDENTIAL BuildConfig.groovy dependencies { runtime 'mysql:mysql-connector-java:5.1.22' 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' } }
  • 31. 31CONFIDENTIAL 31CONFIDENTIAL BuildConfig.groovy plugins { runtime ":hibernate:$grailsVersion", { export = false } runtime ':jquery:1.8.3' compile ':spring-security-core:1.2.7.3' runtime ':console:1.2' build ':release:2.2.1', ':rest-client-builder:1.0.3', { export = false } } }
  • 32. 32CONFIDENTIAL 32CONFIDENTIAL Troubleshooting Dependency Management  Run grails dependency­report • See http://burtbeckwith.com/blog/?p=624 for visualization tips  Increase BuildConfig.groovy logging level • log 'warn' → 'info', 'verbose', or 'debug'
  • 33. 33CONFIDENTIAL 33CONFIDENTIAL Scripts  Gant: http://gant.codehaus.org/  Groovy + Ant - XML  Can be used in apps but more common in plugins  Put in the 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
  • 34. 34CONFIDENTIAL 34CONFIDENTIAL 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)
  • 35. 35CONFIDENTIAL 35CONFIDENTIAL Scripts  _Events.groovy • Respond to 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) eventCreateWarStart = { name, stagingDir → … } eventGenerateWebXmlEnd = { … }
  • 36. 36CONFIDENTIAL 36CONFIDENTIAL Scripts  Reuse existing scripts with includeTargets • includeTargets << grailsScript("_GrailsWar")  Include common code in _*Common.groovy • includeTargets << new File(                  cloudFoundryPluginDir,                     "scripts/CfCommon.groovy")
  • 37. 37CONFIDENTIAL 37CONFIDENTIAL 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 /testing-your-grails-scripts  Run with the rest with grails test­app or alone with grails test­app ­­other
  • 38. 38CONFIDENTIAL 38CONFIDENTIAL Scripts 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 Typical Structure
  • 39. 39CONFIDENTIAL 39CONFIDENTIAL Custom Artifacts  ControllerMixinArtefactHandler extends ArtefactHandlerAdapter  interface ControllerMixinGrailsClass extends InjectableGrailsClass  DefaultControllerMixinGrailsClass extends AbstractInjectableGrailsClass implements ControllerMixinGrailsClass
  • 40. 40CONFIDENTIAL 40CONFIDENTIAL 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 → ... } }
  • 42. 42CONFIDENTIAL 42CONFIDENTIAL 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
  • 43. 43CONFIDENTIAL 43CONFIDENTIAL Testing  Use build.xml or Gradle to create single target that tests and builds plugin  Use inline plugin or install from zip  Zip install is deprecated, so better to use the maven-install script • Will resolve as a BuildConfig dependency (using mavenLocal()) <target name='package' description='Package the plugin' depends='test, doPackage, post-package-cleanup'/> grails install-plugin /path/to/plugin/grails-myplugin-0.1.zip
  • 44. 44CONFIDENTIAL 44CONFIDENTIAL Testing  Use CI, e.g. CloudBees BuildHive: • https://fbflex.wordpress.com/2012/07/12/using-cl oudbees-buildhive-to-test-grails-plugins/ • https://buildhive.cloudbees.com/job/burtbeckwith /job/grails-database-session/
  • 46. 46CONFIDENTIAL 46CONFIDENTIAL Becoming A Plugin Developer  Create an account at grails.org  Discuss your idea on the User mailing list • http://grails.org/Mailing+lists  Submit a request at http://grails.org/plugins/submitPlugin • Monitor the submission for questions and comments  Build (and test!) your plugin and run: • grails publish-plugin --stacktrace  Profit!
  • 47. 47CONFIDENTIAL 47CONFIDENTIAL 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() }
  • 48. 48CONFIDENTIAL 48CONFIDENTIAL Source Control and Release Management  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" } }
  • 49. 49CONFIDENTIAL 49CONFIDENTIAL Source Control and Release Management  Use “release” plugin http://grails.org/plugin/release • Sends tweet from @grailsplugins and email to plugin forum http://grails-plugins.847840.n3.nabble.com/ • Will not check code into SVN for you plugins { build ':release:2.2.1', ':rest-client-builder:1.0.3', { export = false } }
  • 51. 51CONFIDENTIAL 51CONFIDENTIAL Best Practices and Tips  Delete anything auto-generated that you don't use • grails-app/views/error.gsp • Empty grails-app/i18n/messages.properties • _Uninstall.groovy and other generated scripts • web-app files • grails-app/conf/UrlMappings.groovy • Empty descriptor callbacks
  • 52. 52CONFIDENTIAL 52CONFIDENTIAL Best Practices and Tips  Exclude files used in development or testing • Use def pluginExcludes = [...] • src/docs • Test artifacts  Create .gitignore (manually or with integrate-with –git)  Open every file, decide that you own it or not
  • 53. 53CONFIDENTIAL 53CONFIDENTIAL Best Practices and Tips  Use dependency management in BuildConfig.groovy, not lib dir  Change the minimum Grails version to 2.0 or the lowest version you're comfortable supporting: • def grailsVersion = '2.0 > *'
  • 54. 54CONFIDENTIAL 54CONFIDENTIAL Best Practices and Tips  Write tests  Run them often  Run tests before commit and especially before release (use build.xml or Gradle)  Create test apps (ideally programmatically)  Programmatically build inline plugin location: def customerName = System.getProperty("customer.name") grails.plugin.location."$customerName" = "customer-plugins/$customerName"
  • 55. 55CONFIDENTIAL 55CONFIDENTIAL Best Practices and Tips  Prefer Java to Groovy (or @CompileStatic) for performance if applicable  Instead of using inline plugins, install into a test app and use Meld or another diff tool to keep in sync  Before you release, run package-plugin and open the ZIP, look at what's there
  • 56. 56CONFIDENTIAL 56CONFIDENTIAL Best Practices and Tips  Use a sensible naming convention, e.g. grails.plugin.<pluginname>  Most plugin metadata is not optional: • Fix grailsVersion • Update description and documentation • Set value for license, issueManagement, scm (and organization, developers if applicable)
  • 57. 57CONFIDENTIAL 57CONFIDENTIAL 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!
  • 58. 58CONFIDENTIAL 58CONFIDENTIAL Best Practices and Tips  http://grails.org/Creating+Plugins  http://grails.org/The+Plug-in+Developers+Guide  http://blog.springsource.com/2010/05/18/managing-plu gins-with-grails-1-3/  http://grails.org/doc/latest/guide/plugins.html
  • 60.