Tuesday, 29 May 2018

Python subprocess stdout and stderr

In our machine learning pipeline we have number of python subprocesses being started from main python process. Originally subprocess were started using using this simple procedure

import subprocess

def check_call(commands, shell=False):
    process = subprocess.Popen(commands, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    stdout, stderr = process.communicate()
    if proc.returncode != 0:
        raise IOError(
                'Call failed, cmd=%s, return_code=%s, stderr=%s, stdout=%s' % (commands, process.returncode, stderr, stdout))
    return stdout, stderr

Drawback of this solution is that process.communicate() is blocking and subprocess standard output and error output is being accumulated into variable and available only after execution ends or fails. In our case that could be tens of minutes of even few hours. Issue was bit overcame by logging into file in subprocess, which gives some sort of real time feedback about it's proceeding. Also when subprocess hangs it will block main process forever and manual action might be necessary to unblock pipeline.

I've been looking form better solution which would make standard output lines available as soon as it is produced by subprocess. While it is old problem, I've found only prototypes and no ready to use code. So here comes my take on it based on unbutu's stackoverflow response with another one from Vadim Fint, merged together and pimped up a bit. Code is for Python 2.7 and it will probably work in Python 3 as well, but then you probably should go with proper Python 3 solution

Asynchronous version is lightweight as it does not need to spawn threads to read outputs and perform timeout checks. Using only standard python library, works for us very well.


import sys
import subprocess
import fcntl
import select
import os
import datetime

def execute(commands, sysout_handlers=[sys.stdout.write], syserr_handlers=[sys.stderr.write], shell=False, cwd=None, timeout_sec=None):
    """Executes commands using subprocess.Popen and asynchronous select and fcntl to handle subprocess standard output and standard error stream
    
    Examples:
        execute(['python2.7', 'random_print.py'])
        execute(['python2.7', 'random_print.py'], outlist.append, errlist.append)
        execute(['python2.7', 'random_print.py'], timeout_sec = 3)
        execute(['ls', '-l'], cwd = '/tmp')
    
    :param commands: list of strings passed to subprocess.Popen()
    :param sysout_handlers: list of handlers for standard output stream 
    :param syserr_handlers: list of handlers for standard error stream 
    :param shell: boolean, default false, default False, passed to subprocess.Popen()
    :param cwd: string, default None, passed to subprocess.Popen()
    :param timeout_sec: int, default None, number of seconds when terminate process. Cannot be less then 1 second
    :return: process returncode or None when timeout is reached. Allways check this value
    """
    
    def make_async(fd):
        # https://stackoverflow.com/a/7730201/190597
        '''add the O_NONBLOCK flag to a file descriptor'''
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
    
    def read_async(fd):
        # https://stackoverflow.com/a/7730201/190597
        '''read some data from a file descriptor, ignoring EAGAIN errors'''
        try:
            return fd.read()
        except IOError, e:
            if e.errno != errno.EAGAIN:
                raise e
            else:
                return ''
    
    def handle_line(line, handlers):
        if isinstance(handlers, list):
            for handler in handlers:
                handler(line)
        else:
            handlers(line)

    def handle_output(fds, handler_map):
        for fd in fds:
            line = read_async(fd)
            handlers = handler_map[fd.fileno()]
            handle_line(line, handlers)

    process = subprocess.Popen(commands, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=shell, cwd=cwd)
    make_async(process.stdout)
    make_async(process.stderr)
    handler_map = { process.stdout.fileno() : sysout_handlers, process.stderr.fileno() : syserr_handlers }
    
    started = datetime.datetime.now()
    while True:
        rlist, wlist, xlist = select.select([process.stdout, process.stderr], [], [], 1) # 1 second wait for any output
        handle_output(rlist, handler_map)
        if process.poll() is not None:
            handle_output([process.stdout, process.stderr], handler_map)
            break
        if timeout_sec is not None and (datetime.datetime.now() - started).total_seconds() > timeout_sec:
            sys.stderr.write('Terminating subprocess %s on timeout %d seconds\n' % (commands, timeout_sec))
            process.kill()
            break

    return process.returncode

With default handlers printing subprocess outputs, usage is pretty simple...


returncode = execute['python2.7', '/somewhere/random_print.py'])
print(returncode)

In case you really want to accumulate outputs as you have some plans with it, like parsing it or passing as an input into some other process.


stdoutlist = []
stderrlist = []
returncode = execute(['python2.7', '/somewhere/random_print.py'],[stdoutlist.append],[stderrlist.append])
print(returncode)
print(stdoutlist)
print(stderrlist)

Or you can go ham and use multiple handlers for output lines


import StringIO
stdoutio = StringIO.StringIO()
stderrio = StringIO.StringIO()
stdout_lines = []
stderr_lines = []
stdout_handlers = [sys.stdout.write, stdout_lines.append, stdoutio.write]
stderr_handlers = [sys.stderr.write, stderr_lines.append, stderrio.write]
returncode = execute(['python2.7', '/somewhere/random_print.py'], stdout_handlers, stderr_handlers)
print(returncode)
print(stdout_lines)
print(stdoutio.getvalue())
print(stderr_lines)
print(stderrio.getvalue())

To be complete, here goes my random_print.py, I've been testing with


import sys
import time
import random

for i in range(50):
    if random.choice([True, False]):
        sys.stdout.write('random out-'+ str(i)+'\n')
        sys.stdout.flush()
    else:
        sys.stderr.write('random err-'+ str(i)+'\n')
        sys.stderr.flush()
    time.sleep(0.1)
    
raise Exception('You shall not pass')

Monday, 16 October 2017

Scala type alias in Apache Spark

There is one feature in Scala that I see quite rarely - type aliases. While it can be easily misused and bring only confusion into Scala project, there is very good use-case for it in Apache Spark Jobs on RDDs

Spark job pipelines can be long and complex, which combined with type inference Scala, often leads to code which very hard to understand. Usually you can fight against this by making "check-points", where you assign interim result into value just to make it for reader easier to follow and understand long stream of transformations chained together.

For example, long code of combining two Maps into another was extracted into method. You can see that author took advantage of Scala type inference but recognised need to inform reader about type of result by creating long expressive name for it. Method name pretty much repeats the same idea of type explaining

val eligibleSegment2EligibleCountries = extractEligibleSegment2EligibleCountries(filteredSegment2PositiveCount, segmentCountry2PositiveCounts)
I might be a good idea to put explicit type of value into code. Reader then knows exactly what the result is and does not have to jump away to examine method's return type
val eligibleSegment2EligibleCountries: List[(Int, Set[Int])] = extractEligibleSegment2EligibleCountries(filteredSegment2PositiveCount, segmentCountry2PositiveCounts)
Bit better but it can be dramatically improved by using type aliases. In this domain, Segment ID and Country ID are Integers so let's create alias for them
type SegmentId = Int
type CountryId = Int
Now collection type becomes really self-explanatory to reader and we can also save some characters on variable and method names
val es2c: List[(SegmentId, Set[CountryId])] = extract(fs2pcount, sc2pcount)
But there are also have other numeric types which have some special meaning in the domain of the job - Counts and Rates
type Count = Long
type SampleRate = Double
Then very easy to understand method signatures or variable types can be used
def counts2rates(counts: Map[SegmentId, Count], maxLimit: Long): Map[SegmentId, SampleRate]
def train(exploded: RDD[(SegmentId, DmpCookieProfile)]): RDD[Either[SegmentId, (SegmentId, Count)]]

One might consider aliasing whole Map or List but I believe it would contrary obscure collection data types rather then helping reader trying to understand the code

Happy type aliasing

Thursday, 16 March 2017

Apache Spark sample and coalesce

It is wasteful to work with large number of small partitions of data, especially when S3 is used as data storage. IO then becomes unacceptably large part of time spent in task, most annoyingly when Spark is just moving data files from _temporary location into final destination, after real work has been completed.

Small tip how to down-sample dataset but keeping resulting partitions sizes similar to original dataset. Key element is to get original number of partition, decrease it accordingly and coalesce RDD with it.

It is useful when you test your Spark job on single node (or few) but with the amount of data you expect production cluster nodes should be able to handle.


  def sample(sparkCtx: SparkContext, inputPath: String, outputPath: String, fraction: Double, seed: Int = 1) = {
    val inputRdd = sparkCtx.textFile(inputPath)
    val outputPartitions = (inputRdd.partitions.length * fraction).toInt
    inputRdd
    	.sample(false, fraction, seed)
    	.coalesce(outputPartitions, shuffle = false)
        .saveAsTextFile(outputPath, codec = classOf[GzipCodec])
  }

Happy sampling!

Monday, 20 June 2016

Maven, SBT, Gradle local repository sharing

I've run into environment where different project were using different build tools - Maven, Gradle and SBT. Problem was how to reuse build artifacts between them and here goes small summary of my investigation. I will cover only local file repositories and NOT publishing/retrieving to/from remote repositories.

TL;DR every tool is able to use publish into and retrieve from Maven local repository

I'm using today's latest versions of Maven 3.3.9, Gradle 2.14, SBT 0.13.11 While Maven dependency management and artifact publishing is pretty stable, SBT and Gradle are still evolving quite a lot so check your versions carefully.

All build tools (unless you override default configuration) use your home directory to keep local repository inside of it. It is different on various operating systems and with my user name mvanek, then it will be

  • Linux ${USER_HOME} is /home/mvanek
  • Mac OS X ${USER_HOME} is /Users/mvanek
  • Windows 10 %USERPROFILE% is C:\Users\mvanek

Maven 3.3.9

  • mvn package - Operates inside target subdirectory of your project
  • mvn install - Also copy jar into ${USER_HOME}/.m2/repository

SBT 0.13.11

sbt build operates inside target subdirectory of your project

Let's have following simple build.sbt:
organization := "bt"
name := "bt-sbt"
version := "1.0.0-SNAPSHOT"

scalaVersion := "2.11.7"
sbtVersion := "0.13.11"

resolvers += Resolver.mavenLocal // Also use $HOME/.m2/repository

libraryDependencies += "commons-codec" % "commons-codec" % "1.10" 
libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.6" % "test"

SBT -> Ivy

SBT is using Apache Ivy internally so executing sbt publish-local (which same as sbt publishLocal) will build and store produced jars into ${USER_HOME}/.ivy2/local/bt/bt-sbt_2.11 subdirectories Because Scala applications are bound to Scala version they are compiled with, Ivy module/Maven artifactId/Jar file name will be bt-sbt_2.11 to reflect that.

SBT -> Maven

Since SBT 0.13.0 publishing into Maven local repo is trivial. Execute sbt publish-m2 which is same as sbt publishM2 to build and store compiled binary, source and javadoc jars into ${USER_HOME}/.m2/repository/bt/bt-sbt_2.11/1.0.0-SNAPSHOT

Note that for file cache of remote repository's artifacts SBT uses ${USER_HOME}/.ivy2/cache directory.

Gradle 2.14

Gradle by itself does not have concept of local repository. gradle build - Operates inside build subdirectory of your project

Gradle's build behaviour changes with plugins applied inside build.gradle. Let's assume only java plugin is used in simple build.gradle file
apply plugin: 'java'

group = 'bt'
version = '1.0.0-SNAPSHOT'

task sourceJar(type: Jar) {
    from sourceSets.main.allJava
}

repositories {
    mavenCentral()
}

dependencies {
 compile group: 'commons-codec', name: 'commons-codec', version: '1.10'
 testCompile group: 'junit', name: 'junit', version: '4.12'
}

Name of the directory that contains Gradle project files is taken project name. This is important because project name will become Maven artifactId and it cannot be redefined in build.gradle. You can redefine it using settings.gradle file with line rootProject.name = 'bt-gradle'. There are also options to configure it just for individual plugins but I'd not recommend it because then you need to configure it for every plugin that might be affected (some publish plugin for example)

Gradle -> Maven

For sharing with Maven, probably easiest choice is maven plugin

Apply plugin in your build.gradle apply plugin: 'maven' then execute build via gradle install and your jar will land in ${USER_HOME}/.m2/repository/bt/bt-gradle/1.0.0-SNAPSHOT/bt-gradle-1.0.0-SNAPSHOT.jar

Another Gradle -> Maven option is maven-publish plugin which might be good choice if you also plan to publish artifacts into remote repository as well.

Add into build.gradle

apply plugin: 'maven-publish'

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
        }
    }
}
and execute build using gradle publishToMavenLocal

Gradle -> Ivy

Because SBT is using Ivy distribution instead of Maven, ivy-publish plugin should be weapon of choice for this.
apply plugin: 'ivy-publish'

publishing {
    publications {
        ivyJava(IvyPublication) {
            from components.java
        }
    }
    
    repositories {
        ivy {
            url "${System.properties['user.home']}/.ivy2/local"
        } 
    }
}
then execute buid using gradle publishIvyJavaPublicationToIvyRepository and jar will appear in ${USER_HOME}/.ivy2/local/bt/gradle-built/1.0.0-SNAPSHOT/gradle-built-1.0.0-SNAPSHOT.jar. This is unfortunately wrong as it is Maven layout, not Ivy. You can add layout explicitly
    repositories {
        ivy {
            layout "ivy"
            url "${System.properties['user.home']}/.ivy2/local"
        } 
    }
which is better and will work for simple jar build but it will fail when you attach sources. Yet another reason why I'll never use Gradle unless I'm tortured for a week at least.

Note that for file cache of remote repository's artifacts Gradle uses ${USER_HOME}/.gradle/caches/modules-2/files-2.1 directory

Happy local jar sharing!

Tuesday, 22 March 2016

Fun with Spring Boot auto-configuration

I favour configuration as straighforward as possible. Unfortunately Spring Boot is pretty much opposite as it employs lots of auto-configuration. Sometimes it is way too eager and initializes everything it stumbles upon.

If you are building fresh new project, you might be spared, but when converting pre-existing project or building something slightly unusual, you will very likely meet Spring Boot initialization failures.

There are two main groups of initialization sources

  • Libraries in classpath - Which might be dragged into classpath as a transitive dependency of library you really use.
  • Beans in application context - Spring Boot auto-configuration often supports only single resource of some kind. Database DataSource or JMS ConnectionFactory for example. When you have more than one, initializer gets confused and fails.
  • Combination of both - otherwise it would be too easy

Complete list of auto configuration classes is listed in documantation. For the record, I'm using Spring Boot 1.3.3 and Spring Framework 4.2.5

Having simple Spring Boot application like this...

@SpringBootApplication
public class AutoConfigBoom {

    @Bean
    @ConfigurationProperties(prefix = "datasource.ds1")
    DataSource ds1() {
        return DataSourceBuilder.create().build();
    }

    public static void main(String[] args) {
        SpringApplication.run(AutoConfigBoom.class, args);
    }
}
... and application.properties...
datasource.ds1.driverClassName=org.mariadb.jdbc.Driver
datasource.ds1.url=jdbc:mysql://localhost:3306/whatever?autoReconnect=true
datasource.ds1.username=hello
datasource.ds1.password=dolly
...if you happen to have JPA implementation like Hibernate in classpath, JPA engine will be initialized automatically. You might spot messages in logging output...
2016-03-22 18:45:55,560|main      |INFO |o.s.o.j.LocalContainerEntityManagerFactoryBean: Building JPA container EntityManagerFactory for persistence unit 'default'
2016-03-22 18:45:55,577|main      |INFO |o.hibernate.jpa.internal.util.LogHelper: HHH000204: Processing PersistenceUnitInfo [
 name: default
 ...]
2016-03-22 18:45:55,639|main      |INFO |org.hibernate.Version: HHH000412: Hibernate Core {5.1.0.Final}
2016-03-22 18:45:55,640|main      |INFO |org.hibernate.cfg.Environment: HHH000206: hibernate.properties not found
2016-03-22 18:45:55,641|main      |INFO |org.hibernate.cfg.Environment: HHH000021: Bytecode provider name : javassist
2016-03-22 18:45:55,678|main      |INFO |org.hibernate.annotations.common.Version: HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2016-03-22 18:45:55,686|main      |WARN |org.hibernate.orm.deprecation: HHH90000006: Attempted to specify unsupported NamingStrategy via setting [hibernate.ejb.naming_strategy]; NamingStrategy has been removed in favor of the split ImplicitNamingStrategy and PhysicalNamingStrategy; use [hibernate.implicit_naming_strategy] or [hibernate.physical_naming_strategy], respectively, instead.
2016-03-22 18:45:56,049|main      |INFO |org.hibernate.dialect.Dialect: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
If it is undesired as it only slows down application start up, exclude particular initializers...
@SpringBootApplication(
  exclude = { HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class })
public class AutoConfigBoom {
  ...
}
...which is just shortcut for...
@Configuration
@EnableAutoConfiguration(
  exclude = { HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class })
@ComponentScan
public class AutoConfigBoom {
  ...
}

To make things more spicy, let's declare second DataSource. Let's assume that XA Transactions spanning multiple transactional resources are not required.

@SpringBootApplication
public class AutoConfigBoom {

    @Bean
    @ConfigurationProperties(prefix = "datasource.ds1")
    DataSource ds1() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "datasource.ds2")
    DataSource ds2() {
        return DataSourceBuilder.create().build();
    }

    public static void main(String[] args) {
        SpringApplication.run(AutoConfigBoom.class, args);
    }
}
If you have Hibernate JPA in classpath you will get...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration': Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.dataSource; 
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ds2' defined in com.example.boom.AutoConfigBoom: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; 
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: ds2,ds1
...because JPA engine is now confused which DataSource to use. If you really intend to use JPA EntityManager, then easiest solution is mark one DataSource with @Primary annotation...

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "datasource.ds1")
    DataSource ds1() {
        return DataSourceBuilder.create().build();
    }

...otherwise exclude HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class from auto-configuration as shown above. @Primary annotation will also help you in case of...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ds1' defined in com.example.boom.AutoConfigBoom: Initialization of bean failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; 
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: ds2,ds1
Now, DataSourceInitializer cannot be simply excluded, but it can be turned off by adding...
spring.datasource.initialize=false
into application.properties, but you will get yet another initialization failure...
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration': Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private javax.sql.DataSource org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration$JdbcTemplateConfiguration.dataSource; 
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: ds1,ds2

...which will force you to exclude DataSourceAutoConfiguration and also DataSourceTransactionManagerAutoConfiguration. Probably not worth it. Rather use @Primary to avoid this madness.

Small tip at last. We had few legacy apps, which were good candidates for Spring Bootification. Here goes typical Spring Boot wrapper I wrote to make upgrade/transition as seamless as possible. It reuses legacy external legacy properties file, which is now well covered in documantation. Part of upgrade was also logging migration to slf4j and logback (SLF4JBridgeHandler)

public final class LegacyAppWrapper {

    static {
        SLF4JBridgeHandler.removeHandlersForRootLogger();
        SLF4JBridgeHandler.install();
    }

    public static void main(String[] args) {
        // Do not do initialization tricks
        System.setProperty(
          "spring.datasource.initialize", "false");

        // Stop script does: curl -X POST http://localhost:8080/shutdown
        System.setProperty(
          "endpoints.shutdown.enabled", "true");

        // Instruct Spring Boot to use our legacy external property file
        String configFile = "file:" + System.getProperty("legacy.config.dir") + "/" + "legacy-config.properties";
        System.setProperty(
          "spring.config.location", configFile);

        ConfigurableApplicationContext context = SpringApplication.run(LegacyAppSpringBootConfig.class, args); // embedded http server blocks until shutdown
    }
}

Happy auto-configuration exclusions

Friday, 18 March 2016

Join unrelated entities in JPA

With SQL, you can join pretty much any two tables on almost any columns that have compatible type. This is not the possible in JPA as it relies heavily on relation mapping.

JPA relation between two entities must be declared, usually using @OnToMany or @ManyToOne or another annotation on some JPA entity's field. But sometimes you cannot simply introduce new relation into your existing domain model as it can also bring all sorts of troubles, like unnecessary fetches or lazy loads. Then ad hoc joining comes very handy.

JPA 2.1 introduced ON clause support, which is useful but not ground breaking. It only allows to use additional joining condition to one that implicitly exists because of entity relation mapping.

To cut story short, JPA specification still does not allow ad hoc joins on unrelated entities, but fortunately both two most used JPA implementation can do it now.

Of course, you still have to map columns (most likely numeric id columns) using @Id or @Column annotation, but you do not have to declare relation between entities to be able to join them.

EclipseLink since version 2.4 - User Guide and Ticket

Hibernate starting with version 5.1.0 released this February - Announcement and Ticket

Using this powerful tool, we can achieve unimaginable.

@Entity
@Table(name = "CAT")
class Cat {

    @Id
    @Column(name = "NAME")
    private String name;

    @Column(name = "KITTENS")
    private Integer kittens;
}

@Entity
@Table(name = "INSURANCE")
class Insurance {

    @Id
    @Column(name = "NUMBER")
    private Integer number;

    @Temporal(TemporalType.DATE)
    private Date startDate;
}

For example to join number of kittens your cat has with your insurance number!
String jpaql="SELECT Cat c JOIN Insurance i ON c.kittens = i.number";
entityManager.createQuery(jpaql);

If you try this with Hibernate version older than 5.1.0 you will get QuerySyntaxException
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join!

Happy ad hoc joins!

Monday, 16 November 2015

Upgrading Querydsl 3 to 4

Querydsl is for some time now my weapon of choice when it comes to writing typesafe JPA queries. Main advantage is great readibility of code comparing to standard JPA Criteria API. Sometimes I also use Querydsl SQL module when JPA is not avaliable or JPA entity mapping is too poor (sadly common case) that can't be used in complex queries.

Anyway, today I've been upgrading from Querydsl 3.6.x to latest 4.0.x and I've met numerous API changes. Unfortunately I did not find any migration instructions so here comes my notes. Might be useful to someone.

Simple query

Before:
QEntity qEntity = QEntity.entity;
List<Entity> list = new JPAQuery(emDomain).from(qEntity).list(qEntity);
After:
QEntity qEntity = QEntity.entity;
List<Entity> list = new JPAQuery<Entity>(emDomain).from(qEntity).fetch();

SearchResults -> QueryResults

Before:
SearchResults<Tuple> results = query.listResults(qEntity.id, qEntity.name);
After:
QueryResults<Tuple> results = query.select(qEntity.id, qEntity.name).fetchResults();

Join fetch

Before:
query.leftJoin(qEntity.approvedCreatives).fetch();
After:
query.leftJoin(qEntity.approvedCreatives).fetchJoin();

Single result

Before:
Tuple tuple = query.singleResult(qEntity.id, qEntity.name);
After:
Tuple tuple = query.select(qEntity.id, qEntity.name).fetchOne();

Subqueries

Before:
JPAQuery query = new JPAQuery(emDomain);
ListSubQuery<Long> subQuery = new JPASubQuery().from(qCampaing).where(qCampaing.id.eq(campaingId)).join(qCampaing.segments, qSegment).list(qSegment.id);
query.from(qSegment).where(qSegment.id.in(subQuery));
After:
JPAQuery<Segment> query = new JPAQuery(emDomain);
JPQLQuery<Long> subQuery = JPAExpressions.selectFrom(qCampaing).where(qCampaing.id.eq(campaingId)).join(qCampaing.segments, qSegment).select(qSegment.id);
query.from(qSegment).where(qSegment.id.in(subQuery));

Happy typesafe Querdsling!

Thursday, 27 November 2014

Certificates with SHA-1 and SunCertPathBuilderException

As SHA-1 is heading to deprecation as hashing algoritm for certificate signatures, unpleasant effects start to appear.

Our partners we need to communicate with over HTTPS have brand new certificate signed by GoDaddy Certificate Authority. Accessing their https secured site via browser does not show anything alarming.

But accessing REST endpoint hosted on same site using java HttpUrlConnection blows up with javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

What is going on?

Every internet browser comes with quite a big set of preinstalled Certificate Authorities (CA) trusted certificates, because your browser's vendors trusts them. And because they are CAs and they are trusted, then every certificate that is signed by them is trusted too.

Same story with JVM. There is truststore file inside every JVM named cacerts. In Oracle jdk1.7.0_67 there is 87 Certificate Authorities in it as they are trused by Oracle. GoDady is there too, so why that SunCertPathBuilderException? Let's examine it more closely.

Every JVM is also shipped with command line tool named keytool. Using it you can list and also modify any keystore in jks format such as cacerts Executing... (default password is changeit)

 
keytool -list -v -keystore ${JAVA_HOME}/jre/lib/security/cacerts -storepass changeit | grep -A 14 godaddy
...will print following...
Alias name: godaddyclass2ca
Creation date: 20-Jan-2005
Entry type: trustedCertEntry

Owner: OU=Go Daddy Class 2 Certification Authority, O="The Go Daddy Group, Inc.", C=US
Issuer: OU=Go Daddy Class 2 Certification Authority, O="The Go Daddy Group, Inc.", C=US
Serial number: 0
Valid from: Tue Jun 29 18:06:20 BST 2004 until: Thu Jun 29 18:06:20 BST 2034
Certificate fingerprints:
  MD5:  91:DE:06:25:AB:DA:FD:32:17:0C:BB:25:17:2A:84:67
  SHA1: 27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4
  SHA256: C3:84:6B:F2:4B:9E:93:CA:64:27:4C:0E:C6:7C:1E:CC:5E:02:4F:FC:AC:D2:D7:40:19:35:0E:81:FE:54:6A:E4
  Signature algorithm name: SHA1withRSA
  Version: 3
Now cmparing to certificate from HTTPS website... GoDaddyG2 cerificate

There is obvious mismatch. Apart from different certificate name, validity date range also notice that Signature Algorithm is "SHA-256 with RSA". GoDaddy's certificate in JVM is different from the one in use on website, therefore SunCertPathBuilderException.

To fix this, we need to add right (G2) GoDaddy's certificate into JVM cacert keystore. Visiting GoDaddy's certificate repository obvious candidate "GoDaddy Class 2 Certification Authority Root Certificate - G2" can be found there.

wget https://certs.godaddy.com/repository/gdroot-g2.crt
keytool -printcert -file gdroot-g2.crt
Will give us something we saw in website certificate...
Owner: CN=Go Daddy Root Certificate Authority - G2, O="GoDaddy.com, Inc.", L=Scottsdale, ST=Arizona, C=US
Issuer: CN=Go Daddy Root Certificate Authority - G2, O="GoDaddy.com, Inc.", L=Scottsdale, ST=Arizona, C=US
Serial number: 0
Valid from: Mon Aug 31 20:00:00 EDT 2009 until: Thu Dec 31 18:59:59 EST 2037
Certificate fingerprints:
  MD5:  80:3A:BC:22:C1:E6:FB:8D:9B:3B:27:4A:32:1B:9A:01
  SHA1: 47:BE:AB:C9:22:EA:E8:0E:78:78:34:62:A7:9F:45:C2:54:FD:E6:8B
  SHA256: 45:14:0B:32:47:EB:9C:C8:C5:B4:F0:D7:B5:30:91:F7:32:92:08:9E:6E:5A:63:E2:74:9D:D3:AC:A9:19:8E:DA
  Signature algorithm name: SHA256withRSA
  Version: 3

Now just import gdroot-g2.crt into JVM cacerts truststore

sudo keytool -import -alias godaddyg2ca -file gdroot-g2.cer -keystore ${JAVA_HOME}/jre/lib/security/cacerts -storepass changeit

Owner: CN=Go Daddy Root Certificate Authority - G2, O="GoDaddy.com, Inc.", L=Scottsdale, ST=Arizona, C=US
Issuer: CN=Go Daddy Root Certificate Authority - G2, O="GoDaddy.com, Inc.", L=Scottsdale, ST=Arizona, C=US
Serial number: 0
Valid from: Tue Sep 01 01:00:00 BST 2009 until: Thu Dec 31 23:59:59 GMT 2037
Certificate fingerprints:
  MD5:  80:3A:BC:22:C1:E6:FB:8D:9B:3B:27:4A:32:1B:9A:01
  SHA1: 47:BE:AB:C9:22:EA:E8:0E:78:78:34:62:A7:9F:45:C2:54:FD:E6:8B
  SHA256: 45:14:0B:32:47:EB:9C:C8:C5:B4:F0:D7:B5:30:91:F7:32:92:08:9E:6E:5A:63:E2:74:9D:D3:AC:A9:19:8E:DA
  Signature algorithm name: SHA256withRSA
  Version: 3

Extensions: 

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

#2: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  Key_CertSign
  Crl_Sign
]

#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 3A 9A 85 07 10 67 28 B6   EF F6 BD 05 41 6E 20 C1  :....g(.....An .
0010: 94 DA 0F DE                                        ....
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Problem solved and REST call should succeed from now using this JVM

For completeness sake, if you want to get rid of it, execute

keytool -delete -alias godaddyg2ca -keystore ${JAVA_HOME}/jre/lib/security/cacerts

What in case you are not allowed to modify JVM cacerts truststore?

Then make a copy of it, import gdroot-g2.cer into it and use this custom truststore instead of default JVM truststore using -Djavax.net.ssl.trustStore=/path/to/custom_cacerts -Djavax.net.ssl.trustStorePassword=changeit java parameters

What in case you need multiple keystores or something similarily complex?

Such scenarios cannot be solved simply by using JVM switches and parameters anymore and you have to roll your own X509TrustManager implementation. Then you need to plug it into your http client connection setup - (HttpsUrlConnection SSLSocketFactory) (Apache HttpClient 3 SecureProtocolSocketFactory) (Apache HttpClient 4 SSLConnectionSocketFactory ) (Jersey SslConfigurator)

Monday, 3 November 2014

Airbrake for logback

I've you've been observing this ticket for a while and it seems to be pretty ignored. Well not anymore or at least not by me. Undramatic sources of Airbrake Logback Appender are in GitHub airbrake-logback repo

Grab it from Maven central repo

<dependency>
    <groupId>net.anthavio</groupId>
    <artifactId>airbrake-logback</artifactId>
    <version>1.0.0</version>
</dependency>

Use it...well...as usual

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="30 seconds">

    <appender name="AIRBRAKE" class="net.anthavio.airbrake.AirbrakeLogbackAppender">
        <apiKey>YOUR_AIRBRAKE_API_KEY</apiKey>
        <env>test</env>
        <enabled>true</enabled>

        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
    </appender>

    <root>
        <level value="info" />
        <appender-ref ref="AIRBRAKE" />
    </root>
</configuration>

Happy Logback based Airbraking

Friday, 31 October 2014

Disqus java rest api client library released

After almost year long sleep in 1.0.0-SNAPSHOT I finally released Disquo project which is java client library for Disqus REST API

It is deployed into Maven central repository with following coordinates:

    <dependency>
        <groupId>net.anthavio.disquo</groupId>
        <artifactId>disquo-api</artifactId>
        <version>1.0.0</version>
    </dependency>

It covers all Disqus v3.0 api endpoints functionality and authentication modes: OAuth 2 (access_token), Single sign-on (remote_auth), Anonymous ("Guest Commenting" must be enabled for site/forum)

To get Application keys needed for Disqus API, you should to visit Disqus and Log in or Create an Account then Register new application and grab generated "Public Key" and "Secret Key" and optionaly "Access Token"

DisqusApplicationKeys keys = new DisqusApplicationKeys("...api_key...", "...secret_key...");
//Construct Disqus API client
DisqusApi disqus = new DisqusApi(keys);
DisqusResponse<List<DisqusPost>> response = disqus.posts().list(threadId, null);
List<DisqusPost> posts = response.getResponse();
for (DisqusPost post : posts) {
  String text = post.getAuthor().getName() + " posted " + post.getMessage();
  System.out.println(text);
}
disqus.close();

More examples can be found on GitHub project page. If you find a bug, please report it to GitHub issues page

Happy Disqusing!

Thursday, 30 October 2014

Vaadin & Spring Boot & WebSockets & OpenShift & Java8

Spring Boot is around for a while and because Vaadin caught my interest lately, plus Spring4Vaadin appeared, I gave it a spin. To make it more challenging, I decided to use Java 8 and deploy it on OpenShift. All the code is hosted on GitHub

Application is simple chat with OAuth2 sign in using Facebook/Google/GitHub/LinkedIn/Disqus. High-tech is way it broadcasts chat messages to chat participants using server push which in turn uses WebSocket mechanism.

Some informations about Spring Boot and OpenShift are part of the Spring Boot Documentation and some more in this blog post.

I've created DIY gear using OpenShift application console but same can be done using rhc app create vinbudin -t diy-0.1. Application code was already on GitHub and to get it running on OpenShift, following steps must be performed.

1. Add git upstream repository (openshift remote)

git clone git@github.com:anthavio/vinbudin.git
git remote add openshift ssh://your_uuid@vinbudin-yourdomain.rhcloud.com/~/git/vinbudin.git/

2. Add OpenShift build hooks

Build hooks in .openshift/action_hooks are shell scripts that are executed when you push something into OpenShift remote repository. Typically they stop application, run maven/ant/sbt to build application and start it again.

3. Push to the openshift

That's it. When you execute following command, you will see build hooks executed and project will be built and deployed on your openshift gear.

git push openshift master

You can still git push origin master to GitHub repository without invoking build on OpenShift

Maven 3.2.3 and Java 8 on OpenShift

OpenShift gears (28 Oct 2014) have only Java 1.7.0_71 and Maven 3.0.5. If you want to use different, most probably newer versions, just download and unpack them in .openshift/action_hooks/deploy into ${OPENSHIFT_DATA_DIR}

WebSockets on OpenShift

Situation seems to be same as two years ago when this blog post was written. You still have to access port 8000 to get WebSockets working.

Thanks to Vaadin/Atmosphere push implementation which automaticaly downgrade to long-polling when websockets mechanism is unavailable, user experience is not affected, but observing messages exchanged between browser and server, you will easily spot the problem.

Open Chrome Developer Tool Network tab and navigate to http://vinbudin-openshift.anthavio.net/ui

Request URL:ws://vinbudin-openshift.anthavio.net/ui/PUSH/?v-uiId=0&v-csrfToken=731062c6-712d-4320-a92c-3742fe3b4451&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.1.5.vaadin4-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json;%20charset=UTF-8&X-atmo-protocol=true
Request Method:GET
Status Code:501 Not Implemented

WebSocket upgrade request was rejected. Ouch!

Now doing same, but with port 8000 in url - http://vinbudin-openshift.anthavio.net:8000/ui

Request URL:ws://vinbudin-openshift.anthavio.net:8000/ui/PUSH/?v-uiId=0&v-csrfToken=731062c6-712d-4320-a92c-3742fe3b4451&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.1.5.vaadin4-jquery&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&X-Cache-Date=0&Content-Type=application/json;%20charset=UTF-8&X-atmo-protocol=true
Request Method:GET
Status Code:101 Switching Protocols

WebSocket upgrade request was accepted and protocol was switched. Hurray!

Happy Vaadin & Spring Boot & OpenShift websocketing!

Tuesday, 16 September 2014

Spring OAuth2RestTemplate and self-signed server certificate

It might happen to you that you ended up using spring-security-oauth2 on OAuth2 client side. Personally I would not recommend to use it as it brings much more complexity into task that is not that difficult. But every use-case is diferent.

If you also happen to integrate with site using self-signed certificate, you'll inevitably encounter following exception.

org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException: Error requesting access token.
 at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:144) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:198) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:538) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:518) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:256) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
...
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://somewhere.something.info/oauth2/token":sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:558) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:511) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:136) ~[spring-security-oauth2-2.0.2.RELEASE.jar:na]
 ... 86 common frames omitted
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[na:1.7.0_55]
 at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884) ~[na:1.7.0_55]
 at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276) ~[na:1.7.0_55]
 at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270) ~[na:1.7.0_55]
 at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1341) ~[na:1.7.0_55]
 at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153) ~[na:1.7.0_55]
 at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868) ~[na:1.7.0_55]
 at sun.security.ssl.Handshaker.process_record(Handshaker.java:804) ~[na:1.7.0_55]
 at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016) ~[na:1.7.0_55]
 at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312) ~[na:1.7.0_55]
 at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339) ~[na:1.7.0_55]
 at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323) ~[na:1.7.0_55]
 at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563) ~[na:1.7.0_55]
 at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185) ~[na:1.7.0_55]
 at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153) ~[na:1.7.0_55]
 at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:52) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:542) ~[spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]
 ... 88 common frames omitted
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385) ~[na:1.7.0_55]
 at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292) ~[na:1.7.0_55]
 at sun.security.validator.Validator.validate(Validator.java:260) ~[na:1.7.0_55]
 at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326) ~[na:1.7.0_55]
 at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231) ~[na:1.7.0_55]
 at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126) ~[na:1.7.0_55]
 at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323) ~[na:1.7.0_55]
 ... 102 common frames omitted
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196) ~[na:1.7.0_55]
 at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268) ~[na:1.7.0_55]
 at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380) ~[na:1.7.0_55]
 ... 108 common frames omitted

Exception is throw when https://somewhere.something.info/oauth2/token is used to trade OAuth2 code for access token. You probably know what to do. Time for stupid trick with (totaly unsecure) X509TrustManager! As OAuth2RestTemplate extends RestTemplate, it inherits public void setRequestFactory(ClientHttpRequestFactory requestFactory) method and it can be used to make the trick.

private static void disableCertificateChecks(OAuth2RestTemplate oauthTemplate) throws Exception {

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[] { new DumbX509TrustManager() }, null);
        ClientHttpRequestFactory requestFactory = new SSLContextRequestFactory(sslContext);

        //This is for OAuth protected resources
        oauthTemplate.setRequestFactory(requestFactory);
}

Code for SSLContextRequestFactory and DumbX509TrustManager is gisted here

Now, if you try to run through test once again, you will still get same SunCertPathBuilderException again. Why?

Answer is in hidden in bowels of OAuth2AccessTokenSupport, which is base class of AuthorizationCodeAccessTokenProvider. To cut the story short, it is creating it's own RestTemplates for token endpoint operations.

Luckily again, overridable setRequestFactory(...) is also provided on OAuth2AccessTokenSupport. Repeating same trick again finaly gives us working, exception free solution:

    private static void disableCertificateChecks(OAuth2RestTemplate oauthTemplate) throws Exception {

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[] { new NastyX509TrustManager() }, null);
        ClientHttpRequestFactory requestFactory = new SSLContextRequestFactory(sslContext);

        //This is for OAuth protected resources
        oauthTemplate.setRequestFactory(requestFactory);

        //AuthorizationCodeAccessTokenProvider creates it's own RestTemplate for token operations
        AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
        provider.setRequestFactory(requestFactory);
        oauthTemplate.setAccessTokenProvider(provider);
    }

Remember, you've just created huge security hole in your application. Make doubly sure it is never used in production

Happy unsecure https REST OAuth2 calls!

PS: if you favour more advanced http transport layer then basic Java HttpURLConnection (and you should on server side) like HttpComponents 4.3, then simplest possible ClientHttpRequestFactory creation would be:

        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
        CloseableHttpClient httpClient = HttpClients.custom().setSslcontext(sslContext).build();
        ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

Wednesday, 4 June 2014

Netflix OSS github repo is full of goodies

If you haven't browse through Netflix OSS github repositories yet, you should do it immediately. It would be very surprising if you could not find something useful there.

I've found three projects (Feign, Hystrix, Archaius) that address directly the same problem that I've been building similar library to solve. Many others are inspirational or interesting at least, like RxJava quite popular in "reactive circles".

Some of them may have (better?) alternatives like Retrofit, some other are used as bricks in interesting projects like Halfpipe.

Apparently everybody is going crazy about Spring Boot. Let's hope it will not share destiny with Spring Roo.

Tuesday, 29 April 2014

Fluent Builder method ordering

Classic simple fluent builder usually suffers from some annoyances.

Let's look a this example:
ComplexClass cc = ComplexClass.Builder()
  .addThis(42).setThat("I'm that").addSomethingOther("I'm other")
  .addYetAnother("yet yet yet").mixPudding(true).setChickenFeedingDevice(device)
  .addThis(99).withTimeout(5000).setThat("I'm another that").build()
Disregarding silly and inconsistent method naming...
  • large number of builder methods confuse user
  • builder method can be mistakenly called multiple times

Having way to enforce order into method chaining will allow to build something more like wizzard or workflow which wiil simplify Builder usage greatly.

Let's introduce some interfaces according following rules
  • Any interface declares only subset of Builder methods
  • Interface method return value is another interface instead of Builder instance
  • Builder itself implements all interfaces

Together this basicaly forms very simple example of formal grammar where order in interface chaining represents production rules

To demonstrate idea just described, I built Selenium2/WebDriver WaitBuilder. It uses WbBegin interface as initial building point, WbAnd interface allowing to add multiple multiple conditions and finaly WbEnd with .seconds(int seconds) method instead of traditional .build().

Selenium has WebDriverWait class allowing conditional waits, which is very useful for testing pages, where elements appear dynamicaly or to perform assertion of Post/Redirect/Get (redirect after form submission) in time-boxed manner. SeleniumWaitBuilder allows to combine multiple conditions together.

It enables to write such cool chains such as...
//pass test if "results-table" element will appear in 5 seconds, fail otherwise
SeleniumWaitBuilder.with(driver)
 .passOn().element(By.id("results-table")).seconds(5);

//pass test if title become "Example Domain" and in 5 seconds or fail immediately if it happen to contain "error" string
SeleniumWaitBuilder.with(driver).passOn()
  .title().equals("Example Domain")
 .and().failOn()
  .title().contains("error")
 .seconds(5);

SeleniumWaitBuilder.with(driver).passOn()
  .title().endsWith("Example Domain")
  .element(By.id("result-table"))
 .and().failOn()
  .title().contains("error")
  .url().contains("/500")
 .seconds(5);

And finally, hero of today's blog post - mighty SeleniumWaitBuilder itself!

I admit that this is overkill for most of the builders but still, it is neat...

Happy contitional waiting!

Wednesday, 23 April 2014

Java cloud hosted continuous integration services

Last year I resigned to maintain my own VPS hosted CI server with Git Repos, Jenkins, Sonar, Maven repository, LDAP, etc... and moved source code repositories to GitHub. I'm uploading build artifacts into Sonatype OSSRH in case of libraries and with web applications deployments, I'm still experimenting with Openshift and some other services. But I also lost possibility do build and deploy project on demand. Fortunately many cloud hosted CI services popped up last year or two.

CircleCI

Predefined, not very extensive toolset for Java projects is avaliable. It has recognized my pom.xml automaticaly without any configuration. Uses circle.yml configuration file. It is does not have free plan (only trial), cheapest Solo plan is for $19/month.

Travis-CI

Java is quite well supported. It is cofigured using .travis.yml. There is free (unlimited) plan and also quite expensive paid plans

Codeship

Neat interface, but you are allowed to use only few preinstalled java tools. Free plan is limited to 50 builds per month, while Basic plan will cost you $49 per month.

drone.io

Simplistic with basic java support. Free unlimited plan.

Cloudbees DEV@Cloud

Jenkins in the cloud with all it's awesomeness. You can choose pretty much any Java, Maven or Gradle version you can imagine plus zillions of Jenkins plugins. Pricing is trickier here because billing is build time based and offering includes application hosting (you might not be interested in). Free plan includes 100 build minutes and there is also FOSS plan. Starter plan with 40 hours of build per month will cost you $60 + $17 = $77 per month

Another Cloudbees service is BuildHive where you will get unlimited number of builds, but you will use shared and slower Jenkins instance with very limited configuration and only for GitHub repositories.

Test drive with Phanbedder

I have recently built little library named Phanbedder and blogged about it few days ago. While very tiny in java code size, it is pretty unusual because it launches separate processes of bundeled PhantomJS native binary during the tests. This makes it perfect candidate for testing cloud CI services.

Good news is that every above mentioned service managed to compile and test it using mvn clean test -Denforcer.skip=true command. I use maven-enforcer-plugin to enforce Java 6 to be used for compilation. But because many of CIs offers only Java 7, I had to switch enforcer off...

Trickier part is execution of mvn deploy. I'm uploading maven snapshot artifacts into Sonatype OSSRH and also release versions later into Maven central. For snapshot deployment into Sonatype OSS Nexus, username and password must be provided to make maven-deploy-plugin work, otherwise...

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.8.1:deploy (default-deploy) on project phanbedder-1.9.7: Failed to deploy artifacts: Could not transfer artifact net.anthavio:phanbedder-1.9.7:jar:1.0.1-20140422.184656-7 from/to sonatype-oss-snapshots (https://oss.sonatype.org/content/repositories/snapshots): Failed to transfer file: https://oss.sonatype.org/content/repositories/snapshots/net/anthavio/phanbedder-1.9.7/1.0.1-SNAPSHOT/phanbedder-1.9.7-1.0.1-20140422.184656-7.jar. Return code is: 401, ReasonPhrase: Unauthorized. -> [Help 1]

Normaly, deployment credentials are stored inside your personal maven settings.xml, but obviously this file is not present on cloud CI server. Workarounds exists for Travis-ci. Cloudbees DEV@Cloud has most elegant solution, but I guess no deployment with undisclosed credentials can be done from BuildHive and others.

Now, here goes links to public success build logs for Travis-CI, drone.io, BuildHive and DEV@Cloud. Sadly CircleCI and Codeship does not seem to support public projects.

Mentioned CI services can be webhook triggered, provide integrated browser testing and deployment into popular cloud hosting services like Heroku or Google App Engine. They evolve pretty quickly as they add more integrations as I write... Listing and comparing features here is not worth the effort so check documentation pages.

Everybody has different needs. All my projects are open source hobby projects so I guess I'll go with webhook triggered snapshot builds on BuildHive or I might use Travis-CI to have it with snapshot deployments.

For Maven central release deployment builds, I see only one option - Cloudbees DEV@Cloud. In some next blog post, I'll describe how fully automatic deployment can be achieved using Cloudbees DEV@Cloud, maven-release-plugin and Sonatype OSSRH.

Happy cloud hosted CI builds!

Monday, 21 April 2014

PhantomJS embedder for Selenium GhostDriver

There is quite a few Drivers for Selenium2/WebDriver. Two of them are particulary interesting, because they allow fast headless browser tests - HtmlUnitDriver and PhantomJSDriver.

Using HtmlUnitDriver is piece of cake, because HtmlUnit is pure java library, but disadvantage is limited JavaScript execution support, making it usable for mostly static html sites only.

PhantomJSDriver from GhostDriver project allows to employ PhantomJS, which is a headless WebKit, much much closer to real web browser. As native binary having it's dependencies staticaly linked, PhantomJS does not need any installation. Just unzip it somewhere.

Selenium 2 has annoying habit of needing to specify full path to browser binary when Driver instace is being created. For most common browsers like Chrome or Firefox, some basic discovery is performed, but it usualy fails for me and it is same story with PhantomJS now.

Most probably, you will get folowing exception

java.lang.IllegalStateException: The path to the driver executable must be set by the phantomjs.binary.path capability/system property/PATH variable; for more information, see https://github.com/ariya/phantomjs/wiki. The latest version can be downloaded from http://phantomjs.org/download.html
 at com.google.common.base.Preconditions.checkState(Preconditions.java:177)
 at org.openqa.selenium.phantomjs.PhantomJSDriverService.findPhantomJS(PhantomJSDriverService.java:237)
 at org.openqa.selenium.phantomjs.PhantomJSDriverService.createDefaultService(PhantomJSDriverService.java:182)
 at org.openqa.selenium.phantomjs.PhantomJSDriver.<init>(PhantomJSDriver.java:99)

Another obstacle usualy is different Operating System between developer's machine (MacOS, Windows) and continuous integration server (Linux). Because PhantomJS is native application, therefore every OS needs it's own binary to execute and you'll need to distribute right versions to every host that will ever build/test your project.

To escape from both annoyances, I've created Phanbedder. Tiny library that bundles PhantomJS binaries and unpacks right one for you on any of supported platform - Linux, Windows and Mac OSX.


File phantomjs = Phanbedder.unpack(); //Phanbedder to the rescue!
DesiredCapabilities dcaps = new DesiredCapabilities();
dcaps.setCapability(PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, phantomjs.getAbsolutePath());
PhantomJSDriver driver = new PhantomJSDriver(dcaps);

//Usual Selenium stuff follows
try {
 driver.get("https://www.google.com");
 WebElement query = driver.findElement(By.name("q"));
 query.sendKeys("Phanbedder");
 query.submit();
 Assertions.assertThat(driver.getTitle()).contains("Phanbedder");
} finally {
 driver.quit();
}

To run code above you'll need following dependencies. Number 1.9.7. in artifactId stands for PhantomJS version bundeled inside.

    
      net.anthavio
      phanbedder-1.9.7
      1.0.0
    

    
      com.github.detro.ghostdriver
      phantomjsdriver
      1.1.0
    

Because this library is targeting various OSes, testing is tricky. I have tested it on Mac OS X 10.6, Windows 7 and I've also gave it a spin on travis-ci (good) and Cloudbees Jenkins (great). Source code is hosted on GitHub and deployed into maven central again using Cloudbees Cloud@DEV

Happy Phanbedding!

Tuesday, 15 April 2014

How many Base64 encoders is in JDK/JRE

Base64 variants

Base64 encoding is an algorithm that converts binary data into ASCII. Resulting string consist of characters A-Z,a-z,0-9 and two extra '+' (plus) and '/' (slash) and also padding character '=' (equals). Conversion does not happens the same every time, there is few variants of it.

- Simple (basic) encoding creates single longlonglonglonglonglonglonglonglonglonglonglooooong= base64 encoded line.

- Fixed line lenght encoding, sometimes also called Mime base64 encoding or chunked encoding or simply line folding. Instead of single long line, it produces multiple lines usualy 76 characters long. It is quite important, because it is mandatory in some use scenarios (Binary attachments) , while harmful in others (BASIC authentication header).

- URL (safe) encoding produce string that can be used as parameter value in URL. Because '+' and '/' are not allowed, they are encoded as '-' and '_' while '=' padding character is usually removed.

Now back to initial question...

How many Base64 encoders/decoders is present in Oracle (Sun) JDK?

I found 6 of them

sun.misc.BASE64Encoder Since Java 1.0? Well we all know that we should not touch anything from sun.* or com.sun.* packages. So we don't.

javax.xml.bind.DatatypeConverter Since Java 1.6 - This one actually works, but allows you only basic encoding. No mime or url encoding.

java.util.Base64 Since Java 1.8 - Finaly generaly usable Base64 encoder/decoder allowing basic, mime and url safe encoding.

And finaly some curiosities illustrating how even Sun/Oracle JDK/JRE contributors were missing Base64 encoder, so they created their own.

java.util.prefs.Base64 Since Java 1.4, but has default (package) visibility, therefore not usable

com.sun.net.httpserver.Base64 Since Java 1.6, but has default (package) visibility, therefore not usable

com.sun.org.apache.xml.internal.security.utils.Base64 - Similar story as sun.misc.BASE64Encoder, it also internaly uses XMLUtils.ignoreLineBreaks() to perform line folding...

Let's see some encoding results

Both commons-codec 1.6+ and Java8 java.util.Base64 can produce and consume any of mentioned base64 variants, but beware of quite different encoding results. I think that a lot of headaches is coming because of that.

In following test, commons-codec 1.9 and Java8u5 is used

Mime (chunked) encoding
import org.apache.commons.codec.binary.Base64;

String string = "This string encoded will be longer that 76 characters and cause MIME base64 line folding";
 
byte[] encodeBase64Chunked = Base64.encodeBase64Chunked(string.getBytes());
System.out.println("commons-codec Base64.encodeBase64Chunked\n" + new String(encodeBase64Chunked));

String encodeMimeToString = java.util.Base64.getMimeEncoder().encodeToString(string.getBytes());
System.out.println("java.util.Base64.getMimeEncoder().encodeToString\n" + encodeMimeToString);
prints
commons-codec Base64.encodeBase64Chunked
VGhpcyBzdHJpbmcgZW5jb2RlZCB3aWxsIGJlIGxvbmdlciB0aGF0IDc2IGNoYXJhY3RlcnMgYW5k
IGNhdXNlIE1JTUUgYmFzZTY0IGxpbmUgZm9sZGluZw==

java.util.Base64.getMimeEncoder().encodeToString
VGhpcyBzdHJpbmcgZW5jb2RlZCB3aWxsIGJlIGxvbmdlciB0aGF0IDc2IGNoYXJhY3RlcnMgYW5k
IGNhdXNlIE1JTUUgYmFzZTY0IGxpbmUgZm9sZGluZw==

Java8 mime Encoder ends with '==' padding and does not add last newline (CR/LF) after that!

URL (safe) encoding
String string = "ůůůůů";

String encodeUrlToString = java.util.Base64.getUrlEncoder().encodeToString(string.getBytes());
System.out.println("java.util.Base64.getUrlEncoder().encodeToString\n" + encodeUrlToString);

String encodeBase64URLSafeString = Base64.encodeBase64URLSafeString(string.getBytes());
System.out.println("commons-codec Base64.encodeBase64URLSafeString\n" + encodeBase64URLSafeString);
prints
java.util.Base64.getUrlEncoder().encodeToString
xa_Fr8Wvxa_Frxc=
commons-codec Base64.encodeBase64URLSafeString
xa_Fr8Wvxa_Frxc
Java8 url Encoder leaves padding '=' at the end of the result, which makes it unusable as URL parameter value!

UPDATE: This was reported while ago and it has turned out, that any Encoder can be switched into non-padding using withoutPadding() method.

String string = "ůůůůů";
String encodeUrlToString = Base64.getUrlEncoder().withoutPadding().encodeToString(string.getBytes());
System.out.println("java.util.Base64.getUrlEncoder().withoutPadding().encodeToString\n" + encodeUrlToString);
prints
java.util.Base64.getUrlEncoder().withoutPadding().encodeToString
xa_Fr8Wvxa_Frw

Note: In quite old commons-codec 1.4 chunking was incostitently turned on by default for encode() method, resulting in nasty surprises. See Jira ticket.

Happy Base64 encoding

Friday, 11 April 2014

Spring MockMvc tests

MVC Test Framework arrived with Spring 3.2. It allows to write integration tests (well... almost) for your Spring MVC @Controller(s)

One of server-side cornerstones is MockMvc class. It allows to execute requests on your Controllers very easily, but it needs to be initialized before it is used. Threre are two ways to initialize MockMvc and choice depends on how broad integration with other Spring MVC components your tests need. In my case, it was custom view resolver and few others I removed for sake of simplicity.

First is meant for simple single Controller testing

    @Test
    public void foo() {
        TestedController controller = new TestedController();
        MyCustomViewResolver resolver = new MyCustomViewResolver();
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).setViewResolvers(resolver).build();

        MvcResult result = this.mockMvc.perform(MockMvcRequestBuilders.get("/foo")).andReturn();
        //parse and assert response.getContentAsString() as view was resolved by MyCustomViewResolver
    }
You can employ extensive set of spring-mvc usual suspects, like ConversionService, ViewResolvers, MessageConverters, ... see StandaloneMockMvcBuilder javadoc

All this manual assembling makes me feel little unconfortable. Normaly all those beans are wired together in Spring Dispatcher context.

Another way to initlialize MockMvc is using @WebAppConfiguration and MockMvcBuilders.webAppContextSetup(webAppContext)

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = TestMvcSpringConfig.class)
public class FooTests {

    @Autowired
    private WebApplicationContext webAppContext;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(webAppContext).build();
    }

    @Test
    public void foo() {
        MvcResult result = this.mockMvc.perform(MockMvcRequestBuilders.get("/foo")).andReturn();
        MockHttpServletResponse response = result.getResponse();
        //parse and assert response.getContentAsString() as view was resolved by MyCustomViewResolver
    }

    @EnableWebMvc
    @Configuration
    public static class TestMvcSpringConfig extends WebMvcConfigurerAdapter {

        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }

        @Bean
        public TestedController getController() {
            return new TestedController();
        }

        @Bean
        public ViewResolver viewResolver() {
            MyCustomViewResolver resolver = new MyViewCustomResolver();
            return resolver;
        }
    }

For some unknown reason (that disappeared as quickly as it appeared) Spring was failing to create @EnableWebMvc annotated @Configuration, complaining about missing servlet context. I had to get my hands dirty and roll my own Spring web context. So for completeness, here is how it was done using MockServletContext. May be useful sometime.


    @Test
    public void test() throws Exception {
        MockServletContext servletContext = new MockServletContext();

        AnnotationConfigWebApplicationContext springContext = new AnnotationConfigWebApplicationContext();
        springContext.setServletContext(servletContext);
        springContext.register(TestMvcSpringConfig.class);
        springContext.refresh();

        MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(springContext).build();

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/foo")).andReturn();
    }

Happy Spring MVC testing!

Thursday, 10 April 2014

RPM upgrade and embedded Jetty

Java web application I'm working on recently (let's name it lobster) is embedding and packaging Jetty inside itself. This makes application artifact more self-contained and independent, because it does not require preinstalled and preconfigured server.

To simplify application deployment even more, it is packaged as RPM file, which is uploaded into Nexus serving as Yum repository.

Deployment then is simple matter of executing sudo yum install lobster and thanks to RPM scriptlets, server is automaticaly restarted as a part or installation.

Everything went nice and smoothly, until second release. When yum update happend, we have found how amazingly wierd thing RPM upgrade is.

sudo yum update lobster execution completed, but application failed to start and logfile contained strange exceptions
Caused by: java.io.FileNotFoundException: /opt/lobster/lib/lobster-core-0.4.0.jar (No such file or directory)
 at java.util.zip.ZipFile.open(Native Method) ~[na:1.7.0_40]
 at java.util.zip.ZipFile.(ZipFile.java:215) ~[na:1.7.0_40]
 at java.util.zip.ZipFile.(ZipFile.java:145) ~[na:1.7.0_40]
 at java.util.jar.JarFile.(JarFile.java:153) ~[na:1.7.0_40]
 at java.util.jar.JarFile.(JarFile.java:90) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.URLJarFile.(URLJarFile.java:93) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.URLJarFile.getJarFile(URLJarFile.java:69) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarFileFactory.get(JarFileFactory.java:99) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:122) ~[na:1.7.0_40]
 at sun.net.www.protocol.jar.JarURLConnection.getJarFile(JarURLConnection.java:89) ~[na:1.7.0_40]

What was wierd even more, that it was lobster version 0.5.0 installation and 0.4.0 stated in stacktrace, actualy was previous version!

To make story short, after some googling I've found RPM upgrade sequence.

  1. execute new version %pre [ $1 >= 2 ]
  2. unpack new version files (both old and new are now mixed together)
  3. execute new version %post [ $1 >= 2 ]
  4. execute old version %preun [ $1 == 1 ]
  5. remove old files (only new and unchanged stays)
  6. execute old verion %postun [ $1 == 1 ]

Important is, that between step 2 and 5, mixture of old and new version jar files is present in installation directory! Attempt to start server java process in %post or %preun scriptlet can only result in disaster same as we experienced. Old version jars will be deleted right after scriptlet execution.

Here comes working install/upgrade/uninstall solution

%pre scriptlet

#!/bin/sh
# rpm %pre scriptlet
#
# parameter $1 means
# $1 == 1 ~ initial installation
# $1 >= 2 ~ version upgrade
# never executed for uninstall

echo "rpm: pre-install $1"

# failsafe commands - can't break anything

# make sure that user exist
id -u lobster &>/dev/null || useradd lobster

# make sure that application is not runnig
if [ -f /etc/init.d/lobster ]; then
 /sbin/service lobster stop
fi

%post scriptlet

Important is NOT to start application on rpm upgrade
#!/bin/sh
# rpm %post scriptlet
#
# parameter $1 means
# $1 == 1 ~ initial installation
# $1 >= 2 ~ version upgrade
# never executed for uninstall

echo "rpm: post-install $1"

# initial install
if [ "$1" -eq "1" ]; then
 /sbin/chkconfig --add lobster
 /sbin/service lobster start
fi

%preun scriptlet

#!/bin/sh
# rpm %preun scriptlet
#
# parameter $1 means
# $1 == 0 ~ uninstall last
# $1 == 1 ~ version upgrade
# never executed for first install

echo "rpm: pre-uninstall $1"

# uninstall last
if [ "$1" -eq "0" ]; then
 /sbin/service lobster stop
 /sbin/chkconfig --del lobster
fi

%postun scriptlet

Here is right place to start application on rpm upgrade
#!/bin/sh
# rpm %postun scriptlet
#
# parameter $1 means
# $1 == 0 ~ uninstall last
# $1 == 1 ~ version upgrade
# never executed for first install

# console output is surpressed for postun% !
echo "rpm: post-uninstall $1"

# upgrade
if [ "$1" -ge "1" ]; then
 /sbin/service lobster start
fi

Useful RPM scriptlet documentation is in Fedora Wiki also how to integrate with SysV Init Scripts

Happy RPM deployments!

Monday, 24 March 2014

Spring Security with multiple AuthenticationManagers

Spring security (Acegi security once) configuration was for a long time quite exhausting task. Gluing together all filters, entry points, success handlers and authentication providers was not small price to pay for overwhelming flexibility of this awesome framework.

Starting with version 2.0, simplified namespace configuration (<sec:http/>) was introduced, allowing most common setups to be configured with just a few lines. Not much get changed with version 3.0.

However, this new configuration style introduced also one important limitation - only single one security filter chain with single AuthenticationManager can be configured using it. When you happen to have web application with two faces - Web Pages and REST endpoints, having quite different authentication requirements, you are in trouble. Only option is fallback to traditional bean by bean configuration.

Following gist shows how it can be done

What a massive piece of xml!!!

Limitation of single security filter chain was removed in version 3.1, which allowed to have multiple <http authentication-manager-ref="..."/> elements, each possibly with different AuthenticationManager.

Latest and greatest version 3.2 brought long time awaited Java Configuration, with sweet @EnableWebSecurity and WebSecurityConfigurerAdapter combo. To do not repeat same mistake again, this funny trick can be used to define multiple filter chains and AutheticationManagers.

But as an exercise, I also tried to disassemble configuration into old school bean by bean way. Let's call that poor man's spring security java config.

Following gist shows how it can be done

While this is not as complex setup as xml based example before, it is still big chunk of code.

Happy Spring securing!