<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4576039096616564465</id><updated>2012-02-16T07:55:50.183+01:00</updated><title type='text'>compmoc blog</title><subtitle type='html'>A pragmatic scala blog by a Scala enthusiast</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.crosson.org/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default'/><link rel='alternate' type='text/html' href='http://www.crosson.org/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default?start-index=26&amp;max-results=25'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-2879869280930996613</id><published>2012-02-01T21:53:00.002+01:00</published><updated>2012-02-01T21:53:51.710+01:00</updated><title type='text'>Small script to update &amp; compile a list of svn project</title><content type='html'>Scala script skeleton to update a set of subversion projects.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec scala -deprecation -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;// ======================================================================&lt;br /&gt;import sys.process.Process&lt;br /&gt;import sys.process.ProcessBuilder._&lt;br /&gt;&lt;br /&gt;case class CurDir(cwd:java.io.File)&lt;br /&gt;implicit def stringToCurDir(d:String) = CurDir(new java.io.File(d))&lt;br /&gt;implicit def stringToProcess(cmd: String)(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;implicit def stringSeqToProcess(cmd:Seq[String])(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;&lt;br /&gt;implicit var cwd:CurDir=scala.util.Properties.userDir&lt;br /&gt;def cd(dir:String=util.Properties.userDir) = cwd=dir&lt;br /&gt;// ======================================================================&lt;br /&gt;&lt;br /&gt;val updateList=List("project1", "project2", "project3")&lt;br /&gt;&lt;br /&gt;for(dir&lt;- updateList) {&lt;br /&gt;  println("----------------------------------------")&lt;br /&gt;  println("Processing %s".format(dir))&lt;br /&gt;&lt;br /&gt;  cd(dir)&lt;br /&gt;&lt;br /&gt;  "svn update" !&lt;br /&gt;&lt;br /&gt;  "sbt eclipse compile" !&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-2879869280930996613?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/2879869280930996613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/02/small-script-to-update-compile-list-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/2879869280930996613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/2879869280930996613'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/02/small-script-to-update-compile-list-of.html' title='Small script to update &amp; compile a list of svn project'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-195038438885724173</id><published>2012-01-30T23:30:00.003+01:00</published><updated>2012-01-30T23:42:59.016+01:00</updated><title type='text'>Simplifying scala scripts : Adding #include support to your scripts</title><content type='html'>Test a #include support example by executing the following 5 lines :&lt;pre class="brush: bash;highlight: []"&gt;&lt;br /&gt;$ wget http://dnld.crosson.org/bootstrap.tar.gz&lt;br /&gt;$ tar xvfz bootstrap.tar.gz&lt;br /&gt;$ cd bootstrap&lt;br /&gt;$ sbt assembly&lt;br /&gt;$ ./scripts/test.scala&lt;br /&gt;&lt;/pre&gt;The test.scala example script is the following :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;DIRNAME=`dirname "$0"`&lt;br /&gt;exec java -jar "$DIRNAME"/bootstrap.jar "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;#include "shell.scala"&lt;br /&gt;&lt;br /&gt;cd("/etc/")&lt;br /&gt;&lt;br /&gt;"ls" #| "grep net" !&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;go to /etc directory, and prints files which contain net keyword in their names.&lt;br/&gt;&lt;br/&gt;test.scala script includes the following file : scripts/include/shell.scala&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;import sys.process.Process&lt;br /&gt;import sys.process.ProcessBuilder._&lt;br /&gt; &lt;br /&gt;case class CurDir(cwd:java.io.File)&lt;br /&gt;implicit def stringToCurDir(d:String) = CurDir(new java.io.File(d))&lt;br /&gt;implicit def stringToProcess(cmd: String)(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;implicit def stringSeqToProcess(cmd:Seq[String])(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;&lt;br /&gt;implicit var cwd:CurDir=scala.util.Properties.userDir&lt;br /&gt;def cd(dir:String=util.Properties.userDir) = cwd=dir&lt;br /&gt;&lt;/pre&gt;This file contains some definitions to make possible for the user to change current directory.&lt;br/&gt;&lt;br/&gt;All the include mechanism logic in defined as follow :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;package fr.janalyse.script&lt;br /&gt;&lt;br /&gt;import scala.tools.nsc.ScriptRunner&lt;br /&gt;import scala.tools.nsc.GenericRunnerCommand&lt;br /&gt;import scala.io.Source&lt;br /&gt;import java.io.File&lt;br /&gt;&lt;br /&gt;object Bootstrap {&lt;br /&gt;  val defaultOptions = List("-nocompdaemon","-usejavacp","-savecompiled", "-deprecation")&lt;br /&gt;  val defaultExpandedScriptExt = ".pscala"&lt;br /&gt;  &lt;br /&gt;  val includeRE = """\s*#include\s+"(.+)"\s*"""r&lt;br /&gt;  &lt;br /&gt;  def expand(file:File, availableIncludes:List[File]) : List[String] = {&lt;br /&gt;    val content=Source.fromFile(file).getLines().toList&lt;br /&gt;    // First we remove "shell" startup lines, everything between #! and !#&lt;br /&gt;    val cleanedContent = content.indexWhere { _.trim.startsWith("!#") } match {&lt;br /&gt;      case -1 =&gt; content&lt;br /&gt;      case i  =&gt; content.drop(i+1)&lt;br /&gt;    }&lt;br /&gt;   // Then we expand #include directives&lt;br /&gt;   cleanedContent flatMap {&lt;br /&gt;     case includeRE(filename) =&gt;&lt;br /&gt;       val fileOpt = availableIncludes find {_.getName() == filename}&lt;br /&gt;       fileOpt orElse {&lt;br /&gt;          throw new RuntimeException("%s : Couln't find include file '%s' ".format(file.getName, filename))&lt;br /&gt;       }&lt;br /&gt;       fileOpt map { file =&gt; expand(file, availableIncludes)} getOrElse List.empty[String]  &lt;br /&gt;     case line =&gt; line::Nil&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;    &lt;br /&gt;  def main(cmdargs:Array[String]) {&lt;br /&gt;    val command = new GenericRunnerCommand(defaultOptions ++ cmdargs.toList)&lt;br /&gt;    val scriptDir = new File(cmdargs(0)).getParentFile()&lt;br /&gt;    val includePath = List(new File(scriptDir, "include"), scriptDir)&lt;br /&gt;    val availableIncludes = includePath filter {_.exists()} flatMap {_.listFiles()}&lt;br /&gt;    val scriptname = command.thingToRun &lt;br /&gt;    val script = new File(scriptname)&lt;br /&gt;    val richerScript = new File(scriptname.replaceFirst(".scala", defaultExpandedScriptExt))&lt;br /&gt;    &lt;br /&gt;    if (script.exists()) {&lt;br /&gt;      val jars = util.Properties.javaClassPath.split(File.pathSeparator) map {new File(_)} collect {&lt;br /&gt;        case f if (f.exists() &amp;&amp; f.isFile()) =&gt; f &lt;br /&gt;      }&lt;br /&gt;      val jarsLastModified = (jars map {_.lastModified()} max)&lt;br /&gt;      &lt;br /&gt;      if (!richerScript.exists ||  // -- nothing already available&lt;br /&gt;          (jarsLastModified &gt; richerScript.lastModified) ||   // -- Bootstrap jar is newer&lt;br /&gt;          (script.lastModified &gt; richerScript.lastModified)) { // -- Script has been modified&lt;br /&gt;        val newcontent =  expand(script, availableIncludes).mkString("\n")&lt;br /&gt;        new java.io.FileOutputStream(richerScript) {&lt;br /&gt;          write(newcontent.getBytes())&lt;br /&gt;        }.close()&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    ScriptRunner.runScript(command.settings, richerScript.getPath, command.arguments)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;u&gt;How does it work&lt;/u&gt; :&lt;br&gt;The principle is to override scala standard script startup mechanism by introducing an additionnal step which consist to expand the script with all includes it contains, and then gives to scala the new script resulting of expansion process.&lt;br/&gt;&lt;b&gt;test.scala&lt;/b&gt; becomes &lt;b&gt;test.pscala&lt;/b&gt; which will generate the savedcompile file &lt;b&gt;test.pscala.jar&lt;/b&gt;. No recompilation will be required as soon as no change occured on test.scala or bootstrap.jar file.&lt;br/&gt;&lt;br/&gt;You should also notice that the script is started using 'exec java -jar "$DIRNAME"/bootstrap.jar "$0" "$@"' and not 'exec scala ...' because bootstrap is an assembly jar which contains everything to run and compile scala scripts, and even more if you want, as it can include any third parties you may need, just add library dependencies ! So you only need one file, bootstrap.jar, to run any scala scripts, nothing to install, just one file to upload.&lt;br/&gt;&lt;br/&gt;SBT build configuration : bootstrap/build.sbt&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;import AssemblyKeys._&lt;br /&gt;&lt;br /&gt;seq(assemblySettings: _*)&lt;br /&gt;&lt;br /&gt;name := "bootstrap"&lt;br /&gt;&lt;br /&gt;version := "0.1"&lt;br /&gt;&lt;br /&gt;scalaVersion := "2.9.1"&lt;br /&gt;&lt;br /&gt;libraryDependencies &lt;++=  scalaVersion { sv =&gt;&lt;br /&gt;   ("org.scala-lang" % "scala-swing" % sv) ::&lt;br /&gt;   ("org.scala-lang" % "jline"           % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-compiler"  % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-dbc"       % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scalap"          % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-swing"     % sv  % "compile") ::Nil   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mainClass in assembly := Some("fr.janalyse.script.Bootstrap")&lt;br /&gt;&lt;br /&gt;jarName in assembly := "bootstrap.jar"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;SBT Plugins configuration : bootstrap/project/plugins.sbt file&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;resolvers += Classpaths.typesafeResolver&lt;br /&gt;&lt;br /&gt;addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "2.0.0-M3")&lt;br /&gt;&lt;br /&gt;addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.7.2")&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-195038438885724173?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/195038438885724173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/simplifying-scala-scripts-adding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/195038438885724173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/195038438885724173'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/simplifying-scala-scripts-adding.html' title='Simplifying scala scripts : Adding #include support to your scripts'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-4968904094495684442</id><published>2012-01-26T23:42:00.000+01:00</published><updated>2012-01-26T23:42:52.535+01:00</updated><title type='text'>Simplifying scala scripts</title><content type='html'>I've already written several dozens of scala scripts (series computations, ssh automation, various jmx operations, remote administration, garbage collector log analysis, ...) and found this language quite interesting for use as a script language. There's many reasons for that :&lt;br/&gt;&lt;ul&gt;&lt;li&gt; Script automatic compilation reduce runtime error. I am often amazed at the first attempt to get a script that works and without any runtime error !&lt;/li&gt;&lt;li&gt; Take benefits of scala powerfull collections that make possible to write "sql" like operations&lt;/li&gt;&lt;li&gt; It becomes straightforward to parallelize tasks using Actors; one of my favorite use case is a short script that trigger an explicit garbage collection on several dozens of remote jvm in a very short time&lt;/li&gt;&lt;/ul&gt;But I miss some features that will help to make scala scripts even simpler and concise :&lt;ul&gt;  &lt;li&gt;A #include like feature within script&lt;/li&gt;  &lt;li&gt;A way to modify default imports, to avoid adding always the same imports in all scripts&lt;/li&gt;  &lt;li&gt;the #! !# shell scala bootstrap can become long (and not DRY) once you want to add many external java dependencies&lt;/li&gt;&lt;/ul&gt;In fact those missing features are no so difficult to implement, the following source code is a proof of concept that shows it no so difficult to implement those features. It defines a class, Bootstrap, which can be use to start a scala script and that will bring new imports and definitions to your script.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;package fr.janalyse.script&lt;br /&gt;&lt;br /&gt;import scala.tools.nsc.ScriptRunner&lt;br /&gt;import scala.tools.nsc.GenericRunnerCommand&lt;br /&gt;import scala.io.Source&lt;br /&gt;&lt;br /&gt;object Bootstrap {&lt;br /&gt;&lt;br /&gt;  val header = &lt;br /&gt;"""// WARNING&lt;br /&gt;// Automatically generated file - do not edit !&lt;br /&gt;import sys.process.Process&lt;br /&gt;import sys.process.ProcessBuilder._&lt;br /&gt; &lt;br /&gt;case class CurDir(cwd:java.io.File)&lt;br /&gt;implicit def stringToCurDir(d:String) = CurDir(new java.io.File(d))&lt;br /&gt;implicit def stringToProcess(cmd: String)(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;implicit def stringSeqToProcess(cmd:Seq[String])(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;&lt;br /&gt;implicit var cwd:CurDir=scala.util.Properties.userDir&lt;br /&gt;def cd(dir:String=util.Properties.userDir) = cwd=dir&lt;br /&gt;&lt;br /&gt;"""&lt;br /&gt;&lt;br /&gt;  val footer = &lt;br /&gt;"""&lt;br /&gt;"""&lt;br /&gt;&lt;br /&gt;  def main(cmdargs:Array[String]) {&lt;br /&gt;&lt;br /&gt;    def f(name:String) = new java.io.File(name)&lt;br /&gt;    &lt;br /&gt;    val na = List("-nocompdaemon","-usejavacp","-savecompiled", "-deprecation") ++ cmdargs.toList&lt;br /&gt;    &lt;br /&gt;    val command = new GenericRunnerCommand(na)&lt;br /&gt;    &lt;br /&gt;    import command.settings&lt;br /&gt;    &lt;br /&gt;    val scriptname = command.thingToRun &lt;br /&gt;    val script = f(scriptname)&lt;br /&gt;    val richerScript = f(scriptname.replaceFirst(".scala", ".scala-plus"))&lt;br /&gt;    &lt;br /&gt;    if (script.exists()) {&lt;br /&gt;      if (!richerScript.exists || (script.lastModified &gt; richerScript.lastModified)) {&lt;br /&gt;        val content=Source.fromFile(script).getLines().toList&lt;br /&gt;        val cleanedContent = content.dropWhile(x =&gt; !x.startsWith("!#")).tail.mkString("\n")&lt;br /&gt;        val newcontent =  List(header, cleanedContent, footer).mkString("\n")&lt;br /&gt;        new java.io.FileOutputStream(richerScript) {&lt;br /&gt;          write(newcontent.getBytes())&lt;br /&gt;        }.close()&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    val args = command.arguments&lt;br /&gt;    &lt;br /&gt;    ScriptRunner.runScript(settings, richerScript.getName, args)&lt;br /&gt;  }  &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Then generate a standalone executable jar with this class and all needed dependencies, thanks to such SBT build specification : &lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;import AssemblyKeys._&lt;br /&gt;&lt;br /&gt;seq(assemblySettings: _*)&lt;br /&gt;&lt;br /&gt;name := "bootstrap"&lt;br /&gt;&lt;br /&gt;version := "0.1"&lt;br /&gt;&lt;br /&gt;scalaVersion := "2.9.1"&lt;br /&gt;&lt;br /&gt;libraryDependencies &lt;++=  scalaVersion { sv =&gt;&lt;br /&gt;   ("org.scala-lang" % "scala-swing" % sv) ::&lt;br /&gt;   ("org.scala-lang" % "jline"           % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-compiler"  % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-dbc"       % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scalap"          % sv  % "compile") ::&lt;br /&gt;   ("org.scala-lang" % "scala-swing"     % sv  % "compile") ::Nil   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mainClass in assembly := Some("fr.janalyse.script.Bootstrap")&lt;br /&gt;&lt;br /&gt;jarName in assembly := "bootstrap.jar"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;you'll be able to directly run any scala script like that :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec java -jar bootstrap.jar "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;cd("/etc/")&lt;br /&gt;&lt;br /&gt;"ls" #| "grep net" !&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Thanks to the assembly SBT plugin, you've generated a standalone executable jar, which contains the scala compiler, and our custom scala script startup mechanism.&lt;br/&gt;In a next POST, I'll describe more in detail a new bootstrap implementation that will bring #include feature to scala script.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-4968904094495684442?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/4968904094495684442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/simplifying-scala-scripts.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/4968904094495684442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/4968904094495684442'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/simplifying-scala-scripts.html' title='Simplifying scala scripts'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-5444191917258324301</id><published>2012-01-24T22:19:00.000+01:00</published><updated>2012-01-24T22:19:14.593+01:00</updated><title type='text'>A simple approach to generate reports using scala</title><content type='html'>I was wondering if it was possible to create one executable script containing both the report template and its configuration. So I tried to write a scala script to test this idea :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec scala -nocompdaemon -usejavacp -savecompiled -deprecation "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;import sys.process._&lt;br /&gt;import java.io.{File, FileOutputStream}&lt;br /&gt;&lt;br /&gt;println("Let's generate and display a report")&lt;br /&gt;&lt;br /&gt;val message = "hello"&lt;br /&gt;val guys = List("Marge", "Bart", "Omer")&lt;br /&gt;&lt;br /&gt;val smallreport = &lt;br /&gt;&lt; html&gt;&lt;br /&gt;  &lt; head&gt;&lt;br /&gt;    &lt; title&gt;Hello guys report&lt; /title&gt;&lt;br /&gt;  &lt; /head&gt;&lt;br /&gt;  &lt; body&gt;&lt;br /&gt;    &lt; h1&gt;{message}&lt; /h1&gt;&lt;br /&gt;    {guys map {guy=&gt; &lt;br /&gt;      &lt; h2&gt;{guy}&lt; /h2&gt;&lt;br /&gt;    } }&lt;br /&gt;  &lt; /body&gt;&lt;br /&gt;&lt; /html&gt;&lt;br /&gt;&lt;br /&gt;val reportfile = File.createTempFile("report", ".html")&lt;br /&gt;reportfile.deleteOnExit&lt;br /&gt;&lt;br /&gt;new FileOutputStream(reportfile) {&lt;br /&gt;  write(smallreport.toString.getBytes)&lt;br /&gt;}.close()&lt;br /&gt;&lt;br /&gt;List("firefox", "-new-window", reportfile.toURI.toURL.toString) !&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Note: &lt;i&gt;I've added one space inside each HTML TAG, looks like SyntaxHighlighter doesn't like HTML or XML embedded within scala&lt;/i&gt;&lt;br/&gt;&lt;br/&gt;Make this script executable (chmod u+x reportingScript.scala) and execute it (./reportingScript.scala),  if firefox is available on your operating system, the following window will be displayed :&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Ul_pPRWlpRo/Tx8cThsFr_I/AAAAAAAAEHM/fmDgo3gasjQ/s1600/Capture%2Bd%2527%25C3%25A9cran%2B-%2B24012012%2B-%2B22%253A06%253A17.png" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="215" width="400" src="http://1.bp.blogspot.com/-Ul_pPRWlpRo/Tx8cThsFr_I/AAAAAAAAEHM/fmDgo3gasjQ/s400/Capture%2Bd%2527%25C3%25A9cran%2B-%2B24012012%2B-%2B22%253A06%253A17.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br/&gt;Now we can say :&lt;br/&gt;- it is possible to combine a report template, and data access in a single executable script !&lt;br/&gt;- By using a custom scala startup command, it should be possible to simplify many operations, extending defaults imports, ... &lt;br/&gt;&lt;br/&gt;In a next post I'll try to make such script simpler.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-5444191917258324301?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/5444191917258324301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/simple-approach-to-generate-reports.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5444191917258324301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5444191917258324301'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/simple-approach-to-generate-reports.html' title='A simple approach to generate reports using scala'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-Ul_pPRWlpRo/Tx8cThsFr_I/AAAAAAAAEHM/fmDgo3gasjQ/s72-c/Capture%2Bd%2527%25C3%25A9cran%2B-%2B24012012%2B-%2B22%253A06%253A17.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-5068472690560312665</id><published>2012-01-22T18:25:00.000+01:00</published><updated>2012-01-22T18:25:33.893+01:00</updated><title type='text'>How to generate google stock trend chart in 3 lines...</title><content type='html'>Using &lt;a href="http://code.google.com/p/janalyse-series/"&gt;janalyse-series scala API&lt;/a&gt;, it becomes very simple to generate a trend chart, 3 lines are enough in order to download, parse CSV data and then generate the chart.&lt;pre class="brush: scala;highlight: [8,9,10]"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec java -jar jaseries.jar -nocompdaemon -usejavacp -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;import fr.janalyse.series.CSV2Series&lt;br /&gt;import fr.janalyse.series.view.Chart&lt;br /&gt;&lt;br /&gt;val allSeries = CSV2Series.fromURL("http://ichart.finance.yahoo.com/table.csv?s=GOOG")&lt;br /&gt;val closeSeries = allSeries("Close").rename("Google stock value")    &lt;br /&gt;Chart(closeSeries).toJpgFile(new java.io.File("googleStockTrend.jpg"), 800, 400)&lt;br /&gt;&lt;/pre&gt;The following chart is created.&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-SowjYDsAVPU/TxxFuzEbeeI/AAAAAAAAEG4/GMVoCx_OrWM/s1600/googleStockTrend.jpg" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="200" width="400" src="http://1.bp.blogspot.com/-SowjYDsAVPU/TxxFuzEbeeI/AAAAAAAAEG4/GMVoCx_OrWM/s400/googleStockTrend.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-5068472690560312665?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/5068472690560312665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/how-to-generate-google-stock-trend.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5068472690560312665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5068472690560312665'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/how-to-generate-google-stock-trend.html' title='How to generate google stock trend chart in 3 lines...'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-SowjYDsAVPU/TxxFuzEbeeI/AAAAAAAAEG4/GMVoCx_OrWM/s72-c/googleStockTrend.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-5818666197699113607</id><published>2012-01-22T09:45:00.001+01:00</published><updated>2012-01-22T09:45:52.109+01:00</updated><title type='text'>CSV files merge, based on series names...</title><content type='html'>This example illustrates how &lt;a href="http://code.google.com/p/janalyse-series/"&gt;janalyse-series API&lt;/a&gt; can be use to merge CSV files together while respecting series names. It takes a set of directory containing CSV files, merge all series and write results in a new directory. The merge is only based on series names, not file names, so if for one series, different file names were used, then only one of them will be chosen in the final destination directory, the shortest one.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec jaseries -deprecation -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;/*&lt;br /&gt; * Copyright 2011 David Crosson&lt;br /&gt; * &lt;br /&gt; * Licensed under the Apache License, Version 2.0 (the "License");&lt;br /&gt; * you may not use this file except in compliance with the License.&lt;br /&gt; * You may obtain a copy of the License at&lt;br /&gt; * &lt;br /&gt; *   http://www.apache.org/licenses/LICENSE-2.0&lt;br /&gt; * &lt;br /&gt; * Unless required by applicable law or agreed to in writing, software&lt;br /&gt; * distributed under the License is distributed on an "AS IS" BASIS,&lt;br /&gt; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&lt;br /&gt; * See the License for the specific language governing permissions and&lt;br /&gt; * limitations under the License.&lt;br /&gt; */&lt;br /&gt;import fr.janalyse.series._&lt;br /&gt;import java.io.File&lt;br /&gt;&lt;br /&gt;if (args.size &lt; 2) {&lt;br /&gt;  println("usage : csv-merge srcDir1 ... srcDirN destNewDir")&lt;br /&gt;  println("  Merge and reduce numeric series stored in CSV files")&lt;br /&gt;  System.exit(0)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;case class InputSeries(name:String, filebasename:String, series:Series[Cell])&lt;br /&gt;def file(filename:String) = new File(filename)&lt;br /&gt;def file(dirname:String, filename:String) = new File(dirname, filename)&lt;br /&gt;def file(dir:File, filename:String) = new File(dir, filename)&lt;br /&gt;&lt;br /&gt;def csvFileFilter(f:String):Boolean = {f.endsWith(".csv") ||f.endsWith(".jxtcsv")}&lt;br /&gt;val basename1RE="""(.*)(?:[-_]\d+)[.].+"""r&lt;br /&gt;val basename2RE="""(.*)[.].+"""r&lt;br /&gt;def basename(filename:String) = filename match {&lt;br /&gt;  case basename1RE(basename) =&gt; basename&lt;br /&gt;  case basename2RE(basename) =&gt; basename&lt;br /&gt;  case other =&gt; other&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;val toMerge = args.init&lt;br /&gt;val destNewDir = file(args.last)&lt;br /&gt;&lt;br /&gt;destNewDir.mkdirs()&lt;br /&gt;&lt;br /&gt;// --- Read everything&lt;br /&gt;var inputSeriesList=List.empty[InputSeries]&lt;br /&gt;for( dirname&lt;-toMerge ; &lt;br /&gt;     filename&lt;-file(dirname).list filter csvFileFilter;&lt;br /&gt;     (seriesname, series)&lt;-CSV2Series.fromFile(file(dirname, filename))) {&lt;br /&gt;  val filebasename = basename(filename)&lt;br /&gt;  inputSeriesList = InputSeries(seriesname, filebasename, series)::inputSeriesList&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// --- Merge and Reduce&lt;br /&gt;val seriesGroupByName=inputSeriesList groupBy {is =&gt; is.name}&lt;br /&gt;val mergedSeriesList = for( (seriesname, inputSeriesList4Name) &lt;- seriesGroupByName) yield {&lt;br /&gt;  val mergedseries   = inputSeriesList4Name.map(_.series) reduceLeft {_ &lt;&lt;&lt; _}&lt;br /&gt;  val mergedbasename = inputSeriesList4Name.map(_.filebasename).min&lt;br /&gt;  (mergedseries, mergedbasename)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// --- Write everything&lt;br /&gt;val mergedSeriesGroupByBasename = mergedSeriesList groupBy { case (_, basename) =&gt; basename}&lt;br /&gt;for( (mergedbasename, mergedTuples) &lt;- mergedSeriesGroupByBasename) {&lt;br /&gt;  val seriesList = mergedTuples map {case (series,_) =&gt; series}&lt;br /&gt;  CSV2Series.toFile(seriesList, file(destNewDir, mergedbasename+".csv"))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-5818666197699113607?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/5818666197699113607/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/csv-files-merge-based-on-series-names.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5818666197699113607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5818666197699113607'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/csv-files-merge-based-on-series-names.html' title='CSV files merge, based on series names...'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-6350918716232118590</id><published>2012-01-05T14:31:00.000+01:00</published><updated>2012-01-05T14:34:33.285+01:00</updated><title type='text'>Build Play20 with latest sources, and let's play.</title><content type='html'>All the steps to run your first play 2 web application using latest play improvements; until the first stable release will be ready. The idea here is to build yourself Play. Eclipsify is now taken into account, so once all the steps described here are done, you can import it into eclipse IDE.&lt;pre class="brush: bash;highlight: [1,3,5,7,11,13,15,46,48]"&gt;&lt;br /&gt;$ cd ~/workdir&lt;br /&gt;&lt;br /&gt;$ git clone https://github.com/playframework/Play20.git&lt;br /&gt;&lt;br /&gt;$ cd Play20/framework&lt;br /&gt;&lt;br /&gt;$ ./build&lt;br /&gt;&gt; build-repository&lt;br /&gt;&gt; exit&lt;br /&gt;&lt;br /&gt;$ export PATH=$PATH~/workdir/Play20&lt;br /&gt;&lt;br /&gt;$ cd ~/workdir&lt;br /&gt;&lt;br /&gt;$ play new firstapp&lt;br /&gt;&lt;br /&gt;Getting play console_2.9.1 2.0-RC1-SNAPSHOT ...&lt;br /&gt;:: retrieving :: org.scala-tools.sbt#boot-app&lt;br /&gt; confs: [default]&lt;br /&gt; 5 artifacts copied, 0 already retrieved (5161kB/19ms)&lt;br /&gt;       _            _ &lt;br /&gt; _ __ | | __ _ _  _| |&lt;br /&gt;| '_ \| |/ _' | || |_|&lt;br /&gt;|  __/|_|\____|\__ (_)&lt;br /&gt;|_|            |__/ &lt;br /&gt;             &lt;br /&gt;play! 2.0-RC1-SNAPSHOT, http://www.playframework.org&lt;br /&gt;&lt;br /&gt;The new application will be created in /home/dcr/experiments/firstapp&lt;br /&gt;&lt;br /&gt;What is the application name? &lt;br /&gt;&gt; firstapp&lt;br /&gt;&lt;br /&gt;Which template do you want to use for this new application? &lt;br /&gt;&lt;br /&gt;  1 - Create a simple Scala application&lt;br /&gt;  2 - Create a simple Java application&lt;br /&gt;  3 - Create an empty project&lt;br /&gt;&lt;br /&gt;&gt; 1&lt;br /&gt;&lt;br /&gt;OK, application firstapp is created.&lt;br /&gt;&lt;br /&gt;Have fun!&lt;br /&gt;&lt;br /&gt;$ cd firstapp&lt;br /&gt;&lt;br /&gt;$ play &lt;br /&gt;&gt; eclipsify&lt;br /&gt;&gt; run&lt;br /&gt;--- (Running the application from SBT, auto-reloading is enabled) ---&lt;br /&gt;&lt;br /&gt;[info] play - Listening for HTTP on port 9000...&lt;br /&gt;&lt;br /&gt;(Server started, use Ctrl+D to stop and go back to the console...)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Now everything is ready, to test and modify the simple scala project application using eclipse. More information can be found on : &lt;a href="http://scala-ide.org/docs/tutorials/play20scalaide20/index.html"&gt;play20 and scala ide 20 tutorial&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-6350918716232118590?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/6350918716232118590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2012/01/build-play20-with-latest-sources-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6350918716232118590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6350918716232118590'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2012/01/build-play20-with-latest-sources-and.html' title='Build Play20 with latest sources, and let&apos;s play.'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-5097580887840166231</id><published>2011-12-14T23:46:00.001+01:00</published><updated>2012-01-09T22:15:11.952+01:00</updated><title type='text'>Easy SSH scala scripting</title><content type='html'>Visit &lt;a href="http://code.google.com/p/janalyse-ssh/"&gt;janalyse-ssh&lt;/a&gt;, and download "jassh.jar" standalone executable jar.&lt;br/&gt;In the same directory where you've downloaded "jassh.jar"file, create a file named "helloworld", and copy&amp;paste the following content in it :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec java -jar jassh.jar -nocompdaemon -usejavacp -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;import fr.janalyse.ssh._&lt;br /&gt;SSH.connect(host="localhost", username="test", password="testtest") { ssh =&gt;&lt;br /&gt;  println(ssh.execute("""echo -n "Hello World from `hostname`" """))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Change the specified user to an existing user, or create a "test" user. Give the right password or remove it if you've exported your public SSH key in remote user ~test/.ssh/authorized_keys file&lt;br/&gt;Then make your "helloworld" file executable (chmod u+x helloworld), and execute it :&lt;pre class="brush: bash;highlight: []"&gt;&lt;br /&gt;toto@myhost $ ./helloworld &lt;br /&gt;Hello World from myhost&lt;br /&gt;&lt;/pre&gt;Easy ! And you'll take all benefits of the scala language using just vi, in order to make any kind of remote operations ! No graphical user interface required, no compiler (automatic &amp; transparent compilation on the fly when needed), high performances (I've reached a command throughput up to 545 cmd/s on my host), parallelism using actors, easy parsing using combinators, ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-5097580887840166231?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/5097580887840166231/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/12/easy-ssh-scala-scripting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5097580887840166231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5097580887840166231'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/12/easy-ssh-scala-scripting.html' title='Easy SSH scala scripting'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-8734090956818228594</id><published>2011-12-11T21:36:00.001+01:00</published><updated>2011-12-23T08:11:28.903+01:00</updated><title type='text'>JMX grep scala script</title><content type='html'>A simple script to search for mbeans/attributes-names/attribute-values matching regular expressions given as script parameters. This script is using &lt;a href="http://code.google.com/p/janalyse-jmx/"&gt;janalyse-jmx scala API&lt;/a&gt;; jajmx.jar java executable is used to startup the script.&lt;br/&gt;This jmx grep script can be used against itself, with its own embedded jmx platform. This feature is enabled through java options (JAVA_OPTS) specified within script startup header.&lt;br/&gt;&lt;pre class="brush: bash;highlight: [1,16]"&gt;&lt;br /&gt;$ ./jmxgrep localhost 9999  operating&lt;br /&gt;java.lang:type=OperatingSystem - MaxFileDescriptorCount = 4096&lt;br /&gt;java.lang:type=OperatingSystem - OpenFileDescriptorCount = 18&lt;br /&gt;java.lang:type=OperatingSystem - CommittedVirtualMemorySize = 4520407040&lt;br /&gt;java.lang:type=OperatingSystem - FreePhysicalMemorySize = 7900864512&lt;br /&gt;java.lang:type=OperatingSystem - FreeSwapSpaceSize = 10742177792&lt;br /&gt;java.lang:type=OperatingSystem - ProcessCpuTime = 1490000000&lt;br /&gt;java.lang:type=OperatingSystem - TotalPhysicalMemorySize = 16848113664&lt;br /&gt;java.lang:type=OperatingSystem - TotalSwapSpaceSize = 10742177792&lt;br /&gt;java.lang:type=OperatingSystem - Name = Linux&lt;br /&gt;java.lang:type=OperatingSystem - AvailableProcessors = 6&lt;br /&gt;java.lang:type=OperatingSystem - Arch = amd64&lt;br /&gt;java.lang:type=OperatingSystem - SystemLoadAverage = 0.0&lt;br /&gt;java.lang:type=OperatingSystem - Version = 3.0.6-gentoo&lt;br /&gt;&lt;br /&gt;$ ./jmxgrep localhost 9999 threadcount&lt;br /&gt;java.lang:type=GarbageCollector,name=PS MarkSweep - LastGcInfo = javax.management.openmbean.CompositeDataSupport(compositeTyp...&lt;br /&gt;java.lang:type=Runtime - SystemProperties = javax.management.openmbean.TabularDataSupport(tabularType=ja...&lt;br /&gt;java.lang:type=Threading - DaemonThreadCount = 12&lt;br /&gt;java.lang:type=Threading - PeakThreadCount = 13&lt;br /&gt;java.lang:type=Threading - ThreadCount = 13&lt;br /&gt;java.lang:type=Threading - TotalStartedThreadCount = 13&lt;br /&gt;java.lang:type=GarbageCollector,name=PS Scavenge - LastGcInfo = javax.management.openmbean.CompositeDataSupport(compositeTyp...&lt;br /&gt;&lt;/pre&gt;jmxgrep code (just copy paste this code into a file named jmxgrep, and make it executable using chmod a+x jmxgrep) :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;JAVA_OPTS=""&lt;br /&gt;JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote"&lt;br /&gt;JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.port=9999"&lt;br /&gt;JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.authenticate=false"&lt;br /&gt;JAVA_OPTS=$JAVA_OPTS" -Dcom.sun.management.jmxremote.ssl=false"&lt;br /&gt;SCA_OPTS="-nocompdaemon -usejavacp -savecompiled"&lt;br /&gt;exec java $JAVA_OPTS -jar jajmx.jar $SCA_OPTS "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;import fr.janalyse.jmx._&lt;br /&gt;import JMXImplicits._&lt;br /&gt;&lt;br /&gt;if (args.size &lt; 2) {&lt;br /&gt;  println("Usage   : jmxgrep host port searchMask1 ... searchMaskN")&lt;br /&gt;  println("Example : jmxgrep localhost 1099  vendor")&lt;br /&gt;  println("   will self connect to jmx server, and looks for vendor keyword")&lt;br /&gt;  System.exit(1)&lt;br /&gt;}&lt;br /&gt;val host  = args(0)&lt;br /&gt;val port  = args(1).toInt&lt;br /&gt;val masks = args.toList.drop(2) map {s=&gt;("(?i)"+s).r}&lt;br /&gt;&lt;br /&gt;def truncate(str:String, n:Int=60) = if (str.size&gt;n) str.take(n)+"..." else str&lt;br /&gt;&lt;br /&gt;JMX.connect(host, port) { implicit jmx =&gt;&lt;br /&gt;  for(on &lt;- jmx.browse ; attr &lt;- on.browse) {&lt;br /&gt;    val value = try { on.get[Any](attr).toString} catch { case _ =&gt; "**error**"}&lt;br /&gt;    val found = List(on.toString, attr, value) exists { item =&gt;&lt;br /&gt;      masks exists {re =&gt; (re findFirstIn item).isDefined} &lt;br /&gt;    }&lt;br /&gt;    if (found || masks.isEmpty) println("%s - %s = %s".format(on, attr, truncate(value)))&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Notice the "-savecompiled" scala option which enable the script compilation result to be stored in a file named "jmxgrep.jar". When started, already compiled code will be reuse if the script hasn't been modified since last compilation time. This allow very fast script startup.&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-8734090956818228594?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/8734090956818228594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/12/jmx-grep-scala-script.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/8734090956818228594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/8734090956818228594'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/12/jmx-grep-scala-script.html' title='JMX grep scala script'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-1308297112847539624</id><published>2011-12-11T14:34:00.001+01:00</published><updated>2011-12-14T23:20:01.632+01:00</updated><title type='text'>Scala JMX console &amp; scripts examples</title><content type='html'>I've released a JMX API for scala, (&lt;a href="http://code.google.com/p/janalyse-jmx/"&gt; project-link &lt;/a&gt;) which is straightforward to use in scripts : I provide a single executable jar file named "jajmx.jar", containing everything required to start a scala console or to run a scala script dedicated to jmx operations.&lt;br/&gt;Console mode usage example :&lt;pre class="brush: bash;highlight: [1,6,9,12,15,18,21,23]"&gt;&lt;br /&gt;$ java -jar jajmx.jar -usejavacp&lt;br /&gt;Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).&lt;br /&gt;Type in expressions to have them evaluated.&lt;br /&gt;Type :help for more information.&lt;br /&gt;&lt;br /&gt;scala&gt; import fr.janalyse.jmx._&lt;br /&gt;import fr.janalyse.jmx._&lt;br /&gt;&lt;br /&gt;scala&gt; val jmx=JMX("localhost", 9999, None)&lt;br /&gt;jmx: fr.janalyse.jmx.JMX = fr.janalyse.jmx.JMX@1ce59895&lt;br /&gt;&lt;br /&gt;scala&gt; jmx.domains&lt;br /&gt;res0: List[java.lang.String] = List(JMImplementation, com.sun.management, java.lang, java.util.logging)&lt;br /&gt;&lt;br /&gt;scala&gt; jmx.runtime map {_.get[Long]("Uptime")}&lt;br /&gt;res5: Option[Long] = Some(149014)&lt;br /&gt;&lt;br /&gt;scala&gt; jmx.os map {_.get[String]("Version")}&lt;br /&gt;res6: Option[String] = Some(3.0.6-gentoo)&lt;br /&gt;&lt;br /&gt;scala&gt; jmx("java.lang:type=Memory").set("Verbose", true)&lt;br /&gt;&lt;br /&gt;scala&gt; jmx("java.lang:type=Memory").call("gc")&lt;br /&gt;[GC 45515K-&gt;28456K(310720K), 0.0010380 secs]&lt;br /&gt;[Full GC 28456K-&gt;26792K(310720K), 0.2427710 secs]&lt;br /&gt;res11: Option[Nothing] = None&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;A simple script example (Invoke an explicit GC from JMX) :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec java -jar jajmx.jar -nocompdaemon -usejavacp -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;import fr.janalyse.jmx._&lt;br /&gt;&lt;br /&gt;if (args.size != 2) {&lt;br /&gt;  println("Usage : gcforce host port")&lt;br /&gt;  System.exit(1)&lt;br /&gt;}&lt;br /&gt;val host=args(0)&lt;br /&gt;val port=args(1).toInt&lt;br /&gt;&lt;br /&gt;JMX.connect(host, port) { jmx =&gt;&lt;br /&gt;  val mem  = jmx("java.lang:type=Memory")&lt;br /&gt;  mem.call("gc")&lt;br /&gt;  println("Explicit GC invoked on host %s port %d".format(host,port))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-1308297112847539624?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/1308297112847539624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/12/scala-jmx-console-scripts-examples.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1308297112847539624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1308297112847539624'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/12/scala-jmx-console-scripts-examples.html' title='Scala JMX console &amp; scripts examples'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-3618583375373023195</id><published>2011-12-03T19:18:00.001+01:00</published><updated>2011-12-03T19:49:14.009+01:00</updated><title type='text'>Scala project skeleton using SBT</title><content type='html'>Let's create a minimal scala project skeleton, based on SBT build system, with some SBT plugins enabled (eclipse and assembly). The goal is to generate a single standalone executable jar (without any external dependencies), using scala language (and/or java) and eclipse as an optional IDE.&lt;br/&gt;The scala project skeleton is available as a google code project. visit : &lt;a href="https://code.google.com/p/scala-dummy-project/"&gt;scala-dummy-project&lt;/a&gt; or checkout the project :&lt;pre class="brush: bash;highlight: []"&gt;&lt;br /&gt;# Quick start&lt;br /&gt;$ svn checkout http://scala-dummy-project.googlecode.com/svn/trunk/ scala-dummy-project-read-only&lt;br /&gt;$ cd scala-dummy-project&lt;br /&gt;$ sbt assembly&lt;br /&gt;$ java -jar target/dummy.jar&lt;br /&gt;Hello dcr&lt;br /&gt;&lt;/pre&gt;Requirements are :&lt;br/&gt;- JVM &gt;= 1.5 available in your PATH&lt;br/&gt;- get and install &lt;a href="https://github.com/harrah/xsbt/wiki/Getting-Started-Setup"&gt;SBT (Simple Build Tool)&lt;/a&gt;&lt;br/&gt;- if you want to use eclipse, download and install &lt;a href="http://www.scala-ide.org/"&gt;Scala IDE for eclipse&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;To use eclipse, you must initialize the project for eclipse, run "sbt eclipse" or just "eclipse" from SBT console.&lt;br/&gt;All steps :&lt;pre class="brush: bash;highlight: []"&gt;&lt;br /&gt;$ cd scala-dummy-project&lt;br /&gt;$ sbt &lt;br /&gt;&gt; eclipse&lt;br /&gt;&gt; run&lt;br /&gt;&gt; test&lt;br /&gt;&gt; assembly&lt;br /&gt;&gt; exit&lt;br /&gt;$ java -jar target/dummy.jar&lt;br /&gt;#OR&lt;br /&gt;$ sbt run&lt;br /&gt;&lt;/pre&gt;The project is configured as follow :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;import AssemblyKeys._&lt;br /&gt;&lt;br /&gt;seq(assemblySettings: _*)&lt;br /&gt;&lt;br /&gt;name := "ScalaDummyProject"&lt;br /&gt;&lt;br /&gt;version := "0.1"&lt;br /&gt;&lt;br /&gt;scalaVersion := "2.9.1"&lt;br /&gt;&lt;br /&gt;mainClass in assembly := Some("dummy.Dummy")&lt;br /&gt;&lt;br /&gt;jarName in assembly := "dummy.jar"&lt;br /&gt;&lt;br /&gt;libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test"&lt;br /&gt;&lt;br /&gt;// Junit is just required for eclipse to be able to start tests.&lt;br /&gt;libraryDependencies += "junit" % "junit" % "4.10" % "test"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;What's great with sbt is that it manages all dependencies for you (even sub-dependencies !), no need to download anything, everything is done automatically.&lt;br/&gt;&lt;i&gt;CONTEXT : Scala 2.9.1 / SBT 0.11 / ScalaTest 1.6.1 / sbt-assembly 0.7.2 / sbteclipse 1.5.0 &lt;/i&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-3618583375373023195?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/3618583375373023195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/12/scala-project-skeleton-using-sbt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/3618583375373023195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/3618583375373023195'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/12/scala-project-skeleton-using-sbt.html' title='Scala project skeleton using SBT'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-6639188778886982256</id><published>2011-11-13T17:20:00.001+01:00</published><updated>2011-11-13T18:07:59.427+01:00</updated><title type='text'>Get the elements which are in duplicates in a collection</title><content type='html'>groupBy method is a powerfull feature that can be used for many kind of operations, it is a "group by" SQL like operation. Let's use it to find elements which are in duplicates in a given collection :&lt;pre class="brush: scala;highlight: [2,6]"&gt;&lt;br /&gt;val alist = List(1,2,3,4,3,2,5,7,5)&lt;br /&gt;val duplicatesItem = alist groupBy {x=&gt;x} filter {case (_,lst) =&gt; lst.size &gt; 1 } keys&lt;br /&gt;// The result is : Set(5, 2, 3)&lt;br /&gt;&lt;br /&gt;val dogs=List(Dog("milou"), Dog("zorglub"), Dog("milou"), Dog("gaillac"))&lt;br /&gt;val duplicatesDog = dogs groupBy {_.name} filter {case (_,lst) =&gt; lst.size &gt; 1 } keys&lt;br /&gt;// The result is : Set(milou)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Now if we want to define a function to do the job for us :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;def findDuplicates[A,B](list:List[B])(crit:(B)=&gt;A):Iterable[A] = {&lt;br /&gt;     list.groupBy(crit) filter {case (_,l) =&gt; l.size &gt; 1 } keys &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Let's use this function :&lt;pre class="brush: scala;highlight: [1,4]"&gt;&lt;br /&gt;scala&gt; findDuplicates(alist) {x=&gt;x}&lt;br /&gt;res21: Iterable[Int] = Set(5, 2, 3)&lt;br /&gt;&lt;br /&gt;scala&gt; findDuplicates(dogs) {dog=&gt;dog.name}&lt;br /&gt;res22: Iterable[String] = Set(milou)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-6639188778886982256?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/6639188778886982256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/11/get-elements-which-are-in-duplicates-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6639188778886982256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6639188778886982256'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/11/get-elements-which-are-in-duplicates-in.html' title='Get the elements which are in duplicates in a collection'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-5151395354216503240</id><published>2011-11-12T21:38:00.001+01:00</published><updated>2011-11-12T22:07:28.521+01:00</updated><title type='text'>IO Read binary file with Stream continually helper method</title><content type='html'>A straightforward approach to read a binary stream in Scala. Using continually helper Stream method gives to the code a functional taste.&lt;pre class="brush: scala;highlight: [13,14,15]"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec scala -J-Xmx1g -J-Xms512m -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;import java.io._&lt;br /&gt;import util.Properties.{userHome}&lt;br /&gt;import java.io.File.{separatorChar=&gt; sep, pathSeparatorChar=&gt;pathSep}&lt;br /&gt;&lt;br /&gt;def readBinaryFile(input:InputStream):Array[Byte] = {&lt;br /&gt;  val fos = new ByteArrayOutputStream(65535)&lt;br /&gt;  val bis = new BufferedInputStream(input)&lt;br /&gt;  val buf = new Array[Byte](1024)&lt;br /&gt;  Stream.continually(bis.read(buf))&lt;br /&gt;      .takeWhile(_ != -1)&lt;br /&gt;      .foreach(fos.write(buf, 0, _))&lt;br /&gt;  fos.toByteArray&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Read 191Mo file&lt;br /&gt;val fname=userHome+sep+"LibO_3.4.4_Win_x86_install_multi.exe"&lt;br /&gt;val fb = readBinaryFile(new FileInputStream(fname))&lt;br /&gt;println("%s, %d bytes".format(fname, fb.size))&lt;br /&gt;&lt;/pre&gt;This is quite better than writing : &lt;pre class="brush: scala;highlight: [1,2,3,4,5]"&gt;&lt;br /&gt;  var c=0&lt;br /&gt;  do {&lt;br /&gt;    c = bis.read(buf)&lt;br /&gt;    if (c &gt; 0) fos.write(buf,0,c)&lt;br /&gt;  } while(c &gt; -1)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-5151395354216503240?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/5151395354216503240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/11/io-read-binary-file-with-stream.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5151395354216503240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/5151395354216503240'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/11/io-read-binary-file-with-stream.html' title='IO Read binary file with Stream continually helper method'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-3115664360231216172</id><published>2011-11-09T22:01:00.001+01:00</published><updated>2011-11-12T10:41:41.893+01:00</updated><title type='text'>md5sum in scala</title><content type='html'>How to compute the md5sum of a file (to get the same result as the one given by linux md5sum command)&lt;br/&gt;&lt;i&gt;Inspired from &lt;a href="http://code-redefined.blogspot.com/2009/05/md5-sum-in-scala.html"&gt;MD5Sum in Scala&lt;/a&gt; and modified to work with input streams.&lt;/i&gt;&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;&lt;br /&gt; def md5sum(input:InputStream):String = {&lt;br /&gt;    val bis = new BufferedInputStream(input)&lt;br /&gt;    val buf = new Array[Byte](1024)&lt;br /&gt;    val md5 = java.security.MessageDigest.getInstance("MD5")&lt;br /&gt;    Stream.continually(bis.read(buf)).takeWhile(_ != -1).foreach(md5.update(buf, 0, _))&lt;br /&gt;    md5.digest().map(0xFF &amp; _).map { "%02x".format(_) }.foldLeft(""){_ + _}&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-3115664360231216172?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/3115664360231216172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/11/md5sum-in-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/3115664360231216172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/3115664360231216172'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/11/md5sum-in-scala.html' title='md5sum in scala'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-6387630890880775570</id><published>2011-11-09T21:56:00.001+01:00</published><updated>2011-11-17T21:50:22.015+01:00</updated><title type='text'>Some notes about how to simplify scala code (and monads)</title><content type='html'>&lt;b&gt;This is just some notes...To be continued and completed ... Updated on 2011-11-17&lt;/b&gt;&lt;br/&gt;Interesting articles (and set of comments) to understand and recognize monads :&lt;br/&gt;- &lt;a href="http://www.codecommit.com/blog/ruby/monads-are-not-metaphors"&gt;Monads are not metaphors&lt;/a&gt;&lt;br/&gt;- &lt;a href="http://james-iry.blogspot.com/2007/09/monads-are-elephants-part-1.html"&gt;Monads are elephants&lt;/a&gt;&lt;br/&gt;&lt;br/&gt;Exploring the best way to get a value from a map, or a default value if the key doesn't exist :&lt;pre class="brush: scala;highlight: [3,8,12,19,23]"&gt;&lt;br /&gt;val codes=Map("A"-&gt;10, "B"-&gt;5, "C"-&gt;20)&lt;br /&gt;&lt;br /&gt;{ // Basic approach&lt;br /&gt;  var code = 30&lt;br /&gt;  if (codes contains "D") code = codes.get("D").get&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{ // More compact approach&lt;br /&gt;  val code = if (codes contains "D") codes.get("D").get else 30&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{ // Match approach&lt;br /&gt;  val code = codes.get("D") match {&lt;br /&gt;    case Some(v)=&gt;v&lt;br /&gt;    case None=&gt;30&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{ // Option monad approach&lt;br /&gt;  val code = codes get "D" getOrElse 30&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{ // Compact approach&lt;br /&gt;  val code = codes.getOrElse("D",30)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;With monads, many test cases can be avoided, the code looks like a data flow :&lt;pre class="brush: scala;highlight: [5,6,7]"&gt;&lt;br /&gt;import collection.JavaConversions._&lt;br /&gt;import java.io.File&lt;br /&gt;val sp = java.lang.System.getProperties.toMap&lt;br /&gt;&lt;br /&gt;val lookInto = sp.get("baseDir") orElse sp.get("rootDir") orElse sp.get("user.home")&lt;br /&gt;val lookIntoDirFile = lookInto map {new File(_)} filter {_.exists}&lt;br /&gt;val count = lookIntoDirFile map {_.list.size}&lt;br /&gt;&lt;br /&gt;println(count map {_+" files"} getOrElse "Dir not found")&lt;br /&gt;&lt;br /&gt;// will print "Dir not found" or for example "184 files"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;An other example using Option Monad, the second fullName implementation becomes very simple:&lt;pre class="brush: scala;highlight: [1,2,3,4,5,6,7,8,9,10,20,21,22,23]"&gt;&lt;br /&gt;// Using classical approach, a Java like approach&lt;br /&gt;case class Person1(firstName:String, lastName:String) {&lt;br /&gt;  def fullName() = {&lt;br /&gt;    if (firstName!=null) {&lt;br /&gt;      if (lastName!=null) {&lt;br /&gt;        firstName+" "+lastName&lt;br /&gt;      } else null&lt;br /&gt;    } else null&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;  val p1 = Person1("Einstein", "Albert")&lt;br /&gt;  val p2 = Person1("Aristote", null)&lt;br /&gt;  println("1-%s" format p1.fullName)&lt;br /&gt;  val fullName = if (p2.fullName!=null) p2.fullName else "Unknown"&lt;br /&gt;  println("1-%s" format fullName)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Using Option monad approach  &lt;br /&gt;case class Person2(firstName:Option[String], lastName:Option[String]) {&lt;br /&gt;  def fullName() = firstName flatMap {fn =&gt; lastName map {ln =&gt; fn+" "+ln}}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;  val p1 = Person2(Some("Einstein"), Some("Albert"))&lt;br /&gt;  val p2 = Person2(Some("Aristote"), None)&lt;br /&gt;  println("2-%s" format p1.fullName.getOrElse("Unknown"))&lt;br /&gt;  println("2-%s" format p2.fullName.getOrElse("Unknown"))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;To be continued and completed ...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-6387630890880775570?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/6387630890880775570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/11/some-notes-about-how-to-simplify-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6387630890880775570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6387630890880775570'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/11/some-notes-about-how-to-simplify-scala.html' title='Some notes about how to simplify scala code (and monads)'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-583383585514333153</id><published>2011-11-06T11:07:00.000+01:00</published><updated>2011-11-07T22:04:16.056+01:00</updated><title type='text'>Automatic resource liberation</title><content type='html'>It is very easy to implements automatic resource liberation in Scala, thanks to parametric type which can be use without giving a specific class but rather any class which implements the given method signature !&lt;br/&gt;In our case, we define a method which accepts all classes with a close method.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;def using[T &lt;: { def close()}, R] (resource: T) (block: T =&gt; R) = {&lt;br /&gt;  try     block(resource)&lt;br /&gt;  finally resource.close&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;An example usage :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;import java.io._&lt;br /&gt;&lt;br /&gt;using(new PrintStream("/tmp/dummy")) { o =&gt;&lt;br /&gt;  o.print("Hello world")&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-583383585514333153?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/583383585514333153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/11/automatic-resource-liberation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/583383585514333153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/583383585514333153'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/11/automatic-resource-liberation.html' title='Automatic resource liberation'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-4637191946474561228</id><published>2011-10-04T21:30:00.000+02:00</published><updated>2011-11-06T10:20:46.190+01:00</updated><title type='text'>Scala serialize simple test case</title><content type='html'>A simple use case showing how to make scala classes serializable. This example checks that instances reference graph is entirely stored. When instances are restored, we modify the mutable java Properties instance to check that the change is seen both from service and server instance.&lt;pre class="brush: scala;highlight: [14,19]"&gt;&lt;br /&gt;import java.io._&lt;br /&gt;&lt;br /&gt;case class Common(properties:java.util.Properties) extends Serializable &lt;br /&gt;case class Server(name:String, ip:String, common:Common) extends Serializable&lt;br /&gt;case class Service(server:Server, name:String, port:Int, common:Common) extends Serializable&lt;br /&gt;&lt;br /&gt;val cmm1=Common(new java.util.Properties())&lt;br /&gt;val srv1=Server("localhost", "127.0.0.1",cmm1)&lt;br /&gt;val svc1=Service(srv1, "httpd", 80, cmm1)&lt;br /&gt;&lt;br /&gt;val bufout = new ByteArrayOutputStream()&lt;br /&gt;val obout = new ObjectOutputStream(bufout)&lt;br /&gt;&lt;br /&gt;obout.writeObject(svc1)&lt;br /&gt;&lt;br /&gt;val bufin = new ByteArrayInputStream(bufout.toByteArray)&lt;br /&gt;val obin = new ObjectInputStream(bufin)&lt;br /&gt;&lt;br /&gt;val svc2 = obin.readObject().asInstanceOf[Service]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;assert(svc2 == svc1)&lt;br /&gt;&lt;br /&gt;svc2.common.properties.put("toto", "tata")&lt;br /&gt;&lt;br /&gt;assert(svc2.common == svc2.server.common)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.1 / Java 1.6.0_26&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-4637191946474561228?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/4637191946474561228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/10/scala-serialize-simple-test-case.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/4637191946474561228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/4637191946474561228'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/10/scala-serialize-simple-test-case.html' title='Scala serialize simple test case'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-7174429016619688023</id><published>2011-10-04T21:20:00.000+02:00</published><updated>2011-11-06T10:31:55.847+01:00</updated><title type='text'>Generic operations on scala collections - Using builders</title><content type='html'>Scala collections are very impressive, they achieve a high degree of genericity, a single method can be applied on any kind of collections ! Let's see an example through an operation consisting on removing identical consecutives elements.&lt;br/&gt;&lt;br/&gt;Let's see a first simple implementation :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;def compact[A](list:List[A]):List[A] = {&lt;br /&gt;  var buf  = collection.mutable.ListBuffer.empty[A]&lt;br /&gt;  var prev:Option[A] = None&lt;br /&gt;  for(item &lt;- list) {&lt;br /&gt;    if (prev==None || prev.get!=item) buf += item&lt;br /&gt;    prev=Some(item)&lt;br /&gt;  }&lt;br /&gt;  buf.toList&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Or using folding :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;def compact[A](list:List[A]):List[A] = {&lt;br /&gt;  (List[A]() /: list) { (nl, I) =&gt; nl.headOption match { &lt;br /&gt;      case Some(I) =&gt; nl&lt;br /&gt;      case Some(_)|None=&gt; I::nl&lt;br /&gt;    }&lt;br /&gt;  } reverse&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The problem with those implementations is that the collection type is "hardcoded", if you need to realize the same operation on Queues, Stacks, Vectors,... you will have to provide as many implementations as you have collections types you want to be taken into account by a compact operation.&lt;br&gt;You'll first thing that's this is not a problem, you just have to parameterize not only the item type but also the collection type using such method declaration :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;def compact[A, I[A]&lt;:Iterable[A]](list:I[A]) : I[A] = {&lt;br /&gt;   ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But such approach is a dead end issue, because you need to create a new collection of type I[A] which should inheritate from Iterable[A], but of course it is not possible to create such instance from type parameter. Trying, I.empty[A] or I[A]()  won't work and will generate compiler error. &lt;br/&gt;&lt;br/&gt;Scala provides an elegant solution based on implicits builders, in fact all collections provides builders that we're free to reuse in order to implement generic operations on collections.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;// Fully generic implementation using collection builder&lt;br /&gt;def compact[A, I[A]&lt;:Iterable[A]](list:I[A]) (implicit bf: CanBuildFrom[I[A], A, I[A]]) : I[A] = {&lt;br /&gt;  var builder = bf.apply()&lt;br /&gt;  var prev:Option[A]=None&lt;br /&gt;  for(item &lt;- list) {&lt;br /&gt;    if (prev==None || prev.get != item) builder += item&lt;br /&gt;    prev=Some(item)&lt;br /&gt;  }&lt;br /&gt;  builder.result&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here find the complete example ready to run and test :&lt;pre class="brush: scala;highlight: [8,19,28,37,47,59]"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec scala -deprecation -savecompiled "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;import scala.collection._&lt;br /&gt;import scala.collection.immutable.{Queue,Stack}&lt;br /&gt;import scala.collection.generic.CanBuildFrom&lt;br /&gt;&lt;br /&gt;// Simple implementation&lt;br /&gt;def compact0[A](list:List[A]) = {&lt;br /&gt;  var buf  = collection.mutable.ListBuffer.empty[A]&lt;br /&gt;  var prev:Option[A] = None&lt;br /&gt;  for(item &lt;- list) {&lt;br /&gt;    if (prev==None || prev.get!=item) buf += item&lt;br /&gt;    prev=Some(item)&lt;br /&gt;  }&lt;br /&gt;  buf.toList&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// A bad recursive implementation&lt;br /&gt;def compact1[A](list:List[A], prev:Option[A]=None):List[A] = {&lt;br /&gt;  list match {&lt;br /&gt;    case Nil =&gt; Nil&lt;br /&gt;    case that::remain if (prev == None || prev.get != that) =&gt; that::compact1(remain, Some(that))&lt;br /&gt;    case that::remain =&gt; compact1(remain, Some(that))&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Implementation using folding&lt;br /&gt;def compact2[A](list:List[A]):List[A] = {&lt;br /&gt;  (List[A]() /: list) { (nl, I) =&gt; nl.headOption match { &lt;br /&gt;      case Some(I) =&gt; nl&lt;br /&gt;      case Some(_)|None=&gt; I::nl&lt;br /&gt;    }&lt;br /&gt;  } reverse&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Implementation using folding and a dedicated test function&lt;br /&gt;def compactT1[A](list:List[A], tst:(A,A)=&gt;Boolean):List[A] = {&lt;br /&gt;  (List[A]() /: list) { (nl, i) =&gt; nl.headOption match { &lt;br /&gt;      case Some(iprev) if tst(iprev,i) =&gt; nl &lt;br /&gt;      case Some(_)|None=&gt; i::nl&lt;br /&gt;    }&lt;br /&gt;  } reverse&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// Fully generic implementation using builder&lt;br /&gt;def compact[A, I[A]&lt;:Iterable[A]](list:I[A])(implicit bf: CanBuildFrom[I[A], A, I[A]]):I[A] = {&lt;br /&gt;  var builder = bf.apply()&lt;br /&gt;  var prev:Option[A]=None&lt;br /&gt;  for(item &lt;- list) {&lt;br /&gt;    if (prev==None || prev.get != item) builder += item&lt;br /&gt;    prev=Some(item)&lt;br /&gt;  }&lt;br /&gt;  builder.result&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// Fully generic implementation using builder and dedicated test function&lt;br /&gt;def compactT[A, I[A]&lt;:Iterable[A]](list:I[A], tst:(A,A)=&gt;Boolean)&lt;br /&gt;          (implicit bf: CanBuildFrom[I[A], A, I[A]]):I[A] = {&lt;br /&gt;  var builder = bf.apply()&lt;br /&gt;  var prev:Option[A]=None&lt;br /&gt;  for(item &lt;- list) {&lt;br /&gt;    if (prev==None || !tst(prev.get,item)) builder += item&lt;br /&gt;    prev=Some(item)&lt;br /&gt;  }&lt;br /&gt;  builder.result&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;assert(compact(List.empty) == List())&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val l1 = List(1,1,1,2,3,3,2,2,2,4,4,1,1)&lt;br /&gt;val l1compacted = List(1,2,3,2,4,1)&lt;br /&gt;assert(compact0(l1) == l1compacted)&lt;br /&gt;assert(compact1(l1) == l1compacted)&lt;br /&gt;assert(compact2(l1) == l1compacted)&lt;br /&gt;assert(compact(l1) == l1compacted)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;case class Cell(t:Int, v:Int)&lt;br /&gt;val l2=List(Cell(1,10), Cell(2,11), Cell(2,4), Cell(3,1), Cell(3,2), Cell(2,0), Cell(2,30))&lt;br /&gt;val l2compacted= List(Cell(1,10), Cell(2,11), Cell(3,1), Cell(2,0))&lt;br /&gt;assert(compactT1(l2,(x:Cell,y:Cell)=&gt;x.t==y.t) == l2compacted)&lt;br /&gt;assert(compactT(l2,(x:Cell,y:Cell)=&gt;x.t==y.t) == l2compacted)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val testcase=List(1,1,1,2,3,3,2,2,2,4,4,1,1)&lt;br /&gt;val testresult=List(1,2,3,2,4,1)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val v1 = Vector(testcase :_ *)&lt;br /&gt;val v1compacted = Vector(testresult :_ *)&lt;br /&gt;assert(compact(v1) == v1compacted)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val s1 = Stack(testcase :_ *)&lt;br /&gt;val s1compacted =Stack(testresult :_ *)&lt;br /&gt;assert(compact(s1) == s1compacted)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val q1 = Queue(testcase :_ *)&lt;br /&gt;val q1compacted =Queue(testresult :_ *)&lt;br /&gt;assert(compact(q1) == q1compacted)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val ab1 = collection.mutable.ArrayBuffer(testcase :_ *)&lt;br /&gt;val ab1compacted = collection.mutable.ArrayBuffer(testresult :_ *)&lt;br /&gt;assert(compact(ab1) == ab1compacted)&lt;br /&gt;&lt;br /&gt;// ----------------------------------&lt;br /&gt;val sq1 = Seq(testcase :_ *)&lt;br /&gt;val sq1compacted =Seq(testresult :_ *)&lt;br /&gt;assert(compact(sq1) == sq1compacted)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-7174429016619688023?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/7174429016619688023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/10/generic-operations-on-scala-collections.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7174429016619688023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7174429016619688023'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/10/generic-operations-on-scala-collections.html' title='Generic operations on scala collections - Using builders'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-8742562496860043601</id><published>2011-09-25T19:03:00.001+02:00</published><updated>2011-11-06T10:32:51.149+01:00</updated><title type='text'>Timed numeric series library for Scala</title><content type='html'>The first public release of my open-source timed-series library, &lt;a href="http://code.google.com/p/janalyse-series/"&gt;janalyse-series&lt;/a&gt;, is available. It comes with a CSV parser which guesses used CSV format. &lt;br/&gt;&lt;br/&gt;A use case : Google stock quote operations.&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;export CP=../target/scala-2.9.1.final/janalyse-series_2.9.1-0.5.1.jar&lt;br /&gt;exec scala -cp $CP "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;&lt;br /&gt;import fr.janalyse.series._&lt;br /&gt;&lt;br /&gt;val allSeries = CSV2Series.fromURL("http://ichart.finance.yahoo.com/table.csv?s=GOOG")&lt;br /&gt;val closeSeries = allSeries("Close")&lt;br /&gt;&lt;br /&gt;println("GOOGLE stock summary")&lt;br /&gt;println("Higher : "+closeSeries.max)&lt;br /&gt;println("Lowest : "+closeSeries.min)&lt;br /&gt;println("Week Trend : "+closeSeries.stat.linearApproximation.slope*1000*3600*24*7)&lt;br /&gt;println("Latest : "+closeSeries.last)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice that the startup script example has an hardcoded janalyse-series library dependency, update if necessary. &lt;pre class="brush: scala;highlight: [1]"&gt;&lt;br /&gt;$ ./stock.scala &lt;br /&gt;GOOGLE stock summary&lt;br /&gt;Higher : (07-11-06 00:00:00 -&gt; 741,79)&lt;br /&gt;Lowest : (04-09-03 00:00:00 -&gt; 100,01)&lt;br /&gt;Week Trend : 0.9271503465158119&lt;br /&gt;Latest : (11-03-25 00:00:00 -&gt; 579,74)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-8742562496860043601?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/8742562496860043601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/09/timed-numeric-series-library-for-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/8742562496860043601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/8742562496860043601'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/09/timed-numeric-series-library-for-scala.html' title='Timed numeric series library for Scala'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-1931121396067923190</id><published>2011-09-18T22:01:00.000+02:00</published><updated>2011-11-06T10:34:08.460+01:00</updated><title type='text'>Shell like code in Scala...</title><content type='html'>When you starts a Java Virtual Machine, the current directory is set to the directory in which the JVM was started, and it can't be modified any more. If you want to write some shell-like commands in scala, you'll have to find a way to write you're own change directory command (cd), but as the current directory can't be modified, it is not so simple. &lt;br/&gt;&lt;br/&gt;One approach is to use an implicit mutable variable (which will contain the current directory) and change some implicit definitions which came with scala.sys.process.&lt;br/&gt;&lt;pre class="brush: scala;highlight: [9]"&gt;&lt;br /&gt;#!/bin/sh&lt;br /&gt;exec scala "$0" "$@"&lt;br /&gt;!#&lt;br /&gt;import sys.process.Process&lt;br /&gt;import sys.process.ProcessBuilder._&lt;br /&gt;&lt;br /&gt;case class CurDir(cwd:java.io.File)&lt;br /&gt;implicit def stringToCurDir(d:String) = CurDir(new java.io.File(d))&lt;br /&gt;implicit def stringToProcess(cmd: String)(implicit curDir:CurDir) = Process(cmd, curDir.cwd)&lt;br /&gt;&lt;br /&gt;implicit var cwd:CurDir="/tmp"&lt;br /&gt;def cd(dir:String=util.Properties.userDir) = cwd=dir&lt;br /&gt;&lt;br /&gt;// ----------------------&lt;br /&gt;"pwd"!&lt;br /&gt;&lt;br /&gt;cd("/var/tmp/")&lt;br /&gt;"pwd"!&lt;br /&gt;&lt;br /&gt;cd("/var/log/")&lt;br /&gt;"pwd"!&lt;br /&gt;&lt;br /&gt;cd()&lt;br /&gt;"pwd"!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-1931121396067923190?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/1931121396067923190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/09/shell-like-code-in-scala.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1931121396067923190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1931121396067923190'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/09/shell-like-code-in-scala.html' title='Shell like code in Scala...'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-6340092592049571880</id><published>2011-09-18T11:00:00.000+02:00</published><updated>2011-11-06T10:35:00.244+01:00</updated><title type='text'>Scala map implicit conversion into Java Properties</title><content type='html'>As it looks that there's no implicit conversion of a Scala Map (of Strings) into a Java Properties even in the latest Scala release, let's define one.&lt;br /&gt;&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;  implicit def map2Properties(map:Map[String,String]):java.util.Properties = {&lt;br /&gt;    val props = new java.util.Properties()&lt;br /&gt;    map foreach { case (key,value) =&gt; props.put(key, value)}&lt;br /&gt;    props&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Or even in a one line fashion, using folding :&lt;pre class="brush: scala;highlight: [2]" &gt;&lt;br /&gt;  implicit def map2Properties(map:Map[String,String]):java.util.Properties = {&lt;br /&gt;    (new java.util.Properties /: map) {case (props, (k,v)) =&gt; props.put(k,v); props}&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.1 / Java 1.6.0_26&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-6340092592049571880?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/6340092592049571880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/09/scala-map-implicit-conversion-into-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6340092592049571880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/6340092592049571880'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/09/scala-map-implicit-conversion-into-java.html' title='Scala map implicit conversion into Java Properties'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-7422027155065942848</id><published>2011-09-11T19:29:00.000+02:00</published><updated>2011-11-06T10:39:23.679+01:00</updated><title type='text'>Using O/R Broker for JDBC SQL operations from Scala</title><content type='html'>&lt;a href="http://code.google.com/p/orbroker/"&gt;O/R Broker&lt;/a&gt; is an interesting tool which aim to simplify relational database operations from scala language. Many interesting features such as no need of external configuration files (the mapping is done in scala), sql requests can be stored in plain files which make sql requests tuning easier, no leak (connections, statements, resultsets,... are all "managed"), ...&lt;br/&gt;&lt;br/&gt;Let's first install &amp; prepare a mysql service on a gentoo linux system :&lt;pre class="brush: bash; highlight: [2,4,8,10,12,28]"&gt;&lt;br /&gt;As root user : &lt;br /&gt;$ emerge mysql&lt;br /&gt;     ==&gt; To install the latest mysql&lt;br /&gt;$ emerge --config =dev-db/mysql-5.1.56  &lt;br /&gt;     ==&gt; initialize / prepare the database !! Ask for a root password&lt;br /&gt;     ==&gt; choose 'mysql2011root' for example&lt;br /&gt;     ==&gt; You may have to change the release to the precise one that have been installed&lt;br /&gt;$ eselect rc add mysql  default&lt;br /&gt;     ==&gt; For automatic startup as system starts &lt;br /&gt;$ /etc/init.d/mysql start&lt;br /&gt;     ==&gt; Manual start&lt;br /&gt;$ mysql -u root -h localhost -p            (Will ask you the root password  = 'mysql2011root')&lt;br /&gt;     SHOW DATABASES;&lt;br /&gt;     CREATE DATABASE science;&lt;br /&gt;     USE science;&lt;br /&gt;     CREATE TABLE SCIENTIST (&lt;br /&gt;             SCIENTIST_ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, &lt;br /&gt;             FIRST_NAME VARCHAR(128) NOT NULL,&lt;br /&gt;             LAST_NAME VARCHAR(128) NOT NULL,&lt;br /&gt;              BIRTH_DATE DATE);&lt;br /&gt;     INSERT INTO SCIENTIST (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Albert', 'Einstein', STR_TO_DATE('1879-03-18','%Y-%m-%d'));&lt;br /&gt;     INSERT INTO SCIENTIST (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Thomas', 'Edison', STR_TO_DATE('1847-02-11','%Y-%m-%d'));&lt;br /&gt;     INSERT INTO SCIENTIST (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Isaac', 'Newton', STR_TO_DATE('1643-01-16','%Y-%m-%d'));&lt;br /&gt;     INSERT INTO SCIENTIST (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Samuel', 'Morse', STR_TO_DATE('1781-04-27','%Y-%m-%d'));&lt;br /&gt;     INSERT INTO SCIENTIST (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Kurt', 'Gödel', STR_TO_DATE('1906-04-28','%Y-%m-%d'));&lt;br /&gt;     select * from SCIENTIST;&lt;br /&gt;     GRANT ALL ON SCIENTIST.* TO 'guest'@'localhost' IDENTIFIED BY 'guest2011';&lt;br /&gt;$ mysql -u guest -h localhost -D science -p          (Password = guest2011)&lt;br /&gt;     select * from SCIENTIST;&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;Let's create the SBT build configuration file (Build.scala) with all required dependencies :&lt;pre class="brush: scala; highlight: [9]"&gt;&lt;br /&gt;import sbt._&lt;br /&gt;import Keys._&lt;br /&gt;object SQLSandboxBuild extends Build { &lt;br /&gt;  val ssbsettings = Defaults.defaultSettings  ++ Seq(&lt;br /&gt;    name         := "sqlSandbox",&lt;br /&gt;    version      := "1.0",&lt;br /&gt;    scalaVersion := "2.9.1",&lt;br /&gt;    libraryDependencies ++= Seq (&lt;br /&gt;       "org.orbroker"   % "orbroker"             % "3.1.1"    % "compile",&lt;br /&gt;       "mysql"          % "mysql-connector-java" % "5.1.6"    % "compile",&lt;br /&gt;       "org.scalatest"  %% "scalatest"           % "1.6.1"    % "test",&lt;br /&gt;       "c3p0"           % "c3p0"                 % "0.9.1.2"  % "compile"&lt;br /&gt;    ),     &lt;br /&gt;    resolvers += "GEOTools" at "http://download.osgeo.org/webdav/geotools/",&lt;br /&gt;    resolvers += "JBoss Repository" at "http://repository.jboss.org/maven2",&lt;br /&gt;    resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"&lt;br /&gt;  )&lt;br /&gt;  lazy val ssbproject = Project("ssbproject",file("."), settings = ssbsettings)&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Now the next step is to define the mapping for our Scientists database :&lt;pre class="brush: scala; highlight: [3]"&gt;&lt;br /&gt;case class Scientist(firstName:String, lastName:String, birthDate:Option[Date]=None, id:Option[Int]=None)&lt;br /&gt;&lt;br /&gt;object ScientistExtractor extends RowExtractor[Scientist] {&lt;br /&gt;  val key = Set("SCIENTIST_ID")  &lt;br /&gt;  def extract(row: Row) = {&lt;br /&gt;    val id = row.integer("SCIENTIST_ID")&lt;br /&gt;    val List(firstName,lastName) = List("FIRST_NAME", "LAST_NAME") map {row.string(_).get}&lt;br /&gt;    val birthDate = row.date("BIRTH_DATE")&lt;br /&gt;    Scientist(firstName, lastName, birthDate, id)&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object Tokens extends TokenSet(true) {&lt;br /&gt;  val scientistSelectAll   = Token('scientistSelectAll, ScientistExtractor)&lt;br /&gt;  val scientistSelectById  = Token('scientistSelectById, ScientistExtractor)&lt;br /&gt;  val scientistInsert      = Token[Int]('scientistInsert)&lt;br /&gt;  val scientistDelete      = Token('scientistDelete)&lt;br /&gt;  val scientistUpdate      = Token('scientistUpdate)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;So we defined a Scientist case class, and its extractor which tell how to build a Scientist instance from a row of "SCIENTIST" table data.&lt;br/&gt;&lt;br/&gt;We store our sql request inside plain text files :&lt;pre class="brush: bash; highlight: []"&gt;&lt;br /&gt; $ find src/main/resources/sql/ -name "*.sql"&lt;br /&gt;src/main/resources/sql/scientistSelectAll.sql&lt;br /&gt;src/main/resources/sql/scientistDelete.sql&lt;br /&gt;src/main/resources/sql/scientistSelectById.sql&lt;br /&gt;src/main/resources/sql/scientistUpdate.sql&lt;br /&gt;src/main/resources/sql/scientistInsert.sql&lt;br /&gt;&lt;br /&gt;for example, scientistSelectById looks like :&lt;br /&gt;SELECT *&lt;br /&gt;FROM SCIENTIST&lt;br /&gt;where SCIENTIST_ID = :id&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;In order to be able to execute sql requests, you first need to create a "broker" :&lt;pre class="brush: scala; highlight: []"&gt;&lt;br /&gt;  val broker =  {&lt;br /&gt;    val url = "jdbc:mysql://localhost/science"&lt;br /&gt;    val username = "guest"&lt;br /&gt;    val password = "guest2011"  &lt;br /&gt;    val ds = getPooledDataSource(url,username,password) //new SimpleDataSource(url)&lt;br /&gt;    val builder = new BrokerBuilder(ds)&lt;br /&gt;    val res:Map[Symbol,String] = Tokens.idSet map {sym =&gt; sym -&gt; "/sql/%s.sql".format(sym.name)} toMap;&lt;br /&gt;    ClasspathRegistrant(res).register(builder)&lt;br /&gt;    builder.verify(Tokens.idSet)&lt;br /&gt;    builder.setUser(username, password)&lt;br /&gt;    builder.build&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;Get a scientist : &lt;pre class="brush: scala; highlight: []"&gt;&lt;br /&gt;    val scientist = broker.readOnly() {&lt;br /&gt;      _.selectOne(scientistSelectById, "id"-&gt;1)&lt;br /&gt;    }&lt;br /&gt;    scientist should not equal(None)&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;Get all scientists :&lt;pre class="brush: scala; highlight: []"&gt;&lt;br /&gt;    val scientists = broker.readOnly() {&lt;br /&gt;      _.selectAll(scientistSelectAll)&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;Browse scientists :&lt;pre class="brush: scala; highlight: []"&gt;&lt;br /&gt;    broker.readOnly() {&lt;br /&gt;      _.select(scientistSelectAll) { scientist =&gt;&lt;br /&gt;        println(scientist)&lt;br /&gt;        true&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;And now the classical CRUD operations :&lt;pre class="brush: scala; highlight: [1,7,12,17]"&gt;&lt;br /&gt;    // Create&lt;br /&gt;    val newscientist = broker.transaction() { txn =&gt;&lt;br /&gt;      val scientist = Scientist("Benoist","Mandelbrot")&lt;br /&gt;      val newid = txn.executeForKey(scientistInsert, "scientist"-&gt;scientist)&lt;br /&gt;      scientist.copy(id = newid)&lt;br /&gt;    }&lt;br /&gt;    // Update&lt;br /&gt;    val updatedScientist = newscientist.copy(birthDate = "1924-11-20")&lt;br /&gt;    broker.transaction() { txn =&gt;&lt;br /&gt;      txn.execute(scientistUpdate, "scientist"-&gt;updatedScientist)&lt;br /&gt;    }&lt;br /&gt;    // Read&lt;br /&gt;    val foundScientist = broker.readOnly() {&lt;br /&gt;      _.selectOne(scientistSelectById, "id"-&gt;updatedScientist.id).get&lt;br /&gt;    }&lt;br /&gt;    foundScientist should equal(updatedScientist)&lt;br /&gt;    // Delete&lt;br /&gt;    broker.transaction() { txn =&gt;&lt;br /&gt;      txn.execute(scientistDelete, "id" -&gt; updatedScientist.id.get)&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;Notice here that once the new scientist has been created in the database we got back the automatically created numeric ID, so we return a new instance of scientist which contains the id chosen by the database, the original instance has not been modified, we want to keep all the benefits of immutability !&lt;br/&gt;&lt;br/&gt;And now let's generate some load (40*10000 sql requests executed in parallel) on the database, and check the c3p0 database connection pool using an external jconsole :&lt;pre class="brush: scala; highlight: []"&gt;&lt;br /&gt;    import actors.Actor._&lt;br /&gt;    val howmany=40&lt;br /&gt;    val creator = self&lt;br /&gt;    for (n &lt;- 1 to howmany) {&lt;br /&gt;      actor {&lt;br /&gt;        try {&lt;br /&gt;          for(i&lt;-1 to 10000) {&lt;br /&gt;            val scientists = broker.readOnly() {&lt;br /&gt;               _.selectAll(scientistSelectAll)&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;        } finally {&lt;br /&gt;          creator ! "finished"&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }    &lt;br /&gt;    for (i&lt;- 1 to howmany) receive {&lt;br /&gt;      case _ =&gt;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;The full SBT project is available  here : &lt;a href="http://dnld.crosson.org/sqlsandbox.tar.gz"&gt;sqlsandbox.tar.gz&lt;/a&gt;.&lt;br/&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.1 / Java 1.6.0_26 / SBT 0.10 / ScalaTest 1.6.1 / ORBroker 3.1.1&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-7422027155065942848?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/7422027155065942848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/09/using-or-broker-for-jdbc-sql-operations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7422027155065942848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7422027155065942848'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/09/using-or-broker-for-jdbc-sql-operations.html' title='Using O/R Broker for JDBC SQL operations from Scala'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-1081208861600941111</id><published>2011-09-04T11:48:00.000+02:00</published><updated>2011-11-06T10:40:42.148+01:00</updated><title type='text'>Method receiver implicit conversions - data units use case</title><content type='html'>Scala implicit conversion is a great concept, basically you can use this feature to simplify object instanciation, I mean avoiding java constructor profusion by just providing in scala one construtor, and a set of implicit conversions (and of course default values). What's great with implicits is that they also apply on the receiver, let's see an example.&lt;br /&gt;&lt;br /&gt;We want to be able to give durations or bytes size in a natural way, let's start a scala console through the &lt;a href="https://github.com/harrah/xsbt"&gt;sbt&lt;/a&gt; console, and try out my "unittools" library (download link : &lt;a href="http://dnld.crosson.org/unittools.tar.gz"&gt;unittools.tar.gz&lt;/a&gt;) :&lt;pre class="brush: scala;highlight: [1,3,9,12,15, 18, 21]"&gt;&lt;br /&gt;dcr@lanfeust ~/dev/unittools $ sbt&lt;br /&gt;[info] Set current project to default-0b115b (in build file:/home/dcr/dev/unittools/)&lt;br /&gt;&gt; console&lt;br /&gt;[info] Starting scala interpreter...&lt;br /&gt;[info] &lt;br /&gt;Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_26).&lt;br /&gt;Type in expressions to have them evaluated.&lt;br /&gt;Type :help for more information.&lt;br /&gt;scala&gt; import unittools.UnitTools._&lt;br /&gt;import unittools.UnitTools._&lt;br /&gt;&lt;br /&gt;scala&gt; "10h50m30s".toDuration&lt;br /&gt;res0: Long = 39030000&lt;br /&gt;&lt;br /&gt;scala&gt; "1gb100kb".toSize&lt;br /&gt;res1: Long = 1073844224&lt;br /&gt;&lt;br /&gt;scala&gt; 15444002.toDurationDesc&lt;br /&gt;res1: String = 4h17m24s2ms&lt;br /&gt;&lt;br /&gt;scala&gt; 68675454743L.toSizeDesc&lt;br /&gt;res2: String = 63gb982mb17kb791b&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;That's quite better to write "10h50m30s" inside your configuration files instead of "39030000", or "4h17m24s2ms" instead of "15444002" if you have to report a response time ! &lt;br/&gt;&lt;br/&gt;Of course strings don't have toDuration and toSize methods, in fact the "import unittools.UnitTools._" makes new implicit conversion definitions available to the compiler, those conversions make possible to convert a String instance to an internal object instance for which toDuration or toSize is available.&lt;br/&gt;&lt;br/&gt;the "plumbing" is the following :&lt;pre class="brush: scala;highlight: []"&gt;&lt;br /&gt;package unittools&lt;br /&gt;&lt;br /&gt;class DurationHelper(value:Long, desc:String) {&lt;br /&gt;  def toDuration()=value&lt;br /&gt;  def toDurationDesc()=desc&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class SizeHelper(value:Long, desc:String) {&lt;br /&gt;  def toSize()=value&lt;br /&gt;  def toSizeDesc()=desc&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object UnitTools {&lt;br /&gt;  // Implicit conversions&lt;br /&gt;  implicit def string2DurationHelper(desc:String) = new DurationHelper(desc2Duration(desc), desc)&lt;br /&gt;  implicit def long2DurationHelper(value:Long) = new DurationHelper(value, duration2Desc(value))&lt;br /&gt;&lt;br /&gt;  implicit def string2SizeHelper(desc:String) = new SizeHelper(desc2Size(desc), desc)&lt;br /&gt;  implicit def long2SizeHelper(value:Long) = new SizeHelper(value, size2Desc(value))&lt;br /&gt;&lt;br /&gt;  //...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br/&gt;it's worth noting that the scala unittool internal algorithm contains less code than the java release I first made; 25 lines for scala, 40 lines for java.&lt;br/&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.1 / Java 1.6.0_26 / SBT 0.10 / ScalaTest 1.6.1&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-1081208861600941111?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/1081208861600941111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/09/method-receiver-implicit-conversions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1081208861600941111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1081208861600941111'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/09/method-receiver-implicit-conversions.html' title='Method receiver implicit conversions - data units use case'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-7074261876041813007</id><published>2011-08-25T21:25:00.002+02:00</published><updated>2011-12-09T00:00:45.555+01:00</updated><title type='text'>Playing with JMX and Scala : MBean Creation &amp; "Remote" access</title><content type='html'>&lt;b&gt;** Update (2011-12-07) : scala JMX API project just created... I've started refactoring an older JMX scala API, and I'll release the new API as an open source project. The project link :  &lt;a href="https://code.google.com/p/janalyse-jmx/"&gt;janalyse-jmx : scala JMX API&lt;/a&gt;&lt;/b&gt;&lt;br/&gt;&lt;br/&gt;An example (&lt;a href="http://dnld.crosson.org/jmxsandbox.tar.gz"&gt;download corresponding sbt project&lt;/a&gt;) of how to create a MBean in Scala. We define the MBean interface using scala trait, and make our class implements the trait capabilities. No need to define the getter thanks to the "@BeanProperty" annotation, scala does the job for us. The MBean registration is directly done within Supervisor class instanciation, the jmxRegister method and with an implicit conversion to automatically convert a String to an ObjectName.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala;highlight: [10,11,12,24,25,30,31,32]"&gt;&lt;br /&gt;package jmxsandbox&lt;br /&gt;&lt;br /&gt;import scala.actors.Actor&lt;br /&gt;import scala.reflect.BeanProperty&lt;br /&gt;import java.lang.management.ManagementFactory&lt;br /&gt;import javax.management.ObjectName&lt;br /&gt;&lt;br /&gt;// Some definitions to simplify the code&lt;br /&gt;private object JMXHelpers {&lt;br /&gt;    implicit def string2objectName(name:String):ObjectName = new ObjectName(name)&lt;br /&gt;    def jmxRegister(ob:Object, obname:ObjectName) = &lt;br /&gt;      ManagementFactory.getPlatformMBeanServer.registerMBean(ob, obname)&lt;br /&gt;}&lt;br /&gt;import JMXHelpers._&lt;br /&gt;&lt;br /&gt;// Some messages managed by the Supervisor actor&lt;br /&gt;sealed abstract class Message&lt;br /&gt;case object MAlive extends Message&lt;br /&gt;case object MDead  extends Message&lt;br /&gt;case object MExit  extends Message&lt;br /&gt;case object MGet   extends Message&lt;br /&gt;&lt;br /&gt;// The defined MBean Interface&lt;br /&gt;trait SupervisorMBean {&lt;br /&gt;  def getAlive():Int&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// The class with JMX MBean&lt;br /&gt;class Supervisor extends Actor with SupervisorMBean {&lt;br /&gt;  jmxRegister(this, "JMXSandbox:name=Supervisor")&lt;br /&gt;  @BeanProperty&lt;br /&gt;  var alive=0&lt;br /&gt;  def act() {&lt;br /&gt;    loop { &lt;br /&gt;      react {&lt;br /&gt;        case MAlive =&gt; alive+=1&lt;br /&gt;        case MDead  =&gt; alive-=1&lt;br /&gt;        case MExit  =&gt; exit&lt;br /&gt;        case MGet   =&gt; reply(alive)&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And now the test case, showing how to test within the same JVM our Supervisor MBean. The test case creates an internal MBean server, which will be used by Supervison internal MBean registration. So we take benefits of local and remote-like access from jmx for our test case.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala; highlight: [25,40,41,44]"&gt;&lt;br /&gt;package jmxsandbox&lt;br /&gt;&lt;br /&gt;import java.rmi.registry.LocateRegistry&lt;br /&gt;import java.lang.management.ManagementFactory&lt;br /&gt;import javax.management.remote.JMXConnectorServerFactory&lt;br /&gt;import javax.management.remote.JMXConnectorFactory&lt;br /&gt;import javax.management.remote.JMXServiceURL&lt;br /&gt;&lt;br /&gt;import org.scalatest.FunSuite&lt;br /&gt;import org.scalatest.matchers.ShouldMatchers&lt;br /&gt;&lt;br /&gt;import JMXHelpers._&lt;br /&gt;&lt;br /&gt;class SelfTest extends FunSuite with ShouldMatchers {&lt;br /&gt;  // Let's create and start a local JMX service&lt;br /&gt;  LocateRegistry.createRegistry(4500)&lt;br /&gt;  val url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:4500/jmxapitestrmi")&lt;br /&gt;  val mbs = ManagementFactory.getPlatformMBeanServer()&lt;br /&gt;  val cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs)&lt;br /&gt;  cs.start&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;  test("Checking supervisor state with standard access and from JMX interface") {&lt;br /&gt;    // Create and start the supervisor actor&lt;br /&gt;    val supervisor = new Supervisor {start}&lt;br /&gt;    &lt;br /&gt;    // Send a MAlive message to the supervisor&lt;br /&gt;    supervisor ! MAlive&lt;br /&gt;    &lt;br /&gt;    // get the current alive value from the actor&lt;br /&gt;    val stateDirect = (supervisor !? MGet) match {&lt;br /&gt;      case e:Int =&gt; e&lt;br /&gt;      case _ =&gt; -1&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    // The check&lt;br /&gt;    stateDirect should equal (1)&lt;br /&gt;&lt;br /&gt;    // Do the same but using Supervisor MBean to read the alive value&lt;br /&gt;    val mbserver = JMXConnectorFactory.connect(url).getMBeanServerConnection&lt;br /&gt;    val stateViaJMX = mbserver.getAttribute("JMXSandbox:name=Supervisor","Alive").asInstanceOf[Int]&lt;br /&gt;    &lt;br /&gt;    // The check&lt;br /&gt;    stateViaJMX should equal (stateDirect)&lt;br /&gt;    &lt;br /&gt;    // Ask the actor to exit&lt;br /&gt;    supervisor ! MExit&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.0 / Java 1.6.0_26 / SBT 0.10 / ScalaTest 1.6.1&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-7074261876041813007?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/7074261876041813007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/08/playing-with-jmx-and-scala-mbean.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7074261876041813007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/7074261876041813007'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/08/playing-with-jmx-and-scala-mbean.html' title='Playing with JMX and Scala : MBean Creation &amp; &quot;Remote&quot; access'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4576039096616564465.post-1761151872437306946</id><published>2011-08-22T22:31:00.003+02:00</published><updated>2011-11-06T10:43:44.754+01:00</updated><title type='text'>Simple SBT use case</title><content type='html'>&lt;a href="https://github.com/harrah/xsbt/wiki"&gt;Simple Build Tool (sbt)&lt;/a&gt; is an impressive tool, building is really fast, and configuration quite simple in particular with small projects. No need to learn a new language, as sbt configuration is made using scala ! Of course&amp;nbsp;automatic dependencies resolution is available !&lt;br /&gt;&lt;br /&gt;Consider the following simple project, &lt;a href="http://dnld.crosson.org/naturalsort.tar.gz"&gt;naturalsort.tar.gz&lt;/a&gt;, whose file hierarchy is the following :&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;&lt;br /&gt;naturalsort/&lt;br /&gt;naturalsort/build.sbt&lt;br /&gt;naturalsort/src/main/scala/naturalsort/NaturalSort.scala&lt;br /&gt;naturalsort/src/test/scala/naturalsort/NaturalSortTest.scala&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"build.sbt" just contains :&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: scala"&gt;&lt;br /&gt;name := "NaturalSort"&lt;br /&gt;&lt;br /&gt;version := "1.0"&lt;br /&gt;&lt;br /&gt;scalaVersion := "2.9.0"&lt;br /&gt;&lt;br /&gt;libraryDependencies += "org.scalatest" % "scalatest_2.9.0" % "1.6.1" % "test"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Once sbt is setup, just enter "naturalsort" directory, and run sbt; it will resolve dependencies, and make the sbt console available for you :&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: plain;highlight: [3, 8, 20,23,28]"&gt;&lt;br /&gt;$ cd naturalsort/&lt;br /&gt;$ sbt&lt;br /&gt;&gt;  compile&lt;br /&gt;[info] Updating {file:/home/dcr/dev/naturalsort/}default-76224f...&lt;br /&gt;[info] Done updating.&lt;br /&gt;[info] Compiling 1 Scala source to /home/dcr/dev/naturalsort/target/scala-2.9.0.final/classes...&lt;br /&gt;[success] Total time: 6 s, completed 22 août 2011 22:21:14&lt;br /&gt;&gt; test&lt;br /&gt;[info] Compiling 1 Scala source to /home/dcr/dev/naturalsort/target/scala-2.9.0.final/test-classes...&lt;br /&gt;[info] NaturalSortTest:&lt;br /&gt;[info] - basic tests&lt;br /&gt;[info] - advanced tests&lt;br /&gt;[info] - special cases tests *** FAILED ***&lt;br /&gt;[info]   List(1.1, 1.002, 1.3, 1.010) did not equal List(1.001, 1.002, 1.010, 1.02, 1.1, 1.3) (NaturalSortTest.scala:37)&lt;br /&gt;[error] Failed: : Total 3, Failed 1, Errors 0, Passed 2, Skipped 0&lt;br /&gt;[error] Failed tests:&lt;br /&gt;[error]  naturalsort.NaturalSortTest&lt;br /&gt;[error] {file:/home/dcr/dev/naturalsort/}default-76224f/test:test: Tests unsuccessful&lt;br /&gt;[error] Total time: 4 s, completed 22 août 2011 22:21:35&lt;br /&gt;&gt; ~compile&lt;br /&gt;[success] Total time: 0 s, completed 22 août 2011 22:23:02&lt;br /&gt;1. Waiting for source changes... (press enter to interrupt)&lt;br /&gt;&gt; ~ test-only naturalsort.NaturalSortTest&lt;br /&gt;[info] Compiling 1 Scala source to /home/dcr/dev/naturalsort/target/scala-2.9.0.final/test-classes...&lt;br /&gt;[info] NaturalSortTest:&lt;br /&gt;[info] - extreme tests&lt;br /&gt;...&lt;br /&gt;&gt; package&lt;br /&gt;[info] Packaging /home/dcr/dev/naturalsort/target/scala-2.9.0.final/naturalsort_2.9.0-1.0.jar ...&lt;br /&gt;[info] Done packaging.&lt;br /&gt;[success] Total time: 0 s, completed 4 sept. 2011 10:55:24&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;CONTEXT : Linux Gentoo / Scala 2.9.0 / Java 1.6.0_26 / SBT 0.10 / ScalaTest 1.6.1&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4576039096616564465-1761151872437306946?l=www.crosson.org' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.crosson.org/feeds/1761151872437306946/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.crosson.org/2011/08/simple-sbt-use-case.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1761151872437306946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4576039096616564465/posts/default/1761151872437306946'/><link rel='alternate' type='text/html' href='http://www.crosson.org/2011/08/simple-sbt-use-case.html' title='Simple SBT use case'/><author><name>david crosson</name><uri>https://profiles.google.com/101287587440905525164</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-kznwTfW26LU/AAAAAAAAAAI/AAAAAAAABW8/Brjkxoo0ZZA/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry></feed>
