I have installed Writebook in an Oracle Cloud instance. Writebook uses Docker, and it gets installed by default in host port 5555. However, I want to run Writebook in port 80 of the host because it makes it easier to expose it to the Internet from an Oracle Cloud instance.

  • Stop Docker
  • Edit hostconfig.json for your container hash sudo vi /var/lib/docker/containers/CONTAINERHASH/hostconfig.json and replace "HostPort":"5555" with replace "HostPort":"80".
  • Start Docker.

Courtesy of this great Stackoverflow answer.

I have been trying to install Writebook in an Oracle Cloud instance with Oracle Linux 9. The installer could not install Docker.

To install it manually, I followed this step-by-step guide

Update System Packages

Open a terminal and update your system packages as you see below:

sudo yum update -y

Add Docker Repository

Add Docker’s official repository to your system’s yum sources list as you see in the image below:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Install Docker Engine

Install Docker Engine, CLI, and contained:

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io

Start Docker Service

Enable and start the Docker service:

sudo systemctl enable docker
sudo systemctl start docker

Testcontainers simplifies testing against third-party components such as databases. But sometimes, you want to run your Junit 5 tests and skip those requiring Docker.

To run Testcontainers-based tests, you need a Docker-API compatible container runtime, such as using Testcontainers Cloud or installing Docker locally.

Luckily, Testcontainers Junit5 integration allows you to toggle these tests by annotating them with @Testcontainers(disabledWithoutDocker = true).

See an example of a commit in Micronaut Test.

Today, I was fighting a flaky test in a Micronaut project. I used this simple bash script to run the test a hundred times.

#!/bin/bash

EXIT_STATUS=0

for ((i=1; i<=100; i++))
do
  ./gradlew :http-client:test --tests "io.micronaut.http.client.aop.NotFoundSpec.test 404 handling with Flowable" --rerun-tasks || EXIT_STATUS=$?
  if [ $EXIT_STATUS -ne 0 ]; then
    exit $EXIT_STATUS
  fi
done

exit $EXIT_STATUS

Sonatype offers plugins to check for vulnerabilities in your dependencies.

Web Search

You can search directly in the web interface for vulnerabilities in your dependencies.

For example, to search for org.json:json type: pkg:maven/org.json/json.

Scan Your dependencies

Sonatype OSS Index offers Maven and Gradle Plugins. I focus next on Gradle.

Registration

I signed up for Sonatype OSS Index.

I set the OSS Index username/password as global properties for all Gradle Builds. I added entries to USER_HOME/.gradle/gradle.properties.

ossIndexUsername=xxx@email.com
ossIndexPassword=yyyy

Setup Gradle Plugin

You can get the latest version of org.sonatype.gradle.plugins.scanin the Gradle Plugin Portal

Then, you can apply the plugin:

plugins {
...
id("org.sonatype.gradle.plugins.scan") version "2.8.2"
}

dependencies {
    ....
    ..
    .
}
ossIndexAudit {
    username = project.properties["ossIndexUsername"].toString()
    password = project.properties["ossIndexPassword"].toString()
}

If your project has a vulnerable dependency, when execute the gradle task ossIndexAudit will see something like this:

> Task :ossIndexAudit FAILED
  ________  ___   ___  __   ____  ____________   _  __
 / ___/ _ \/ _ | / _ \/ /  / __/ / __/ ___/ _ | / |/ /
/ (_ / , _/ __ |/ // / /__/ _/  _\ \/ /__/ __ |/    /
\___/_/|_/_/ |_/____/____/___/ /___/\___/_/ |_/_/|_/

  _      _                       _   _
 /_)    /_`_  _  _ _/_   _  _   (/  /_`_._  _   _/ _
/_)/_/ ._//_// //_|/ /_//_//_' (_X /  ///_'/ //_/_\
   _/                _//
Gradle Scan version: 2.8.2
------------------------------------------------------------------------------------------------------------------------------------------------------

Checking vulnerabilities in 52 dependencies
Found vulnerabilities in 1 dependencies
[1/1] - pkg:maven/org.json/json@20230618 - 1 vulnerability found!

   Vulnerability Title:  [CVE-2023-5072] CWE-770: Allocation of Resources Without Limits or Throttling
   ID:  CVE-2023-5072
   Description:  Denial of Service  in JSON-Java versions up to and including 20230618.  A bug in the parser means that an input string of modest size ca...
   CVSS Score:  (7.5/10, High)
   CVSS Vector:  CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
   CVE:  CVE-2023-5072
   Reference:  https://ossindex.sonatype.org/vulnerability/CVE-2023-5072?component-type=maven&component-name=org.json%2Fjson&utm_source=ossindex-client&utm_medium=integration&utm_content=1.8.2


Execution failed for task '::ossIndexAudit'.
> Vulnerabilities detected, check log output to review them

The plugin scans the whole dependency tree. It scans not just your project dependencies but the dependencies of those dependencies.

Last Thursday, August 1st, 2024, I started at Oracle as a Principal Member of Technical Staff. I joined the GDK/Micronaut Team at Oracle Labs.

I want to thank Graeme Rocher and Julia Kindelsberger for the opportunity to join the Oracle Labs GDK/Micronaut Team. This role will allow me to continue contributing to Micronaut. A passion, I have been dedicating myself to in the pasts years.

The new job is quite a change for me. I had a small business, worked as a contractor - later as CTO - in a Spanish startup, and worked as a contractor for a medium-sized US company. All, with a common denominator, I have been self-employed since 2008.

People start in big companies, then move on to create their own thing. I am doing my career in reverse order. :-]

In January 2017, I wrote a blog post titled my first day at OCI. Today is my last day at OCI.

It has been seven and a half years. Thanks to OCI, I started a career in Open-Source, first in Grails and later in Micronaut.

Remote and flexible. Many years of remote work. I remember the pandemic. I was at home with two kids - 4 and 1 years old. My wife was the only one going out. She kept working in a hospital, buying food, etc. I kept working during those months thanks to my wife and OCI's flexibility.

Many Hats. I have done many things:

  • Helping clients with Grails/Micronaut. For example, I vividly remember helping a company to upgrade a Grails application. The catch was its source code variable names, and comments were in Danish. I don't speak Danish. Thus, it was a split desktop with Google Translate and IntelliJ IDEA. :-]
  • Becoming a Technical Writer. I became a technical writer. I have written/reviewed most of the Grails Guides and Micronaut Guides. I am incredibly proud of the Micronaut Guides pipeline. Every tutorial contains a sample project which users can download and run. The code snippets in those tutorials come from a real tested code. We generate applications programmatically. We build and run the tests in every tutorial for every Micronaut release. It is easy to upgrade every tutorial, often one line change, to a new version of Micronaut.
  • Public Speaker. I have been talking about Micronaut to Java user groups and conferences internationally.
  • Open-Source contributor. I have contributed a lot of code to Micronaut. For example, I have contributed to Security, AWS, Views, RSS, Problem+JSON, Email, Microstream, OpenSearch, Chatbots, and Multi-tenancy.
  • Podcast. I hosted, edited, and published the Micronaut podcast.
  • Training I have delivered training events, both online and on-site, for both Grails and Micronaut. I taught about Micronaut AWS Lambda integration, Micronaut Security, etc.
  • Release Manager. I have been responsible for Micronaut releases for two years - from the second quarter of 2022 until the second quarter of 2024. We released 47 patch releases, 17 minor releases, and a major version - Micronaut 4. We aimed to follow strict semantic versioning to ease user applications' upgrade and try to share the roadmap with the community.
  • Partners. I am proud of the work we did with Azul for the Micronaut CRaC integration, with MicroStream and EclipseStore or AWS Lambda
  • Technical Manager. I lead a small remote distributed team at Unity Foundation working on Micronaut. Without the work of Tim Yates, Jeremy Grelle, and Dean Wette, the previously mentioned releases and collaborations would be not possible.
  • Oracle Labs collaboration The previously mentioned releases were only possible with the extensive work of the Oracle Labs Micronaut Team. I am proud of the collaboration and joint effort of two development teams from different companies. It was proof of open-source collaboration by multiple vendors.

Fun memories I am incredibly grateful for the St. Louis trip with my family in December 2022. OCI welcomed me as a partner. It was a great trip, and having my family there was lovely.

To wrap up, I would like to thank OCI, especially Gina Bremehr and Jeff Scott Brown for supporting me during these years.

How do Micronaut, Quarkus, and Spring Boot compare by the number of Stackoverflow questions?

June 2024

FrameworkStackoverflow questions
Grails29877
Micronaut1824
Quarkus4610
Spring Boot149254

The oldest the framework, the more questions they have. But it is undeniable the Spring Boot dominance.

I have been researching Snowflake IDs and how Snowflake IDs work:

Snowflake IDs, or snowflakes, are a form of unique identifier used in distributed computing. The format was created by Twitter and is used for the IDs of tweets.

Snowflakes are 64 bits in binary. The first 41 bits are a timestamp, representing milliseconds since the chosen epoch. The next 10 bits represent a machine ID, preventing clashes. Twelve more bits represent a per-machine sequence number, to allow creation of multiple snowflakes in the same millisecond. The final number is generally serialized in decimal.

A key characteristic, as with KSUID, is that they are sortable:

Snowflakes are sortable by time, because they are based on the time they were created.[2] Additionally, the time a snowflake was created can be calculated from the snowflake. This can be used to get snowflakes (and their associated objects) that were created before or after a particular date.

Java Libraries

I found several Java implementations:

phxql/snowflake-id, which is licensed under LGPL (GNU Lesser General Public License 3.0). It seems active.

I also found this java implementation, which unfortunately it does not specify a license.

I found an implementation and test in Apache Marmotta which is licensed with Apache 2.0 License.

It seems Discord4J contains also a Snowflake ID implementation.

I recently watched an AMA (Ask Me Anything) video between Brian Goetz, Java Language Architect at Oracle, and Nicolai Parlog, Java Developer Advocate at Oracle, where Brian Goetz shared

For Brian, Loom will kill reactive programming, making it a transitional technology. On the one hand, reactive programming allows you to have many asynchronous operations going on, way more than the number of threads you have. On the other hand, you give up:

  • Control flow statements.
  • The ability to write simple loops.
  • The ability to sequentially debug your code.
  • The ability to get clear stack traces.

The reactive programming tradeoff is not worth it.

This is transcription generated with Audio Hijack's Trascribe block:

What do you see as the future of reactive programming in Java going forward? Yeah, so this is a great question. I'm going to give a controversial answer, which some people will like and some people will hate. I think Loom is going to kill reactive programming. I think we are going to realize very quickly... that reactive programming was a transitional technology. It was a reaction to a problem that we had, and when that problem is taken away, it will become obvious that this is not the solution, the reactive is not the solution we want, and I'll explain, 'cause I don't wanna just make a provocative statement and then move on to a different topic. The problem with Reactive is it gets you one good thing. It gets you this event-driven model that allows you to decouple computations from threads. So you can have a lot of asynchronous operations going on, way more than the number of threads that you have. But the cost of it is really high. Basically, you have to give up so much. many things that the language already gives you. You give up control flow statements. You give up being able to write simple loops. You give up having, you know, being able to sequentially debug your code. You give up being able to get clear stack traces of , how did I get to this point where, you know, I, where I experienced this error, all of those things come for free if you're programming with straightforward, you know, sequential code, and reactive frameworks take that all away from you. So they give you one good thing but they take away a bunch of good things that we were all used to and if your code doesn't work, good luck debugging it, and what Loom does is it takes away a bunch of good things that we were all used to and if your code doesn't work, good luck debugging it. it says, well, the real bug was not the programming model. The bug was that threads were too expensive, and so I could only create 1,000, 5,000, 10,000. I can't create a million, and so the, if we just solve that problem of let's make it cheaper to create lots. threads, then people will write just ordinary straightforward sequential code, and it will, using the control flow techniques they know from the language, and using the debuggers that they've already got in their toolbox, and getting clean stack traces when there's an error, and it's going to be great, and I think a lot of people will look at React. and say, "Boy, that was, you know, that was a cost and benefit that were not in line."

Go to the linked site

The following GitHub Action workflow to build and deploy the site to GitHub Pages gh-pages branch:

name: Publish
on:
  push:
    branches: [ "main" ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"
    - name: ⚙️ Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install mkdocs
    - name: 🏗️ Build Site
      run: mkdocs build
    - name: 🚀 Deploy
      uses: JamesIves/github-pages-deploy-action@v4
      with:
        folder: site

PageSpeed Insights (PSI) reports on the user experience of a page on both mobile and desktop devices, and provides suggestions on how that page may be improved.

Being a Google Service, it may soon be killed by Google

In this blog post, I show you how to host a website in GitHub Pages and manage the domain with Hover

Website

I recently joined a local chess association in Guadalajara. They did not have a website, so I offered to create one for them. The website is a static website with HTML and Bootstrap.

The website is simple, but it conveys the association information, and it scores 100% in performance, accessibility, best practices and SEO.

GitHub Organization

Instead of creating it from my personal account, I created a GitHub Organization dedicated to the association. I verified the domain at the GitHub Organization level. You need to verify the domain at the organizational level, not the repository level.

GitHub Pages

Micronaut publishes its documentation to GitHub Pages deploying from branch gh-pages. For this website, I used GitHub Actions as the source instead. The website changes seem remarkably faster.

GitHub Action Workflow

The following GitHub Action workflow deploys the contents of the dist folder.

name: Deploy static content to Pages
on:
  push:
    branches: ["main"]
permissions:
  contents: read
  pages: write
  id-token: write
concurrency:
  group: "pages"
  cancel-in-progress: false
jobs:
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Setup Pages
        uses: actions/configure-pages@v5
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: 'dist'
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

Domain

I use Hover as a domain registrar. I use the following DNS configuration as pointed out by GitHub Pages documentation.

TYPEHOSTVALUETTL
A@185.199.109.15315 Minutes
A@185.199.110.15315 Minutes
A@185.199.111.15315 Minutes
A@185.199.108.15315 Minutes
AAAA@2606:50c0:8000::15315 Minutes
AAAA@2606:50c0:8001::15315 Minutes
AAAA@2606:50c0:8002::15315 Minutes
AAAA@2606:50c0:8003::15315 Minutes
TXT_github-pages-challenge-ajedrezcallejeroguadalajara89676ddaaeb7a6adec23d36402059915 Minutes
CNAMEwwwajedrezcallejeroguadalajara.github.io15 Minutes

Cost

The total cost for the association is 18 USD per year - the cost of the domain.

Summary

I hope this post shows you how easy is to host a website in GitHub Pages and manage the domain with Hover.

If you are in the Guadalajara (Spain) area, I hope to play chess against you soon. You can find the meetup information at ajedrezcallejeroguadalajara.com.

Sometimes, while developing you need to define mavenLocal() repository in a Gradle build. Gradle allows you to constraint the repository only to snapshots.

It is easy to do it with the Gradle Kotlin DSL.

repositories {
    mavenCentral()
    mavenLocal {
        mavenContent {
            snapshotsOnly()
        }
    }
    maven {
        setUrl("https://s01.oss.sonatype.org/content/repositories/snapshots/")
        mavenContent {
            snapshotsOnly()
        }
    }
}

An idempotent operation is defined as one which, if performed more than once, results in the same outcome.

Spring Academy Implementing POST:

An idempotent operation is defined as one which, if performed more than once, results in the same outcome. In a REST API, an idempotent operation is one that even if it were to be performed several times, the resulting data on the server would be the same as if it had been performed only once.