Andrey Hihlovskiy

Professional blog on groovy, gradle, Java, Javascript and other stuff.

Category Archives: Programming

groovy script for running jetty server

The following script starts jetty server and opens the folder, specified on command line, for http access (read-only):

#!/usr/bin/env groovy

@Grab('javax.servlet:javax.servlet-api:3.0.1')
@Grab(group='org.eclipse.jetty', module='jetty-webapp', version='8.1.8.v20121106')
@Grab(group='org.eclipse.jetty', module='jetty-server', version='8.1.8.v20121106', transitive=false)
@Grab(group='org.eclipse.jetty', module='jetty-servlet', version='8.1.8.v20121106', transitive=false)
@GrabExclude('org.eclipse.jetty.orbit:javax.servlet')

import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.*
import groovy.servlet.*

def publishedFolder = args ? args[0] : '.'

def server = new Server(8080)
def context = new ServletContextHandler(server, '/', ServletContextHandler.SESSIONS)
def webappContext = new org.eclipse.jetty.webapp.WebAppContext(publishedFolder, '/jetty')
context.setHandler(webappContext)
server.start()
println 'Jetty server started. Press Ctrl+C to stop.'

Usage:

  1. Save this script to file “jetty.groovy”
  2. Invoke on command-line:
    groovy jetty.groovy /path/to/some/folder"
  3. Enter address in web-browser:
    http://localhost:8080/jetty

Expected result: you see the content of the folder “/path/to/some/folder” in the web-browser.

groovy switch: nasty bug

I found nasty error in Groovy compiler. Consider the following code:

byte b = 1
switch(b) {
  case 0..9:
    println 'it is between 0 and 9'
    break
  default:
    println 'it is something else'
}

It executes ‘default’ part, not the part with 0..9, which is not what a programmer would typically expect.
The reason behind it should be related to type conversion between “byte” and “int” types. With the following workaround:

switch((int)b)

the program executes “proper” case.

groovy: switch statement and closure comprehension – nice for DSL

It is rather easy to extend groovy switch statement with our own DSL:

def isGreaterThan(a, b) { a > b }

def isGreaterThan(b) {
  return { a -> isGreaterThan(a, b) }
}

def isLessThan(a, b) { a < b }

def isLessThan(b) {
  return { a -> isLessThan(a, b) }
}

def x = 5
def y = 6

switch(x) {
  case isGreaterThan(y):
    println "$x is greater than $y"
    break
  case isLessThan(y):
    println "$x is less than $y"
    break
  default:
    println "$x equals $y"
}

The trick here is that single-argument versions of IsGreaterThan, IsLessThan return closures. Switch-statement “understands” closures: it passes it’s argument (x in our case) as a parameter to the closure and expects boolean result being returned from the closure.Same thing can be done via function currying, but it looks not so nice, as with function overload.

By the way, DSL stands for “Domain Specific Language”. See more information here: http://en.wikipedia.org/wiki/Domain-specific_language

Groovy DSL == thermonuclear way of writing XML

import groovy.xml.MarkupBuilder

String createEAD(Closure closure) {
  def writer = new StringWriter()
  def xml = new MarkupBuilder(writer)
  xml.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
  xml.'ead:ead'('xmlns:ead': 'urn:isbn:1-931666-22-9') {
    closure.delegate = new Object() {
      def text(Map attrs, content) {
        def a = attrs.keySet().find { it in ['bold', 'italic', 'underline'] }
        if(a && attrs[a]) {
          xml.'ead:emph' render: a, {
            text attrs.findAll({ it.key != a }), content
          }
        } else
          text content
      }
      def text(content) {
        if(content instanceof String)
          xml.mkp.yield content
        else if(content instanceof Closure)
          content()
      }
    }
    closure()
  }
  return writer.toString()
}

println createEAD {
  text bold: true, italic: true, {
    text 'Hello, '
    text underline: true, 'world!'
  }
}

expected output:

<?xml version='1.0' encoding='UTF-8'?>
<ead:ead xmlns:ead='urn:isbn:1-931666-22-9'>
  <ead:emph render='bold'>
    <ead:emph render='italic'>Hello, 
      <ead:emph render='underline'>world!</ead:emph>
    </ead:emph>
  </ead:emph>
</ead:ead>

Partial interface implementation in groovy

interface X {
  void a()
  void b()
}

class XAdapter implements X {
  void a() { println 'default implementation of a' }
  void b() { println 'default implementation of b' }
}

def o = [
  a: { println 'overridden implementation of a' }
] as XAdapter

o.a()
o.b()

will output:

overridden implementation of a
default implementation of b

Fun with groovy files

The following one-liner can copy very large files without running out of memory:

new File("test").withInputStream { new File("test2") << it }

Just tested it in groovy console – 1 GB file is copied in 5 seconds, memory consumption stays low.
The copy is binary, i.e. it copies bytes, not chars.
One particularity: left-shift operator rather appends than overwrites. If you need to overwrite the file, first need to delete it.

Fun with groovy maps and function call syntax

A function having a Map as first parameter:

void doIt(Map attrs, Object content) {
  println attrs
  println content
}

supports equally valid call syntax variations:

// "classical" call syntax, known from java world
doIt([color: 'red', type: 'fruit'], 'hello!')

// parentheses can be omitted
doIt [color: 'red', type: 'fruit'], 'hello!'

// even square brackets for map can be omitted
doIt color: 'red', type: 'fruit', 'hello!'

// order of map properties does not matter,
// map properties can be intermixed with unnamed parameters.

doIt color: 'red', 'hello!', type: 'fruit'

doIt 'hello!', type: 'fruit', color: 'red'

this effectively allows to implement named parameters in groovy.

Power of switch statement in groovy

Very impressive (and expressive):

def x = 'test'

switch(x) {
  case null:
    println 'null!'
    break
  case ~/(?i)Test/:
    println 'got it!'
    break
  default:
    println 'something else'
}

here second ‘case’ does case-insensitive regex comparison. In general, case may contain any regex, collection, range or class.

Solution for Grails/JDK 1.7.0_25 compatibility problem

The previously reported problem with  Grails/JDK 1.7.0_25 compatibility seems to be specific to OpenJDK. As soon as the one replaces OpenJDK with Oracle JDK, error is gone and Grails applications could be started again.

A happier, groovier way to parse RTF: apache_tika + XmlSlurper

I discovered a new, easier way to parse RTF in java/groovy programs. Consider the following sequence:

1. Instantiate XmlSlurper

2. Instantiate RTFParser (of Apache Tika)

3. Parse RTF (either file or string), passing XmlSlurper to RTFParser (such passing is possible, because RTFParser expects ContentHandler interface, which is implemented by XmlSlurper).

4. Traverse RTF content groovy-style: each, find, findAll, etc.

The example:


package org.akhikhl.test
import org.apache.tika.metadata.Metadata
import org.apache.tika.parser.rtf.RTFParser
class ParseRtf {
def parse(String rtfText) {
// not validating, not ns-aware
XmlSlurper slurper = new XmlSlurper(false, false)
InputStream rtfStream = new ByteArrayInputStream(value.getBytes())
new RTFParser().parse(rtfStream, slurper, new Metadata())
slurper.document.'body'.p.each { p ->
println "Got paragraph: ${p.text()}"
}
}
}

view raw

ParseRtf.groovy

hosted with ❤ by GitHub