Tuesday, 28 January 2014

Java 8 in Eclipse

Have you tried out Java 8 yet? The official release is not until March 2014 but there have been a set of release candidates to play with. It is actually very easy to get up and running.
  1. Download a JDK 8 snapshot from https://jdk8.java.net/ and install it.
  2. Install a version of Eclipse that can handle Java 8 syntax. I downloaded Eclipse Luna 4.4 from http://downloads.efxclipse.org/eclipse-java8/2013-05-19/.
To get started, create a new project in Eclipse and make sure you have chosen the Java 8 JRE.



Here's a class that uses a lambda expression to instantiate the functional interface PowerCalculator. A functional interface is an interface with only one abstract method.

public class TestClass {

    interface PowerCalculator {
        int pow(int n, int exponent);
    }

    public static void main(final String[] args) {
        final PowerCalculator calc = (int n, final int exponent) -> {
            return (int) Math.pow(n, exponent);
        };
        
        int product = calc.pow(3, 4);
        System.out.println(product);
    }
}
This outputs the expected "81".

That was maybe not very cool, but when looking into the more functional style of programming you can do with lambda expressions, this is the most interesting Java upgrade since Java 5 in my opinion.
I wrote an article in 2012 on FP in Java http://macgyverdev.blogspot.se/2012/10/functional-programming-in-java.html and took a quick look now again to see whether the original spec still is valid.

Here is a few examples I tried on the Collections framework. There has been changes since the 2012 draft. For example is the stream() interface added, previously you could do a filter() directly on the collection. The stream interface allows for parallel execution and

public class TestClass {

    public static void main(final String[] args) {
     List<Animal> animals = Arrays.asList(new Animal(10), new Animal(20), new Animal(30), new Animal(40));
     
     // Each animal eats another calorie
     animals.forEach(a -> a.eat(1));
     
     // Print animal
     animals.forEach(a -> a.print());
     
     // Print only the animals which have more than 30 calories
     animals.stream()
            .filter(a -> a.nutrition() > 30)
            .forEach(a -> a.print());
     
     // Calculate total sum of all animals calories
     int sum = animals.stream()
                      .mapToInt(a -> a.nutrition())
                      .sum();
    }
}

class Animal {
 private int calories = 0;
 
 public Animal(int calories) {
  this.calories = calories;
 }
 
 public void eat(int calories) {
  this.calories += calories;
 } 

 public void print() {
  System.out.println("Calories: " + calories);
 } 

 public int nutrition() {
  return calories;
 }
}


The Eclipse support in Luna 4.4 is pretty good. But when using the command completition it is not obvious what the different lamda expression consumers expect. I guess once you have played around with it some more you get accustomed to the Predicate and Consumer APIs.

Friday, 24 January 2014

Setup Jenkins project from Git repository with Findbugs, Cobertura and Checkstyle

I created a Jenkins setup for my current Java hobby project (a site on physical units intended to make ads money, check it out at http://www.all-about-units.com) yesterday and noticed that my old note on how to setup Jenkins (then it was written for Hudson) is a bit out of date. The Jenkins configuration menues for generating Findbugs static analysis, Cobertura code coverage and Checkstyle format control were completely new. In addition to that, I've migrated to Git since then so there are a few steps also involved in getting Git running as code repository within Jenkins.

Here's a workflow for setting up Jenkins with these features.

Install Jenkins and plugins

First of all, if you haven't installed Jenkins the easiest way is to download the war archive from http://jenkins-ci.org/. This article is based on Jenkins version 1.532.1. You can install in in a server container like Tomcat or Jetty, but the easiest way to get started is to run it from the command line like 

java -jar jenkins.war

I created a small bash script which also changes the port since I have another server using the default 8080 port.

#!/bin/sh

nohup java -jar jenkins.war --httpPort=8081

So now you can access Jenkins via http://localhost:8081 or similar.

Now we must install some plugins which are not part of the core distribution. Go to the settings of Jenkins and find the Plugins section.

Here you should at least find the following plugs and install them





Creating Jenkins job

Create a new Jenkins job. My project handles its dependencies via Maven 3 which suits Jenkins very well. Choose the Maven 2/3 option.


In the next step, choose Git as SCM. If you have your Git repository on the same server as Jenkins you can simply add the file path to the repository. Otherwise you setup the security credentials here as well. Also, choose if you want to build master or some other branch.


We haven't talked about the pom.xml for the project yet, but it will be configured to use some Maven goals. So in the Maven goals section, add goals for test package site.

Under Build settings, check the boxes for Publish Checkstyle analysis resultsPublish FindBugs analysis results and Publish duplicate code analysis results.


In the Post-build Actions add a step for Cobertura reporting.


Maven will generate the Cobertura report to the Jenkins workspace under path /target/site/cobertura/coverage.xml so add this in the configuration of the action.



Now you should have a Jenkins job setup ready for building.


Before building we must make sure the pom.xml of the project has the correct plugins and reports configured.

Maven pom.xml configuration

After all the dependency specifications in the pom.xml add something similar to this. In this setup Cobertura is configured in the package phase and that's why we added that Maven goal above. If you hadn't added this in the pom file, you could have added separate Maven goals for Cobertura in Jenkins as well.

<build>
   <finalName>Unitconversion</finalName>
   <plugins>
      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <version>${findbugs.version}</version>
      </plugin>
      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
         <version>${cobertura.version}</version>
         <configuration>
            <formats>
               <format>xml</format>
            </formats>
         </configuration>
         <executions>
            <execution>
               <phase>package</phase>
               <goals>
                  <goal>cobertura</goal>
               </goals>
            </execution>
         </executions>
      </plugin>
   </plugins>
</build>
<reporting>
   <plugins>
      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>findbugs-maven-plugin</artifactId>
         <version>${findbugs.version}</version>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-checkstyle-plugin</artifactId>
         <version>${checkstyle.version}</version>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-report-plugin</artifactId>
         <version>${surefire.reportplugin.version}</version>
      </plugin>
      <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>cobertura-maven-plugin</artifactId>
         <version>${cobertura.version}</version>
         <configuration>
            <formats>
               <format>xml</format>
            </formats>
         </configuration>
      </plugin>
   </plugins>
</reporting>
Run the job and everything should work out of the box. Do another build to start getting history graphs like below of the trend of failing tests, checkstyle warnings, issues found by Findbugs and te code coverage statistics from Cobertura.




Tuesday, 21 January 2014

Share code between Windows and Linux using git

Here's how I setup my git repository on my Linux HTPC which I can store my projects on from the Windows workstation. No extra daemons or servers running. Plain ssh.

First create a repository on the Linux machine.

johan@johanhtpc ~ $ mkdir gitrepos
johan@johanhtpc ~ $ cd gitrepos/
johan@johanhtpc ~ $ mkdir UnitConversion.git
johan@johanhtpc ~ $ cd UnitConversion.git/
johan@johanhtpc ~ $ git --bare init --shared=all

Now, from the Windows machine, I start up gitbash and go to the directory where I have the code I want to share. Then I add a new remote against my Linux machine and name the remote htpc.

Johan@ELLINGTONI5 /c/ws/UnitConversion
$ git init
Initialized empty Git repository in c:/ws/UnitConversion/.git/

Johan@ELLINGTONI5 /c/ws/UnitConversion (master)
$ git remote add htpc johan@johanhtpc:gitrepos/UnitConversion.git

I add everything in this directory to the local repository

Johan@ELLINGTONI5 /c/ws/UnitConversion (master)
$ git add --all

Johan@ELLINGTONI5 /c/ws/UnitConversion (master)
$ git commit

Now, let's push everything over the network to the Linux machine.

Johan@ELLINGTONI5 /c/ws/UnitConversion (master)
$ git push htpc master
johan@johanhtpc's password:
Counting objects: 729, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (601/601), done.
Writing objects: 100% (728/728), 141.03 MiB | 8.35 MiB/s, done.
Total 728 (delta 118), reused 0 (delta 0)
To johan@johanhtpc:johanrepo.git
   869b12e..ab0f0b7  master -> master

Now, if I want to checkout the code on the Linux machine as a working copy, it's really simple

johan@johanhtpc ~/ws $ git clone ~/gitrepos/UnitConversion.git
Cloning into 'UnitConversion'...
done.

Now, push and pull from the local repositories against the common to work. Notice that from the Linux working repository the remote is named by default origin. So when pushing the command will be

johan@johanhtpc ~/ws/UnitConversion $ git push origin master



Wednesday, 1 January 2014

Weather Station using Raspberry Pi, Tomcat and CouchDB

As a Christmas gift I've built a remote temperature sensoring system to make it possible to record and keep track of the temperature in a summer house on an island in the Baltic Sea. The background is that the temperature cannot be too cold in the house during the winter, since the piping may freeze. This gizmo could maybe help in tuning the electric heating of the house to avoid making it too warm but not too cold either. It will also help to identify when the power is out in the house and the heating is malfunctioning making it necessary to travel out to the house to avoid the water to freeze.

Overview

The layout is a Raspberry Pi using a DS18B20 digital temperature sensor that reads the temperature in the house. There is a NMT radio router in the house which serves Internet access. On a Tomcat server in the cloud, a Java web app accepts readings from the Raspberry via a REST API and stores the information in a CouchDB database. The web application also presents a single page web app that reads temperature data via the REST API and presents some nice graphs and tables. The frontend is built using Bootstrap to get a responsive design for both desktop and mobile.


The finished web application would look like this on desktop


and on a phone it would scale appropriately as well.

At the top the application will report for how long the sensor has been active (possibly since the last electricity outtake). If the sensor has not reported any readings during 15 minutes, it is assumed to be offline and a warning will be presented that we have no knowledge of the current temperature. If the ekectricity is gone in the house the heat will probably also be gone.

Setup the hardware

What you need:

  • Raspberry Pi
  • SD card (at least 4GB)
  • Micro USB cable
  • Ethernet cable
  • DS18B20 temperature sensor
  • 4.7 kOhm resistor
  • Wires
  • Piece of PCB bread board
  • Some kind of case
  • Soldering iron

So first of all let's setup the Raspberry Pi unit. I had the oldest model with 256MB RAM and Ethernet. I also have one of the newer 512MB  models and I've tried the setup successfully on both. Since the 256MB version worked, that's the one I've shipped. Here's how to make it into a temperature sensor.

Try out the connections on a breadboard according to this sketch (borrowed from AdaFruit)

The ports on the Pi are if not obvious in the sketch the 3.3V power port at slot 1, the data pin is pin #4 and the third wire is connected to ground.
DS18B20 water proof temp sensor

There are several versions of the DS18B20 temperature sensor. I used the water proof version, it's only marginally more expensive than the others but since it has a chord in contrast to the other ones it can be put outside a window if you want.

Then install the software according to below and make sure everything works. However, to make the final product more stable and resistent to shakes you should of course solder the wires. I recommend using an experiment board for this with lanes. I bought one of these a long time ago from Swedish Kjell & Company. It makes the soldering easy and you have lanes of conducting copper which makes it easy to overview your structure and debug errors with a voltmeter.

In this build the amount of board needed is tiny so not many cents of hardware needed. I bought a general purpose plastic box as well to mount the parts within. The box I found had predrilled holes within the box suitable for attaching PCBs and other parts. Very practical.






The final assembly looked like this with the top of the box removed


Setup the software


mkdir weatherstation
scp /WeatherStationServer/raspberrypi/src/weatherstation.py      pi@piaddress:weatherstation/
  • So the juice is in the weatherstation.py python script. But to run it by default on start up we create a wrapper bash script. Create a file /home/pi/weatherstation/weatherstation.sh containing

 #!/bin/sh
sleep 10
sudo python /home/pi/weatherstation/weatherstation.py

  • Make sure this kicks in when the Raspberry boots by adding this to /etc/rc.local

/home/pi/weatherstation/weatherstation.sh &

  • In the weatherstation.py script, adjust the URI to your potential backend server. The lines containing the following should be adjusted to your server and appname. The appname should be changed to the name of your system preferrably so that you may have multiple systems running on the same backend and CouchDB database.
conn = httplib.HTTPConnection("192.168.1.6:8080")
conn.request("POST", "/WeatherStationServer/api/temperature/appname", params, headers)
  • Reboot the Raspberry Pi and the script should try to post readings to the URI in the script.
If you want to make your own script or just verify that the sensor is working correctly the important thing about this sensor is that when you add the kernel modules that handle the protocol the sensor is using, specific file handles will be created by the operating system containing the current temperature.
So you could alternatively try

sudo modprobe w1-gpio
sudo modprobe w1-therm
cd /sys/bus/w1/devices
ls
cd 28-xxxx (change this to match what serial number pops up)
cat w1_slave

So, assuming you are using the provided python script, now we must setup a server that can handle these temperature postings. The source code is in the GitHub repository, you can pull via https://github.com/johannoren/WeatherStation.git

Install this in a Java web server, I used Tomcat 7. To install Tomcat on a Linux Ubuntu flavoured server is trivial 

sudo apt-get install tomcat7 tomcat7-admin tomcat7-common

I personally use Eclipse to build my code, and then export the Web module as war archive (Right-click on the module in Eclipse and choose Export -> WAR archive). Then you can deploy the war file directly in the Tomcat web admin console which is usually located here http://serveraddress/manager/html.

However, the application must store the temperature data in a database and it is configured to use HTTP RESTful calls to store and retrieve JSON data. CouchDB will make a perfect backend for this.

Some notes on installation and how to work with CouchDB using curl in this blog post http://macgyverdev.blogspot.se/2013/12/couchdb-on-linux-mint.html, but it is trivial, apt-get to install.

sudo apt-get install couchdb -y

Create a database for the particular temperature sensor application via

curl -vX PUT http://127.0.0.1:5984/nameofapp

Depending on where you have deployed the CouchDB databse the Java application must be adjusted to communicate to the correct address and port. Before building and exporting the war archive to deploy in Tomcat make sure this constant is correct

WeatherStation /src/se/noren/weatherstation/WeatherStationServiceImpl.java

private static final String COUCHDB_SERVER = "http://johanhtpc:5984";

That's it, now the web app on the server can start posting readings to the database via essentially doing POSTs to the same URL. I used Spring Templates in the Java code which makes REST calls a no brainer. Look at this source code to figure out how to wrap the Spring Template to handle cookies, error handling etcetera https://github.com/johannoren/WeatherStation/blob/master/src/se/noren/weatherstation/adapter/CouchDBAdapter.java

If you wish to see the contents of the database you can do something like this

curl -X GET http://127.0.0.1:5984/nameofapp/_all_docs?include_docs=true

And if you want to delete it to reset testing, you can guess what you need

curl -vX DELETE http://127.0.0.1:5984/nameofapp

More commands in the previous mentioned post.

All good. That's about it I think, if interested in more details on some part, please comment.

If you want to use Fahrenheit or some other system of measurement for temperatures, check out my new hobby project All About Units where there's a lot of goodies on units.

You can buy your Raspberry Pi from many places on the net. Amazon has got both new and used ones for a cheaper prize.




Addition 2015-01-06:
This setup has been extended with another temperature sensor to monitor outside temperature as well. See this blogpost for the additions: http://macgyverdev.blogspot.se/2015/01/raspberry-pi-weather-station-with.html


Just for reference:
I added Google Analytics tracking to be able to see the utilization of the sensor. Here I learned a new thing as well about Analytics. I had the probe run for some time at home before christmas to see that it behaved stable and didn't crash after a long running time, which it didn't, but I unfortunately noticed that the first deployment I made in Google App Engine of the server backend used up to much resources and went over the free quota limit making the server unusable. So I moved the server backend to another server residing on a different domain. Suddenly the Analytics stats disappeared on december 22nd. I had already started wrapping the present. :-/


So the problem is that Google Analytics is specifying the cookie domain in the Javascript. I think this is new, I have no domains in my old Analytics scripts. So what you need to do if you encounter this problem is to manually change this line in the Google Analytics Javascript snippet

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-46361998-1', 'newdomain.com');
ga('send', 'pageview');