SlideShare una empresa de Scribd logo
1 de 26
Descargar para leer sin conexión
Building Grails Plugins
     tips and tricks from the wild
About Me
•   Mike Hugo, Independent Software Developer

    •   http://piragua.com

    •   http://WhenWorksForYou.com

•   Groovy/Grails since 2007

•   Author of several Grails plugins
        •   code-coverage              •   greenmail

        •   hibernate-stats            •   build-info

        •   test-template              •   ????
• Plugins overview
                                  • Build your own plugin
                                   • testing
                                   • modularization
                                   • configuration
                                   • events
                                   • did I mention testing?


what’s on the menu for tonight?
App                                               Plugin




a plugin is just another grails application, with a few extra files
* GrailsPlugin.groovy
* Install, Uninstall and Upgrade scripts
Cool hooks into the runtime environment of a running grails app, plus ability to add new
‘artefacts’ and participate in reloading events
Existing Plugins




there are a ton of existing plugins from security to Rich UI to searching to...you name it.
common problem - this is one i’ve solved about 6 times. time for a plugin
• grails create-plugin build-status
• cd build-status
• mkdir test/projects
• cd test/projects
• grails create-app statusapp
                      gives you a client you can
                       use to test your plugin.
                                why?
development
• make a change to the plugin
• grails package-plugin
• cd test/projects/statusapp/
• grails install-plugin ../../../grails-build-status-0.1.zip
• grails run-app
• wash, rinse, repeat
In Place Plugins
• In the application just created, modify
   BuildConfig.groovy and add:
• grails.plugin.location."build-status" = "../../.."

• TADA! You’re now working with an in-
   place plugin
Add Controller (test)
import grails.test.*

class BuildInfoControllerTests extends ControllerUnitTestCase {
    void testIndex() {

!   !   controller.index()
!   !
!   !   assertEquals('index', renderArgs.view)
!   !   assertEquals(['app.version'],
           renderArgs.model.buildInfoProperties)
    }
}
Add Controller

class BuildInfoController {

!   static final List infoProperties = ['app.version']

     def index = {
!   ! render view:'index', model:
           [buildInfoProperties:infoProperties]
!   }
}
Add the View
<html>
<head>
    <title>Build Info</title>
</head>
<body>
<div>
    <g:each in="${buildInfoProperties}" var="prop">
        <g:if test="${g.meta(name:prop)}">
            <tr>
                 <td>${prop}</td><td><g:meta name="${prop}"/></td>
            </tr>
        </g:if>
    </g:each>

</div>
</body>
</html>
Functional Testing
• in the app, install the functional test plugin
• grails create-functional-test
  class BuildInfoPageFunctionalTests extends
        functionaltestplugin.FunctionalTestCase {
      void testSomeWebsiteFeature() {
          get('/buildInfo')
          assertStatus 200
          assertContentContains 'app.version'
          assertContentContains 'app.grails.version'
      }
  }
Introduce i18n
• i18n allows a form of customization
• create a messages.properties in the plugin
  i18n directory for default values
• override it in the app to test to make sure
  it works
Introducing Config
        • Allow the client application the ability to
            add or remove properties to display

void testIndex_overrideDefaults(){
    mockConfig """
        buildInfo.properties.exclude = ['app.version']
        buildInfo.properties.add = ['custom.property']
    """

    controller.index()
    assertEquals 'index', renderArgs.view

    def expectedProperties = controller.buildInfoProperties - 'app.version'
    expectedProperties = expectedProperties + 'custom.property'

    assertEquals expectedProperties, renderArgs.model.buildInfoProperties
}
Modularizing Views
      • Put contents of views into templates
      • Allows client to override the default view
//view                           // template
<html>                           <g:each in="${buildInfoProperties}" var="
<head>                               <g:if test="${g.meta(name:prop)}">
    <title>Build Info</title>            <tr>
</head>                                    <td>
<body>                                        <g:message code="${prop}"/>
<div>                                         </td>
<table>                          ! ! ! <td>
! <g:render template="info"                   <g:meta name="${prop}"/>
         plugin="buildstatus">             </td>
</table>                                 </tr>
</div>                               </g:if>
</body>                          </g:each>
</html>
Events
         • We want to capture the start of WAR file
             being built and log the Date/Time
         • What events are available?
          • Search $GRAILS_HOME/scripts for
                “event”
         • What variables are available?
          • binding.variables.each {println it}
http://grails.org/doc/latest/guide/4.%20The%20Command%20Line.html#4.3%20Hooking
%20into%20Events
test it
            • grails.test.AbstractCliTestCase
            • Thank you Peter Ledbrook:
                http://www.cacoethes.co.uk/blog/
                groovyandgrails/testing-your-grails-scripts




http://grails.org/doc/latest/guide/4.%20The%20Command%20Line.html#4.3%20Hooking
%20into%20Events
import grails.test.AbstractCliTestCase
import java.util.zip.ZipFile

class CreateWarEventTests extends AbstractCliTestCase {

    void testCreateWar(){
        execute (['war', '-non-interactive'])

        assertEquals 0, waitForProcess()

        verifyHeader()

        Properties props = new Properties()
        props.load(new ZipFile('target/app-0.1.war').
          getInputStream('WEB-INF/classes/application.properties'))

        assertNotNull props['build.date']
    }

}
eventCreateWarStart = {warname, stagingDir ->
    Ant.propertyfile(file:
      "${stagingDir}/WEB-INF/classes/application.properties") {
        entry(key: 'build.date', value: new Date())
    }
}
return the favor
       • publish your own events to allow clients
           to hook into plugin workflow

eventCreateWarStart = {warname, stagingDir ->
    event("BuildInfoAddPropertiesStart", [warname, stagingDir])

    Ant.propertyfile(file:
      "${stagingDir}/WEB-INF/classes/application.properties") {
        entry(key: 'build.date', value: new Date())
    }

    event("BuildInfoAddPropertiesEnd", [warname, stagingDir])
}
Gradle Build
• http://adhockery.blogspot.com/2010/01/
  gradle-build-for-grails-plugins-with.html
• http://www.cacoethes.co.uk/blog/
  groovyandgrails/building-a-grails-project-
  with-gradle
• One build file in the plugin that runs tests
  on all your ‘apps’ in the test/projects
  directory
in-place plugin caveats
•   Reloading plugin artifacts doesn’t always work

•   Grails 1.1.1

    •   see next slide

•   Grails 1.2.1

    •   Plugin controllers lose GrailsPlugin annotation
        and views cannot be resolved after reloading
        http://jira.codehaus.org/browse/GRAILS-5869
def watchedResources = ["file:${getPluginLocation()}/web-app/**",
        "file:${getPluginLocation()}/grails-app/controllers/**/*Controller.groovy",
        "file:${getPluginLocation()}/grails-app/services/**/*Service.groovy",
        "file:${getPluginLocation()}/grails-app/taglib/**/*TagLib.groovy"
]

def onChange = { event ->
    if (!isBasePlugin()) {
        if (event.source instanceof FileSystemResource && event.source?.path?.contains('web-app')) {
            def ant = new AntBuilder()
            ant.copy(todir: "./web-app/plugins/PLUGIN_NAME_HERE-${event.plugin.version}") {
                fileset(dir: "${getPluginLocation()}/web-app")
            }
        } else if (application.isArtefactOfType(ControllerArtefactHandler.TYPE, event.source)) {
            manager?.getGrailsPlugin("controllers")?.notifyOfEvent(event)
            // this injects the tag library namespaces back into the controller after it is reloaded
            manager?.getGrailsPlugin("groovyPages")?.notifyOfEvent(event)
        } else if (application.isArtefactOfType(TagLibArtefactHandler.TYPE, event.source)) {
            manager?.getGrailsPlugin("groovyPages")?.notifyOfEvent(event)
        } else if (application.isArtefactOfType(ServiceArtefactHandler.TYPE, event.source)) {
            manager?.getGrailsPlugin("services")?.notifyOfEvent(event)
        }
    }
    // watching is modified and reloaded. The event contains: event.source,
    // event.application, event.manager, event.ctx, and event.plugin.
}

ConfigObject getBuildConfig() {
    GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader())
    ConfigObject buildConfig = new ConfigSlurper().parse(classLoader.loadClass('BuildConfig'))
    return buildConfig
}

String getPluginLocation() {
    return getBuildConfig()?.grails?.plugin?.location?.'PLUGIN_NAME_HERE'
}
the real deal




           http://plugins.grails.org/grails-build-info/trunk/
source code available in the grails plugin svn repository, or browse on the web at:
http://plugins.grails.org/grails-build-info/trunk/

Más contenido relacionado

La actualidad más candente

An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbtFabio Fumarola
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation ToolIzzet Mustafaiev
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developersTricode (part of Dept)
 
Micronaut For Single Page Apps
Micronaut For Single Page AppsMicronaut For Single Page Apps
Micronaut For Single Page AppsZachary Klein
 
Scala and Play with Gradle
Scala and Play with GradleScala and Play with Gradle
Scala and Play with GradleWei Chen
 
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
 
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
 
Android gradle-build-system-overview
Android gradle-build-system-overviewAndroid gradle-build-system-overview
Android gradle-build-system-overviewKevin He
 
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
 
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
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersKostas Saidis
 
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
 

La actualidad más candente (20)

Gradle
GradleGradle
Gradle
 
An introduction to maven gradle and sbt
An introduction to maven gradle and sbtAn introduction to maven gradle and sbt
An introduction to maven gradle and sbt
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation Tool
 
Gradle
GradleGradle
Gradle
 
Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developers
 
Apache Lucene for Java EE Developers
Apache Lucene for Java EE DevelopersApache Lucene for Java EE Developers
Apache Lucene for Java EE Developers
 
Building with Gradle
Building with GradleBuilding with Gradle
Building with Gradle
 
Micronaut For Single Page Apps
Micronaut For Single Page AppsMicronaut For Single Page Apps
Micronaut For Single Page Apps
 
Angular beans
Angular beansAngular beans
Angular beans
 
Scala and Play with Gradle
Scala and Play with GradleScala and Play with Gradle
Scala and Play with Gradle
 
Introduction to gradle
Introduction to gradleIntroduction to gradle
Introduction to gradle
 
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 ...
 
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
 
Android gradle-build-system-overview
Android gradle-build-system-overviewAndroid gradle-build-system-overview
Android gradle-build-system-overview
 
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
 
Micronaut Launchpad
Micronaut LaunchpadMicronaut Launchpad
Micronaut Launchpad
 
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]
 
An Introduction to Gradle for Java Developers
An Introduction to Gradle for Java DevelopersAn Introduction to Gradle for Java Developers
An Introduction to Gradle for Java Developers
 
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)
 

Destacado

Reactive Microservice Architecture with Groovy and Grails
Reactive Microservice Architecture with Groovy and GrailsReactive Microservice Architecture with Groovy and Grails
Reactive Microservice Architecture with Groovy and GrailsSteve Pember
 
Application Architectures in Grails
Application Architectures in GrailsApplication Architectures in Grails
Application Architectures in GrailsPeter Ledbrook
 
Burbuja inmobiliaria-financiera
Burbuja inmobiliaria-financieraBurbuja inmobiliaria-financiera
Burbuja inmobiliaria-financieraguestce99ac
 
Burbuja Inmobiliaria Y Financiera
Burbuja Inmobiliaria Y FinancieraBurbuja Inmobiliaria Y Financiera
Burbuja Inmobiliaria Y Financieraguestce99ac
 
Ficha autoevaluacion trabajo final
Ficha autoevaluacion trabajo finalFicha autoevaluacion trabajo final
Ficha autoevaluacion trabajo finalAna Gonzales Pérez
 
Schaumburg Regional Airport Billboard Ads
Schaumburg Regional Airport Billboard AdsSchaumburg Regional Airport Billboard Ads
Schaumburg Regional Airport Billboard Adsmaryjane627
 
Pictures Of Graves Of Prophets & Ahlebaitand
Pictures Of Graves Of Prophets & AhlebaitandPictures Of Graves Of Prophets & Ahlebaitand
Pictures Of Graves Of Prophets & Ahlebaitandzeshan mehmood
 
Vacances D’Hivern
Vacances D’HivernVacances D’Hivern
Vacances D’HivernSEBAS100
 
08年冬训装备总结
08年冬训装备总结08年冬训装备总结
08年冬训装备总结Moohuo
 
Post-Election Health Policy - Impact on Physicians
Post-Election Health Policy - Impact on PhysiciansPost-Election Health Policy - Impact on Physicians
Post-Election Health Policy - Impact on Physiciansguestd63c45
 

Destacado (13)

Reactive Microservice Architecture with Groovy and Grails
Reactive Microservice Architecture with Groovy and GrailsReactive Microservice Architecture with Groovy and Grails
Reactive Microservice Architecture with Groovy and Grails
 
Application Architectures in Grails
Application Architectures in GrailsApplication Architectures in Grails
Application Architectures in Grails
 
Burbuja inmobiliaria-financiera
Burbuja inmobiliaria-financieraBurbuja inmobiliaria-financiera
Burbuja inmobiliaria-financiera
 
Organismo
OrganismoOrganismo
Organismo
 
Burbuja Inmobiliaria Y Financiera
Burbuja Inmobiliaria Y FinancieraBurbuja Inmobiliaria Y Financiera
Burbuja Inmobiliaria Y Financiera
 
Ficha autoevaluacion trabajo final
Ficha autoevaluacion trabajo finalFicha autoevaluacion trabajo final
Ficha autoevaluacion trabajo final
 
Schaumburg Regional Airport Billboard Ads
Schaumburg Regional Airport Billboard AdsSchaumburg Regional Airport Billboard Ads
Schaumburg Regional Airport Billboard Ads
 
Pictures Of Graves Of Prophets & Ahlebaitand
Pictures Of Graves Of Prophets & AhlebaitandPictures Of Graves Of Prophets & Ahlebaitand
Pictures Of Graves Of Prophets & Ahlebaitand
 
Saint-P
Saint-PSaint-P
Saint-P
 
Vacances D’Hivern
Vacances D’HivernVacances D’Hivern
Vacances D’Hivern
 
08年冬训装备总结
08年冬训装备总结08年冬训装备总结
08年冬训装备总结
 
Post-Election Health Policy - Impact on Physicians
Post-Election Health Policy - Impact on PhysiciansPost-Election Health Policy - Impact on Physicians
Post-Election Health Policy - Impact on Physicians
 
Navigating Complicated Issues for Seniors
Navigating Complicated Issues for Seniors Navigating Complicated Issues for Seniors
Navigating Complicated Issues for Seniors
 

Similar a Building Grails Plugins - Tips And Tricks

Gretty: Managing Web Containers with Gradle
Gretty: Managing Web Containers with GradleGretty: Managing Web Containers with Gradle
Gretty: Managing Web Containers with GradleAndrey Hihlovsky
 
Mastering Grails 3 Plugins - GR8Conf EU 2016
Mastering Grails 3 Plugins - GR8Conf EU 2016Mastering Grails 3 Plugins - GR8Conf EU 2016
Mastering Grails 3 Plugins - GR8Conf EU 2016Alvaro Sanchez-Mariscal
 
Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Alvaro Sanchez-Mariscal
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!David Gibbons
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to DjangoJames Casey
 
Mastering Grails 3 Plugins - GR8Conf US 2016
Mastering Grails 3 Plugins - GR8Conf US 2016Mastering Grails 3 Plugins - GR8Conf US 2016
Mastering Grails 3 Plugins - GR8Conf US 2016Alvaro Sanchez-Mariscal
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenerytoddbr
 
After max+phonegap
After max+phonegapAfter max+phonegap
After max+phonegapyangdj
 
混搭移动开发:PhoneGap+JQurey+Dreamweaver
混搭移动开发:PhoneGap+JQurey+Dreamweaver混搭移动开发:PhoneGap+JQurey+Dreamweaver
混搭移动开发:PhoneGap+JQurey+Dreamweaveryangdj
 
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rulesSrijan Technologies
 
Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016Alvaro Sanchez-Mariscal
 
Google App Engine with Gaelyk
Google App Engine with GaelykGoogle App Engine with Gaelyk
Google App Engine with GaelykChoong Ping Teo
 
Google Play Services Rock
Google Play Services RockGoogle Play Services Rock
Google Play Services RockPeter Friese
 
Google Cloud Platform 2014Q1 - Starter Guide
Google Cloud Platform   2014Q1 - Starter GuideGoogle Cloud Platform   2014Q1 - Starter Guide
Google Cloud Platform 2014Q1 - Starter GuideSimon Su
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StoryKon Soulianidis
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gearsdion
 
OpenCms Days 2014 - User Generated Content in OpenCms 9.5
OpenCms Days 2014 - User Generated Content in OpenCms 9.5OpenCms Days 2014 - User Generated Content in OpenCms 9.5
OpenCms Days 2014 - User Generated Content in OpenCms 9.5Alkacon Software GmbH & Co. KG
 

Similar a Building Grails Plugins - Tips And Tricks (20)

Gretty: Managing Web Containers with Gradle
Gretty: Managing Web Containers with GradleGretty: Managing Web Containers with Gradle
Gretty: Managing Web Containers with Gradle
 
Mastering Grails 3 Plugins - GR8Conf EU 2016
Mastering Grails 3 Plugins - GR8Conf EU 2016Mastering Grails 3 Plugins - GR8Conf EU 2016
Mastering Grails 3 Plugins - GR8Conf EU 2016
 
Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016
 
How to Webpack your Django!
How to Webpack your Django!How to Webpack your Django!
How to Webpack your Django!
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
Mastering Grails 3 Plugins - GR8Conf US 2016
Mastering Grails 3 Plugins - GR8Conf US 2016Mastering Grails 3 Plugins - GR8Conf US 2016
Mastering Grails 3 Plugins - GR8Conf US 2016
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
Grails Advanced
Grails Advanced Grails Advanced
Grails Advanced
 
After max+phonegap
After max+phonegapAfter max+phonegap
After max+phonegap
 
混搭移动开发:PhoneGap+JQurey+Dreamweaver
混搭移动开发:PhoneGap+JQurey+Dreamweaver混搭移动开发:PhoneGap+JQurey+Dreamweaver
混搭移动开发:PhoneGap+JQurey+Dreamweaver
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
[Srijan Wednesday Webinars] Ruling Drupal 8 with #d8rules
 
Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016
 
Google App Engine with Gaelyk
Google App Engine with GaelykGoogle App Engine with Gaelyk
Google App Engine with Gaelyk
 
Google Play Services Rock
Google Play Services RockGoogle Play Services Rock
Google Play Services Rock
 
Google Cloud Platform 2014Q1 - Starter Guide
Google Cloud Platform   2014Q1 - Starter GuideGoogle Cloud Platform   2014Q1 - Starter Guide
Google Cloud Platform 2014Q1 - Starter Guide
 
Single Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle StorySingle Page JavaScript WebApps... A Gradle Story
Single Page JavaScript WebApps... A Gradle Story
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
Droidcon Paris 2015
Droidcon Paris 2015Droidcon Paris 2015
Droidcon Paris 2015
 
OpenCms Days 2014 - User Generated Content in OpenCms 9.5
OpenCms Days 2014 - User Generated Content in OpenCms 9.5OpenCms Days 2014 - User Generated Content in OpenCms 9.5
OpenCms Days 2014 - User Generated Content in OpenCms 9.5
 

Último

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 

Último (20)

Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Building Grails Plugins - Tips And Tricks

  • 1. Building Grails Plugins tips and tricks from the wild
  • 2. About Me • Mike Hugo, Independent Software Developer • http://piragua.com • http://WhenWorksForYou.com • Groovy/Grails since 2007 • Author of several Grails plugins • code-coverage • greenmail • hibernate-stats • build-info • test-template • ????
  • 3. • Plugins overview • Build your own plugin • testing • modularization • configuration • events • did I mention testing? what’s on the menu for tonight?
  • 4. App Plugin a plugin is just another grails application, with a few extra files * GrailsPlugin.groovy * Install, Uninstall and Upgrade scripts
  • 5. Cool hooks into the runtime environment of a running grails app, plus ability to add new ‘artefacts’ and participate in reloading events
  • 6. Existing Plugins there are a ton of existing plugins from security to Rich UI to searching to...you name it.
  • 7. common problem - this is one i’ve solved about 6 times. time for a plugin
  • 8. • grails create-plugin build-status • cd build-status • mkdir test/projects • cd test/projects • grails create-app statusapp gives you a client you can use to test your plugin. why?
  • 9. development • make a change to the plugin • grails package-plugin • cd test/projects/statusapp/ • grails install-plugin ../../../grails-build-status-0.1.zip • grails run-app • wash, rinse, repeat
  • 10. In Place Plugins • In the application just created, modify BuildConfig.groovy and add: • grails.plugin.location."build-status" = "../../.." • TADA! You’re now working with an in- place plugin
  • 11. Add Controller (test) import grails.test.* class BuildInfoControllerTests extends ControllerUnitTestCase { void testIndex() { ! ! controller.index() ! ! ! ! assertEquals('index', renderArgs.view) ! ! assertEquals(['app.version'], renderArgs.model.buildInfoProperties) } }
  • 12. Add Controller class BuildInfoController { ! static final List infoProperties = ['app.version'] def index = { ! ! render view:'index', model: [buildInfoProperties:infoProperties] ! } }
  • 13. Add the View <html> <head> <title>Build Info</title> </head> <body> <div> <g:each in="${buildInfoProperties}" var="prop"> <g:if test="${g.meta(name:prop)}"> <tr> <td>${prop}</td><td><g:meta name="${prop}"/></td> </tr> </g:if> </g:each> </div> </body> </html>
  • 14. Functional Testing • in the app, install the functional test plugin • grails create-functional-test class BuildInfoPageFunctionalTests extends functionaltestplugin.FunctionalTestCase { void testSomeWebsiteFeature() { get('/buildInfo') assertStatus 200 assertContentContains 'app.version' assertContentContains 'app.grails.version' } }
  • 15. Introduce i18n • i18n allows a form of customization • create a messages.properties in the plugin i18n directory for default values • override it in the app to test to make sure it works
  • 16. Introducing Config • Allow the client application the ability to add or remove properties to display void testIndex_overrideDefaults(){ mockConfig """ buildInfo.properties.exclude = ['app.version'] buildInfo.properties.add = ['custom.property'] """ controller.index() assertEquals 'index', renderArgs.view def expectedProperties = controller.buildInfoProperties - 'app.version' expectedProperties = expectedProperties + 'custom.property' assertEquals expectedProperties, renderArgs.model.buildInfoProperties }
  • 17. Modularizing Views • Put contents of views into templates • Allows client to override the default view //view // template <html> <g:each in="${buildInfoProperties}" var=" <head> <g:if test="${g.meta(name:prop)}"> <title>Build Info</title> <tr> </head> <td> <body> <g:message code="${prop}"/> <div> </td> <table> ! ! ! <td> ! <g:render template="info" <g:meta name="${prop}"/> plugin="buildstatus"> </td> </table> </tr> </div> </g:if> </body> </g:each> </html>
  • 18. Events • We want to capture the start of WAR file being built and log the Date/Time • What events are available? • Search $GRAILS_HOME/scripts for “event” • What variables are available? • binding.variables.each {println it} http://grails.org/doc/latest/guide/4.%20The%20Command%20Line.html#4.3%20Hooking %20into%20Events
  • 19. test it • grails.test.AbstractCliTestCase • Thank you Peter Ledbrook: http://www.cacoethes.co.uk/blog/ groovyandgrails/testing-your-grails-scripts http://grails.org/doc/latest/guide/4.%20The%20Command%20Line.html#4.3%20Hooking %20into%20Events
  • 20. import grails.test.AbstractCliTestCase import java.util.zip.ZipFile class CreateWarEventTests extends AbstractCliTestCase { void testCreateWar(){ execute (['war', '-non-interactive']) assertEquals 0, waitForProcess() verifyHeader() Properties props = new Properties() props.load(new ZipFile('target/app-0.1.war'). getInputStream('WEB-INF/classes/application.properties')) assertNotNull props['build.date'] } }
  • 21. eventCreateWarStart = {warname, stagingDir -> Ant.propertyfile(file: "${stagingDir}/WEB-INF/classes/application.properties") { entry(key: 'build.date', value: new Date()) } }
  • 22. return the favor • publish your own events to allow clients to hook into plugin workflow eventCreateWarStart = {warname, stagingDir -> event("BuildInfoAddPropertiesStart", [warname, stagingDir]) Ant.propertyfile(file: "${stagingDir}/WEB-INF/classes/application.properties") { entry(key: 'build.date', value: new Date()) } event("BuildInfoAddPropertiesEnd", [warname, stagingDir]) }
  • 23. Gradle Build • http://adhockery.blogspot.com/2010/01/ gradle-build-for-grails-plugins-with.html • http://www.cacoethes.co.uk/blog/ groovyandgrails/building-a-grails-project- with-gradle • One build file in the plugin that runs tests on all your ‘apps’ in the test/projects directory
  • 24. in-place plugin caveats • Reloading plugin artifacts doesn’t always work • Grails 1.1.1 • see next slide • Grails 1.2.1 • Plugin controllers lose GrailsPlugin annotation and views cannot be resolved after reloading http://jira.codehaus.org/browse/GRAILS-5869
  • 25. def watchedResources = ["file:${getPluginLocation()}/web-app/**", "file:${getPluginLocation()}/grails-app/controllers/**/*Controller.groovy", "file:${getPluginLocation()}/grails-app/services/**/*Service.groovy", "file:${getPluginLocation()}/grails-app/taglib/**/*TagLib.groovy" ] def onChange = { event -> if (!isBasePlugin()) { if (event.source instanceof FileSystemResource && event.source?.path?.contains('web-app')) { def ant = new AntBuilder() ant.copy(todir: "./web-app/plugins/PLUGIN_NAME_HERE-${event.plugin.version}") { fileset(dir: "${getPluginLocation()}/web-app") } } else if (application.isArtefactOfType(ControllerArtefactHandler.TYPE, event.source)) { manager?.getGrailsPlugin("controllers")?.notifyOfEvent(event) // this injects the tag library namespaces back into the controller after it is reloaded manager?.getGrailsPlugin("groovyPages")?.notifyOfEvent(event) } else if (application.isArtefactOfType(TagLibArtefactHandler.TYPE, event.source)) { manager?.getGrailsPlugin("groovyPages")?.notifyOfEvent(event) } else if (application.isArtefactOfType(ServiceArtefactHandler.TYPE, event.source)) { manager?.getGrailsPlugin("services")?.notifyOfEvent(event) } } // watching is modified and reloaded. The event contains: event.source, // event.application, event.manager, event.ctx, and event.plugin. } ConfigObject getBuildConfig() { GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader()) ConfigObject buildConfig = new ConfigSlurper().parse(classLoader.loadClass('BuildConfig')) return buildConfig } String getPluginLocation() { return getBuildConfig()?.grails?.plugin?.location?.'PLUGIN_NAME_HERE' }
  • 26. the real deal http://plugins.grails.org/grails-build-info/trunk/ source code available in the grails plugin svn repository, or browse on the web at: http://plugins.grails.org/grails-build-info/trunk/