mercredi 27 décembre 2017

Kotlin To Javascript and Grails 3.3.2

Here is some sections of the build.gradle file we use for Grails 3.3.2 application, using the kotlin-gradle-plugin.

Both assemble and bootRun works fine. Assemble task generates the war file with javascript assets plugin being activated, and used after compileKotlin2Js task.

buildscript {
    ext.kotlin_version = "1.2.10"//'${kotlinVersion}'
    ext.web_dir = "grails-app/assets/javascripts/kt"
    /* . . . */
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        /* . . . */
        classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.7"
    }
}

/* . . . */
apply plugin: 'kotlin2js'
/* . . . */
apply plugin: "asset-pipeline"
/* . . . */

repositories {
    mavenLocal()
    jcenter()
    maven { url "http://repo.grails.org/grails/core" }
}

dependencies {
    assets "com.craigburke.angular:angular-template-asset-pipeline:2.3.0"
    assets "com.craigburke.angular:angular-annotate-asset-pipeline:2.4.0"
    /* . . . */
    runtime 'com.bertramlabs.plugins:asset-pipeline-grails:2.14.7'
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

assets {
    minifyJs = true
    minifyCss = true
    enableSourceMaps = false
    configOptions = [:] //useful for custom config on extension libraries
    minifyOptions = [
            optimizationLevel: 'SIMPLE',
            angularPass      : true
            // Can use @ngInject annotation for Angular Apps
    ]
    includes = []
    excludes = ['**/*.less'] //Example Exclude GLOB pattern
    packagePlugin = false //set to true if this is a library
    developmentRuntime = true
    jarTaskName = null
}

/* Kotlin javascript section +++ */
//sourceSets {
//    main.kotlin.srcDirs += "src/main/kotlin"
////    test.kotlin.srcDirs += "src/test/kotlin"
//}


//compileKotlin2Js {
//    kotlinOptions.outputFile = "${projectDir}/${web_dir}/MyApp.js"
//    kotlinOptions.moduleKind = "amd"
//    kotlinOptions.sourceMap = true
//}

task assembleWeb(type: Sync) {
    // Copy kotlin.js and kotlin-meta.js from jar into web directory
    configurations.compile.grep { File file ->
        file.name.startsWith("kotlin")
    }.each { File file ->
        copy {
            includeEmptyDirs = false
            def pff = zipTree(file)
            from pff
            include "*.js"
            into "${projectDir}/${web_dir}"
        }
    }
}

compileKotlin2Js.doLast() {
    copy {
        includeEmptyDirs = false
        from new File("build/classes/main")
        include "*.js"
        into "${web_dir}"
    }
}

assetCompile.dependsOn compileKotlin2Js
assetCompile.dependsOn assembleWeb
/* Kotlin javascript section --- */
/* . . . */

The important part is surrounded by "Kotlin Javascript Section" comments. 

You cannot set kotlinOptions.outputFile, because it will copy all the content of the "build/classes/main" directory into the assets directory (which is very annoying in case of Grails applications).

You have to copy "*.js" files from  "build/classes/main" directory into the assets folder you have chosen.

Usually, I would have open a bug report against this Gradle plugin for this kind of behavior, but I do not know Gradle deeply enough, and I am confused with the Intellij bug tracker system. 

Hope this helps someone!

mercredi 6 septembre 2017

Kotlin to Javascript, Gradle (Grails 3)

It is challenging to make all those happy things working together.

First, because like me, you are too lazy to read the complete Gradle stuffs, and second, because if you read Kotlinlang website, dedicated sections related to this subject, it will not work :/ .

TL; TR, here is the build.gradle file sections modified for Kotlin2Js to be alive:


buildscript {
    ext.kotlin_version = "1.1.4-3"//'${kotlinVersion}'    
    ext.web_dir = "grails-app/assets/javascripts/kt"    

[. . .]
    dependencies {

        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
} [. . .] apply plugin: 'kotlin2js' [. . .] dependencies { [. . .] compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"}
    [. . .]
assets {
    [. . .] // Nothing to change
}
/* Kotlin javascript section +++ */ clean.doFirst() { delete("${web_dir}") }
build.doLast() {
        // Copy kotlin.js and kotlin-meta.js from jar into web directory    configurations.compile.each { File file ->
        configurations.compile.each { File file ->
        copy {
includeEmptyDirs = false from zipTree(file.absolutePath)
            into "${projectDir}/${web_dir}"
            include "*.js"
} } } compileKotlin2Js.doLast() { copy { includeEmptyDirs = false from new File("build/classes/main")
        include "*.js"
        into "${web_dir}"    }
        }
}
/* Kotlin javascript section --- */ bootRun { jvmArgs('-Xmx3064m', '-Dspring.output.ansi.enabled=always', '-server') } runCommand { jvmArgs('-Xmx8064m', '-Dspring.output.ansi.enabled=always', '-server') }

Assets plugin will compact the JavaScript code as expected.

If you are feed up with AngularJS, 2, 4, AngularDart ... and other Javascript FW who wants to rule the world with MVVMC and others, give Kotlin and simple DOM manipulation a chance! Everything is not perfect, but I used to enjoy static code analysis, to avoid bad behavior at runtime.

You will benefit almost simple Gradle integration (which is not yet available in Dart), IDE more efficient auto-completion, with real static analysis (AngularTS massive JSON uses, makes it more difficult).

mardi 21 juillet 2015

Grails 3 and Spring boot security with Secured annotation

It is possible to use Spring Boot Security in order to replace Spring Security Core plugin. This is explained in two blog post:

Grails 3 App with Security (Part 1)
Grails 3 App with Security (Part 2) - Gorm-based authentication

However, if you want to use the Secured annotation, you have to care about 2 things:

  • Roles names have "ROLE_" string prepended to the role name you create with the "AuthenticationManagerBuilder"
  • Add simply "@EnableGlobalMethodSecurity(securedEnabled = true)" annotation to the SecurityConfiguration class
All in all, here is a sample controller:

package test

import org.springframework.security.access.annotation.Secured
class ToProtectController {

    @Secured(value = ["ROLE_USER"])
    def index() {
        println session.SPRING_SECURITY_CONTEXT?.getAuthentication()?.getPrincipal()

        render "index"    }

    def toto() {
        render 'toto'    }
}
 A sample WebSecurityConfigurerAdapter:


@Configuration@EnableWebMvcSecurity@EnableGlobalMethodSecurity(securedEnabled = true)class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers('/admin*//**').hasAnyRole('ADMIN')
                .antMatchers('/home*//**').hasAnyRole('USER', 'ADMIN')
                .antMatchers('/').permitAll()
                .and()
                .formLogin().permitAll()
                .and()
                .logout().permitAll()
    }
    
    @Autowired    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser('user').password('user').roles('USER')
                .and()
                .withUser('admin').password('admin').roles('ADMIN');
    }
}
 Notice the "EnableGlobalMethodSecurity" annotation.

Hope this helps!


mardi 16 décembre 2014

Mageia 5 systemd-nspawn

A killer feature of systemd is systemd-nspawn. From the man page, "Spawn a namespace container for debugging, testing and building", it is a kind of chroot on steroids, I feel, not limited to "testing and building", but with some care, can be used for production apps. There is little or no resources on how to use this tool on Mageia linux distribution which integrates systemd since a long time (Mandriva integrated Systemd before Mageia fork even exists).

Archlinux provides a rich set of docs which are a good practical starting point. This blog entry mostly adapt the systemd container pages to Mageia


The main differences between Archlinux and Mageia regarding these documents are the packaging system and the network configuration. The Mageia chroot page explain how to populate a directory (lets use a btrfs one) with base system with minimum configuration.

Lets suppose you have a directory named "mageia", first add all media:
  # urpmi.addmedia --distrib --urpmi-root mageia 
  ftp://mirror.netcologne.de/mageia/distrib/cauldron/x86_64/

Then install basesystem and other packages needed for your application:
  # urpmi  --urpmi-root mageia basesystem
  # urpmi  --urpmi-root mageia java

You have to create a regular user (i.e. other than root, which you can log with) and set the root passwd in the chroot environment (I did not succeed to log directly as root).

Log as root without booting
  # cd mageia
  # systemd-nspawn -D .

Change the root passwd in the chroot 
  # passwd

Add regular user in chroot and exit
  # createuser test
  # exit

You can now launch the container and log in using the regular user you just created
   # systemd-nspawn -bD .

To adapt network configuration from the Archlinux page, I do have to remove the default route that was created for br0 on Magiea. This is depending on your configuration, so it is better to check if nothing strange appears in your route after having started systemd-networkd service.

You can even copy the chroot directory on a Debian installation to use your Mageia chroot on your Debian (and vice-versa). 

Grails webflow plugin integration test sample

It is difficult to find resources up to date about how to write Grails Webflow integration tests. You would lose precious time reading internet entries you would better invest in writing integration tests.

I am using Grails 2.4.3, the latest Webflow plugin and Spring security plugin which I want to test along with the flow.

package reportbyorigin

import grails.test.mixin.TestMixin
import grails.test.mixin.webflow.WebFlowUnitTestMixin

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder

import spock.lang.*
import taackaccess.User

@TestMixin(WebFlowUnitTestMixin)
class AllControllerSpec extends GroovyTestCase {

    void setUp() {
        User admin = User.findByUsername("admin")
        Authentication auth =
          new UsernamePasswordAuthenticationToken(admin, null)
          SecurityContextHolder.context.authentication = auth
    }

    def cleanup() {
    }

    void "test flow user instance"() {
        mockController(AllController)
  
        when: "user login"
            statEntryFlow.putDatasOnFlow.action()

        then: "test flow values"
            flow.loggedUser instanceof User
    }
}

The tricky parts are "void setUp()" instead of "def setup()", "extends GroovyTestCase" instead of all you can read on the internet, "mockController(<yourcontroller>)".

Hope this sample will help someone.