Groovy: “Groovy” language
Not everyone thinks the Java programming language is sexy. But the Java virtual machine is a dominant force in everything from the most conservative enterprises to the most eccentric start-ups. Today, there are many alternative languages that compile to Java bytecode. There are JVM based implementations of Python, Ruby, and JavaScript. There are entirely new languages like JetBrains’ Kotlin and RedHat’s Ceylon. Clojure’s recent revival of interest in Lisp and Scala is largely responsible for the server-side shift to functional programming in 2000.
Groovy is everyone’s grandfather and is almost everywhere today. When it first appeared 13 years ago, Groovy was an instant hit. The language and the related Grails Web framework combine the emerging popularity of Ruby on Rails with a very shallow learning curve for Java developers. Almost overnight, Groovy completely replaced the previous JVM scripting alternative, BeanShell.
Enthusiasm for the Rails model eventually waned, and strongly typed languages became the trend again. Frankly, many of the people who flocked to Groovy simply because it was “new” continue to develop new things. Groovy hasn’t gone away, though. Instead, it has become a full-fledged role for the language of “corporate chic”. You can see it everywhere. Almost all applications on the JVM that expose scripting interfaces do so with Groovy as a first-class citizen. Groovy is a popular automated test space with QA, deeply embedded in the Spring framework, and is a rapidly growing base cradle building system.
We don’t hype Groovy as much as we used to, but it’s ingrained in the Java ecosystem, and it’s still expanding. It’s a stable, safe option, for which it’s easy to find talent (or quick on-the-job training). Although there are more trendy buzzwords to put on your resume today, the risk of Groovy dying out anytime soon seems minimal. Groovy “works” and is a very handy tool that every Java developer should use in their toolbox.
Gradle as Groovy App Server
Aside from history, let’s talk about a recent use case that prevented me from using Groovy skills. I need to quickly set up a registry of “key” configuration parameters for many applications running in a variety of environments. I want to capture these parameters as a collection of properties files in source control. One file per application, nested in subdirectories of each environment:
... Qa - env/application - Amy polumbo roperties application - p. roperties... The staging env/application - Amy polumbo roperties application - p. roperties...Copy the code
Whenever I commit changes to these properties files in source control, I expect Jenkins (or another continuous integration server) to synchronize their values with the runtime “registry.” The registry may eventually become something like ETCD or Consul and Vault, but we can start working quickly with a traditional MySQL database.
Since most of our continuous integration build jobs these days are based on Gradle, and since Gradle is Groovy native, we can bake this “synchronous” job into a Gradle build. With Java Exec-based tasks that point to Groovy scripts, you can use Gradle as a Groovy application server!
- build.gradle
apply plugin: 'groovy' repositories { mavenCentral() mavenLocal() } // [1] Declare a localGroovy() dependency, to use // the Groovy library that ships with Gradle. dependencies { compile localGroovy() The compile (" mysql: mysql connector - Java: 5.1.35 "), the compile (" com. H2database: h2:1.4.187 ") testCompile (" junit: junit: 4.12 ")} / / [2] Create a task of type 'JavaExec', referencing // a Groovy script and any input arguments. task runScript(type: JavaExec) { description 'Run a Groovy script to sync the environment config registry with the properties files in source control' classpath = sourceSets.main.runtimeClasspath main 'com.mypackage.SyncScript' args Arrays.asList('jdbc:mysql://registry/db', 'com.mysql.jdbc.Driver', 'user', 'password').toArray() } // [3] Tell Gradle to invoke your Groovy script task. defaultTasks 'runScript'Copy the code
Writing Gradle build scripts that execute some arbitrary Groovy code is fairly straightforward. Since the preferred way to run Gradle today is through streamlined wrapper scripts, this solution can be delivered directly from source control repositories anywhere without having to install Gradle.
In other words, Jenkins can run Groovy scripts as long as the source control repository is committed.
Groovy SQL
Now, for the really neat part, Groovy “synchronizes” the scripts themselves. The script scans any number of each environment directory, scans any number of each application properties file in each directory, and synchronizes these properties with MySQL database tables.
// Iterate through each per-environment directory new File('config').eachDir { File environmentDirectory -> // Iterate through each per-application properties file environmentDirectory.eachFileMatch FileType.FILES, ~/.+\.properties/, { File applicationFile -> def environment = environmentDirectory.name def application = applicationFile.name.replace('.properties', '') println "Processing properties for env: '$environment', application: '$application'" // Parse the file into a java.util.Properties object def properties = new Properties() applicationFile.withInputStream { stream -> properties.load(stream) } ... }}Copy the code
Java 8 Streams makes this kind of thing friendlier and more readable in the pure Java world, but it still doesn’t touch the simplicity of Groovy’s extensions to classes like File. The eachDir () and eachFileMatch () add-on methods can be easily done by iterating through all directories and scanning for files with the extension “properties”. The withInputStream () method helps us load the contents of each file into a java.util.properties with a single line object.
In addition to extensions to java.io.File, Groovy provides its own groovy.sql. SQL class to facilitate JDBC operations. This reduces a lot of the boilerplate required to construct a database query and allows us to process its ResultSet within a closure:
database = groovy.sql.Sql.newInstance(jdbcUrl, jdbcUsername, jdbcPassword, jdbcDriver)
database.resultSetConcurrency = ResultSet.CONCUR_UPDATABLE
// Iterate through the properties, and sync MySQL
properties.entrySet().each {
def name = it.key
def value = it.value
def existingRecordQuery = '''
SELECT environment, service, property_name, property_value FROM environment_properties
WHERE environment = ? AND service = ? AND property_name = ?
'''
database.query(existingRecordQuery, [environment, service, name]) { ResultSet rs ->
if (rs.next()) {
def existingValue = rs.getString('property_value')
if (existingValue.equals(value)) {
// Existing property value is unchanged. No-op.
} else {
// Existing property value has changed. Update.
rs.updateString('property_value', value)
rs.updateRow()
}
} else {
// New property. Insert.
rs.moveToInsertRow()
rs.updateString('environment', environment)
rs.updateString('service', service)
rs.updateString('property_name', name)
rs.updateString('property_value', value)
rs.insertRow()
}
}
}
// TODO: Remove from the database properties that have
// been removed from the properties file.Copy the code
Some interesting things are happening here:
- In line 2, we change the concurrency setting to resultSet.concur_updatable. Many Java developers don’t know that Java even supports it!
- This setting allows you to update, insert, or delete rows in a ResultSet object without having to construct other JDBC statements. See the examples that occur on lines 20 and 29. Many of the benefits of ORM lie in the simplicity of raw JDBC!
- As you can see in lines 8-11, Groovy allows multi-line string literals with triple quotes. This makes it more readable to include long SQL strings in your source code.
- In line 12, we see that groovy.sql. SQL allows you to execute statements and process their results within closures. One convenience is that the underlying JDBC statement closes automatically at the end.
conclusion
This particular use case is very specific, but it demonstrates several concepts that are broadly useful in isolation. Groovy is a very powerful language that is likely to be popular in environments where there are no alternatives. It’s native to Gradle, which has quickly become the dominant build tool in the Java ecosystem, so Groovy is easy to leverage through your continuous integration server. Finally, Groovy provides a complete class library and extensions to core Java classes that really remove the boilerplate and complexity of many common tasks.
Technical articles selected
- Java one line of code to print a heart
- Linux performance monitoring software Netdata Chinese version
- Interface Test Code Coverage (JACOCO) solution sharing
- Performance testing framework
- How to perform performance tests on a Linux command line interface
- Graphic HTTP brain map
- Automatically turn the Swagger document into test code
- Five lines of code to build a static blog
- Probe into the Linear interface testing framework based on Java
- Mid-practice for Selenium testing in JUnit
Selected non-technical articles
- Why software testing as a career path?
- Programming thinking for everyone
- 7 Steps to becoming a Good Automation Test Engineer
- An important reason for the existence of manual testing
- 7 Skills to become an automated test
- Automated and manual testing to keep the balance!
- Automated test lifecycle
- How do YOU introduce automated testing in DevOps