(Quick Reference)

15 プラグイン - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: 2.3.0

Translated by: T.Yamamoto, Japanese Grails Doc Translating Team. Special thanks to NTT Software.

15 プラグイン

Grails is first and foremost a web application framework, but it is also a platform. By exposing a number of extension points that let you extend anything from the command line interface to the runtime configuration engine, Grails can be customised to suit almost any needs. To hook into this platform, all you need to do is create a plugin.
Grailsは、第一義にはWebアプリケーションフレームワークです。しかし、それだけに留まらず、プラットフォームでもあります。 Grailsプラットフォームには、コマンドラインのコマンドを追加することから始まって、実行時設定のエンジンまで、何でも拡張できるような多くの拡張ポイントが準備されており、ほとんど全てのニーズに適合するようにカスタマイズすることができます。 このプラットフォームを拡張するためにしなければならないのは、プラグインを作成することだけです。

Extending the platform may sound complicated, but plugins can range from trivially simple to incredibly powerful. If you know how to build a Grails application, you'll know how to create a plugin for sharing a data model or some static resources.

15.1 プラグインの作成とインストール

Creating Plugins


Creating a Grails plugin is a simple matter of running the command:


grails create-plugin [PLUGIN NAME]

This will create a plugin project for the name you specify. For example running grails create-plugin example would create a new plugin project called example.
こうすることで指定した名前のプラグインプロジェクトが作成されます。例えば、grails create-plugin exampleを実行すると、exampleという新規プラグインプロジェクトが作成されます。

Make sure the plugin name does not contain more than one capital in a row, or it won't work. Camel case is fine, though.

The structure of a Grails plugin is very nearly the same as a Grails application project's except that in the root of the plugin directory you will find a plugin Groovy file called the "plugin descriptor".

The only plugins included in a new plugin project are Tomcat and Release. Hibernate is not included by default.

Being a regular Grails project has a number of benefits in that you can immediately test your plugin by running:


grails run-app

Plugin projects don't provide an index.gsp by default since most plugins don't need it. So, if you try to view the plugin running in a browser right after creating it, you will receive a page not found error. You can easily create a grails-app/views/index.gsp for your plugin if you'd like.


The plugin descriptor name ends with the convention GrailsPlugin and is found in the root of the plugin project. For example:

class ExampleGrailsPlugin {
   def version = "0.1"

… }

All plugins must have this class in the root of their directory structure. The plugin class defines the version of the plugin and other metadata, and optionally various hooks into plugin extension points (covered shortly).


You can also provide additional information about your plugin using several special properties:


  • title - short one-sentence description of your plugin
  • version - The version of your plugin. Valid values include example "0.1", "0.2-SNAPSHOT", "1.1.4" etc.
  • grailsVersion - The version of version range of Grails that the plugin supports. eg. "1.2 > *" (indicating 1.2 or higher)
  • author - plugin author's name
  • authorEmail - plugin author's contact e-mail
  • description - full multi-line description of plugin's features
  • documentation - URL of the plugin's documentation

  • title - このプラグインを説明する短い一文。
  • version - このプラグインのバージョン。例えば「0.1」「0.2-SNAPSHOT」「1.1.4」などの有効な値。
  • grailsVersion - プラグインがサポートするGrailsのバージョンを、バージョン範囲で指定する。例えば「1.2 > *」(これは「1.2以上」であることを示す)
  • author - プラグインの開発者名
  • authorEmail - プラグイン開発者に連絡するためのe-mailアドレス
  • description - 複数行に渡るプラグイン機能のフル説明
  • documentation - プラグインのドキュメントへのURL

Here is an example from the Quartz Grails plugin:
以下は、Quartz Grailsプラグインからの例です:

class QuartzGrailsPlugin {
    def version = "0.1"
    def grailsVersion = "1.1 > *"
    def author = "Sergey Nebolsin"
    def authorEmail = "nebolsin@gmail.com"
    def title = "Quartz Plugin"
    def description = '''\
The Quartz plugin allows your Grails application to schedule jobs\
to be executed using a specified interval or cron expression. The\
underlying system uses the Quartz Enterprise Job Scheduler configured\
via Spring, but is made simpler by the coding by convention paradigm.\
    def documentation = "http://grails.org/plugin/quartz"

… }

Installing Local Plugins

To make your plugin available for use in a Grails application run the maven-install command:

grails maven-install

This will install the plugin into your local Maven cache. Then to use the plugin within an application declare a dependency on the plugin in your grails-app/conf/BuildConfig.groovy file:


Notes on excluded Artefacts


Although the create-plugin command creates certain files for you so that the plugin can be run as a Grails application, not all of these files are included when packaging a plugin. The following is a list of artefacts created, but not included by package-plugin:


  • grails-app/conf/BootStrap.groovy
  • grails-app/conf/BuildConfig.groovy (although it is used to generate dependencies.groovy)
  • grails-app/conf/Config.groovy
  • grails-app/conf/DataSource.groovy (and any other *DataSource.groovy)
  • grails-app/conf/UrlMappings.groovy
  • grails-app/conf/spring/resources.groovy
  • Everything within /web-app/WEB-INF
  • Everything within /web-app/plugins/**
  • Everything within /test/**
  • SCM management files within **/.svn/** and **/CVS/**

  • grails-app/conf/BootStrap.groovy
  • grails-app/conf/BuildConfig.groovy (dependencies.groovyの生成には使用される)
  • grails-app/conf/Config.groovy
  • grails-app/conf/DataSource.groovy (これと他の任意の*DataSource.groovy)
  • grails-app/conf/UrlMappings.groovy
  • grails-app/conf/spring/resources.groovy
  • /web-app/WEB-INF配下のすべて
  • /web-app/plugins/**配下のすべて
  • /test/** 配下のすべて
  • **/.svn/****/CVS/**配下のSCM管理ファイル

If you need artefacts within WEB-INF it is recommended you use the _Install.groovy script (covered later), which is executed when a plugin is installed, to provide such artefacts. In addition, although UrlMappings.groovy is excluded you are allowed to include a UrlMappings definition with a different name, such as MyPluginUrlMappings.groovy.


Customizing the plugin contents

You can specify what to exclude in addition to the default excludes by adding elements to the pluginExcludes descriptor property (described below). In addition, there are two ways to configure the contents of the plugin ZIP or JAR file.

One is to create an event handler for the CreatePluginArchiveStart event, which is fired after all of the plugin files have been copied to the staging directory. By adding an event handler you can add, modify, or delete files as needed. Add the handler to _Events.groovy in the scripts directory, for example

eventCreatePluginArchiveStart = { stagingDir ->
   // update staging directory contents here

You can customize the location of the staging directory with the grails.project.plugin.staging.dir attribute in BuildConfig.groovy or as as system property.

Note that there is also a CreatePluginArchiveEnd event which is fired after the ZIP or JAR is packaged.

You can also do this work in a Closure in BuildConfig.groovy with the property grails.plugin.resources which is analogous to the grails.war.resources property, e.g.

grails.plugin.resources = { stagingDir ->
   // update staging directory contents here

Specifying Plugin Locations


An application can load plugins from anywhere on the file system, even if they have not been installed. Specify the location of the (unpacked) plugin in the application's grails-app/conf/BuildConfig.groovy file:


// Useful to test plugins you are developing.
grails.plugin.location.shiro =

// Useful for modular applications where all plugins and // applications are in the same directory. grails.plugin.location.'grails-ui' = "../grails-grails-ui"

// 開発中のプラグインをテストするのに便利。
grails.plugin.location.shiro =

// すべてのプラグインとアプリケーションを同じディレクトリに置き、 // モジュール化するのに便利。 grails.plugin.location.'grails-ui' = "../grails-grails-ui"

This is particularly useful in two cases:
  • You are developing a plugin and want to test it in a real application without packaging and installing it first.
  • You have split an application into a set of plugins and an application, all in the same "super-project" directory.


  • 開発中のプラグインを、パッケージ化とインストールをスキップして、実アプリケーションにすぐに組み込んでテストしたいとき。
  • アプリケーションが複数のプラグイン群に分割されており、それらすべてが同じ「スーパープロジェクト」ディレクトリ配下にある場合。

The Artifactory repository for Grails now includes all the dependencies for published plugins. So, if you are using inline plugins that have dependencies, it is necessary to do a secondary resolve because these dependencies might not be in the repository. Therefore, you should set legacyResolve to true in your BuildConfig.groovy if you are using inline plugins with dependencies.

15.2 プラグインリポジトリ

h4. Distributing Plugins in the Grails Central Plugin Repository


The preferred way to distribute plugin is to publish to the official Grails Central Plugin Repository. This will make your plugin visible to the list-plugins command:

grails list-plugins

which lists all plugins that are in the central repository. Your plugin will also be available to the plugin-info command:


grails plugin-info [plugin-name]

which prints extra information about it, such as its description, who wrote, etc.


If you have created a Grails plugin and want it to be hosted in the central repository, you'll find instructions for getting an account on this wiki page.


When you have access to the Grails Plugin repository, install the Release Plugin by declaring it as a 'build' scoped dependency in grails-app/conf/BuildConfig.groovy file:

Grailsプラグインリポジトリにアクセス権を持っていれば、リリースプラグインgrails-app/conf/BuildConfig.groovy ファイルの依存管理'build'スコープに定義してインストールします。

grails.project.dependency.resolution = {
    plugins {
        build ':release:3.0.0'

And execute the publish-plugin command to release your plugin:

grails publish-plugin

This will automatically publish the plugin to the central repository. If the command is successful, it will immediately be available on the plugin portal at http://grails.org/plugin/<pluginName>. You can find out more about the Release plugin and its other features in its user guide.

h4. Configuring Additional Repositories


The process for configuring repositories in Grails differs between versions. For version of Grails 1.2 and earlier please refer to the Grails 1.2 documentation on the subject. The following sections cover Grails 1.3 and above.

Grailsにおけるリポジトリの設定手順は、Grailsのバージョンによって異なっています。Grails 1.2以前の情報についてはGrails 1.2のドキュメンテーションを参照ください。以降の節は、Grails 1.3以降について記述しています。

Grails 1.3 and above use Ivy under the hood to resolve plugin dependencies. The mechanism for defining additional plugin repositories is largely the same as defining repositories for JAR dependencies. For example you can define a remote Maven repository that contains Grails plugins using the following syntax in grails-app/conf/BuildConfig.groovy:

Grails 1.3以上では、下位層に隠されているIvyがプラグインの依存性を解決します。プラグインリポジトリを追加定義する仕組みは、 JAR依存性を定義する方法とほぼ同じです。例えば、Grailsプラグインを含むリモートMavenリポジトリを定義するには、 grails-app/conf/BuildConfig.groovy中で以下のように記述します:

repositories {
    mavenRepo "http://repository.codehaus.org"

// ...or with a name mavenRepo name: "myRepo", root: "http://myserver:8081/artifactory/plugins-snapshots-local" }

You can also define a SVN-based Grails repository (such as the one hosted at http://plugins.grails.org) using the grailsRepo method:


repositories {
    grailsRepo "http://myserver/mygrailsrepo"

// ...or with a name grailsRepo "http://myserver/svn/grails-plugins", "mySvnRepo" }

There is a shortcut to setup the Grails central repository:

repositories {

The order in which plugins are resolved is based on the ordering of the repositories. So in this case the Grails central repository will be searched last:


repositories {
    grailsRepo "http://myserver/mygrailsrepo"

All of the above examples use HTTP; however you can specify any Ivy resolver to resolve plugins with. Below is an example that uses an SSH resolver:


def sshResolver = new SshResolver(user:"myuser", host:"myhost.com")
        "/path/to/repo/grails-[artifact]/tags/" +
sshResolver.latestStrategy =
        new org.apache.ivy.plugins.latest.LatestTimeStrategy()

sshResolver.changingPattern = ".*SNAPSHOT" sshResolver.setCheckmodified(true)

The above example defines an artifact pattern which tells Ivy how to resolve a plugin zip file. For a more detailed explanation on Ivy patterns see the relevant section in the Ivy user guide.


h4. Publishing to Maven Compatible Repositories


In general it is recommended for Grails 1.3 and above to use standard Maven-style repositories to self host plugins. The benefits of doing so include the ability for existing tooling and repository managers to interpret the structure of a Maven repository.

You use the Release plugin to publish a plugin to a Maven repository. Please refer to the section of the Maven deployment user guide on the subject.

15.3 プラグイン構造を理解する

As as mentioned previously, a plugin is basically a regular Grails application with a plugin descriptor. However when installed, the structure of a plugin differs slightly. For example, take a look at this plugin directory structure:


+ grails-app
     + controllers
     + domain
     + taglib
 + lib
 + src
     + java
     + groovy
 + web-app
     + js
     + css

When a plugin is installed the contents of the grails-app directory will go into a directory such as plugins/example-1.0/grails-app. They will not be copied into the main source tree. A plugin never interferes with a project's primary source tree.


Dealing with static resources is slightly different. When developing a plugin, just like an application, all static resources go in the web-app directory. You can then link to static resources just like in an application. This example links to a JavaScript source:


<g:resource dir="js" file="mycode.js" />

When you run the plugin in development mode the link to the resource will resolve to something like /js/mycode.js. However, when the plugin is installed into an application the path will automatically change to something like /plugin/example-0.1/js/mycode.js and Grails will deal with making sure the resources are in the right place.

プラグインを開発モード(development mode)で実行するときは、このようなリソースへのリンクは/js/mycode.jsなどに解決されます。しかし、プラグインがアプリケーションにインストールされたときは、パスは自動的に/plugin/example-0.1/js/mycode.jsのように自動的に変換され、Grailsはリソースを正しく扱うことができます。

There is a special pluginContextPath variable that can be used whilst both developing the plugin and when in the plugin is installed into the application to find out what the correct path to the plugin is.


At runtime the pluginContextPath variable will either evaluate to an empty string or /plugins/example depending on whether the plugin is running standalone or has been installed in an application


Java and Groovy code that the plugin provides within the lib and src/java and src/groovy directories will be compiled into the main project's web-app/WEB-INF/classes directory so that they are made available at runtime.


15.4 基本アーティファクトの提供

h4. Adding a new Script


A plugin can add a new script simply by providing the relevant Gant script in its scripts directory:


+ MyPlugin.groovy
   + scripts     <-- additional scripts here
   + grails-app
        + controllers
        + services
        + etc.
    + lib

+ MyPlugin.groovy
   + scripts     <-- ここにスクリプトを追加する
   + grails-app
        + controllers
        + services
        + etc.
    + lib

h4. Adding a new grails-app artifact (Controller, Tag Library, Service, etc.)

Grails-appアーテファクト(Controller, Tag Library, Service, 他)の追加

A plugin can add new artifacts by creating the relevant file within the grails-app tree. Note that the plugin is loaded from where it is installed and not copied into the main application tree.


+ controllers < additional controllers here + services < additional services here + etc. <-- additional XXX here
+ ExamplePlugin.groovy
   + scripts
   + grails-app
        + controllers  <-- コントローラを追加するのはここ。
        + services <-- サービスを追加するのはここ。
        + etc.  <-- 他も同様。
    + lib

h4. Providing Views, Templates and View resolution


When a plugin provides a controller it may also provide default views to be rendered. This is an excellent way to modularize your application through plugins. Grails' view resolution mechanism will first look for the view in the application it is installed into and if that fails will attempt to look for the view within the plugin. This means that you can override views provided by a plugin by creating corresponding GSPs in the application's grails-app/views directory.



For example, consider a controller called BookController that's provided by an 'amazon' plugin. If the action being executed is list, Grails will first look for a view called grails-app/views/book/list.gsp then if that fails it will look for the same view relative to the plugin.


However if the view uses templates that are also provided by the plugin then the following syntax may be necessary:


<g:render template="fooTemplate" plugin="amazon"/>

Note the usage of the plugin attribute, which contains the name of the plugin where the template resides. If this is not specified then Grails will look for the template relative to the application.


h4. Excluded Artefacts


By default Grails excludes the following files during the packaging process:


  • grails-app/conf/BootStrap.groovy
  • grails-app/conf/BuildConfig.groovy (although it is used to generate dependencies.groovy)
  • grails-app/conf/Config.groovy
  • grails-app/conf/DataSource.groovy (and any other *DataSource.groovy)
  • grails-app/conf/UrlMappings.groovy
  • grails-app/conf/spring/resources.groovy
  • Everything within /web-app/WEB-INF
  • Everything within /web-app/plugins/**
  • Everything within /test/**
  • SCM management files within **/.svn/** and **/CVS/**

  • grails-app/conf/BootStrap.groovy
  • grails-app/conf/BuildConfig.groovy (この情報はdependencies.groovyの生成に用いられるが、BuildConfig自体は含められない)
  • grails-app/conf/Config.groovy
  • grails-app/conf/DataSource.groovy (その他の*DataSource.groovyも同様)
  • grails-app/conf/UrlMappings.groovy
  • grails-app/conf/spring/resources.groovy
  • /web-app/WEB-INF中のすべて
  • /web-app/plugins/**中のすべて
  • /test/**中のすべて
  • **/.svn/****/CVS/**中のSCMが管理するファイル

If your plugin requires files under the web-app/WEB-INF directory it is recommended that you modify the plugin's scripts/_Install.groovy Gant script to install these artefacts into the target project's directory tree.


In addition, the default UrlMappings.groovy file is excluded to avoid naming conflicts, however you are free to add a UrlMappings definition under a different name which will be included. For example a file called grails-app/conf/BlogUrlMappings.groovy is fine.


The list of excludes is extensible with the pluginExcludes property:


// resources that are excluded from plugin packaging
def pluginExcludes = [

// プラグインのパッケージングからは除外するリソース
def pluginExcludes = [

This is useful for example to include demo or test resources in the plugin repository, but not include them in the final distribution.


15.5 規約の評価

Before looking at providing runtime configuration based on conventions you first need to understand how to evaluate those conventions from a plugin. Every plugin has an implicit application variable which is an instance of the GrailsApplication interface.


The GrailsApplication interface provides methods to evaluate the conventions within the project and internally stores references to all artifact classes within your application.


Artifacts implement the GrailsClass interface, which represents a Grails resource such as a controller or a tag library. For example to get all GrailsClass instances you can do:


for (grailsClass in application.allClasses) {
    println grailsClass.name

GrailsApplication has a few "magic" properties to narrow the type of artefact you are interested in. For example to access controllers you can use:


for (controllerClass in application.controllerClasses) {
    println controllerClass.name

The dynamic method conventions are as follows:

  • *Classes - Retrieves all the classes for a particular artefact name. For example application.controllerClasses.
  • get*Class - Retrieves a named class for a particular artefact. For example application.getControllerClass("PersonController")
  • is*Class - Returns true if the given class is of the given artefact type. For example application.isControllerClass(PersonController)

  • *Classes - 特定のアーテファクト名のすべてのクラスを取り出す。 例えばapplication.controllerClasses
  • get*Class - 特定のアーテファクトの、指定した名前のクラスを取り出す。 例えばapplication.getControllerClass("PersonController")
  • is*Class - もし指定したクラスが指定したアーテファクトタイプであればtrueを返す。 例えば、application.isControllerClass(PersonController)

The GrailsClass interface has a number of useful methods that let you further evaluate and work with the conventions. These include:


  • getPropertyValue - Gets the initial value of the given property on the class
  • hasProperty - Returns true if the class has the specified property
  • newInstance - Creates a new instance of this class.
  • getName - Returns the logical name of the class in the application without the trailing convention part if applicable
  • getShortName - Returns the short name of the class without package prefix
  • getFullName - Returns the full name of the class in the application with the trailing convention part and with the package name
  • getPropertyName - Returns the name of the class as a property name
  • getLogicalPropertyName - Returns the logical property name of the class in the application without the trailing convention part if applicable
  • getNaturalName - Returns the name of the property in natural terms (eg. 'lastName' becomes 'Last Name')
  • getPackageName - Returns the package name

  • getPropertyValue - そのクラスの指定したプロパティの初期値を取得する。
  • hasProperty - もしクラスが指定したプロパティを持っていたらtrueを返す。
  • newInstance - このクラスの新しいインスタンスを返す。
  • getName - 取得可能であれば、末尾の規約部分を除いた、アプリケーションにおける論理名を返す。
  • getShortName - そのクラスのパッケージ接頭辞を除いた短縮名を返す。
  • getFullName - 末尾の規約部分と先頭のパッケージ部分を含むクラスのフルネームを返す。
  • getPropertyName - クラス名をプロパティ名として返す。
  • getLogicalPropertyName - 末尾の規約部分を除き、アプリケーションにおけるクラスの論理プロパティ名を返す。
  • getNaturalName - 自然な語句としてのプロパティ名を返す。(例: 'lastName'は'Last Name'になる)
  • getPackageName - パッケージ名を返す。

For a full reference refer to the javadoc API.

全体のリファレンスについては、javadoc APIを参照してください。

15.6 ビルドイベントのフック

h4. Post-Install Configuration and Participating in Upgrades


Grails plugins can do post-install configuration and participate in application upgrade process (the upgrade command). This is achieved using two specially named scripts under the scripts directory of the plugin - _Install.groovy and _Upgrade.groovy.


_Install.groovy is executed after the plugin has been installed and _Upgrade.groovy is executed each time the user upgrades the application (but not the plugin) with upgrade command.

_Install.groovyはプラグインがインストールされた後に実行され、_Upgrade.groovyコマンドはアプリケーションが upgradeコマンドで更新されるたびに実行されます(プラグインをupgradeコマンドで更新した時ではありません)。

These scripts are Gant scripts, so you can use the full power of Gant. An addition to the standard Gant variables there is also a pluginBasedir variable which points at the plugin installation basedir.


As an example this _Install.groovy script will create a new directory type under the grails-app directory and install a configuration template:


ant.mkdir(dir: "${basedir}/grails-app/jobs")

ant.copy(file: "${pluginBasedir}/src/samples/SamplePluginConfig.groovy", todir: "${basedir}/grails-app/conf")

The pluginBasedir variable is not available in custom scripts, but you can use fooPluginDir, where foo is the name of your plugin.


h4. Scripting events


It is also possible to hook into command line scripting events. These are events triggered during execution of Grails target and plugin scripts.


For example, you can hook into status update output (i.e. "Tests passed", "Server running") and the creation of files or artefacts.


A plugin just has to provide an _Events.groovy script to listen to the required events. Refer the documentation on Hooking into Events for further information.


15.7 ランタイム設定へのフック

Grails provides a number of hooks to leverage the different parts of the system and perform runtime configuration by convention.


h4. Hooking into the Grails Spring configuration


First, you can hook in Grails runtime configuration by providing a property called doWithSpring which is assigned a block of code. For example the following snippet is from one of the core Grails plugins that provides i18n support:

まず、doWithSpringという名前の、クロージャブロックが代入されたプロパティを提供することで、Grails実行時設定にフックすることができます。例えば以下のコード断片は、 i18nサポートを提供するコアGrailsプラグインに含まれているものです:

import org.springframework.web.servlet.i18n.CookieLocaleResolver
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor
import org.springframework.context.support.ReloadableResourceBundleMessageSource

class I18nGrailsPlugin {

def version = "0.1"

def doWithSpring = { messageSource(ReloadableResourceBundleMessageSource) { basename = "WEB-INF/grails-app/i18n/messages" } localeChangeInterceptor(LocaleChangeInterceptor) { paramName = "lang" } localeResolver(CookieLocaleResolver) } }

This plugin configures the Grails messageSource bean and a couple of other beans to manage Locale resolution and switching. It using the Spring Bean Builder syntax to do so.


h4. Participating in web.xml Generation


Grails generates the WEB-INF/web.xml file at load time, and although plugins cannot change this file directly, they can participate in the generation of the file. A plugin can provide a doWithWebDescriptor property that is assigned a block of code that gets passed the web.xml as an XmlSlurper GPathResult.


h5. Add servlet and servlet-mapping


Consider this example from the ControllersPlugin:


def doWithWebDescriptor = { webXml ->

def mappingElement = webXml.'servlet-mapping'

def lastMapping = mappingElement[mappingElement.size() - 1] lastMapping + { 'servlet-mapping' { 'servlet-name'("grails") 'url-pattern'("*.dispatch") } } }

Here the plugin gets a reference to the last <servlet-mapping> element and appends Grails' servlet after it using XmlSlurper's ability to programmatically modify XML using closures and blocks.


h5. Add filter and filter-mapping


Adding a filter with its mapping works a little differently. The location of the <filter> element doesn't matter since order is not important, so it's simplest to insert your custom filter definition immediately after the last <context-param> element. Order is important for mappings, but the usual approach is to add it immediately after the last <filter> element like so:

マッピングを伴うフィルターの追加は少し異なります。順序は重要ではないので、<filter>要素の場所は問題になりません。なのでカスタムフィルタ定義を最後の<context-param>要素のすぐ後に挿入するのが最も簡単です。マッピングに関しては 順序は重要 です。しかし通常の場合、<filter>要素の直後に追加してしまいます:

def doWithWebDescriptor = { webXml ->

def contextParam = webXml.'context-param'

contextParam[contextParam.size() - 1] + { 'filter' { 'filter-name'('springSecurityFilterChain') 'filter-class'(DelegatingFilterProxy.name) } }

def filter = webXml.'filter' filter[filter.size() - 1] + { 'filter-mapping'{ 'filter-name'('springSecurityFilterChain') 'url-pattern'('/*') } } }

In some cases you need to ensure that your filter comes after one of the standard Grails filters, such as the Spring character encoding filter or the SiteMesh filter. Fortunately you can insert filter mappings immediately after the standard ones (more accurately, any that are in the template web.xml file) like so:


def doWithWebDescriptor = { webXml ->

// Insert the Spring Security filter after the Spring // character encoding filter. def filter = webXml.'filter-mapping'.find { it.'filter-name'.text() == "charEncodingFilter" }

filter + { 'filter-mapping'{ 'filter-name'('springSecurityFilterChain') 'url-pattern'('/*') } } }

h4. Doing Post Initialisation Configuration


Sometimes it is useful to be able do some runtime configuration after the Spring ApplicationContext has been built. In this case you can define a doWithApplicationContext closure property.


class SimplePlugin {

def name = "simple" def version = "1.1"

def doWithApplicationContext = { appCtx -> def sessionFactory = appCtx.sessionFactory // do something here with session factory } }

15.8 実行時のダイナミックメソッド追加

h4. The Basics


Grails plugins let you register dynamic methods with any Grails-managed or other class at runtime. This work is done in a doWithDynamicMethods closure.


For Grails-managed classes like controllers, tag libraries and so forth you can add methods, constructors etc. using the ExpandoMetaClass mechanism by accessing each controller's MetaClass:

コントローラやタグライブラリなどのようなGrails管理下のクラスについては、それぞれのコントローラのMetaClassExpandoMetaClass の機構でアクセスすることによって、メソッドやコンストラクタなどを追加できます:

class ExamplePlugin {
    def doWithDynamicMethods = { applicationContext ->
        for (controllerClass in application.controllerClasses) {
             controllerClass.metaClass.myNewMethod = {-> println "hello world" }

In this case we use the implicit application object to get a reference to all of the controller classes' MetaClass instances and add a new method called myNewMethod to each controller. If you know beforehand the class you wish the add a method to you can simply reference its metaClass property.


For example we can add a new method swapCase to java.lang.String:


class ExamplePlugin {

def doWithDynamicMethods = { applicationContext -> String.metaClass.swapCase = {-> def sb = new StringBuilder() delegate.each { sb << (Character.isUpperCase(it as char) ? Character.toLowerCase(it as char) : Character.toUpperCase(it as char)) } sb.toString() }

assert "UpAndDown" == "uPaNDdOWN".swapCase() } }

h4. Interacting with the ApplicationContext


The doWithDynamicMethods closure gets passed the Spring ApplicationContext instance. This is useful as it lets you interact with objects within it. For example if you were implementing a method to interact with Hibernate you could use the SessionFactory instance in combination with a HibernateTemplate:


import org.springframework.orm.hibernate3.HibernateTemplate

class ExampleHibernatePlugin {

def doWithDynamicMethods = { applicationContext ->

for (domainClass in application.domainClasses) {

domainClass.metaClass.static.load = { Long id-> def sf = applicationContext.sessionFactory def template = new HibernateTemplate(sf) template.load(delegate, id) } } } }

Also because of the autowiring and dependency injection capability of the Spring container you can implement more powerful dynamic constructors that use the application context to wire dependencies into your object at runtime:


class MyConstructorPlugin {

def doWithDynamicMethods = { applicationContext -> for (domainClass in application.domainClasses) { domainClass.metaClass.constructor = {-> return applicationContext.getBean(domainClass.name) } } } }

Here we actually replace the default constructor with one that looks up prototyped Spring beans instead!


15.9 自動リロードイベントへの参加

h4. Monitoring Resources for Changes


Often it is valuable to monitor resources for changes and perform some action when they occur. This is how Grails implements advanced reloading of application state at runtime. For example, consider this simplified snippet from the Grails ServicesPlugin:


class ServicesGrailsPlugin {
    def watchedResources = "file:./grails-app/services/*Service.groovy"

… def onChange = { event -> if (event.source) { def serviceClass = application.addServiceClass(event.source) def serviceName = "${serviceClass.propertyName}" def beans = beans { "$serviceName"(serviceClass.getClazz()) { bean -> bean.autowire = true } } if (event.ctx) { event.ctx.registerBeanDefinition( serviceName, beans.getBeanDefinition(serviceName)) } } } }

First it defines watchedResources as either a String or a List of strings that contain either the references or patterns of the resources to watch. If the watched resources specify a Groovy file, when it is changed it will automatically be reloaded and passed into the onChange closure in the event object.


The event object defines a number of useful properties:


  • event.source - The source of the event, either the reloaded Class or a Spring Resource
  • event.ctx - The Spring ApplicationContext instance
  • event.plugin - The plugin object that manages the resource (usually this)
  • event.application - The GrailsApplication instance
  • event.manager - The GrailsPluginManager instance

  • event.source - イベントの発生元。リロードされたClassもしくはSpring Resource
  • event.ctx - Spring ApplicationContextインスタンス
  • event.plugin - このリソースを管理しているプラグインオブジェクト(通常this)。
  • event.application - GrailsApplicationインスタンス
  • event.manager - GrailsPluginManagerインスタンス

These objects are available to help you apply the appropriate changes based on what changed. In the "Services" example above, a new service bean is re-registered with the ApplicationContext when one of the service classes changes.


h4. Influencing Other Plugins


In addition to reacting to changes, sometimes a plugin needs to "influence" another.


Take for example the Services and Controllers plugins. When a service is reloaded, unless you reload the controllers too, problems will occur when you try to auto-wire the reloaded service into an older controller Class.


To get around this, you can specify which plugins another plugin "influences". This means that when one plugin detects a change, it will reload itself and then reload its influenced plugins. For example consider this snippet from the ServicesGrailsPlugin:


def influences = ['controllers']

h4. Observing other plugins


If there is a particular plugin that you would like to observe for changes but not necessary watch the resources that it monitors you can use the "observe" property:


def observe = ["controllers"]

In this case when a controller is changed you will also receive the event chained from the controllers plugin.


It is also possible for a plugin to observe all loaded plugins by using a wildcard:


def observe = ["*"]

The Logging plugin does exactly this so that it can add the log property back to any artefact that changes while the application is running.

ロギングプラグインはちょうどこのようなことを行なっており、アプリの実行中に変更があった 任意の アーティファクトにlogプロパティを設定し直しています。

15.10 プラグインのロード順を理解する

h4. Controlling Plugin Dependencies


Plugins often depend on the presence of other plugins and can adapt depending on the presence of others. This is implemented with two properties. The first is called dependsOn. For example, take a look at this snippet from the Hibernate plugin:


class HibernateGrailsPlugin {

def version = "1.0"

def dependsOn = [dataSource: "1.0", domainClass: "1.0", i18n: "1.0", core: "1.0"] }

The Hibernate plugin is dependent on the presence of four plugins: the dataSource, domainClass, i18n and core plugins.

Hibernateプラグインは4つのプラグインに依存しています: dataSourcedomainClassi18nそしてcoreプラグインです。

The dependencies will be loaded before the Hibernate plugin and if all dependencies do not load, then the plugin will not load.


The dependsOn property also supports a mini expression language for specifying version ranges. A few examples of the syntax can be seen below:


def dependsOn = [foo: "* > 1.0"]
def dependsOn = [foo: "1.0 > 1.1"]
def dependsOn = [foo: "1.0 > *"]

When the wildcard character is used it denotes "any" version. The expression syntax also excludes any suffixes such as -BETA, -ALPHA etc. so for example the expression "1.0 > 1.1" would match any of the following versions:

ワイルドカード文字が任意のバージョンを表わすために使われます。また、この式のシンタックスは、「-BETA」や「-ALPHA」といった接尾辞を除外します。なので例えば「1.0 > 1.1」は以下のバージョンにマッチします。

  • 1.1
  • 1.0
  • 1.0.1
  • 1.0.3-SNAPSHOT
  • 1.1-BETA2

h4. Controlling Load Order


Using dependsOn establishes a "hard" dependency in that if the dependency is not resolved, the plugin will give up and won't load. It is possible though to have a weaker dependency using the loadAfter and loadBefore properties:


def loadAfter = ['controllers']

Here the plugin will be loaded after the controllers plugin if it exists, otherwise it will just be loaded. The plugin can then adapt to the presence of the other plugin, for example the Hibernate plugin has this code in its doWithSpring closure:

ここでは、もしcontrollersプラグインが存在すれば、それがロードされた後に、このプラグインがロードされます。 さもなければ(controllersプラグインが存在しなければ)、このプラグインは単にロードされます。プラグインは他のプラグインの存在に適応します。たとえば、HibernateプラグインはdoWithSpringクロージャで以下を行っています:

if (manager?.hasGrailsPlugin("controllers")) {
    openSessionInViewInterceptor(OpenSessionInViewInterceptor) {
        flushMode = HibernateAccessor.FLUSH_MANUAL
        sessionFactory = sessionFactory
    grailsUrlHandlerMapping.interceptors << openSessionInViewInterceptor

Here the Hibernate plugin will only register an OpenSessionInViewInterceptor if the controllers plugin has been loaded. The manager variable is an instance of the GrailsPluginManager interface and it provides methods to interact with other plugins.


You can also use the loadBefore property to specify one or more plugins that your plugin should load before:


def loadBefore = ['rabbitmq']

h4. Scopes and Environments


It's not only plugin load order that you can control. You can also specify which environments your plugin should be loaded in and which scopes (stages of a build). Simply declare one or both of these properties in your plugin descriptor:


def environments = ['development', 'test', 'myCustomEnv']
def scopes = [excludes:'war']

In this example, the plugin will only load in the 'development' and 'test' environments. Nor will it be packaged into the WAR file, because it's excluded from the 'war' phase. This allows development-only plugins to not be packaged for production use.


The full list of available scopes are defined by the enum BuildScope, but here's a summary:

利用可能なスコープの全てのリストはenum BuildScopeで定義されていますが、以下はその抜粋です:

* test - when running tests
* functional-test - when running functional tests
* run - for run-app and run-war
* war - when packaging the application as a WAR file
* all - plugin applies to all scopes (default)
  • test - テスト実行時
  • functional-test - ファンクショナルテスト実行時
  • run - run-appもしくはrun-war時
  • war - アプリケーションがWARファイルにパッケージ化されたとき
  • all - 全てのスコープに適用されるプラグイン(デフォルト)

Both properties can be one of:


  • a string - a sole inclusion
  • a list - a list of environments or scopes to include
  • a map - for full control, with 'includes' and/or 'excludes' keys that can have string or list values

  • a string - 1つ含む
  • a list - 含められるべき環境もしくはスコープのリスト
  • a map - 全ての制御。キーは'includes'か'excludes'で、バリューは文字列もしくはリスト

For example,


def environments = "test"

will only include the plugin in the test environment, whereas


def environments = ["development", "test"]

will include it in both the development and test environments. Finally,

はdevelopment test環境の両方を含みます。最後に

def environments = [includes: ["development", "test"]]

will do the same thing.


15.11 アーテファクトAPI

You should by now understand that Grails has the concept of artefacts: special types of classes that it knows about and can treat differently from normal Groovy and Java classes, for example by enhancing them with extra properties and methods. Examples of artefacts include domain classes and controllers. What you may not be aware of is that Grails allows application and plugin developers access to the underlying infrastructure for artefacts, which means you can find out what artefacts are available and even enhance them yourself. You can even provide your own custom artefact types.


15.11.1 使用可能なアーテファクトの検索

As a plugin developer, it can be important for you to find out about what domain classes, controllers, or other types of artefact are available in an application. For example, the Searchable plugin needs to know what domain classes exist so it can check them for any searchable properties and index the appropriate ones. So how does it do it? The answer lies with the grailsApplication object, and instance of GrailsApplication that's available automatically in controllers and GSPs and can be injected everywhere else.

プラグイン開発者からすると、アプリケーションにおいて、どのドメインクラス・コントローラや他のアーテファクトが利用可能かが分かる、ということが重要かもしれません。 例えば、Searchableプラグインは、インデックス化すべきであることを指定するsearchableプロパティをチェックするために、どんなドメインクラスが存在しているかをまず知る必要があります。では、どんなふうにチェックできるのでしょう? 答えはgrailsApplicationオブジェクトとGrailsApplicationのインスタンスにあります。これらはコントローラとGSP中では自動的に利用可能となり、他の任意の場所で注入しておくことができます。

The grailsApplication object has several important properties and methods for querying artefacts. Probably the most common is the one that gives you all the classes of a particular artefact type:


for (cls in grailsApplication.<artefactType>Classes) {

In this case, artefactType is the property name form of the artefact type. With core Grails you have:


  • domain
  • controller
  • tagLib
  • service
  • codec
  • bootstrap
  • urlMappings

So for example, if you want to iterate over all the domain classes, you use:


for (cls in grailsApplication.domainClasses) {

and for URL mappings:


for (cls in grailsApplication.urlMappingsClasses) {

You need to be aware that the objects returned by these properties are not instances of Class. Instead, they are instances of GrailsClass that has some particularly useful properties and methods, including one for the underlying Class:


  • shortName - the class name of the artefact without the package (equivalent of Class.simpleName).
  • logicalPropertyName - the artefact name in property form without the 'type' suffix. So MyGreatController becomes 'myGreat'.
  • isAbstract() - a boolean indicating whether the artefact class is abstract or not.
  • getPropertyValue(name) - returns the value of the given property, whether it's a static or an instance one. This works best if the property is initialised on declaration, e.g. static transactional = true.

  • shortName - パッケージ部分を除いたアーテファクトのクラス名(Class.simpleNameと等価)
  • logicalPropertyName - プロパティ中で用いられる名アーテファクトの名前から型接尾辞を除いたもの。MyGreatControllerは「myGreat」になる。
  • isAbstract() - アーテファクトクラスがabstractかどうかを表すブーリアン値
  • getPropertyValue(name) - 指定したプロパティ値を、staticか非staticかどうかに関わらず返す。もしプロパティが「static transactional = true」のように初期化されて宣言されていたときにも動作する。

The artefact API also allows you to fetch classes by name and check whether a class is an artefact:


  • get<type>Class(String name)
  • is<type>Class(Class clazz)

The first method will retrieve the GrailsClass instance for the given name, e.g. 'MyGreatController'. The second will check whether a class is a particular type of artefact. For example, you can use grailsApplication.isControllerClass(org.example.MyGreatController) to check whether MyGreatController is in fact a controller.


15.11.2 アーテファクト型の追加

Plugins can easily provide their own artefacts so that they can easily find out what implementations are available and take part in reloading. All you need to do is create an ArtefactHandler implementation and register it in your main plugin class:


class MyGrailsPlugin {
    def artefacts = [ org.somewhere.MyArtefactHandler ]

The artefacts list can contain either handler classes (as above) or instances of handlers.


So, what does an artefact handler look like? Well, put simply it is an implementation of the ArtefactHandler interface. To make life a bit easier, there is a skeleton implementation that can readily be extended: ArtefactHandlerAdapter.


In addition to the handler itself, every new artefact needs a corresponding wrapper class that implements GrailsClass. Again, skeleton implementations are available such as AbstractInjectableGrailsClass, which is particularly useful as it turns your artefact into a Spring bean that is auto-wired, just like controllers and services.


The best way to understand how both the handler and wrapper classes work is to look at the Quartz plugin:

ハンドラとラッパーの動作を理解するのにベストなやり方は、Quartz pluginのコードを読んでみることです:

Another example is the Shiro plugin which adds a realm artefact.


15.12 バイナリープラグイン

Regular Grails plugins are packaged as zip files containing the full source of the plugin. This has some advantages in terms of being an open distribution system (anyone can see the source), in addition to avoiding problems with the source compatibility level used for compilation.

As of Grails 2.0 you can pre-compile Grails plugins into regular JAR files known as "binary plugins". This has several advantages (and some disadvantages as discussed in the advantages of source plugins above) including:
Grails 2.0から、プラグインを通常のJARファイルとしてプリコンパイルパッケージした、バイナリプラグインを生成配布することが可能になります。バイナリプラグインにすることで以下の利点があります。

  • Binary plugins can be published as standard JAR files to a Maven repository
  • Binary plugins can be declared like any other JAR dependency
  • Commercial plugins are more viable since the source isn't published
  • IDEs have a better understanding since binary plugins are regular JAR files containing classes

  • Mavenリポジトリで通常のJARファイルで配布可能。
  • バイナリプラグインは他のJARと同じように依存管理が行える。
  • ソースコードを公開しない商用プラグインが可能
  • 通常のJARになることによって、IDE等の環境で扱いやすくなる


To package a plugin in binary form you can use the package-plugin command and the --binary flag:

grails package-plugin --binary

Supported artefacts include:

  • Grails artifact classes such as controllers, domain classes and so on
  • I18n Message bundles
  • GSP Views, layouts and templates

  • コントローラ、ドメイン等のGrailsのアーテファクトクラス
  • I18nメッセージファイル
  • GSPビュー、レイアウト、テンプレート

You can also specify the packaging in the plugin descriptor:

def packaging = "binary"

in which case the packaging will default to binary.

Using Binary Plugins

The packaging process creates a JAR file in the target directory of the plugin, for example target/foo-plugin-0.1.jar. There are two ways to incorporate a binary plugin into an application.
パッケージを実行するとJARファイルはプラグインプロジェクトのtargrtディレクトリに生成されます。例としてtarget/foo-plugin-0.1.jar 。 バイナリプラグインを使用するには2つの方法があります。

One is simply placing the plugin JAR file in your application's lib directory. The other is to publish the plugin JAR to a compatible Maven repository and declare it as a dependency in grails-app/conf/BuildConfig.groovy:

dependencies {
    compile "mycompany:myplugin:0.1"

Since binary plugins are packaged as JAR files, they are declared as dependencies in the dependencies block, not in the plugins block as you may be naturally inclined to do. The plugins block is used for declaring traditional source plugins packaged as zip files