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 - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Alvaro Sanchez-Mariscal
 
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
 
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 - Greach 2016
Mastering Grails 3 Plugins - Greach 2016Mastering Grails 3 Plugins - Greach 2016
Mastering Grails 3 Plugins - Greach 2016
 
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
 
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

Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
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
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
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
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 

Último (20)

Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
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
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
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.
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 

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/