вторник, 10 декабря 2013 г.

понедельник, 28 октября 2013 г.

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):
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.

пятница, 20 сентября 2013 г.

groovy switch: nasty bug

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

1
2
3
4
5
6
7
8
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:

1
swtch((int)b)

the program executes "proper" case.

среда, 4 сентября 2013 г.

groovy: switch statement and closure comprehension – nice for DSL

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


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.

среда, 7 августа 2013 г.

Groovy DSL == thermonuclear way of writing XML

The code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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!'
  }
}


produces XML:

1
2
3
4
5
6
7
8
<?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>

Firefox 23: Javascript is always ON

From Firefox 23 Release Notes:
"Enable JavaScript" preference checkbox has been removed and user-set values will be reset to the default
YESSS!!! javascript is now always ON, it is not even possible to turn it off! Other browsers, unite!
Bureaucrats will probably have to reconsider what they mean under Barrierefreiheit.

вторник, 6 августа 2013 г.

Partial interface implementation in groovy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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

четверг, 1 августа 2013 г.

Copy very large files with groovy

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

1
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:
1
2
3
4
void doIt(Map attrs, Object content) {
  println attrs
  println content
}
supports equally valid call syntax variations:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// "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.

среда, 31 июля 2013 г.

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.

вторник, 23 июля 2013 г.

Memory leaks in GradleDaemon?

Just observation: GradleDaemon eats tremendous amout of operating memory (1.5 to 2 GB) after 2 hour uptime and repeated compilation of a large project set (approx. 200 gradle projects). I'm just wondering if it a sign of memory leaks.

Ugly bug in Linux Mint/MATE

Whenever you switch between Firefox and Eclipse (Juno/Kepler) and window-compositing is enabled, Caja crashes. That means: menu and taskbar disappear, all Caja windows are closed. The bug is still not fixed in Linux Mint 15 Olivia. I have to switch to Cinnamon :(

понедельник, 22 июля 2013 г.

пятница, 19 июля 2013 г.

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.

среда, 17 июля 2013 г.

Change in JDK 1.7.0_25 breaks all grails applications:

https://bugzilla.redhat.com/show_bug.cgi?id=976693 

I just tried grails 2.2.3 - the problem is still not fixed, the application fails to start with an error message "Could not determine Hibernate dialect for database name [H2]".

Any workarounds suggesting to replace hibernate libraries don't work.

The following additional parameter allows to start grails:

grails -noreloading run-app

But hey, it's no fun to start in no-reloading mode! Oracle, but things back!

воскресенье, 14 июля 2013 г.

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

I discovered a new 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, since RTFParser expects ContentHandler interface, which is implemented by XmlSlurper).
4. Traverse RTF content groovy-style: each, find, findAll, etc.

Example of code here:
https://gist.github.com/akhikhl/5993538

четверг, 11 июля 2013 г.

Programmatic configuration of slf4j/logback

Now I have experience with programmatic configuration of slf4j/logback.
Task
A program must open separate log file for each processed input file.
Solution for task
Instead of configuring logback via xml, the one needs to “manually” instantiate encoders, appenders and loggers, then configure and link them together.
Caveat 1
Logback goes crazy on attempt to share encoder (i.e. PatternLayoutEncoder) between appenders.
Solution for caveat 1
Create separate encoder for each appender.
Caveat 2
Logback refuses to log anything, if encoders and appenders are not associated with logging context.
Solution for caveat 2
Call setContext on each encoder and appender, passing LoggerFactory as a parameter.
Caveat 3
Logback refuses to log anything, if encoders and appenders are not started.
Solution for caveat 3
encoders and appenders need to be started in the correct order, i.e. first encoders, then appenders.
Caveat 4
RollingPolicy objects (i.e. TimeBasedRollingPolicy) produce strange error messages like “date format not recognized”, when they are not attached to the same context as appender.
Solutin for caveat 4
call setContext on RollingPolicy same way as on encoders and appenders.

Here is working example of “manual” logback configuration:
https://gist.github.com/akhikhl/5977126

My conclusion: logback is much easier to configure via XML. “Manual” configuration is rather tedious task and should be avoided, unless it is dictated by project needs.

среда, 10 июля 2013 г.

Disappointment with groovy/XmlSlurper

Greatest disappointment with groovy/XmlSlurper: it does not read/interpret XML comments. Quite critical for massive XML processing/transformations, when it is necessary to keep change delta to minimum.
In the last project I had to recede to JDOM2 - it reads, interprets and writes XML comments without problems. Sad, volume of code doubles compared to XmlSlurper.

пятница, 5 июля 2013 г.

groovy XmlParser and XmlSlurper

I am absolutely astonished by functionality of groovy classes XmlParser and XmlSlurper. The both are similar to each other, with one important difference: XmlParser is more DOM-like (all data in memory), while XmlSlurper is more SAX-like (data parsing delayed until needed).
The most charming thing is how both work together with closures, regexps and collection methods. I am seriously thinking about shifting all XML-specific code to these facilities.
http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlParser 
http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlSlurper

пятница, 14 июня 2013 г.

Meet Gretty: gradle plugin for running web-applications under Jetty 8.1.8

I created little gradle plugin for running web-applications under Jetty 8.1.8.

The main advantage for a programmer is that now it’s possible to use servlet-api 3.0 and higher (under standard gradle-jetty plugin it was not possible, because jetty was too old).

Full sources, documentation and examples here:

https://github.com/akhikhl/gretty

пятница, 7 июня 2013 г.

Gradle script: multiproject git-gradle management

Suppose you build your software project from many open-source components, most of which are already available via git. How to automate clone/pull/build/install cycle, especially across projects from different git-repositories? How to establish high-level inter-project dependencies?

For that I wrote gradle script, which implements multiproject git-gradle management. It works as follows: you write configuration file, name it “config.gradle”, put it to the same folder as “build.gradle” (of multiproject git-gradle) and then run “gradle build”.

Full documentation and sources are available at:
https://github.com/akhikhl/multiproject-git-gradle

четверг, 6 июня 2013 г.

Automated git-pull

Suppose you have 20 git-repositories, which you actively pull and push from/to central location (e.g. github). Don't you think pulling them by hand is too mechanical? And what if you forget to pull some?

I wrote little gradle script capable of automated git-pull:

https://gist.github.com/akhikhl/5727210

You drink your morning coffee and the machine does the job for you.

Credits come to the creators of excellent gradle-git plugin:

https://github.com/ajoberstar/gradle-git

среда, 5 июня 2013 г.

Programming for fun: script for batch installation of maven artifacts

I created gradle script that delivers batch installation of maven artifacts to local maven repository (source code here: https://github.com/akhikhl/contribs).

The script supports two tasks - installContribs and cleanContribs - but can be extended with additional tasks (for example, implementing deployment to corporate repo).

how installContribs task works:

1. you call it with the command-line:

gradle -b contribs.gradle 
(or you rename script to "build.gradle" and just put it somewhere in the multi-project tree, it will be called by gradle automatically).

2. installContribs task iterates the current folder (where the script resides) and all it's subfolders.

3. in each folder it iterates files with extension "pom".

4. for each found pom-file it looks for ".jar", "-sources.jar" and "-javadoc.jar" and install all found files (together with pom) to the local maven repository.

5. pom-file without jars will be installed as an artifact on it's own. Typical use-case: installation of parent-poms and aggregator-poms.

The script accurately calculates inputs/outputs. If all files were not changed since the last installation, it does not install anything and shows "UP-TO-DATE" in the console.

cleanContribs task makes script "forget" about the time of the last artifact installation. As the result, running script with installContribs task will install all artifacts anew.

Programming for fun: script for mass checksum (MD5 and SHA1) calculation in the file system.

I created little gradle script for mass checksum (MD5 and SHA1) calculation in the file system:

https://github.com/akhikhl/checksums

At the beginning that was more like exercise in using gradle for non-compilation tasks and in integrating apache-commons into gradle script.

Now, I think, I will do more gradle than bash, because gradle scripts are: a) portable b) have access to limitless power of all java libraries.

воскресенье, 2 июня 2013 г.

суббота, 1 июня 2013 г.

checkableRows example (jQuery)

Example of checkableRows, selectableRows and focusable behavior

Example of checkableRows, selectableRows and focusable behavior.

Use mouse, UP, DOWN and SPACE keys.
Allow multiple selection (click with CTRL or SHIFT key).
Product IdArtistAlbumYearI like it
001BeatlesPlease Please Me1963
002BeatlesA Hard Day's Night1964
003BeatlesYellow Submarine1969
004Rolling StonesDecember's Children (And Everybody's)1965
005Rolling StonesBeggars Banquet1968
006Rolling StonesGoats Head Soup1973
Selected product Ids: []
Checked product Ids: []
Log:
If you feel interested, see checkableRows source code and documentation and more examples on a separate page.

четверг, 30 мая 2013 г.

Sash/splitter example (javascript)

jQuery Sash Plugin example I created jQuery Sash Plugin. This example demonstrates how it works. Just drag gray bar to left and right.
left panel
right panel
If you feel interested, see source code and documentation and more examples on a separate page.

среда, 29 мая 2013 г.

selectableRows behavior (javascript)

Simplest example of selectableRows behavior
Example of selectableRows behavior on table element. Click within the table to see how it works.
ArtistAlbumYear
BeatlesPlease Please Me1963
BeatlesA Hard Day's Night1964
BeatlesYellow Submarine1969
Rolling StonesDecember's Children (And Everybody's)1965
Rolling StonesBeggars Banquet1968
Rolling StonesGoats Head Soup1973
If you feel interested, have a look at the source code and documentation
See more examples of selectableRows on a separate page.

focusable behavior (javascript)

Simplest example of focusable behavior
Below is the simplest example of "focusable" behavior. Three divs have "focusable" class and can get "focused" class from mouse clicks or from keyboard navigation to nested elements.
If you feel interested, have a look at the source code and documentation
See also this example on a separate page.