Tuesday, June 14, 2016

Legacy DB, Grails & Domain Classes

When having to build Grails apps around a legacy DB, this plugin is a great start.

The DB reverse engineer plugin (works with Grails 3)

It is a good idea to create a Integration test to just check you can access these tables. The integration test will be run on your development envrionment and you will need to have some data in there. Be careful obviously as it is bad practise to rely on existing data, but this helped me get all the mappings properly wired up.
Start with something as simple as:
package com.webtracker.api.prodcat

import com.webtracker.api.Company
import com.webtracker.api.Project
import com.webtracker.api.WpActivationKey
import grails.test.mixin.integration.Integration
import grails.transaction.Rollback
import spock.lang.Specification

/**
 * Sanity domain Integration tests, uses development DB
 *
 * Created by demian on 14/06/16.
 */
@Integration
@Rollback
class DomainSpec extends Specification{

    def setup() {
    }

    def cleanup() {

    }

    void "Can we list and load an activation key"() {
        when:
        def keys = WpActivationKey.list()
        def key1 = WpActivationKey.get keys[0].id
        def key2 = WpActivationKey.findByActivationKey keys[0].activationKey

        then:
        keys.size() > 0
        key1 == key2

    }

    void "Can we list and load a company"() {
        when:
        def companies = Company.list()
        def company1 = Company.get companies[0].id
        def company2 = Company.findByName companies[0].name

        then:
        companies.size() > 0
        company1 == company2
    }

    void "Can we list and load a project"() {
        when:
        def projects = Project.list()

        then:
        projects.size() > 0
    }
}

I ran into a few stumbling blocks, all easily overcome
In my case the auto timestamping did not work out the box (as column names where different), but that was incredibly easy to fix.

Here is my Domain Class snippet
 Date dateCreated
 Long projectId

 static mapping = {
  version false
 }

 static constraints = {
  activationKey maxSize: 100, unique: true
        dateCreated column: 'created_date'
 }

I started getting this error
Caused by: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp
This is because that is a valid SQL date but not in Gorm, this was fixed by appending the following to application.yml datasource:url: connection string
?zeroDateTimeBehavior=convertToNull

Intellij YES

After years of working in Eclipse and Sublime 3 I decided to give Intellij a chance. I am very impressed.
I am not much of a fan of IDE's that do a lot of magic as I find it leads to lazy programming, and Intellij does a LOT of magic. But it is very very good at it's magic.
The plugins are of superb quality.
So impressed I bought it.
It even has groovy repl debugging
I also find it faster than eclipse (though I did recently change to an SSD, but I also used it on a regular HD) It also works great in Ubuntu

Back in Grails World and So Happy (Interceptor)

I have the opportunity to develop some in Grails again and I am just so happy. Just a breath of fresh air.

Had to build a simple token authentication for a restful web service.

Ended up with this code using the Grails 3 Interceptor.
I find it readable, concise and clear. (By the way generated this code below with hilite.me great tool)
package com.webtracker.api.prodcat

import grails.compiler.GrailsCompileStatic
import grails.converters.JSON
import org.apache.catalina.connector.Response

/**
 * This method is expensive as it can be called before every controller
 */
@GrailsCompileStatic
class TokenInterceptor {

    TokenInterceptor() {
        matchAll()
    }

    boolean before() {
        if (params?.apikey) {
            WpActivationKey key = WpActivationKey.findByActivationKey(params?.apikey)
            if (key) {
                true
            } else {
                response.status = Response.SC_FORBIDDEN
                render([errors: ['api key not valid']] as JSON)
                false
            }
        } else {
            response.status = Response.SC_FORBIDDEN
            render([errors: ['no api key specified']] as JSON)
            false
        }
    }

    boolean after() {
        true
    }

    void afterView() {
        // no-op
    }
}

Just remember to make your Domain class cacheable so you do not have to query all the time
@Cacheable("activationKeys")

Monday, May 25, 2015

Functional Thinking with Neal Ford

Pretty basic stuff, but I enjoyed watching it. He tries to stick to mostly Java. Touches on some interesting variables & Clojure stuff towards the end. https://www.youtube.com/watch?v=JeK979aqqqc

Thursday, April 16, 2015

A little more on Scala Futures

After continuing the article and continuing to functional compositions and the flatmap.

I thought it helpful to include my Eclipse worksheet code, which can be played with and run.


import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try,Success,Failure}

object Actors3 {
  println("Actors3----")
  
  val r = scala.util.Random
  
  val usdQuote = future {
    Thread.sleep(1000)
    r.nextInt(10)
  }
  val canQuote = future {
    Thread.sleep(1000)
    r.nextInt(10)
  }

  val purchase = for {
    usd <- usdQuote
    can <- canQuote
    if (can > usd)
  } yield "Can Strong"
  
  purchase onSuccess {
    case e => println(s"e1=${e}")
  }

  println("This is the most interesting")
  val purchase2 = usdQuote flatMap {
    usd => canQuote.withFilter(can => (can > usd)).map(can => "Can Strong")
  } recover {
    case _ => "Falsies"
  }
  
  println(s"purchase2=${purchase2}")
  purchase2 onSuccess {
    case e => println(s"e2=${e}")
  }
  Thread.sleep(4000)
  println("End----")
}

Wednesday, April 15, 2015

Scala & Play

Just learnings in Scala. Some decent resources
http://danielwestheide.com/scala/neophytes.html
And the Book Scala for the Impatient
http://www.horstmann.com/scala/index.html

Scala Futures

A nice walkthrough of Futures what they are in Scala and how to use them
http://docs.scala-lang.org/overviews/core/futures.html

In Eclipse the following Worksheet code can be executed based on the examples. You can run in a worksheet to see the async calls all come back at the same time.


import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.util.{Try,Success,Failure}

object Actors {
  println("Actors----")                           
  val r = scala.util.Random                       
  
  def getAmount(): Int = {
    Thread.sleep(3000)
    r.nextInt(10)
  }                                               
  println("Lets do three getAmount which take 3 seconds each")
                                                  
  val f1: Future[Int] = future {
    getAmount()
  }
  val f2: Future[Int] = future {
    getAmount()
  }
  val f3: Future[Int] = future {
    getAmount()
  }

  println("OnComplete starts")                    
  f1 onComplete {
    case Success(ans) => println(s"1.ASYNC COMPLETED : ${ans}")
    case Failure(t) => println(s"ERROR : ${t}")
  }
  f2 onComplete {
    case Success(ans) => println(s"2.ASYNC COMPLETED : ${ans}")
    case Failure(t) => println(s"ERROR : ${t}")
  }
  f3 onComplete {
    case Success(ans) => println(s"3.ASYNC COMPLETED : ${ans}")
    case Failure(t) => println(s"ERROR : ${t}")
  }
  
  println("Wait")                                 
  Thread.sleep(4000)                              
  println("Wait Over")                            
  println("Doing syncronously takes long")        
  println(getAmount())                           
  println(getAmount())                            
  println(getAmount())                            
  
  
  println("Composition----Callback")              
  val amount = future {
    getAmount()
  }
  Thread.sleep(4000)
  amount onSuccess { case a =>
    val purchase = future {
      if (a >= 5) "BUY"
       else "SELL"
    }
    purchase onSuccess {
      case a => println(s"purchase [${a}]")
    }
  }
  Thread.sleep(1000)                              

  println("Composition----Map")                   
  val amount2 = future {
    getAmount()
  }
  Thread.sleep(4000)
  
  val purchase = amount2 map { a =>
    if (a >= 5) "BUY"
    else "SELL"
  }
  purchase onSuccess {
    case a => println(s"purchase [${a}]")
  }
  
  println("End----")
}