Magnolia 5.3 reached end of life on June 30, 2017. This branch is no longer supported, see End-of-life policy.
This documentation refers to Groovy module 2.2 and greater. The Groovy module is compatible with Magnolia 5 starting from version 2.0. If you are using Groovy module before 2.2, see .
The module uses Groovy language 2.1.8
Magnolia Groovy module adds Groovy capabilities to Magnolia. Groovy is a popular dynamic language for the JVM. To know more about it, please visit the Groovy official website which has plenty of tutorials and excellent documentation both for beginners and advanced users of the language. The module provides a web based Unix-like console where you can access contents in Magnolia repositories in a "groovish" way, a scripts
repository where you can store your scripts and the ability to plugin Groovy classes into Magnolia at runtime, without the need for deploying them and restarting the servlet container. All these tools make for a more agile approach to coding and maintaining Magnolia based websites.
The Groovy module is bundled with Magnolia and typically already installed. You can download it from our Nexus repository.
Groovy is a Community Edition module. It is typically already installed. Launch the Configuration app and go to /modules/groovy
to check.
Thanks to the .(dot) notation and other handy shortcuts such as .nodes
(alternatively .children
), .properties
, .metaData
and .parent
you can read any content node and property, change their values, create nodes and delete them, all with clean, concise syntax. The module is shipped with some preinstalled scripts that demonstrate most of these features. As an example, here is how to navigate to and print the node data named abstract
:
session = ctx.getJCRSession('website') node = session.getNode('/demo-project') node.about.history.abstract
One noticeable thing about the above snippet is that it is all you need to write: no imports, no need to catch exceptions, etc. Compare it to the Java code that achieves the same result.
import info.magnolia.context.MgnlContext; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; public class Test { public static void main(String[] args) { try { Session session = MgnlContext.getJCRSession("website"); Node node = session.getNode("/demo-project/about/history"); String value = node.getProperty("abstract").getString(); System.out.println(value); } catch (RepositoryException e) { e.printStackTrace(); } } }
And, most importantly, with Groovy you do not need to deploy your class and restart the server. As an additional bonus, when using the Groovy Unix-like shell which comes with the module, when you navigate a repository, by calling the print()
method on a node its children and properties are shown in the output, giving you an overview of the data structure. The screenshot below illustrates this.
Using the print()
method differs from previous versions where the data structure was displayed automatically on pressing the Enter key. However, in many cases that caused the output to be unnecessarily verbose. What is printed now by default is simply the node path.
Being able to navigate a repository data like this can come in handy, for instance, when writing and testing your own scripts or trying things out. Or when you need to use the Rescue App because the Magnolia UI, for whatever reason, is not available.
As node
here is basically an instance of a JCR Node coated in a special "groovysh" wrapper, you to call any of the Node interface methods and take advantage of the Groovy goodies at the same time.
node.about.properties.each { println it.name } println node.about.parent //(this can be null)
If you want to print out all node properties but jcr ones, you can do:
node.about.properties.findAll { !it.name.startsWith('jcr:') }.each{ println it.name }
Autocompletion in the console
The ctx
context object is always available. In Groovy it represents MgnlGroovyConsoleContext
, a special instance of Magnolia's Context
.
Multiline code in the console
To enter multiline code in the Groovy console, press Shift + Enter at the end of each line. This enters the multiline mode. Once you've entered a block of text, press Enter at the end of the command to run it. This is useful when writing Groovy statements more complex than a simple one-liner.
It is also possible to assign values to properties or create new ones.
node.foo = 3.14d node.bar = true node.baz = 'some text' node.qux = 100
This will assign the values on the right hand side to the properties on left hand side. Should those not exist, they will be automatically created. Moreover, the correct type will be detected based on the value assigned (Boolean
, String
, Long
or Double
).
All the above assignments will be in-memory only unless explicitly persisted via a call to save()
on the current JCR session.
This feature allows you to virtually replace every Magnolia Java class with a Groovy one. Although not a major issue for most tasks, due to its dynamic nature Groovy is slower than Java. Nevertheless, replacing classes can come in handy in situations where you cannot deploy and restart the server, but need to quickly fix or add a piece of logic.
Two Apache Ant version 1.9.2 jars are required to test this example. Download Ant 1.9.2 and extract the files. Add ant.jar
and ant-launcher.jar
. to your file system at /<CATALINA_HOME>/webapps/<contextPath>/WEB-INF/lib
and restart Magnolia.
The Groovy module ships with a sample class my.commands.GroovyMailCommand
that sends an email. Here is how you could use it to create a new scheduled job on-the-fly using a Groovy command and the Scheduler module.
The GroovyMailCommand
is accessible in Tools > Groovy Scripts /my/commands/GroovyMailCommand
.
package my.commands import info.magnolia.commands.* /* * This groovy class is an example that serves to show how it can be used as a replacement of a traditional Java class on the fly. */ public class GroovyMailCommand extends MgnlCommand { public boolean execute(Context ctx) { def ant = new AntBuilder() def buildname = ctx.get('buildname') ant.mail(mailhost:'mailhost', mailport:'25', subject: ctx.get('subject')){ from(address:ctx.get('from')) to(address:ctx.get('to')) message("The ${buildname} nightly build has completed") } } } //this is for testing only ctx.put('from', 'foo@mail.com') ctx.put('to', 'bar@mail.com') ctx.put('subject', 'hello') ctx.put('buildname', 'TEST123') if(new GroovyMailCommand().execute(ctx)) println 'mail sent successfully'
Replace
mailhost
with your SMTP server address.
Create a command configuration in the Configuration app as shown below. We added it to the Mail module in /modules/mail/commands/default
, but you can add it to your own module or another of your choice. Specify the fully qualified name of the Groovy class (matching the path in the repository where it is saved my.commands
) as if it were a plain Java class (which it actually is).
Node name | Value |
---|---|
modules | |
commands | |
default | |
sendMail | |
sendMailWithGroovy | |
class | my.commands.GroovyMailCommand |
Create a scheduled job configuration referring to the command in the Configuration app > /modules/scheduler/config/jobs
. The parameters will be used at runtime by the Groovy script.
Node name | Value |
---|---|
modules | |
scheduler | |
config | |
jobs | |
demo | |
sendMail | |
params | |
buildname | TEST123 |
from | me@me.com |
subject | Hello |
to | you@you.com |
active | true |
catalog | default |
command | sendMailWithGroovy |
cron | 0 0 * * * * |
description | send mail every hour |
Replace the from
and to
email addresses with actual addresses.
You can use this command to replace a similar Java command at runtime. Or you can edit it and have it compiled and replaced on-the-fly (a kind of class hot deploy). This relies on the Magnolia observation mechanism. Every time the value of the class
node data changes the Groovy class will be recompiled.
Forcing Groovy class reloading
If you already set a Groovy class to replace a regular Java class in Magnolia configuration and you subsequently edit it, you'll notice that your changes aren't picked up automatically. This is a known issue but a workaround exists, i.e. manually triggering the reloading of the configuration node using your Groovy class, e.g. by modifying your template definition to force node2bean to reload it and thus reload the class itself. See also - MGNLGROOVY-68Getting issue details... STATUS
The MgnlGroovyRescueApp
is a special Vaadin app that can be used to bypass the Magnolia filter chain. This is useful when you need to perform rescue operations on a corrupted Magnolia instance or when the Magnolia UI is not loading. To enable the servlet you must explicitly comment out the Magnolia filter chain in the web.xml
file and register the Groovy Rescue App.
All operations performed in the Groovy Rescue App are executed in system context, meaning no security restrictions are enforced. This might expose your data to risk of irreversible damages if you are not aware of what you are doing. In other words, use it at your own risk.
/<CATALINA_HOME>/webapps/<contextPath>/WEB-INF/web.xml
in a text editor.filter
and filter-mapping
sections:<!-- <filter> <display-name>Magnolia global filters</display-name> <filter-name>magnoliaFilterChain</filter-name> <filter-class>info.magnolia.cms.filters.MgnlMainFilter</filter-class> </filter> <filter-mapping> <filter-name>magnoliaFilterChain</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> -->
<servlet> <servlet-name>Vaadin</servlet-name> <servlet-class>com.vaadin.server.VaadinServlet</servlet-class> <init-param> <description>Groovy Rescue App</description> <param-name>UI</param-name> <param-value>info.magnolia.module.groovy.rescue.MgnlGroovyRescueApp</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>Vaadin</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
http://host/<contextPath>
Use Groovy commands to navigate to the data you want to change.
In the following example we delete an erroneous configuration node untitled
from /config/modules/someModule/virtualURIMapping
.
Session
of config
repository to session
.session = ctx.getJCRSession('config')
root
.root = session.getNode('/modules/someModule/virtualURIMapping/')
untitled
.root.getNode('untitled').remove()
session.save()
Tomcat should notice that web.xml changed and read the changes automatically. If this does not happen, stop Magnolia, edit web.xml
, and start Magnolia again. Then try to access Magnolia.
The WebDAV module supports access to the Groovy scripts workspace. This allows you to use your favorite code editor to create and edit scripts.
The Groovy module 2.2 console has an issue that prevents one from pasting text into the console itself. Since version 2.2.2 the issue no longer affects Chrome - MGNLGROOVY-104Getting issue details... STATUS
Maven POM dependency sample:
<dependency> <groupId>info.magnolia</groupId> <artifactId>magnolia-module-groovy</artifactId> <version>2.2.2</version> </dependency>