Water reflections on a roof

Fluido skin and Markdown syntax highlighting

doxia-module-markdown is a Maven plugin that enables Markdown in Maven documentations. In version 1.8, the developers have moved from Pegdown to Flexmark as Markdown parser. It's a good choice, as Flexmark is considerable faster and is still being maintained, while Pegdown officially reached its end of life in 2016.

However, with that switch, code blocks are not syntax highlighted any more. The reason is that the maven-fluido-skin uses code-prettify for syntax highlighting. It runs browser-side, highlighting all <pre> and <code> blocks selecting the prettyprint CSS class. This was true with Pegdown, but Flexmark selects a source class instead.

An obvious workaround is to use a small JavaScript snippet that adds a prettyprint class to all blocks selecting a source class, and then running prettyPrint() again. To do so, this block needs to be added to the <head> section of site.xml:

<head>
  <!-- Workaround for https://issues.apache.org/jira/browse/DOXIA-571 -->
  <![CDATA[<script type="text/javascript">
    $(document).ready(function () {
      $(".source").addClass("prettyprint");
      prettyPrint();
    });
  </script>]]>
</head>

It's hard to tell if this is a bug in doxia-module-markdown or in maven-fluido-skin. Also see my bug report at Apache's JIRA.


This was a Google Plus comment that I have now moved to my blog as Google Plus is going to be closed. Thanks to Clement Escoffier for the inspiration.

How acme4j handles POST-as-GET requests

In the latest ACME draft 15, Let's Encrypt introduced POST-as-GET requests. It is a breaking change that is not downward compatible to previous drafts.

This brought me into an uncomfortable position. While the Pebble server enforces the use of POST-as-GET, other servers don't support it yet, like the Let's Encrypt server. For this reason, acme4j needs to support both the pre-draft-15 GET requests and the post-draft-15 POST-as-GET requests. Luckily I have found a solution that is totally transparent to the user, at least as long as no other ACME server is used.

This is how acme4j v2.4 works:

  • If you connect to Boulder via an acme://letsencrypt.org URI, acme4j falls back to a compatibility mode that still sends GET requests. Let's Encrypt has announced a sunset date for GET requests on November 1st, 2019. You are safe to use acme4j v2.4 (and older versions) up to this date.
  • If you connect to a Pebble server via an acme://pebble URI, the new POST-as-GET requests are used.
  • If you connect to a different server implementation via http: or https: URI, acme4j sends POST-as-GET requests now. This is likely going to fail at runtime, if the server you connect to does not support draft-15 yet.
  • As a temporary workaround, you can add a postasget=false parameter to the server URI (e.g. https://localhost:14000/dir?postasget=false) to make acme4j enter the fallback mode and send GET requests again.

As soon as Let's Encrypt supports POST-as-GET on their production servers, I will remove the fallback mode from acme4j again. It just clutters the code, and I also have no proper way to test it after that.

Hint: Before updating acme4j, always have a look at the migration guide. It will show you where you can expect compatibility issues.

Errors in GitLab SonarQube plugin

The sonar-gitlab-plugin is an useful plugin to connect SonarQube with GitLab. After pushing, the branch is inspected by SonarQube, and code smells are immediately commented in the commit.

Unfortunately, the error messages of that plugin are a little difficult to understand. It took me a while to collect this little cookbook of error fixes.

  • Unable found project for null project name
    In SonarQube, as Administrator, select the project. Then in Administration ⭢ General Settings ⭢ GitLab, enter the project ID of your project and save it. The project ID is the group name in GitLab, followed by a slash and the name of the project, e.g. shred/timemachine.

  • Unable found project for mygroup/myproject
    In SonarQube, check that the project ID is correct and there are no spelling mistakes. In GitLab, make sure that SonarQube's GitLab user is actually a member of the project, and that the user has Developer rights. I hit a strange bug in GitLab here. The SonarQube user was a member of the project, but still this error occured. When logging in as the SonarQube user, the project was not on the roll of projects. Removing and adding Developer rights to the user didn't help. The only thing that finally worked was to add the SonarQube user to a different project, even if just for a moment. It seems to be a caching problem in GitLab.

  • Multiple found projects for mygroup/myproject
    You should never see this error, but if you do, be more specific with the projectID.

Stream trouble

I just had a stream of objects I wanted to sort and convert to a list. Optionally it should also be limited to a maximum number of entries. Piece of cake with Java 8:

Stream<T> stream = collection.stream().sorted(comparator);
if (max >= 0) {
  stream.limit(max);
}
List<T> result = stream.collect(Collectors.toList());

Or so I thought... The code above throws an IllegalStateException at runtime, stating that the "stream has already been operated upon or closed".

The cause should be obvious. However it took me a while to find it, so I am posting it in case other people (possibly you when you came here via search engine) get stuck at the same place. Stream operations are very likely to return a different Stream object. The limit() method is such an example. In my code above, limit() operates on the stream and returns a limited stream. However I just throw away the returned stream and invoke collect() on the original stream, which was now already operated upon.

The solution is simple:

if (max >= 0) {
  stream = stream.limit(max);
}
Mavenize your Sass

Sass is a kind of precompiler for CSS that offers additional features like nested styles, variables or includes. The syntax of scss files is similar to standard CSS, so it's very easy to learn.

My goal is to:

  • nicely integrate Sass into the Maven build process,
  • use Jetty to see the web application with the compiled css files, and
  • see changes to a Sass file live (without running Maven or restarting Jetty).
Read this article...