Tag Archives: groovy

Ant hooks using Groovy via XML transform

This time the Ant Hook scripts using Groovy is implemented by transforming the target Ant build script. (old post in draft status)

In the post, Ant Hooks using Groovy Script via Scriptdef, we used the Ant BuildListener interface to add a hooks feature that invokes a Groovy script mapped to build events. Then in the last post Ant hooks using Groovy, continued we added the ability to skip a target execution.

The problem with the former implementations is that the target Ant script must be modified to take advantage of hooks. Using XMLTask, we can modify the ant script directly. The InsertHooks.groovy script reads the hooks.inix file and transforms the build.xml to build-hooked.xml. The build-hooked.xml file will have an Ant build listener set to the Hook.groovy script.

The scripts are not general purpose, of course. Just a proof of concept thing.

Approach

hooks.inix:

[>hook/root/compile?when=after,skip=false]
	println " hook: root,{target=${event.target.name},when=post,event=$event}"
[<]

[>hook/demo1/deploy?when=before,skip=true]
	println "  hook: {project=${event.project.name},target=${event.target.name},when=pre,event=$event}"
[<]

[>hook/demo1/compile?when=before,skip=false]
	println "  hook: {project=${event.project.name},target=${event.target.name},when=pre,event=$event}"
[<]

[>fragment]
	<path id="libs">    
		<fileset dir="lib">
            <include 
                name="groovy-all-2.2.1.jar" />
        </fileset> 
    	
    	<pathelement location="src/main/groovy"/>
	</path>    
     
    <!-- Groovy library -->
    <taskdef name="groovy"
       classname="org.codehaus.groovy.ant.Groovy"
       classpathref="libs"/> 
    
    <!-- sets a BuildListener to the project -->
    <scriptdef name="set-listener" 
        language="Groovy"
        classpathref="libs" 
        src="src/main/groovy/com/octodecillion/util/ant/Hook.groovy"> 
    	<attribute name="path"/>
    </scriptdef>
     
    <!-- install the listener -->
    <set-listener path="hooks.inix"/>   
     
[<fragment]

InsertHooks.groovy

package com.octodecillion.util.ant

import static com.octodecillion.util.inix.Inix.EventType.END

import com.octodecillion.util.inix.Inix

import org.apache.tools.ant.*

import static groovy.io.FileType.FILES

/**
 * Insert the XML into Ant script to enable hooks.
 *   
 * @author josef betancourt
 */
class InsertHooks{

	def ant
	def DEBUG = false
	static final String srcFilePath='build.xml'
	static final String destFilePath="build-hooked.xml"
	static final String INIXFILE = 'hooks.inix'	
	static final String XMLTASK = 'com.oopsconsultancy.xmltask.ant.XmlTask'
	
	static main(args){
		new InsertHooks().execute()
	}
	
	/** An Ant task entry point */
	public void execute() throws BuildException{
		def ant = new AntBuilder()
		
		try {
			
			def fragment = loadFragment(INIXFILE)
			if(!fragment){
				throw new BuildException("'fragment' from $INIXFILE is invalid")
			}		
			
			def engine = new groovy.text.SimpleTemplateEngine()
			def template = engine.createTemplate(fragment)			 
			def xml = template.make([hookFilePath:INIXFILE])
			  
			ant.path(id: "path") {
				fileset(dir: 'lib') {
				   include(name: "**/xml*.jar")
				}
			}
	 
			ant.taskdef(name:'xmltask',classname:
				XMLTASK,
				classpathref: 'path')
			 
			def xpath = '(//target)[1]' 
			ant.xmltask(source:srcFilePath,dest:destFilePath, 
				expandEntityReferences:false,report:false){
				insert(position:"before",path:xpath,xml:xml)				 
			}
				 
			new File(destFilePath).eachLine{
				println it
			}
			
		} catch (Exception e) {
			e.printStackTrace()
			throw new BuildException(e.getMessage(), e)
		}
	}
	
	def loadFragment(String path){
		def text = ''
		def inix = new Inix(path)
		def theEvent = inix.next()
		 
		while(theEvent && theEvent != Inix.EventType.END ){
			Inix.Event event = inix.getEvent()

			if(event.isSection("fragment")){
				text = event.text
				break
			}
			
			theEvent = inix.next()
		}
		
		return text
	}	
	
}

// end Script

Hook.groovy

package com.octodecillion.util.ant

import groovy.transform.TypeChecked;
import groovy.transform.TypeCheckingMode;

import java.util.List;
import java.util.Map;
import java.util.regex.Pattern

import com.octodecillion.util.inix.Inix

import org.apache.tools.ant.BuildEvent
import org.apache.tools.ant.BuildException
import org.apache.tools.ant.Project
import org.apache.tools.ant.SubBuildListener;

import static groovy.io.FileType.FILES

// wire in the listener
def path = binding.attributes.get('path')
if(!path){
	throw new BuildException("'path' to hook inix not set")
}

def listener = new HookListener(project,path)
listener.project = project
project.addBuildListener(listener)

// end wiring

/**
 * Ant build listener that invokes groovy hook scripts.
 *  
 * @author josef betancourt
 *
 */
//@TypeChecked
class HookListener implements SubBuildListener {
	Project project
	boolean DEBUG = false
	
	/**                          */
    def HookListener(Project project, String path){
		this.project = project
		loadInix(path)				
    }    
    
	/** load scripts in inix file */
	def loadInix(String path){
		debugln("load inix")
		def inix = new Inix()
		inix.reader = new BufferedReader(
			new FileReader(new File(path)))
		 
		def theEvent = inix.next()
		def found = false
		 
		while(theEvent && theEvent != Inix.EventType.END ){
			def event = inix.getEvent()

			if(isHook(event)){
				found = true
				def key = [event.path[2],((String)(event.params['when'])).
					toUpperCase()].join('/')
					
				String txt = event.text
				String skString = event.params['skip']
				boolean sk = (skString.compareTo('true')==0 ? true : false)
				debugln "key=$key, ${event.params['skip']}, skip=$sk"
					
				def node = new HookNode(txt, sk)
			
				def prj = event.path[1]				
				if(!hooks[prj]){
					hooks[prj] = [:]
				}	
				
				hooks[prj].put(key,node);			
			}
			
			theEvent = inix.next()
		}
		
		dumpHooks()		
		
	}

    /** invoked by Ant build */
	@Override
    public void targetStarted(BuildEvent event) {
		die("targetStarted invoked with null event", !event)
		invokeTargetHook(event, When.BEFORE)
    }
    
	/** invoked by Ant build */
    @Override
    public void targetFinished(BuildEvent event) {
		die("targetFinished invoked with null event", !event)
		invokeTargetHook(event, When.AFTER)
    }

    /** Invoke the target's hook script */
    def invokeTargetHook(BuildEvent event, When when){
        def b = new Binding()
        b.setProperty("event",event)
		b.setProperty("hook",this)
		
        def shell = new GroovyShell(b)
		
		def hookName = "${event.target.name}/$when"
		def pHook = hooks[event.project.name][hookName]
		def rHook = hooks['root'][hookName]	
		debugln("invokeTargetHook: $hookName\npHook:  $pHook\nrHook:  $rHook")
			
		boolean skipSet = false
		
		if(pHook){
			skipSet = pHook.skip	
			debugln("skipSet=$skipSet")
			shell.evaluate(pHook.text)
			
			if(!override && rHook){
				skipSet = skipSet ? skipSet : rHook.skip
				shell.evaluate(rHook.text)
			}			
			
		}else if(rHook){
			skipSet = rHook.skip			
			shell.evaluate(rHook.text)		
		}
		
		if( skipSet && (pHook || rHook) && (when == When.BEFORE) ){
			createSkipforTarget(event)
		}		
    } 

	/**   */
	private createSkipforTarget(BuildEvent event) {
		debugln "setting skip: ${event.target.name}_skipTarget"
		event.project.setProperty("${event.target.name}_skipTarget", "true")
		event.target.setUnless("${event.target.name}_skipTarget")
	}
	
	/** throw exception if flg is true */
	private die(Object msgObject, boolean flg){
		if(flg){
			throw new IllegalArgumentException(String.valueOf(msgObject))			
		}		
	}	
	
	@TypeChecked(TypeCheckingMode.SKIP)
	private isHook(ev){		
		ev.path && ev.path[0] == 'hook'		
	}
    
	private dumpHooks() {
		if(!DEBUG){
			return			
		}
		
		hooks.each{
			it.each{ node ->
				debugln(node)
			}
		}		
	}
	
	private debugln(Object msg){
		if(DEBUG){
			println(msg)
		}
	}
	
	String TARGETHOOK = "target"
	def override = true;
	
	enum When{
		BEFORE('before'),AFTER('after')
		String name
		
		When(s) {this.name = s}
	}
	
	private class HookNode {
		String text
		boolean skip
		public HookNode(String text, boolean skip){
			this.text = text
			this.skip = skip
		}
		
		def String toString() {return "s:$skip"};
	}
	
	Map<String, Map<String,HookNode>> hooks = [:]
	
    //@formatter:off
    @Override
    public void subBuildFinished(BuildEvent event) {}
    @Override
    public void subBuildStarted(BuildEvent event) {}
    @Override
    public void buildFinished(BuildEvent event) {}
    @Override
    public void buildStarted(BuildEvent event) {}
    @Override
    public void messageLogged(BuildEvent event) {}
    @Override
    public void taskFinished(BuildEvent event) {}
    @Override
    public void taskStarted(BuildEvent event) {}
	//@formatter:on
} // end class HookListener

// end Script

Further reading

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

Groovy is a language

A few years ago I wrote a few Groovy language scripts to help with some configuration and testing needs. I discussed these with my co-workers. But, lo and behold, for weeks they thought I was saying that the scripts were Groovy, as in cool, not Groovy as in the JVM based dynamic language. They never heard of Groovy. We had a big laugh.

This situation made me think again that developers have differing interests in their field. No offense, but a certain percentage just go to work and do what is required and punch out at the end of the day. It is Java today, but it may as well be COBOL, there is always opportunity to copy and paste and do the minimum to “solve” the current business stakeholder requirements.

I’m sure this is only true for some corporate IT environments which have a top down rigid structure and legacy applications. Introducing change into the software process and tools is difficult. Stability and safety is paramount. Thus, the worker who toes the line and is not disruptive is an asset. Sure, there is talk of change and new techniques, but at the end of the day: “no, we can’t use that, we have this.” The new web businesses and open-source projects are different, of course.

BTW, Groovy is now slowly being used in my company. But, not sure many have heard of it yet.

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

Groovy Object Notation using ConfigSlurper

In an old post in 2010 I was exploring the idea of using Groovy syntax as a data interchange format, GrON, just as JSON is a “subset” of Javascript.

Just noticed that Groovy has, since version 1.5, the ConfigSlurper class. “ConfigSlurper is a utility class for reading configuration files defined in the form of Groovy scripts. Configuration settings can be defined using dot notation or scoped using closures.”

Example use of ConfigSlurper

We can store a configuration found on the ConfigSlurper API page into a section of an Inix file:

[>configuration/finance]
    grails.webflow.stateless = true
    smtp {
        mail.host = 'smtp.myisp.com'
        mail.auth.user = 'server'
    }
    resources.URL = "http://localhost:80/resources"
[<configuration/finance]

Then to read it we just load that section and parse with a ConfigSlurper. As shown below.

import static org.junit.Assert.*;
import org.junit.Test;
import com.octodecillion.util.inix.Inix

class ExampleSlurpInix {
  @Test
  public final void test() {		
  	def scriptString = new Inix('resources\\test-data.inix')
              .load("configuration/finance")

  	def config = new ConfigSlurper().parse(scriptString)
		
  	assert config.toString() == 
  	'[grails:[webflow:[stateless:true]], smtp:[mail:[host:smtp.myisp.com, auth:[user:server]]], resources:[URL:http://localhost:80/resources]]'
  }
}

That’s one of the application types I was envisioning GrON to be used for: An easier format to store and transfer configuration, test, and other types of data. The issue is that as noted in the original post, this is insecure for use as data interchange unless a GrON parser that does not execute Groovy is used.

Links

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

Getting “svn info” using Groovy

In a Subversion utility I had to the get the revision number of the HEAD of the current working copy. An answer found gave a Linux command line solution. Here is my Groovy version.

Groovy allows the ability to execute a String. This returns a Process instance, we wait for its termination, and then we query the process for the return code, the output to stderr, and to stdout.

Below I take the output and stick it into a Properties object, then dump the entries. Of course, in practice I will be using the Properties in the solution (should have used a Map).

def command = ['svn','info','-rHEAD']
def proc = command.execute()
proc.waitFor()

int code = proc.exitValue()
if(code != 0){
    println "code: '${code}'"
    println "stderr: ${proc.err.text}"
    return
}

def props = new Properties()

proc.in.eachLine{
    def m = (it =~ /^(.*?):(.*)$/)
    if(m){
        def matches = m[0]
        def key = matches[1].trim()
        def value = matches[2].trim()
        props.put(key,value)
    }else{
        println 'Could not parse the output of svn info'
    }
}

println 'Properties ...'
props.each{
    println "[${it.key}]=[${it.value}]"
}

Example output
Note: The brackets were added to provide a visual test of output, they are not stored. Also, the content was manually changed.

Properties ...
[Last Changed Date]=[201.............pr 2014)]
[Last Changed Rev]=[737]
[Path]=[Widget]
[Repository UUID]=[ec14......b668719305]
[Revision]=[744]
[Relative URL]=[^/widget/branches/skunk]
[Repository Root]=[https://widget/svn/widget]
[Last Changed Author]=[alfred e. newman]
[URL]=[https://widget/svn/widget/branches/skunk]
[Node Kind]=[directory]

Example error output
On error the output would be something like:

code: '1'
stderr: svn: E155007: 'C:\temp' is not a working copy

Via SvnAnt?
An alternative is to use the svnant Ant task. This task has a subcommand ‘WcVersion’. It didn’t work for me.

Ant example is shown below, but you could of use the AntBuilder in Ant.

<target name="svn-info" depends="" description="- svn project info">
	<svn username="${svn.username}" password="${svn.password}">
		<wcversion path=".." prefix="svn" />
	</svn>		
</target>

Update
SvnAnt’s info command can be used to get this information. See http://subclipse.tigris.org/svnant/svntask.html#info

Links

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

Groovy implementation of INIX file format, part 2

Continued experimentation with the INIX “ini” file format. I take the original post code and add an alias feature.

Background
In three prior posts I presented a very simple metadata file storage approach. Pretty much using the INI file format with the sections as “heredocs.” In original INI format, afaik, the data within the sections were properties only, x=y.

Updates

  • Dec 25, 2015: Just saw a mention of Tom’s Obvious, Minimal Language (TOML) This is not directly related to what I’m after with Inix, but interesting as an example of a simple markup language.
  • Alias
    Now I am working on adding the ability for a section of data to load data from another section. The sections to load are indicated by the ‘@’ symbol and then the section path. Multiple sections can be indicated. Though I’m using the term ‘alias’ for this, perhaps a better term is ‘importing’. So far, I can parse the alias from the tag string.

    I have not implemented the actual import. One complexity left to solve is recursion. If this section imports another section, what if that section imports others sections?

    Alias use case
    Since currently the Inix file format is being used for test data, aliasing allows reuse of data without duplication, i.e., DRY. This is problematic with hierarchical data like JSON or XML, but much easier with lists or maps. Further features like overriding and interpolation would be useful for Java Properties data. The goal would be to eventually support use of the Cascading Configuration Pattern.

    Example 1

    [>First]
    Data in first    
    [<]
    
    [>Second@First]
    Data in second
    [<]
    

    Now when the data in section “Second” is loaded, the data from the aliased section is prepended to the current section data:

    Data in first    
    Data in second
    

    Tag format
    The section tag format is now: [>path#fragment@aliases?querystring]. Note that unlike a URI, the fragment does not appear at the end of the string.

    The section ID is really the path#fragment. Thus, the end tag could be [<] or can use the section ID: [<path#fragment]. Example 2

    [>demo1/deploy#two@account897@policy253?enabled=true&owner=false]
    stuff here
    [<demo1/deploy#two]
    

    Grammar
    The start of a grammar follows, but has not been ‘checked’ by attempted use of a parser generator like Antlr.

    grammar Inix;
    section: start CRLF data end;
    start: '[>' path (fragment)?(alias)*('?' args)? ']';
    end: '[<' path? ']';
    path: NAME ('/' NAME)*;
    fragment: '#' NAME;
    alias: '@' NAME
    args: (NAME=NAME ('&' NAME=NAME)*)?;
    data: (ANYTHING CRLF)*;
    NAME: ('a'..'z' | 'A'..'Z')('a' .. 'z' | 'A'..'Z'|'0'..'9'|'_');
    
    TODO:

    1. Do the actual import of aliased section data.
    2. Allow multiple params per param key: ?measure=21,measure=34,measure=90. Or better yet, just allow array in arg string: measure=[21,34,90],color=red

     

    Implementation
    Source code available at Github: https://gist.github.com/josefbetancourt/7701645

    Listing 2, Implementation

    Test class
    Note that there are not enough tests and the implementation code has not been reviewed.

    Listing 3, Test class

    The test data is:

    Listing 4, data file

    Environment
    Groovy Version: 2.2.2 JVM: 1.7.0_25 Vendor: Oracle Corporation OS: Windows 7

    Further Reading

    1. The Evolution of Config Files from INI to TOML
    2. Groovy Object Notation using ConfigSlurper
    3. Configuration Files Are Just Another Form of Message Passing (or Maybe Vice Versa)
    4. INI file
    5. Data File Metaformats
    6. Here document
    7. JSON configuration file format
    8. Creating External DSLs using ANTLR and Java
    9. Groovy Object Notation (GrON) for Data
      Interchange
    10. Cloanto Implementation of INI File Format
    11. http://groovy.codehaus.org/Tutorial+5+-+Capturing+regex+groups
    12. URI
    13. Designing a simple file format
    14. The Universal Design Pattern
    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

    Regex group capture with optional delimeter

    Ever had one of those days where the simplest thing seems complex? A simple regex is doing that to me now.

    This is the example, simplified. You have a string “BEFOREAFTER”. If this string has a ‘x’ in it, you want to capture everything before the ‘x’, else you want to capture the whole string. So,
      “BEFOREAFTER” gives “BEFOREAFTER”
      “BEFORExAFTER” gives “BEFORE”

    jump to solution

    Yes, I know this can be done programmatically or just using String.split(….). Don’t you hate on Stackoverflow and other places where they say don’t do it that way, but you still want to know: yes, but if I do choose this way, how would it be done? This is a learning incident.

    This should be easy, regex 101, right? I thought so too. I thought /^(.*)x?.*/ would work, nope. I tried captures with non-greedy quantifiers, zero-width this or that, etc. I even went back to reading Mastering Regular Expresssions by Jeffrey E. F. Friedl, O’Reilly Media, Inc. Great book by the way.

    My solution just has to be wrong. Here it is written using the Groovy language.

    def re = /^(.*)x|^(.*)/
    
    getCaptureGroup(re,"BEFORExAFTER")
    getCaptureGroup(re,"BEFOREAFTER")
    getCaptureGroup(re,"")
    getCaptureGroup(re,null)
    getCaptureGroup(null,"x")
    
    def getCaptureGroup(regex, inString){
      def found = ""	
    
      def m = (inString =~ regex)
      if(m){
        List matches = (List)m[0]		
        found =  matches[1] ? matches[1] : 
          (matches[2] ? matches[2] : "")
       }	
    	
       println "Using pattern $regex in String '$inString', 
        found group: '($found)' of type: ${found.getClass().getSimpleName()}"
    }
    

    The output of this script is:

    Using pattern ^(.*)x|^(.*) in String 'BEFORExAFTER', found group: '(BEFORE)' of type: String
    Using pattern ^(.*)x|^(.*) in String 'BEFOREAFTER', found group: '(BEFOREAFTER)' of type: String
    Using pattern ^(.*)x|^(.*) in String '', found group: '()' of type: String
    Using pattern ^(.*)x|^(.*) in String 'null', found group: '(null)' of type: String
    Using pattern null in String 'x', found group: '()' of type: String
    


    Any other way of designing the regex using the Java regex engine?

    Solved
    I found a Stackoverflow entry that solved a similar question here.

    So the solution is now:

    def re = /^(.*?)(?:x.*|$)/
    
    getCaptureGroup(re,"BEFOREAFTER")
    getCaptureGroup(re,"BEFORExAFTER")
    getCaptureGroup(re,null)
    getCaptureGroup(null,"x")
    println ""
    
    def getCaptureGroup(regex, inString){
      def found = ""
    	
      def m = (inString =~ regex)
      if(m){
      	List matches = (List)m[0]		
      	found =  matches[1]
      }	
      
      println "Using pattern $regex in String '$inString', 
        found group: '($found)' of type: ${found.getClass().getSimpleName()}"
    }
    

    Or as one line:
    println ((“BEFORExAFTER” =~ /^(.*?)(?:x.*|$)/)[0][1])

    Further reading

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

    File ASCII Hex Dump using Groovy

    Viewing the bytes of a file is not a common operation. Many most environments and file editors do have tools to do this. Except when they don’t. Like Windows 7, it does not include it, having removed the ‘Dump’ command. Jump to source.

    Intro
    Dumping the bytes of a file is a very simple Programming 101 exercise. Groovy makes this even simpler since it adds the “eachByte()” closure to the java.io.File class. The closure is not just syntax, it hides the closing of the resource. As with any toy problem, it could become more complex as you add more features: showing visible ASCII chars, different byte-endian, code-pages, GUI, and so forth.

    A typical hex dump looks like this:

    OFFSET     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f  | ASCII
    00000000: 4c 69 6e 65 20 6f 6e 65 0d 0a 4c 69 6e 65 20 74  | L i n e   o n e . . L i n e   t 
    00000010: 77 6f 0d 0a 4c 69 6e 65 20 74 68 72 65 65 0d 0a  | w o . . L i n e   t h r e e . . 
    00000020: 21 2f 30 31 32 33 34 0d 0a 35 0d 0a 36 37 38 39  | ! / 0 1 2 3 4 . . 5 . . 6 7 8 9 
    00000030: 41 7a     

    Approach
    Via the ‘eachByte()’ closure on File, we read 16 bytes at a time and store into a list that we then dump. Each output line has a byte offset value, the 16 bytes, and the ASCII representation of those bytes for printable characters.

    Source
    The source is also available at Groovy Hex Dump Gist

    HexDump.groovy

    HexDumpTest.groovy

    TDD
    After I wrote the first version of this I went back to write a JUnit test for it. Could not, it was too complex. Thus, I rewrote it to be testable. Hardly worth it for a throw away script but very instructive. If I had practiced Test Driven Development, this testing issue would not have occurred.

    The trick was to output via a closure that would capture the output: { line -> lines << line}. The list is then analyzed for expected output.

    Lesson: If it is too complex to test, it is too complex.

    File Dump Utilities
    Rather than writing one, it is best to download or use those available in developer tools.

    Linux has the OD command and many others. Some are also available on Cygwin.
    Eclipse has several plug-ins for binary editing, such as the Eclipse Hex Editor Plugin

    Environment

    • Groovy 2.2
    • Windows 7
    • Eclipse 4.3

    References

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

    Use Groovy to recurse folders and create files via template

    Via scripting one can create multiple files in a folder hierarchy and customize the file contents based on the folder location. This can be easily done using the Groovy language.

    Note: In the past “package.html” files were used, but the latest approach is to create “package-info.java” files. These Java files contain the package Javadoc info, and have other uses. Kind of the return of Java classes as configuration as used in the bad ole complex early EJB days.

    In this particular use case, I have a legacy Java project that does not contain package level Javadoc files. There are about a hundred package folders. It would be daunting to create these manually. It is not a mere copy since the package info must contain the specific package declaration: package x.y.z;.

     

    In listing 1 below, the processFolders method takes in a closure “createInfo” and a variable length argument of Strings. The strings are to allow creating the files starting at multiple base folders. With the paths.each{} we take each string and create a File object. Now we recurse all folders at this file location. At each folder in the recursion we invoke the closure.

    import groovy.io.FileType
    
    def processFolders(createInfo, String... paths) {
        paths.each{
            def base = it
            new File(it).eachFileRecurse(FileType.DIRECTORIES){ file -> 
                 def path = file.getPath()
                 println "$path"
                 createInfo(base, path)                                
            }
       }
    }
    
    def templateText = ''' 
    /**
     * TODO Summary.
     * <p>
     * TODO Description.
     */
    package ${pack};
    '''
    
    def template = new groovy.text.SimpleTemplateEngine()
           .createTemplate(templateText)
    
    processFolders({base, p ->
        def pack = (p-base).replace(File.separator, '.')
              .replaceFirst(/^\.+/, '');
        new File(p,"package-info.java").text = template.make(['pack':pack]) 
    }, 'src\\main\\java','src\\test\\java')
    
    
    Listing 1
     

    Because we are using variable length arguments, which must be the last parameter in a method, we can’t use the usual Groovy closure idiom, and define it inline (but maybe there is a way?):

    processFolders(){
       ... body of closure ...
    }
    

    Alternatively, we could have used a named closure instead of inline, as follows:

    def proc = {base, p ->
        def pack = (p-base).replace(File.separator, '.').replaceFirst(/^\.+/, '');
        new File(p,"package-info.java").text = template.make(['pack':pack]) 
    }
    

    At each folder during recurse, we keep the base folder, then later we subtract the folder paths (yup, Groovy allows String subtraction), and convert the folder path into a package string. Then we resolve the template with the binding containing the package name. The String produced by the template is written to a new file via the file’s ‘text’ property.

    The result when run is the creation of package-info.java files at each subfolder, and the package line will be correct. Each file will have two TODO entries for the summary and description. Of course, the same code with minor changes can be used to create package.html files instead. Or just add a switch for ‘old’ or ‘new’ package level info file.

    Updates
    March 4, 2014: Changed to use eachDirRecurse. Not tested yet.
    March 5, 2014: Hmmmm. eachDirRecurse didn’t work.

    Environment

    • Groovy Version: 2.2.2 JVM: 1.7.0_25 Vendor: Oracle Corporation OS: Windows 7
    • Eclipse 4.3
    • Groovy-Eclipse Feature: 2.9.0.xx-20140228-1800-e43-SNAPSHOT

    Some links

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

    Groovy template fails if language keywords used

    While using the SimpleTemplateEngine to process a template with a “$package” expression I got an error. Rename this expression to “$pack” and it works.

    Puzzling. Then I looked at the source code for the template engine. Oops, forgot that Groovy uses script parsing of text to implement many powerful features, like templates. Kind of like extreme EYODF*. Thus, a snippet of the source code for SimpleTemplateEngine shown in listing 1 below, the word “package” is interpreted as the Java language keyword “package“.

    try {
      template.script = groovyShell.parse(script, "SimpleTemplateScript" + counter++ + ".groovy");
    } catch (Exception e) {
      throw new GroovyRuntimeException("Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): " + e.getMessage());
    }
    
    Listing 1

    Below is an example of this.

    def templateText = '''package $package;'''
    
    def engine = new groovy.text.SimpleTemplateEngine(true)
    def template = engine.createTemplate(templateText)
    def binding = ['package':'a/b/c']
    
    def s = template.make(binding)
    println s
    
    Listing 2

    Results in:

    Caught: groovy.lang.GroovyRuntimeException: Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): startup failed:
    SimpleTemplateScript1.groovy: 1: unexpected token: package @ line 1, column 23.
       out.print("""package $package;""");
                             ^
    
    1 error
    

    Now change the expression to $pack:

    def templateText = '''package $pack;'''
    
    def engine = new groovy.text.SimpleTemplateEngine() // pass in true to see debug output
    def template = engine.createTemplate(templateText)
    def binding = ['pack':'a/b/c']
    
    def s = template.make(binding)
    println s
    
    Listing 3

    And, the result is:

    package a/b/c;
    

    Environment

    • Groovy Version: 2.2.2 JVM: 1.7.0_25 Vendor: Oracle Corporation OS: Windows 7
    • Eclipse 4.3
    • Groovy-Eclipse Feature: 2.9.0.xx-20140228-1800-e43-SNAPSHOT

    Some links

    EYODF*: “Eat Your Own Dog Food”

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.

    Enum to Switch on Class types in Java and Groovy

    The Java Switch statement is usually considered a code smell since it’s use can be eliminated by better use of Object Oriented Programming (OOP) design. Nowhere is this more apparent than with a related technique: attempting to switch on Class types by using the instanceof operator.

    Real world
    Unfortunately, in the real world, OOP is sometimes lacking. The code may be using a minimal interface based design. Refactoring, redesigns, or sophisticated OO legerdemain cannot be used in such a project. What’s worse, these projects typically have no unit tests.

    In this situation, one must resort to use of ‘switch’ or nested “if else”. This is a situation I recently encountered with legacy code that used if-else conditionals and instanceof since the target classes had no commonality. I was curious at the alternatives, so wrote up this blog post.

    Important! The examples here do not reproduce the actual usage of the instanceof, wherein inheritance is taken account. See this Stackoverflow article for some info.

    Groovy approach
    In Groovy this is much easier since the switch statement supports much more types to switch on. In listing 1 below we simply use the classes directly. Note that this is not documented anywhere, afaik.

    Groovy Example source
    Listing 1

    package com.octodecillion.experiment
    
    class GroovySwithOnClass {
    
        static main(args) {
            
            switch(Class2.class){
                case Class1.class:
                    assert false
                    break
                case Class2.class:
                    assert true
                    break
                case Class2.class:
                    assert false
                    break
                default:
                    assert false
            }    
        }
        
        public static class Class1{}
    
        public static class Class2{}
    
        public static class Class3{}
    
    }
    

    Now that is sweet and to the point!

    Just to see if possible, one could explicitly switch on a Closure’s hashCode as follows:

    class SwithOnClosure {
    
        static main(args) {
            Closure cl1 = {}
            Closure cl2 = {}
            Closure cl3 = {}
            
            switch(cl2.hashCode()){
                case cl1.hashCode():
                    assert false
                    break
                case cl2.hashCode():
                    println "on cl2"
                    assert true
                    break
                case cl3.hashCode():
                    assert false
                    break
                default:
                    assert false
            }
        }
        
    }
    

    For some more Groovy Enum goodness, the reading list at end gives some more examples.

    Java Approach
    In contrast to the Groovy used above, in Java things get more wordy. Below in listing 2 a JUnit class illustrates two methods of using a switch that acts on Class types.

    Java 7
    The method “testOnJava7” shows that in Java 7 the switch can be on String values, so we just use the fully qualified class name (FQCN) as the case labels. This is not optimal, of course, any change to package or class names would break the switch.

    Unfortunately, you can’t use the class name found by, for example, Class1.class.getName(), to use for the case labels. The case labels must be “constant expressions“. Even creating String “constants” with private final String CLASS1 = …. would not work, afaik.

    Tip: In Java 7 the switch works with:
    • char
    • byte
    • short
    • int
    • Character
    • Byte
    • Short
    • Integer
    • String
    • Enum type
     

    Java 6
    In Java 6, the ‘switch’ is more limited. In method “testOnJava6” we create an Enum ‘Switcher’ that stores the FQCNs of the classes to switch on. To allow the conversion of class name to enum we have to implement the ‘fromString(String className)’ method (learned this in “Effective Java”).

    Java Example source
    Listing 2

    package com.octodecillion.experiment;
    
    import static org.junit.Assert.fail;
    import java.util.HashMap;
    import java.util.Map;
    import org.junit.Test;
    
    /**
     * @author josef betancourt
     */
    public class SwitchOnClass {    
        @Test
        public final void testOnJava7(){        
            switch(Class1.class.getName()){        
                case "com.octodecillion.experiment
                    .SwitchOnClass$Class1":
                    break;                
                case "com.octodecillion.experiment
                    .SwitchOnClass$Class2":
                    fail();
                    break;
                case "com.octodecillion.experiment
                    .SwitchOnClass$Class3":    
                    fail();
                    break;
                default:
                    fail();                    
            }        
        }
    
        @Test
        public final void testOnJava6() {
            switch(Switcher.fromString(Class1.class.getName())){            
                case CLASS1:
                    break;
                case CLASS2:
                    fail();                
                    break;
                case CLASS3:
                    fail();
                    break;                
                default:
                    fail();            
            }        
        }
    
        /** enum type that stores the class names as field */
        public static enum Switcher{        
            CLASS1(Class1.class),
            CLASS2(Class2.class),
            CLASS3(Class3.class);    
            
            private static final Map<String,Switcher>classNameToEnum = 
                 new HashMap<String, Switcher>();
            
            static{
               for(Switcher sw : values()){
                    classNameToEnum.put(sw.className, sw);
                }            
            }
            
            /** convert class name to the enum type */
            public static Switcher fromString(String className){
                return classNameToEnum.get(className);
            }
            
            private String className;
            
            // constructor
            Switcher(Class<?> klass){
                this.className = klass.getName();
            }
            
        } // end enum Switcher
        
        public static class Class1{}
    
        public static class Class2{}
    
        public static class Class3{}    
    }
    

    Alternatives
    1. Don’t do any of the above. Use instanceof to invoke a method specific to the target class. In this way future maintenance and possible OO refactoring can be done. This is possible with the Enum use too, but may be using the Enum for the wrong reason.

    2. An alternative is to change the classes in question to partake in the enum use as shown by Gaʀʀʏ in a Stackoverflow article. This, imho, is not a good approach since it mixes concerns.

    3. Still another approach was suggested by a colleague: switch on the hash code of a class, this would remove the maintenance of an Enum just for use of an instanceof replacement.

    4. An interesting approach is to forgo the use of a switch altogether and just use the enum to invoke type specific behavior. A state machine? See “Avoid switch! Use enum!

    5. Use the Visitor Pattern. However, this assumes you have or can modify the existing classes.

    Updates
    Feb 13, 2014: Changed the format of the post.
    Feb 15, 2014: added example with closures.
    Nov 7, 2015: Interesting discussion on the Guava project, Issue 562, IfElse and Switch Functions. The OP suggested something that would a Predicate and allow multiway conditionals. The commentators said it was not “Java”, so won’t fix.

    Environment

    • Windows 7
    • Eclipse 4.3
    • Java 7
    • JUnit 4
    • Groovy 2.2

    Further reading

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.