Now, there is nothing sexy about this post - it is not cutting edge, there is no big data involved, no AI, just simple tools that I think make a software engineer's life happier and fun.
I have embraced some parts of functional programming in Java 8 - sometimes it is quite difficult to read and debug - but it is clear and concise - less error prone - you know the usual shebang.
I still think that Scala has an edge over Java 8 - but I must say that I cannot wait for Scala 2.12 - as the binary compatibility and compilation speed are big issues.
The Scala IDE is great - but not there yet if you ask me, and I would hate to go and use IntelliJ - just not the tool for me.
This post is about using Scala with Maven, and some really cool stuff using Scalatra and jOOQ to build a simple RESTful server.
pom.xml
All you need for dependencies in one epic pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Pento</groupId> <artifactId>PentoPay</artifactId> <version>1.0</version> <build> <pluginManagement> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>3.2.1</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <executions> <execution> <id>scala-compile-first</id> <phase>process-resources</phase> <goals> <goal>add-source</goal> <goal>compile</goal> </goals> </execution> <execution> <id>scala-test-compile</id> <phase>process-test-resources</phase> <goals> <goal>testCompile</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <executions> <execution> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>3.7.3</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-meta</artifactId> <version>3.7.3</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-codegen</artifactId> <version>3.7.3</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-scala</artifactId> <version>3.7.3</version> </dependency> <dependency> <groupId>org.scalatra</groupId> <artifactId>scalatra_2.11</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> <version>9.3.8.v20160314</version> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> <version>9.3.8.v20160314</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> <version>10.12.1.1</version> </dependency> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.12.1.1</version> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>2.4.5</version> </dependency> </dependencies> </project>
Scalatra
Using Scalatra, the bootstrap class (with Guice Module for DI), the servlet definition and the launcherimport javax.servlet.ServletContext import com.google.inject.Guice import org.pento.services.{PingModule, PingService} import org.scalatra.LifeCycle class ScalatraBootstrap extends LifeCycle { private lazy val injector = Guice.createInjector(new PingModule()) override def init(context: ServletContext): Unit = { context mount (injector.getInstance(classOf[PingService]), "/main-service/") } }
package org.pento.services import java.time.Clock import com.google.inject.{AbstractModule, Provides, Singleton} class PingModule extends AbstractModule { override def configure(): Unit = { bind(classOf[PingService]).asEagerSingleton() } @Provides @Singleton def provideClock() = Clock.systemUTC() }
package org.pento.services import java.time.Clock import javax.inject.Inject import org.scalatra.ScalatraServlet class PingService @Inject() (val clock: Clock) extends ScalatraServlet { get ("/ping") { clock.millis() } }
package org.pento.services import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.DefaultServlet import org.eclipse.jetty.webapp.WebAppContext import org.scalatra.servlet.ScalatraListener object PentoServer { val server = new Server(5899) val context = new WebAppContext() context.setContextPath("/") context.setResourceBase("src/main/scala") context.addEventListener(new ScalatraListener) context.addServlet(classOf[DefaultServlet], "/") server.setHandler(context) server.start() server.join() def main(args: Array[String]) { } }Neat. Simple.
Now to the database and jooq code generation
Who writes SQL those days? Well we have to.. but not in the code. jOOQ is probably one of the best libs I have used from Java and SCALA. Here is a simple jOOQ config that generates code from a given existing schema<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <configuration> <!-- Configure the database connection here --> <jdbc> <driver>org.apache.derby.jdbc.ClientDriver</driver> <url>jdbc:derby://localhost:1527/C:/Users/tj/Google Drive/IT-Projects/PentoPay/derby/PentoDb;create=true</url> <user>APP</user> <password>*</password> </jdbc> <generator> <name>org.jooq.util.DefaultGenerator</name> <database> <name>org.jooq.util.derby.DerbyDatabase</name> <inputSchema>APP</inputSchema> <includes>.*</includes> </database> <generate> <relations>true</relations> <deprecated>false</deprecated> <generateAnnotation>true</generateAnnotation> <records>true</records> <immutablePojos>true</immutablePojos> <globalObjectReferences>true</globalObjectReferences> <fluentSetters>false</fluentSetters> </generate> <target> <packageName>jooq.pento.db</packageName> <directory>C:/Users/tj/Google Drive/IT-Projects/PentoPay/src/main/java</directory> </target> </generator> </configuration>Some very nice utility classes to manage AutoCloseable and some fancy resource management (take back the jdbc connection to the pool post request). The code below allows automatically call close on an AutoCloseable
def using[T <: AutoCloseable, R](resource: T)(block: T => R): R = { try { block(resource) } finally { if (resource != null) resource.close() } }The one below deals specifically with jOOQ DSL Context:
override def withSession[R](block: (DSLContext) => R): Option[R] = { import org.pento.utils.PentoUtils.using using(ds.getConnection) {connection => try { Some(block(DSL.using(connection, sqlDialect, jooqSettings))) } catch { case t: Throwable => None } } } // withSessionAll in one, how to do a simple query. This is quite neat.
package org.pento.db import com.google.inject.Inject import com.zaxxer.hikari.HikariDataSource import jooq.pento.db.tables.records.LastaccessRecord import org.jooq.conf.Settings import org.jooq.impl.DSL import org.jooq.{DSLContext, SQLDialect} import org.pento.utils.LastAccess trait DataSource { def withSession[R](block: DSLContext => R): Option[R] } class DataSourceImpl @Inject() () extends DataSource { val ds = { val hds = new HikariDataSource() hds.setDriverClassName("") hds.setJdbcUrl("") hds.setUsername("") hds.setPassword("") hds } val sqlDialect = SQLDialect.valueOf("DERBY") val jooqSettings = new Settings() override def withSession[R](block: (DSLContext) => R): Option[R] = { import org.pento.utils.PentoUtils.using using(ds.getConnection) {connection => try { Some(block(DSL.using(connection, sqlDialect, jooqSettings))) } catch { case t: Throwable => None } } } // withSession } trait DB { def allAccesses: Option[List[LastAccess]] } class DBImpl @Inject() (val ds: DataSource) extends DB { override def allAccesses: Option[List[LastAccess]] = { import jooq.pento.db.tables.Lastaccess.LASTACCESS import scala.collection.JavaConversions._ ds.withSession{ctx => { val rs = ctx.select(LASTACCESS.TS) .from(LASTACCESS) .fetchInto(classOf[LastaccessRecord]) (for{r <- rs} yield LastAccess(r.value1())).toList }} } }
No comments:
Post a Comment