Saturday, July 13, 2019

Book: Spring Microservices in Action


This is a brilliantly written book.

https://github.com/carnellj/spmia-chapter1

Microservice Architecture

@SpringBootApplication
@RestController
@RequestMapping
@PathVariable

Flexible, Resilient, Scalable

IaaS, PaaS, SaaS, FaaS, CaaS

Client-side load balancing, Circuit breaker, Fallback, Bulkhead

Log correlation. Log aggregation. Microservice tracing

Spring Cloud:
Netflix Eureka (discovery), Zuul (routing), Ribbon (LN), Hystrix (Circuit Breaker), Sleuth/Uipkin (logging, tracing, aggregation), Oauth2/JWT

https://cloud.spring.io/spring-cloud-security/ Spring Security

https://jwt.io JavaScript Web Token

https://travis-ci.org


Hystrix proxies all RestTemplate. calls to add timeout. Ribbon also injects RestTemplate with all available service instances for LB and FO


to expose a bean there are 2 ways:
either one of @Component, @Service, @Repository
or @Configuration + @Bean


Apache Thrift, Apache Avro

12 factor apps: codebase in git, dependencies in maven, config in separate files, backing services (DB etc) cloud-ready,
immutable builds, stateless processes, port binding, horizontal scaling, disposable services, dev=prod, streamable logs (splunk, fluentd), scripted admin tasks.


Actuator health check.








Friday, July 12, 2019

dockerfile cmd and entrypoint

very confusing, poor design IMHO


Dockerfile:

FROM ubuntu
ENV myname "pierre"
ENTRYPOINT ["/bin/bash", "-c", "echo hello ${myname}"]


docker built -t hello01 .
docker run hello01





FROM ubuntu
ENTRYPOINT ["sleep"]

docker built -t hello02 .
docker run hello02

#this sleep for 5s
docker run hello02 5

#this gives error because parameter is missing
docker run hello02



FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]


this version uses a default time of 5, if not specified in command line
"docker run hello02" will sleep for 5
"docker run hello02 10" will sleep for 10









Thursday, July 11, 2019

Java JSSE SSL flags

-Djavax.net.debug=help

all turn on all debugging
ssl turn on ssl debugging

The following can be used with ssl:

record enable per-record tracing
handshake print each handshake message
keygen print key generation data
session print session activity
defaultctx print default SSL initialization
sslctx print SSLContext tracing
sessioncache print session cache tracing
keymanager print key manager tracing
trustmanager print trust manager tracing
pluggability print pluggability tracing
handshake debugging can be widened with:
data hex dump of each handshake message
verbose verbose handshake message printing


record debugging can be widened with:

plaintext hex dump of record plaintext
packet print raw SSL/TLS packets


Other non-so-famous properties:


https://www.oracle.com/technetwork/java/javase/overview/tlsreadme2-176330.html

-Dsun.security.ssl.allowUnsafeRenegotiation=true

-Dsun.security.ssl.allowLegacyHelloMessages=true

https://www.oracle.com/technetwork/java/javase/8u161-relnotes-4021379.html

-Djdk.tls.allowLegacyResumption=true

-Djdk.tls.allowLegacyMasterSecret=true

-Djdk.tls.traceHandshakeException=true

-Djdk.tls.useExtendedMasterSecret=true

-Djdk.tls.legacyAlgorithms=???

-Djdk.tls.ephemeralDHKeySize=???

https://docs.oracle.com/javase/10/security/java-secure-socket-extension-jsse-reference-guide.htm


jdk.tls.client.cipherSuites

jdk.tls.server.cipherSuites






Wednesday, July 10, 2019

kubectl generators and restart option

https://kubernetes.io/docs/reference/kubectl/conventions/#generators

the only non-deprecated generatori is "run-pod/v1" :

kubectl run nginx --image=nginx --generator=run-pod/v1 --dry-run -o yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: nginx
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}



kubectl run nginx --image=nginx --dry-run -o yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      run: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}



#create nginx POD only

kubectl run nginx --image=nginx --port=80 --restart=Never --dry-run -o yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: nginx
    ports:
    - containerPort: 80
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Never
status: {}


#create deployment nginx and pod

kubectl run nginx --image=nginx --port=80 --restart=Always --dry-run -o yaml

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: nginx
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      run: nginx
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
        resources: {}
status: {}




Friday, June 28, 2019

Helidon MicroProfiles

https://helidon.io/docs/latest/#/microprofile/01_introduction


Quickstart Helidon SE https://helidon.io/docs/latest/#/guides/02_quickstart-se

Quickstart Helidon MP https://helidon.io/docs/latest/#/guides/03_quickstart-mp

"MicroProfile is a collection of enterprise Java APIs that should feel familiar to Java EE developers. MicroProfile includes existing APIs such as JAX-RS, JSON-P and CDI, and adds additional APIs in areas such as configuration, metrics, fault tolerance and more."



More on MP https://helidon.io/docs/latest/#/microprofile/01_introduction

Saturday, June 22, 2019

maven-install-plugin copies files to your local .m2 repo

http://maven.apache.org/plugins/maven-install-plugin/usage.html

you can run this command from anywhere, no need for a pom.xml:


$ mvn install:install-file -Dfile=/c/pierre/downloads/apache-maven-3.5.3-bin.zip -DgroupId=pippo -DartifactId=pluto -Dpackaging=zip -Dversion=3.0
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-install-plugin:2.4:install-file (default-cli) @ standalone-pom ---
[INFO] Installing C:\pierre\downloads\apache-maven-3.5.3-bin.zip to c:\pierre\.m2\repository\pippo\pluto\3.0\pluto-3.0.zip
[INFO] Installing C:\Users\pierl\AppData\Local\Temp\mvninstall5440042488979291271.pom to c:\pierre\.m2\repository\pippo\pluto\3.0\pluto-3.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.689 s
[INFO] Finished at: 2019-06-22T16:08:57+02:00
[INFO] ------------------------------------------------------------------------




and the generated pom.xml is

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>pippo</groupId>
  <artifactId>pluto</artifactId>
  <version>3.0</version>
  <packaging>zip</packaging>
  <description>POM was created from install:install-file</description>
</project>



Wednesday, June 19, 2019

Spring Boot 2 HTTPS

see also https://www.baeldung.com/spring-boot-https-self-signed-certificate

https://better-coding.com/enabling-https-in-spring-boot-application/


generate the self-signed certificate:

keytool -genkeypair -alias baeldung -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore baeldung.p12 -validity 3650

and store it in src/main/resources/keystore folder

in applications.properties:
server.port=8443

management.endpoints.web.exposure.include=*
management.endpoint.shutdown.enabled=true

# The format used for the keystore. It could be set to JKS in case it is a JKS file
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
#server.ssl.key-store=classpath:keystore/baeldung.p12
server.ssl.key-store=src/main/resources/keystore/baeldung.p12
# The password used to generate the certificate
server.ssl.key-store-password=password
# The alias mapped to the certificate
server.ssl.key-alias=baeldung
server.ssl.key-password=password

#trust store location
trust.store=classpath:keystore/baeldung.p12
#trust store password
trust.store.password=password



maven common plugins

For a very good overall tutorial on Maven, read this https://www.baeldung.com/maven

For a list of most plugins https://maven.apache.org/plugins/



https://www.baeldung.com/executable-jar-with-maven


maven-dependency-plugin



maven-jar-plugin

maven-assembly-plugin

maven-shade-plugin

com.jolira.onejar-maven-plugin

spring-boot-maven-plugin

tomcat7-maven-plugin


https://www.baeldung.com/maven-profiles

maven-help-plugin


https://www.baeldung.com/maven-dependency-latest-version


versions-maven-plugin

https://www.baeldung.com/maven-enforcer-plugin


maven-enforcer-plugin


https://www.mojohaus.org/build-helper-maven-plugin/usage.html

build-helper-maven-plugin

https://www.baeldung.com/maven-release-nexus
https://www.baeldung.com/install-local-jar-with-maven/

maven-install-plugin
maven-deploy-plugin
maven-release-plugin
nexus-staging-maven-plugin


https://www.baeldung.com/integration-testing-with-the-maven-cargo-plugin

maven-surefire-plugin



Sunday, June 16, 2019

Spring bean lifecycles and BeanPostProcessor


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class MyComponent implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet from InitializingBean");
}

@PostConstruct
public void onPostConstruct() {
System.out.println("onPostConstruct");
}

@PreDestroy
public void onPreDestroy() {
System.out.println("onPreDestroy");
}


@Override
public void destroy() throws Exception {
System.out.println("destroy from DisposableBean ");
}


}

the sequence is:

onPostConstruct
afterPropertiesSet from InitializingBean
onPreDestroy
destroy from DisposableBean



and you can intercept instantiatio of every bean with a BPP :


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CustomBeanPostProcessor implements BeanPostProcessor {

    public CustomBeanPostProcessor() {
        System.out.println("0. Spring calls constructor");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out.println(bean.getClass() + "  " + beanName);
        return bean;
    }
}



fstab and UUID for device identification, docker and friends

https://help.ubuntu.com/community/Fstab

on my VirtualBox Centos7:

cat /etc/fstab

/dev/mapper/cl-root / xfs defaults 0 0
UUID=70139d85-209e-4997-9d06-af6659221021 /boot xfs defaults 0 0
/dev/mapper/cl-swap swap swap defaults 0 0

this is:
[Device] [Mount Point] [File System Type] [Options] [Dump] [Pass]


ls -l /dev/disk/by-uuid/
total 0
lrwxrwxrwx. 1 root root 9 Jun 14 17:41 2019-05-13-13-58-35-65 -> ../../sr0
lrwxrwxrwx. 1 root root 10 Jun 14 17:41 27882150-dbcf-44a5-8461-a7e16020ee6f -> ../../dm-1
lrwxrwxrwx. 1 root root 10 Jun 14 17:41 70139d85-209e-4997-9d06-af6659221021 -> ../../sda1
lrwxrwxrwx. 1 root root 10 Jun 14 17:41 96e9a0f9-2b77-4cfc-be6e-f4c982e57123 -> ../../dm-0
lrwxrwxrwx. 1 root root 10 Jun 15 19:08 fdad3ac1-1c70-4371-8f9e-72ab7f0167df -> ../../dm-3


blkid
/dev/sr0: UUID="2019-05-13-13-58-35-65" LABEL="VBox_GAs_6.0.8" TYPE="iso9660"


on the host VM:

mount | sort

cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
configfs on /sys/kernel/config type configfs (rw,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
/dev/mapper/cl-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/docker-253:0-34242903-3869b9e3d61005155d7ce7222280b67d4c034537b462d76016409d74c39c403b on /var/lib/docker/devicemapper/mnt/3869b9e3d61005155d7ce7222280b67d4c034537b462d76016409d74c39c403b type xfs (rw,relatime,seclabel,nouuid,attr2,inode64,logbsize=64k,sunit=128,swidth=128,noquota)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on /boot type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/sr0 on /run/media/centos/VBox_GAs_6.0.8 type iso9660 (ro,nosuid,nodev,relatime,uid=1000,gid=1000,iocharset=utf8,mode=0400,dmode=0500,uhelper=udisks2)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=3989408k,nr_inodes=997352,mode=755)
fusectl on /sys/fs/fuse/connections type fusectl (rw,relatime)
gvfsd-fuse on /run/user/1000/gvfs type fuse.gvfsd-fuse (rw,nosuid,nodev,relatime,user_id=1000,group_id=1000)
hugetlbfs on /dev/hugepages type hugetlbfs (rw,relatime,seclabel)
mqueue on /dev/mqueue type mqueue (rw,relatime,seclabel)
nfsd on /proc/fs/nfsd type nfsd (rw,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
proc on /run/docker/netns/9c46943f17e7 type proc (rw,nosuid,nodev,noexec,relatime)
pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime)
shm on /var/lib/docker/containers/55284026cd2880cf08c45e66754fcf8011c9cf3227f1564022afad7807cbee27/mounts/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,seclabel,size=65536k)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=31,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=13854)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,seclabel,size=801028k,mode=700,uid=1000,gid=1000)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)


on the docker centos7 container:

mount | sort

/dev/mapper/cl-root on /etc/hostname type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/cl-root on /etc/hosts type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/cl-root on /etc/resolv.conf type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
/dev/mapper/docker-253:0-34242903-3869b9e3d61005155d7ce7222280b67d4c034537b462d76016409d74c39c403b on / type xfs (rw,relatime,seclabel,nouuid,attr2,inode64,logbsize=64k,sunit=128,swidth=128,noquota)
cgroup on /sys/fs/cgroup/blkio type cgroup (ro,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (ro,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (ro,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (ro,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (ro,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (ro,nosuid,nodev,noexec,relatime,net_prio,net_cls)
cgroup on /sys/fs/cgroup/perf_event type cgroup (ro,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/pids type cgroup (ro,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/systemd type cgroup (ro,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
devpts on /dev/console type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=666)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=666)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime,seclabel)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
proc on /proc/bus type proc (ro,relatime)
proc on /proc/fs type proc (ro,relatime)
proc on /proc/irq type proc (ro,relatime)
proc on /proc/sys type proc (ro,relatime)
proc on /proc/sysrq-trigger type proc (ro,relatime)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,seclabel,size=65536k)
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime,seclabel)
tmpfs on /dev type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /proc/acpi type tmpfs (ro,relatime,seclabel)
tmpfs on /proc/asound type tmpfs (ro,relatime,seclabel)
tmpfs on /proc/kcore type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /proc/keys type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /proc/sched_debug type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /proc/scsi type tmpfs (ro,relatime,seclabel)
tmpfs on /proc/timer_list type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /proc/timer_stats type tmpfs (rw,nosuid,seclabel,size=65536k,mode=755)
tmpfs on /sys/firmware type tmpfs (ro,relatime,seclabel)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,relatime,seclabel,mode=755)


one can notice lot of differences in the VM and the container mounts, notably all the cgroup in docker are ro while in vm they are rw. Some mounts "/dev/mapper/cl-root on /etc/*" in docker


What is tmpfs? https://en.wikipedia.org/wiki/Tmpfs

What is xfs? https://en.wikipedia.org/wiki/XFS

What is FUSE (fusectl) ? https://en.wikipedia.org/wiki/Filesystem_in_Userspace#Examples






Friday, June 14, 2019

bash comparison and validation of string

trying to understand Bash syntax is really wasted time.... just copy/paste working examples


array=("pippo pluto topolino")
value=pluto

[[ " ${array[@]} " =~ " ${value} " ]] && echo "YES" || echo "NO"

if [[ " ${array[@]} " =~ " ${value} " ]]; then echo trovato; fi

pippo="ciao"
[[ $pippo = "ciao" ]] && echo "1yes"
[[ "ciao" = "ciao" ]] && echo "2yes"

x="valid"
if [ "$x" = "valid" ]; then
  echo "x has the value 'valid'"
fi

[[ "$x" = "valid" ]] && echo "x is valid" 

[ "$x" == "valid" ] && echo "x has the value 'valid'"

[ "$x" == "valid" ] && echo "i am valid" || echo "i am invalid"



Tuesday, June 11, 2019

Java SSL server and client

https://www.baeldung.com/java-ssl-handshake-failures

this article is inspiring but it contains several errors/omissions.

The actually working code with detailed keytool commands is here https://github.com/vernetto/ssltests



Ultimate resource to learn SSL handshake is https://tls.ulfheim.net/

Sunday, June 9, 2019

shell testing

I have never seen in my life a bash shell being covered by automated tests.

I have thought of using Java and Mockito and Junit5, but it's not very straightforward to run shells from Java (in 2019.... maybe in 2 years it will be normal).

But I think it would be an excellent idea.

This is an inspiring article https://www.leadingagile.com/2018/10/unit-testing-shell-scriptspart-one/

This is the shunit2 framework:

https://github.com/kward/shunit2/


Here the reference manual for shell scripting http://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html but it's a bit too academic.

https://www.tldp.org/LDP/abs/html/index.html this one is richer of examples

PS shell scripting sucks

CRI-O

https://cri-o.io/

CRI-O = "Container Runtime Interface" "Open Container Initiative"
"a lightweight alternative to using Docker as the runtime for kubernetes"

https://www.quora.com/How-is-CRI-O-different-from-Docker-technology

"The CRI-O Container Engine is a implementation of a CRI (Kubernetes Container Runtime interface) that dedicated to Kubernetes. It implements only the features necessary to implement the CRI. Basically whatever Kubernetes needs. The goal to be as simple as possible and to never ever break Kubernetes. CRI-O is only for running containers in production. It runs OCI containers based on OCI images, which basically says it can run any container image sitting at Docker.io, Quay.IO, or any other container registry. It also launches OCI containers with runc.

Docker has a whole bunch of different technology, but I am guessing you are asking about the Docker daemon. Docker daemon is a general purpose container engine that implements API for launching OCI Container using the same runc that CRI-O uses. Docker daemon supports multiple different orchestrators including the Docker Client, Docker Swarm, Kubernetes, Mesosphere. It also supports everything from playing with containers to building containers.

The team behind CRI-O believes that building containers and developing and playing with containers should be done by different tools than the container engine that is used by Kubernetes. The CRI-O team has developed the Podman and Buildah container engines for developing/playing with containers and building container images.

Since these three tasks are done separately CRI-O can run with much tighter security than is required for building and developing containers."




CRI-O and kubeadm

https://katacoda.com/courses/kubernetes/getting-started-with-kubeadm-crio





What is a "pause" container and a "PID namespace sharing" ? https://www.ianlewis.org/en/almighty-pause-container


What is Weave ? https://www.weave.works/docs/cloud/latest/overview/

What is a Nodeport ? https://kubernetes.io/docs/concepts/services-networking/service/#nodeport



Saturday, June 8, 2019

Cloud-Native Applications in Java


excellent book covering basically EVERYTHING about the Java Cloud ecosystem.



Jakarta EE microprofiles, some readings

https://openliberty.io/blog/2018/06/08/java-microservices-microprofile.html


https://jakarta.ee/about/

https://www.amazon.com/Hands-Cloud-Native-Microservices-Jakarta-microservices-ebook/dp/B07NDBQPLF/ref=sr_1_4?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&keywords=microprofiles&qid=1558959093&s=books&sr=1-4




RHEL6 legacy services

just upgrade to RHEL7 please.... or RHEL8...

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/ch-services_and_daemons

change keyboard to Swiss German:

vi /etc/sysconfig/keyboard

KEYTABLE=”de_CH-latin1″
MODEL=”pc105+inet”
LAYOUT=”de_CH”
KEYBOARDTYPE=”pc”

shutdown -r now


cat /etc/inittab should tell you id:5:initdefault: which is the default runlevel

runlevel checks current runlevel

system-config-services UI utility to configure services

service bla status

services are defined in /etc/rc.d/init.d/

ls /etc/xinetd.d here other services https://en.wikipedia.org/wiki/Xinetd

ntsysv to enable/disable services to startup ( ntsysv --level 35 will edit runlevel 3 and 5)

chkconfig --list or chkconfig --list httpd

chkconfig httpd on or chkconfig httpd on --level 35
chkconfig httpd off or chkconfig httpd off --level 35

service --status-all

service httpd start




/var/lock/subsys/ -> " lock files created by their init scripts" see here


before start:
if [ ! -f /var/lock/subsys/servicename ]; then
start # start service here
fi


at the end of start:
touch /var/lock/subsys/servicename

at the end of stop:
rm -f /var/lock/subsys/servicename

WARNING: stale files could linger if abrupt shutdown -> always check also existence of PID (must write PID file)


What happens at boot?
/etc/rc.d/rc.sysinit
/etc/inittab
/etc/rc.d/rcN.d (N = current runlevel)


Template for service scripts is in /usr/share/doc/initscripts-*/sysvinitfiles

sudo stat /proc/1/exe -> /sbin/init
stat /sbin/init -> /lib/systemd/systemd
/sbin/init --version



/etc/rc.d/init.d/functions







Thursday, June 6, 2019

SSL renegotiation and resumption

"Resumption and renegotiation are rather opposites. Resumption restarts a previous TLS session in a new TCP connection, using the same TLS parameters. Renegotiation continues an existing TLS session in the same TCP connection, but changes some of the parameters.
"


in Fiddler, check for the renegotiation_info field in the CONNECT requestsmethods


https://www.ssllabs.com/ssltest/


Secure Renegotiation Supported
Secure Client-Initiated Renegotiation Yes
Insecure Client-Initiated Renegotiation No

Session resumption (caching) Yes
Session resumption (tickets) No


check DisableRenegoOnClient link


https://www.salt.ky/disabling-tlsssl-renegotiation-in-configuration-manager-2012/ and https://support.microsoft.com/en-us/help/977377/microsoft-security-advisory-vulnerability-in-tls-ssl-could-allow-spoof

"Modify the key to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SecurityProviders\SCHANNEL\DisableRenegoOnClient | DWORD=0"



https://backstage.forgerock.com/knowledge/kb/article/a28022128 -Djdk.tls.rejectClientInitiatedRenegotiation=true


-Dsun.security.ssl.allowUnsafeRenegotiation=true ( see https://www.oracle.com/technetwork/java/javase/tlsreadme2-176330.html on why this is a bad idea)

Doc on Session Resumption https://spacehost.de/tls-session-resumption-caching-tickets/

jdk.tls.useExtendedMasterSecret=false
jdk.tls.allowLegacyResumption=true
jdk.tls.allowLegacyMasterSecret=true


Here more explanation on Resumption and Renegotiation



To understand JSSE in general read this guide https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html



viewing https handshakes in fiddler

https://textslashplain.com/2015/10/12/viewing-https-handshakes-in-fiddler/




https://stackoverflow.com/questions/12323944/fiddler-httpmethod-get-put-post-delete-column

Right-click the column bar and select Customize columns....

Collection: Miscellaneous
Field Name: RequestMethod







https://gumroad.com/l/dwf2/IntroSale



Thursday, May 30, 2019

branching models, trunk based development

the only good git presentations are VISUAL - unless you visualize what happens in terms of commits, there is NO WAY you can learn.


here they explain very well the meaning of -no-ff (no fast forward)

git merge --no-ff myfeature

https://nvie.com/posts/a-successful-git-branching-model/

"The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature. "

interesting the explanation of Feature branches, Release branches, Hotfix branches


Here great explanation of merge vs rebase https://git-scm.com/book/en/v2/Git-Branching-Rebasing



https://jenkins-x.io/about/accelerate/


Really interesting what they say here:

https://trunkbaseddevelopment.com/



Tuesday, May 28, 2019

Codota!

I have just read/watched the Baeldung article on Codota https://www.baeldung.com/codota

this thing seems to have a big future... as IT developer, I am often confronted with a blank screen and a "and now what?" and googling for working examples... with so many frameworks libraries languages etc, it's unrealistic to expect that every developer should remember all by heart... nor people having the discipline of building a collection of quickstarts/examples.

having an IDE who can guide you through the syntax of each specific framework is really enormously boosting productivity and self-confidence.

I will explore the tool when I have time

Sunday, May 19, 2019

JAXRS all-in-one

All annotations are summarized here https://dzone.com/articles/introduction-to-restful-web-service-a-jax-rs-speci

"Base URL for any web application is:

http://<server>:<port>/<context-root>

Append tag from web.xml with Base URL that forms:

http://<server>:<port>/<context-root>/<url-pattern>

Append class-level @Path(“class-level”) annotation and then method-level @Path(“method-level”) annotation that forms:

http://<server>:<port>/<context-root>/<url-apptern>/<class-level>/<method-level>"





https://dzone.com/articles/an-introduction-to-jax-rs-annotations-part-1

https://dzone.com/articles/what-are-jax-rs-annotations


https://readlearncode.com/java-ee/what-is-javax-ws-rs-core-context-httpservletresponse-and-httpservletrequest/


https://readlearncode.com/java-ee/what-are-the-jax-rs-annotations-get-post-path-applicationpath/


https://dzone.com/articles/what-is-javaxwsrscorecontext



@ApplicationPath("api")
extends Application

@Path("/books")

@GET
@Produces(MediaType.APPLICATION_JSON)

@POST
@Consumes(MediaType.APPLICATION_JSON)

@PUT
@HEAD

@DELETE

@Path("{isbn}")

@PathParam("isbn") String isbn

@QueryParam

@OPTIONS

@javax.ws.rs.HeaderParam
javax.ws.rs.core.Response

javax.ws.rs.core.SecurityContext



It's all very clear apart @Context... read here to understand @Context
https://readlearncode.com/java-ee/what-is-javax-ws-rs-core-context-httpheaders-and-uriinfo/

this for SecurityContext : https://readlearncode.com/java-ee/what-is-javax-ws-rs-core-context-securitycontext/


and some more coding examples here https://www.mkyong.com/webservices/jax-rs/get-http-header-in-jax-rs/




Friday, May 17, 2019

More interesting readings on quarkus and microprofiles

I reveive from my friend Rob:

This will soon overhaul Spring Boot. Look how they fast grow with integrating all enterprise patterns on Quarkus. This community is the driver https://smallrye.io/

Look at this suberb documentation

https://quarkus.io/guides/, almost covering everything you need

https://quarkus.io/guides/logging-guide
https://quarkus.io/guides/jwt-guide
https://quarkus.io/guides/transaction-guide

and then this amazing reactive streaming doc

https://quarkus.io/guides/kafka-guide


this will leave spring boot behind really soon


Worth reading is also https://www.baeldung.com/quarkus-io

Interesting also eclipse.microprofile https://www.baeldung.com/eclipse-microprofile running on Open Liberty



Thursday, May 16, 2019

Jooq and QueryDSL as alternatives to JPQL, Panache,

HQL (and JPQL) both suck because they are not statically typed..."lack of type safety and absence of static query checking" "concatenation of strings which is usually very unsafe "

"Criteria Query API ended up very verbose and practically unreadable. "


https://www.jooq.org/

"jOOQ generates Java code from your database and lets you build type safe SQL queries through its fluent API. "

So this is no ORM framework, it uses your DB as it is, it simply allows you to write safer SQL queries directly in a fluent Java API. No Hocus-Pocus, it's a 1-to-1 mapping between DB and Java.

Here some examples https://www.jooq.org/doc/3.11/manual-single-page/#jooq-in-7-steps



http://www.querydsl.com/

how to use it https://www.baeldung.com/querydsl-with-jpa-tutorial and https://www.baeldung.com/intro-to-querydsl



If you want to use Native SQL or JPQL in Spring: https://www.baeldung.com/spring-data-jpa-query


This is the horribly verbose JPA Criteria API https://www.baeldung.com/hibernate-criteria-queries
" the main and most hard-hitting advantage of Criteria queries over HQL is the nice, clean, Object Oriented API."




Apache SSL and ciphersuites

Useful commands and links

https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#sslciphersuite


openssl ciphers -v

http://www.openssl.org/docs/apps/ciphers.html

httpd -v
httpd -V

https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html

openssl s_client -connect 129.123.123.112:443

yum list all
yum install nmap


nmap -p 443 --unprivileged -script ssl-enum-ciphers 129.123.123.112

https://www.tecklyfe.com/nmap-script-test-ssl-versions-cipher-suites/

SSLCipherSuite HIGH:!aNULL:!MD5

SSLCipherSuite HIGH:!aNULL:!MD5:!SSLv3:!TLSv1

PORT    STATE SERVICE
443/tcp open  https
| ssl-enum-ciphers: 
|   SSLv3: No supported ciphers found
|   TLSv1.0: No supported ciphers found
|   TLSv1.1: No supported ciphers found
|   TLSv1.2: 
|     ciphers: 
|       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - strong
|       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - strong
|       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - strong
|       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - strong
|       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - strong
|       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - strong
|       TLS_RSA_WITH_AES_128_CBC_SHA256 - strong
|       TLS_RSA_WITH_AES_128_GCM_SHA256 - strong
|       TLS_RSA_WITH_AES_256_CBC_SHA256 - strong
|       TLS_RSA_WITH_AES_256_GCM_SHA384 - strong
|     compressors: 
|       NULL
|_  least strength: strong





https://en.wikipedia.org/wiki/Évariste_Galois

talking about GCM ciphers https://en.wikipedia.org/wiki/Galois/Counter_Mode






yarn react and materialui

open cmd with admin rights:
choco install yarn
close this cmd and open a "normal" cmd

yarn create react-app app
cd app
yarn add bootstrap@4.1.3 react-cookie@3.0.4 react-router-dom@4.3.1 reactstrap@6.5.0
yarn add @material-ui/core
yarn start


in App.js:


import React, {Component} from 'react';
import './App.css';
import Button from '@material-ui/core/Button';
import Table from '@material-ui/core/Table';
import TableRow from '@material-ui/core/TableRow';
import TableCell from '@material-ui/core/TableCell';




Friday, May 10, 2019

CDI in IntelliJ Java Enterprise projects

I was following this https://www.jetbrains.com/help/idea/creating-and-running-your-first-java-ee-application.html tutorial to deploy a Primefaces application to Wildfly 16, but I kept getting an error


unable to find cdi beanmanager

I have tried adding Maven support and adding the dependency

<dependencies>

<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>

</dependencies>


to no avail.

Funnily, setting webapp version="2.3" instead of version="4.0" in web.xml fixes the problem.


Then I added CDI support as shown here:

https://www.jetbrains.com/help/idea/context-and-dependency-injection-cdi.html

and using version="4.0" and things are working.

good old friend JMeter

JMeter is one of those primitive animals that never goes extinct.

Decent presentation:




Excellent comparison with SoapUI
https://octoperf.com/blog/2018/06/05/jmeter-vs-soapui/

JMeter is good for a VERY quick and dirty PERFORMANCE test of a service.


Incorporating JMeter Performance tests in Maven builds: https://www.ubik-ingenierie.com/blog/shift-left-performance-tests-jmeter-maven/ and this is the plugin https://github.com/jmeter-maven-plugin/jmeter-maven-plugin/wiki





Some books on the topic:




Sai Matam, Jagdeep Jain - Pro Apache JMeter_ Web Application Performance Testing Apress (2017)

Bayo Erinle - JMeter Cookbook Packt Publishing (2014)

Bayo Erinle - Performance Testing with JMeter 3 Enhance the performance of your web application Packt Publishing (2017)





GraalVM native image

download GraalVM CE and unzip it to /home/centos/graalvm-ce-19.0.0/

export JAVA_HOME=/home/centos/graalvm-ce-19.0.0/
export GRAALVM_HOME=/home/centos/graalvm-ce-19.0.0/

cd /home/centos/graalvm-ce-19.0.0/bin
./java -version
sudo ./gu install native-image

vi HelloWorld.java

public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("hello world");
        }
}



./javac HelloWorld.java

time ./java HelloWorld


hello world

real 0m0.074s
user 0m0.057s
sys 0m0.019s



./native-image -H:+ReportExceptionStackTraces HelloWorld

Build on Server(pid: 6249, port: 45750)
[helloworld:6249]    classlist:     299.78 ms
[helloworld:6249]        (cap):     359.96 ms
[helloworld:6249]        setup:     479.50 ms
Error: Basic header file missing (). Make sure headers are available on your system.
com.oracle.svm.core.util.UserError$UserException: Basic header file missing (). Make sure headers are available on your system.
 at com.oracle.svm.core.util.UserError.abort(UserError.java:65)
 at com.oracle.svm.hosted.c.CAnnotationProcessor.reportCompilerError(CAnnotationProcessor.java:138)
 at com.oracle.svm.hosted.c.codegen.CCompilerInvoker.compileAndParseError(CCompilerInvoker.java:74)
 at com.oracle.svm.hosted.c.CAnnotationProcessor.compileQueryCode(CAnnotationProcessor.java:131)
 at com.oracle.svm.hosted.c.CAnnotationProcessor.process(CAnnotationProcessor.java:84)
 at com.oracle.svm.hosted.c.NativeLibraries.finish(NativeLibraries.java:311)
 at com.oracle.svm.hosted.NativeImageGenerator.processNativeLibraryImports(NativeImageGenerator.java:1523)
 at com.oracle.svm.hosted.NativeImageGenerator.setupNativeLibraries(NativeImageGenerator.java:997)
 at com.oracle.svm.hosted.NativeImageGenerator.setupNativeImage(NativeImageGenerator.java:829)
 at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:521)
 at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:441)
 at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
 at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
 at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
 at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
 at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Error: Image build request failed with exit status 1



sudo yum install glibc-devel
sudo yum install zlib-devel
sudo yum install gcc

./native-image HelloWorld

time ./helloworld
hello world

real 0m0.012s
user 0m0.001s
sys 0m0.011s




References:

https://www.graalvm.org/






Monday, May 6, 2019

Accelerate

https://www.kobo.com/us/en/ebook/accelerate-7




This is an excellent book - not only about technology but mostly about culture, leadership, teamwork, innovation.

I don't share the enthusiastic vision of the author for which life is about serving corporations to beat competition and cut jobs. However it's an educational book.


JDK maven Nexus and HTTPS

If your Nexus repository uses certificates signed by your own Root CA, chances are that a JDK doesn't trust them.

Then when you run

mvn package

you get


sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target


Go to your JAVA_HOME\jre\lib\security folder, where the cacerts file is located, and issue

keytool -list -v -keystore cacerts

enter "changeit" as password

this shold tell you all your trusted CAs

You should import your own CA certificate to into this keystore.


I have tried also setting:


set MAVEN_OPTS="-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true -Dmaven.wagon.http.ssl.ignore.validity.dates=true"

but it disn't work for me.




Panache as a wrapper for Hibernate

https://quarkus.io/guides/hibernate-orm-panache-guide

https://developers.redhat.com/courses/quarkus/effective-data-hibernate-and-panache-quarkus/

The product seems very well conceived, it really streamlines your JPA code.

One more aspect where the Java world has completely screwed up, is the 20 different ways you can implement DB queries....
ah if only ORM had been embedded into the language from the beginning, we would be dealing with a single persistence framework.



Thursday, May 2, 2019

Enabling Swagger in a Java EE application

This should be enough:

0) add Maven dependencies:

com.wordnik:swagger-jaxrs_2.10:1.3.1


1) with an Application, register the Swagger jaxrs resources:

import java.util.Set;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rest")
public class JaxRsActivator extends Application {

 @Override
 public Set<Class<?>> getClasses() {
  Set<Class<?>> resources = new java.util.HashSet<>();
  resources.add(com.wordnik.swagger.jaxrs.listing.ApiListingResource.class);
  resources.add(com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider.class);
  resources.add(com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON.class);
  resources.add(com.wordnik.swagger.jaxrs.listing.ResourceListingProvider.class);
//  resources.add(BearerTokenFilter.class);
  addRestResourceClasses(resources);
  return resources;
 }

 private void addRestResourceClasses(Set<Class<?>> resources) {
  resources.add(BlaService.class);
  resources.add(MumbleService.class);
 }

}




2) register the Swagger configuration:


import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

import com.wordnik.swagger.config.ConfigFactory;
import com.wordnik.swagger.config.ScannerFactory;
import com.wordnik.swagger.config.SwaggerConfig;
import com.wordnik.swagger.jaxrs.config.DefaultJaxrsScanner;
import com.wordnik.swagger.jaxrs.reader.DefaultJaxrsApiReader;
import com.wordnik.swagger.reader.ClassReaders;

@WebServlet(name = "SwaggerJaxrsConfig", loadOnStartup = 1)
public class SwaggerJaxrsConfig extends HttpServlet {

 @Override
 public void init(ServletConfig servletConfig) {
  try {
   super.init(servletConfig);
   SwaggerConfig swaggerConfig = new SwaggerConfig();
   ConfigFactory.setConfig(swaggerConfig);
   swaggerConfig.setBasePath("/rest");
   swaggerConfig.setApiVersion("2.1");
   ScannerFactory.setScanner(new DefaultJaxrsScanner());
   ClassReaders.setReader(new DefaultJaxrsApiReader());
  } catch (ServletException e) {
   System.out.println(e.getMessage());
  }
 }
}





3) then you can annotare your services methods:

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;


@Path("/pippo")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Api(value = "/pippo", description = "REST service end-points exposed to Pippo")
public class PippoService {
 @GET
 @Path("/profiles")
 @Produces(MediaType.APPLICATION_JSON)
 @ApiOperation(value = "All Pippos", notes = "List all Pippos")
 @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Server error, check log files") })
 public List listPippobyQuery(
                 @ApiParam(value = "the hostname where Pippo resides") @QueryParam("hostname") String hostName) {

  return listPippo(hostName);
 }
}











Monday, April 29, 2019

JAXRS client with Jersey

As usual we start from the excellent Baeldung https://www.baeldung.com/jersey-jax-rs-client

The working solution is in https://github.com/vernetto/jerseyrest and the client is in the test directory (Jersey is provided with "test" scope, while the "main" can be built with maven and deployed to WebLogic for instance)

The project is to turn the Service in a set of services with different types of payloads (JSON, XML, binary) and different marshaling/unmarshaling frameworks (Jexson, GSON...) , then run some performance test (using junit5) under different load conditions.





Swagger for Java EE reasteasy or jersey

Making Swagger work in Spring is very easy.

You can use it also in Java EE (Wildfly, WebLogic, even Tomcat!!! )

but all the documentation I have found is a bit outdated:

I have tried APIEE https://dzone.com/articles/apiee-an-easy-way-to-get-swagger-on-java-ee and https://github.com/phillip-kruger/apiee but it's not showing my services and I see no error.

Some other outdated articles:

https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-Jersey-2.X-Project-Setup-1.5



https://github.com/swagger-api/swagger-core/wiki/Swagger-Core-RESTEasy-2.X-Project-Setup-1.5

I have no time now, but if I need to write REST services in Java EE I would not live without Swagger...

Gradle deploy to Nexus

mkdir /home/centos/gitclones/gradletest
cd /home/centos/gitclones/gradletest
gradle init --type java-application

gradle build

vi build.gradle
add to plugins:
id 'maven'

maven Plugin for Gradle is documented here https://docs.gradle.org/current/userguide/maven_plugin.html

gradle install

ls -ltra /home/centos/.m2/repository/gradletest/unspecified/
total 4956
-rw-r--r-- 1 centos docker 2371522 Apr 29 13:23 gradletest-unspecified.zip
-rw-r--r-- 1 centos docker 2693120 Apr 29 13:23 gradletest-unspecified.tar
-rw-r--r-- 1 centos docker     752 Apr 29 13:23 gradletest-unspecified.jar
-rw-r--r-- 1 centos docker     756 Apr 29 13:23 gradletest-unspecified.pom


cat /home/centos/.m2/repository/gradletest/unspecified/gradletest-unspecified.pom

  <groupId></groupId>
  <artifactId>gradletest</artifactId>
  <version>unspecified</version>


group and version are missing!

then you can follow the steps here https://medium.com/dot-debug/deploying-artifacts-to-maven-using-gradle-b669acc1b6f8

you define the group and version in your projects' build.gradle, you define nexus username/password/url in ~/.gradle/gradle.properties and you use the maven-publish plugin to publish to Nexus





IntelliJ IDEA Essentials




this is a really precious book, very focused and essential, to learn very practical tricks on how to use Intellij effectively




Sunday, April 28, 2019

JPG to PDF conversion in Java

https://gist.github.com/gholker/9a6b68ae51b3bef8931b946958dd81f2


Create a Spring Initializer App (plain vanilla)


add this dependency: com.itextpdf:itextpdf:5.5.13

run this code


package org.pierre.jpgtopdf;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


@SpringBootApplication
public class JpgtopdfApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(JpgtopdfApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        File root = new File("D:\\pierre\\tasse2019\\");
        String outputFile = "output.pdf";
        List<String> files = new ArrayList<String>();
        String[] alljpgs = root.list((dir, name) -> name.endsWith("jpg"));
        files.addAll(Arrays.asList(alljpgs));

        Document document = new Document();
        PdfWriter.getInstance(document, new FileOutputStream(new File(root, outputFile)));
        document.open();
        for (String f : files) {
            document.newPage();
            Image image = Image.getInstance(new File(root, f).getAbsolutePath());
            image.setAbsolutePosition(0, 0);
            image.setBorderWidth(0);
            image.scaleAbsolute(PageSize.A4);
            document.add(image);
        }
        document.close();
    }
}




It's amazingly fast!



CDI and javax.transaction.TransactionScoped

I was wondering how TransactionScoped works, and I stumbled upon this wonderful example:

https://www.byteslounge.com/tutorials/java-ee-cdi-transactionscoped-example

This also is a great explanation on Injected beans https://www.byteslounge.com/tutorials/java-ee-cdi-dependency-injection-inject-tutorial

It's so clearly explained that I was deeply impressed by this www.byteslounge.com
Gonçalo Marques. We need more of this stuff. Often people post partial, overcomplicated examples.... Gonçalo instead goes straight to the point.

Tuesday, April 23, 2019

Jenkins enable project based security

Sometimes you share a Jenkins instance amongst several projects (IMHO this is bad practice, each project should have its own Jenkins to minimize interference)

This is how to do it (copied from https://stackoverflow.com/questions/32111825/jenkins-how-to-set-authorization-on-project-basis )


a) make sure Matrix Authorization Strategy Plugin is installed (Manage Jenkins/Manage Plugins/Installed Plugins)

b) "Manage Jenkins", "Configure Global Security", add the target user to the "Project-based Matrix Authorization Strategy ",
add the target user with permissions "Overall/Read and Job/Read"

c) on the main page, select the target project, "Enable project-based security", add the target user and on the right, click on the "grant all permissions" button

at this point the user has login and can administer the target project, but only view other projects.

Jenkins would be a much better tool if all these configuration operations could be easily scriptable. Nowadays it's just a huge clickodrome and very awkward to manage, you have to wade through zillion of configuration pages and unless you are really experienced it's sometimes frustrating ... you don't even have a "search" functionality for configuration options, you have to remember all locations by heart...

Sunday, April 21, 2019

Simple Spring Boot and React working example

https://developer.okta.com/blog/2018/07/19/simple-crud-react-and-spring-boot

Matt Raible is a boss and he is so straight to the point and precise.

Remember that if you have in your pom.xml the dependency spring-boot-starter-security, then Spring Boot will enable security by default with username "user" and a dynamically generated password:

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-security.html

so for the time being I have excluded this dependency.

This https://www.baeldung.com/spring-security-login should explain more how to handle web security with the great fluent api provided by Spring.

Friday, April 19, 2019

Intellij and WebLogic

https://www.jetbrains.com/help/idea/configuring-and-managing-application-server-integration.html



Wednesday, April 17, 2019

never copy/paste from outlook or Word

Microsoft sucks




The command on the left was copied from an email (Outlook). And it was failing, returning EVERYTHING, not only config.xml.

Then I have typed all over again (right pane) and it was working

Visually they look absolutely the same, even in Notepad++. But a closer inspection reveals hidden chars.

Copying and pasting from Outlook or Word has caused more victims than the 1919 Spanish Flu.

I remember a production delivery failed because someone copied a command from a Word document where Word had capitalized a property name.



CompletableFuture

https://www.callicoder.com/java-8-completablefuture-tutorial/

package com.example.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(com.example.demo.DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        CompletableFuture<String> completableFuture = new CompletableFuture<String>();
        completableFuture.complete("Future's Result");

        String result = completableFuture.get();
        System.out.println(result);


        CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                // Simulate a long-running Job
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new IllegalStateException(e);
                }
                System.out.println("I'll run in a separate thread than the main thread.");
            }
        });
        // Block and wait for the future to complete
        future.get();
    }

}







Ruminations about Jenkins

The jobs are defined in here:

$JENKINS_HOME/jobs

For every project (item), there is a folder.

In every folder there is a config.xml file which hopefully should contain the entire project definition.

My assumption is that one should simply save the config.xml, and this is enough to recreate the project elsewhere.

I am worried because the Project definitions in Jenkins are not saved in bitbucket,
and we don’t have an automated way to export them from PROD and import them to a UAT instance.

One COULD tar the $JENKINS_HOME/jobs folder, but it’s very bulky.


[jobs]$ cd myproject/

[myproject]$ ls -ltra

drwxr-xr-x. 3 pippo pippogroup 4096 Jul 18 2016 modules
-rw-r--r--. 1 pippo pippogroup 6 Apr 25 2018 nextBuildNumber
lrwxrwxrwx. 1 pippo pippogroup 26 Apr 25 2018 lastSuccessful -> builds/lastSuccessfulBuild
lrwxrwxrwx. 1 pippo pippogroup 22 Apr 25 2018 lastStable -> builds/lastStableBuild
drwxr-xr-x. 5 pippo pippogroup 4096 Apr 25 2018 workspace
drwxr-xr-x. 24 pippo pippogroup 4096 Apr 25 2018 builds
-rw-r--r--. 1 pippo pippogroup 7257 Apr 25 2018 config.xml
drwxr-xr-x. 5 pippo pippogroup 4096 Apr 25 2018 .
drwxr-xr-x. 360 pippo pippogroup 20480 Mar 18 15:06 ..


especially the workspace is a PIG

So for the time being I will simply tar up all the config.xml and untar them in UAT:


cd $JENKINS_HOME/jobs

find . –maxdepth 2 –name config.xml | tar cvf /var/tmp/alljenkinsconfig.tar –T –

(maxdepth is important to avoid picking up files coming from the workspaces)

However we should really really IMHO push all those config.xml to bitbucket, regularly – ideally automatically whenever someone changes a config.xml:

git init
#set origin and remote
find . –maxdepth 2 –name config.xml –exec git add {} \;
git commit -m "blablabla"
git push


Incidentally, many project folders contain spaces, which makes it much trickier to write scripts to manipulate them.

I am not in favor of Capital Punishment, apart from cases when people create folders containing spaces.


Jenkins sucks anyway. Design is from Napoleonian Era, UI made by a freak, configuration freakishly XML based without fluent Administration Groovy API,
actually in the old times they were much better at designing stuff, think of the Tour Eiffel or the Pyramids and the Coliseum.
Nowadays any idiotic monkey can code freakish products like Maven or Jenkins and become a celebrity.



Thread dumps analysis

this post provides useful insights on how to detect issues from a Thread Dump:

http://allthingsmdw.blogspot.com/2012/02/analyzing-thread-dumps-in-middleware_08.html

For a quick thread dump consolidation one can use https://spotify.github.io/threaddump-analyzer/ or https://www.jetbrains.com/help/idea/analyzing-external-stacktraces.html (both are quite equivalent)....

Problem is that these tools are Application Server agnostic and don't tell you what is normal and what is not. I think some AI should be added to the tool, plus some graphical rendering for instance of the lock analysis.

When I have time I want to look into https://fastthread.io/

Anyway advanced thread analysis is a skill in itself and should be done with proper tooling... manually sorting stuff can be overwhelming for the regular human being.

Saturday, April 13, 2019

Mockito revisited

https://github.com/mockito/mockito


I have used Mockito in 2010. Then I never did SERIOUS Java development any more (shame on me...)

Yet I strongly believe that a solid implementation of Mocks is the foundation of healthy, fully testable software.
If you can't entirely automate your application tests, you are playing with your life.


https://search.maven.org/artifact/org.mockito/mockito-core/2.26.0/jar

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.26.0</version>
</dependency>









https://github.com/in28minutes/MockitoTutorialForBeginners



https://www.baeldung.com/mockito-annotations

source code is here https://github.com/eugenp/tutorials/tree/master/testing-modules/mockito


https://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/Mock.html

@Mock
List mockedList;


https://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/Spy.html

@Spy
List spiedList = new ArrayList();


https://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/ArgumentCaptor.html

@Captor
ArgumentCaptor argCaptor;


I am getting : Illegal reflective access by org.mockito.internal.util.reflection.AccessibilityChanger
Hopefully Mockito folks will fix this one da.







Wednesday, April 10, 2019

Gradle plugin for Jenkins

Maven Sucks, so we welcome Gradle - it can't possibly be worse than Maven!

https://wiki.jenkins.io/display/JENKINS/Gradle+Plugin

it seems that Gradle Plugin is installed as part of the "common plugins". I use an old Jenkins 2.138.


export GRADLE_HOME=/home/centos/gradle/gradle-4.8
#make sure $GRADLE_HOME/bin is in $PATH
cd /home/centos/gitclones
git clone https://github.com/jitpack/gradle-simple
cd gradle-simple/
gradle clean
gradle build
#check if jar was built
ls -ltra build/libs


I configure a freestyle Jenkins item to checkout from Github and "clean build" as gradle tasks...
Then I inspect /home/centos/.jenkins/workspace/gradletest/build/libs/ and the jar has been built there... great!


If I want to copy the plugin to another machine, it's in /home/centos/.jenkins/plugins/gradle.jpi

The MANIFEST.MF says:

Manifest-Version: 1.0
Plugin-Dependencies: structs:1.3
Long-Name: Gradle Plugin
Compatible-Since-Version: 1.0
Plugin-Developers: Stefan Wolf:wolfs:
Group-Id: org.jenkins-ci.plugins
Extension-Name: gradle
Plugin-Version: 1.31
Jenkins-Version: 1.651.3
Url: https://wiki.jenkins.io/display/JENKINS/Gradle+Plugin
Short-Name: gradle







Tuesday, April 9, 2019

Effective Java third edition


the source code:

https://github.com/jbloch/effective-java-3e-source-code






*clone (p. 86)
copy constructor/ copy factory
compareTo()
java.util.Comparator.comparingInt + thenComparingInt


immutable objects

composition over inheritance

default methods

generics and collections

unbounded wildcard types (<?>)

PECS producer extends consumer super

isAnnotationPresent
@ExceptionTest
@Repeatable


java.util.function
Operator
Predicate
Function
Supplier
Consumer



Monday, April 8, 2019

Generics and collections

this one has no compilation errors:

Set a;
Set<Object> b;
Set<? super Object> c;

a = new HashSet();
b = new HashSet<>();
c = new HashSet<>();

c = a;
c = b;
b = a;
b = c;
a = c;
a = b;



but if I use

Set<Object> b;
Set<?> c;

then "c = b" gives compilation error

Error:(26, 13) java: incompatible types: java.util.Set cannot be converted to java.util.Set


This is interesting, since ? means "any Object and subclasses"... while "? super Object" means "Object and its superclasses"
but Object has no superclasses, so effectively it's only Object.


If I use:
b = new HashSet<>();
Set<?? extends Object> c;

then
b = c;
fails with the same error:

Error:(26, 13) java: incompatible types: java.util.Set cannot be converted to java.util.Set


The raw type a can be assigned all the time to all the others.


similarly, collections are INVARIANT:
Set<Number> numset = new HashSet<>();
Set<Integer> intset = new HashSet<>();
Set<?> allset = new HashSet<>();

numset = intset; // INVALID
intset = numset; // INVALID
allset = numset; // VALID
numset = allset; // INVALID



but arrays are COVARIANT:

Number[] numarr = new Number[1];
Integer[] intarr = new Integer[1];
numarr = intarr; // VALID
intarr = numarr; // INVALID










Sunday, April 7, 2019

Amazing brushes by Reto




a colleague of mine, Reto, is a passionate photographer and Photoshop artist , here some links to his creations:

https://creativemarket.com/xresch/2642460-1500-Brushes-Megapack

https://creativemarket.com/xresch

https://affinity.serif.com/en-gb/store/product/180-smoke-and-cloud-brushes/




Intellij , maven and the source or target java language level

I create a new Java "maven" project, set it to Java 12 (ctrl-alt-shift-S, MOdules, Language level), but when I build I get:

"Warning:java: source value 1.5 is obsolete and will be removed in a future release"


Apparently this is due to the prehistoric, nonsensical Maven Compiler Plugin using Java 1.5 by default

https://stackoverflow.com/questions/27037657/stop-intellij-idea-to-switch-java-language-level-every-time-the-pom-is-reloaded


you can either insert in the pom.xml :
<properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>



or
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>1.11</source>
                <target>1.11</target>
            </configuration>
        </plugin>

    </plugins>

</build>



Remember also to make sure that ctrl-alt-S (Settings) Settings -> Build, Execution, Deployment -> Build Tools -> Maven -> Importing is set to use JDK 12. So complicated. So brittle. So Maven.

Working with Maven is like traveling back to prehistoric times, like the Mural de la Prehistoria in Cuba, https://en.wikipedia.org/wiki/Vi%C3%B1ales_Valley



developers on the right about to be eaten by Maven on the left


Priceless String manipulation Intellij plugin

ctrl-alt-S, then "Plugins" search for "String Manipulations"; install and reboot.

for instance, if you need to "escape XML" (that is transform reserve chars in "% bla ;" sequences :

File/new scratch file (or ctrl-alt-shift-ins), paste your XML, select all, right click "String manipulation", "escape xml"


Normally I used Notepad++ and the "XML Tools Plugin", but this seems more useful.





Wednesday, April 3, 2019

git synchronize repositories

It happens that an external Git repository has to be mirrored internally in a corporate git repository. This cloning and mirroring should include branches, tags, commit history etc. and be one-way (internal changes are lot upon synchronization)

Luckily you don't have to write special scripts, all is provided by git:


https://help.github.com/en/articles/duplicating-a-repository



Let's make an experiment

in github I create a "gitclonesource" and a "gitclonedestination" empty repositories

mkdir gitclonetests
cd gitclonetests


#let's prepare the source
mkdir gitclonesource
cd gitclonesource
git init
echo "ciao" > README.md
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/vernetto/gitclonesource.git
git push -u origin master

#create branch
git checkout -b mybranch
echo "hello" >> mybranch.txt
git add mybranch.txt
git commit -am "added mybranch.txt"
git push --set-upstream origin mybranch

#create tag
git checkout master
git tag -a v1.4 -m "my version 1.4"
git push --tags



#now clone source and push to destination with all branches and tags
cd ..
#this will create a folder gitclonesource.git
git clone --bare https://github.com/vernetto/gitclonesource.git
#when you cd, you will see a message BARE:master if using Git bash
cd gitclonesource.git/
git push --mirror https://github.com/vernetto/gitclonedestination

Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 600 bytes | 200.00 KiB/s, done.
Total 7 (delta 0), reused 0 (delta 0)
To https://github.com/vernetto/gitclonedestination
 * [new branch]      master -> master
 * [new branch]      mybranch -> mybranch
 * [new tag]         v1.4 -> v1.4




and, lo and behold, in the gitclonedestination I can find my branch and the tag! All cloned in one go!

at this point you can cleanup the gitclonedestination.git:

cd ..
rm -rf gitclonedestination.git








Monday, April 1, 2019

WebLogic Security documentation

https://docs.oracle.com/middleware/12213/wls/INTRO/security.htm#INTRO232



https://docs.oracle.com/cd/E19798-01/821-1841/girbe/index.html JACC "Java Authorization Contract for Containers"

https://docs.oracle.com/javase/8/docs/api/java/security/Permission.html java.security.Permission

https://docs.oracle.com/javase/8/docs/api/java/lang/SecurityManager.html java.lang.SecurityManager





Java Authentication Service Provider Interface for Containers (JASPIC)




Training Material:

https://www.udemy.com/how-to-secure-oracle-weblogic-12c/


https://www.udemy.com/oracle-weblogic-12c-for-administrators/


Old book https://www.amazon.com/Securing-Weblogic-Server-Luca-Masini/dp/1849687781





Best Spring books

reblogging for my own reference, I am planning to read all those 5 books...

https://javarevisited.blogspot.com/2018/04/5-spring-framework-books-experienced-Java-developers-2018.html

- Spring in Action 5
- Cloud Native Java
- Learning Spring Boot 2.0
- Spring 5 Recipes
- Spring Microservices in Action



I am already going through https://www.udemy.com/spring-framework-5-beginner-to-guru/ but I find it incredibly non-concise - lot of repeated stuff, very lengthy and boring coding sessions where you don't really see much new, lot of unnecessary verbosity. Not my style, I like crisp, focused, simple examples and just fundamental facts and concepts.


Saturday, March 30, 2019

Java EE 8 Application Development book

David R. Heffelfinger - Java EE 8 Application Development-Packt Publishing (2017)



I am going through the examples of the book, using WLS 12.2.1.3 (it supports only Java EE 7, unfortunately), and IntelliJ 2019.1

here how to setup your environment (very easy!) :

https://www.jetbrains.com/help/idea/creating-and-running-your-first-java-ee-application.html#bfda7423


Code is here https://github.com/PacktPublishing/Java-EE-8-Application-Development


You can run also on Wildfly 16 https://wildfly.org/downloads/ which supports Java EE 8


Java EE 8 Javadoc https://javaee.github.io/javaee-spec/javadocs/index.html?overview-summary.html

Friday, March 29, 2019

bash script cheatsheet




Tuesday, March 26, 2019

Camel rediscovered

https://cleverbuilder.com/articles/camel-tutorial/

testing rest with  http://rest-assured.io/

https://github.com/rest-assured/rest-assured/wiki/Usage#json-schema-validation

http://camel.apache.org/enterprise-integration-patterns.html


http://camel.apache.org/components.html





Old posts:

http://www.javamonamour.org/2017/10/camel-in-action-second-edition.html


http://www.javamonamour.org/2017/08/apache-camel-training.html

http://www.javamonamour.org/2011/04/camel-is-cool.html

http://www.javamonamour.org/2010/07/enterprise-integration-patterns.html

Helm tutorials on Katacoda

I have been through some youtube tutorials on Helm but I found them too blablaistic. I like essential, crisp and down to earth presentations, not all-encompassing philosophical sermons.

https://www.katacoda.com/aptem/scenarios/helm


curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
helm init
helm repo update
kubectl get pods -n kube-system
helm version

in Chart.yaml there is basically nothing (version and chartname)

in equirements.yaml there are dependencies

in templates/configmap.yaml the ConfigMap

in templates/service.yaml the Service Definition (with port/nodePort)

in templates/pv.yaml the PersistenVolume


helm dependency update lets-chat

helm inspect lets-chat

helm install lets-chat --name demo -f my_values.yml --debug --dry-run

helm install lets-chat --name demo --namespace demo -f my_values.yml

helm list

helm status demo

kubectl get pods -n demo

sed -i 's/0.4.7/0.4.6/g' lets-chat/Chart.yaml

helm upgrade demo lets-chat --set replicas=2

helm history demo

helm rollback demo 1





maven the reference guide the complete reference

https://books.sonatype.com/mvnref-book/pdf/mvnref-pdf.pdf




https://www.baeldung.com/maven usual excellent Baeldung tutorial


https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html to understand those obfuscated concepts of "lifecycle", "phase", "goal"






Monday, March 25, 2019

Book: java by comparison by Simon Harrer, Jörg Lenhard, Linus Dietz

Interesting book, concise and a breeze to read

https://pragprog.com/book/javacomp/java-by-comparison



Source code is here https://pragprog.com/titles/javacomp/source_code

My first (not very functional) implementation of FizzBuzz:

import java.util.stream.IntStream;

public class ConsoleBasedFizzBuzz implements FizzBuzz {
    public static void main(String[] args) {
        FizzBuzz fizzBuzz = new ConsoleBasedFizzBuzz();
        fizzBuzz.print(1, 100);
    }

    private static void accept(int i) {
        StringBuffer result = new StringBuffer();
        if (i % 3 == 0) result.append("Fizz");
        if (i % 5 == 0) result.append("Buzz");
        if (result.length() == 0) result.append(i);
        System.out.println(result);
    }

    @Override
    public void print(int from, int to) {
        IntStream.range(from, to).forEach(ConsoleBasedFizzBuzz::accept);
    }
}



"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."


Avoid Unnecessary Comparisons
Avoid Negations
Return Boolean Expressions Directly
Simplify Boolean Expressions
Avoid NullPointerException in Conditionals
Avoid Switch Fallthrough
Always Use Braces
Ensure Code Symmetry
Replace Magic Numbers with Constants
Favor Enums Over Integer Constants
Favor For-Each Over For Loops
Avoid Collection Modification During Iteration
Avoid Compute-Intense Operations During Iteration
Group with New Lines
Favor Format Over Concatenation
Favor Java API Over DIY
Remove Superfluous Comments
Remove Commented-Out Code
Replace Comments with Constants
Replace Comments with Utility Methods
Document Implementation Decisions
Document Using Examples
Structure JavaDoc of Packages
Structure JavaDoc of Classes and Interfaces
Structure JavaDoc of Methods
Structure JavaDoc of Constructors
Use Java Naming Conventions
Follow Getter/Setter Conventions for Frameworks
Avoid Single-Letter Names
Avoid Abbreviations
Avoid Meaningless Terms
Use Domain Terminology
Fail Fast
Always Catch Most Specific Exception
Explain Cause in Message
Avoid Breaking the Cause Chain
Expose Cause in Variable
Always Check Type Before Cast
Always Close Resources
Always Close Multiple Resources
Explain Empty Catch
Structure Tests Into Given-When-Then
Use Meaningful Assertions
Expected Before Actual Value
Use Reasonable Tolerance Values
Let JUnit Handle Exceptions
Describe Your Tests @DisplayName @Disabled
Favor Standalone Tests
Parametrize Your Tests @ParameterizedTest @ValueSource
Cover the Edge Cases
Split Method with Optional Parameters
Favor Abstract Over Concrete Types
Favor Immutable Over Mutable State
Combine State and Behavior
Avoid Leaking References (defensive copying)
Avoid Returning Null
Favor Lambdas Over Anonymous Classes
Favor Method References Over Lambdas
Avoid Side Effects
Use Collect for Terminating Complex Streams
Avoid Exceptions in Streams
Favor Optional Over Null (Optional.ofNullable())
Avoid Optional Fields or Parameters
Use Optionals as Streams

Google Java Style Guide https://google.github.io/styleguide/javaguide.html

Automate Your Build
Favor Logging Over Console Output
Minimize and Isolate Multithreaded Code
Use High-Level Concurrency Abstractions
Speed Up Your Program


import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;

import java.io.IOException;

public class JunitAssertionsTest {

    @Test
    public void testException() {
        Executable when = () -> pippo();
        Assertions.assertThrows(IOException.class, when);
    }

    private void pippo() throws IOException {
        System.out.println("running");
        throw new IOException("ciao");
    }
}