wissel.net

Usability - Productivity - Business - The web - Singapore & Twins

By Date: April 2020

Watching the EventBus


I'm quite fond of Event-driven architecture, so to no surprise, I like vert.x's EventBus and its ability to enable polyglot programming. So it is time to have a closer look

Dem Volk aufs Maul geschaut

(That's a word play on Martin Luther loosly translated as "Watch them how they talk")

I wanted to know, what exactly is happening "on the wire", without disrupting the regular flow. Turns out, there is an easy way to do this. The vert.x EventBus provides the methods addOutboundInterceptor and addInboundInterceptor that provide you with access to a Handler with a DeliveryContext.

From there you can get to the Message or directly the message's body. So I took it for a spin in conjunction with a Websocket. This allows me to watch as the messages flow through:

final HttpServer server = this.vertx.createHttpServer();
server.websocketHandler(this::handlerWebsockets);


Read more

Posted by on 28 April 2020 | Comments (0) | categories: Java vert.x

SimpleXMLDoc revisited


It is 2020, JSON is supposed to have won, with a challenger in sight. XML with its fine distinction between Elements, Attributes and clear ownership demarked by name spaces, was supposed to be gone. But OData made it necessary to look again, as did CalDAV

Out into the OutputStream

The initial version was introduced in the context of XAgents which mandated an OutputStream. I find that adequate and useful, so I kept that. If you just want a String, a ByteArrayOutputStream will do quite nicely

Fluent methods

The big change to the revamped version is the addition of a fluent API. Each method call returns the object instance itself, so you can chain your document creation to look modern (and type less)

Namespace and attributes

Originally I though "simple" would be sufficient to create Elements only. But as time goes by one starts to appreciate name spaces and Attributes, so I added support for these too. To keep things simple: once we specify the namespace at the beginning of the document, we can simply refer to it by its alias name.

A sample:

    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    final SimpleXMLDoc doc = new SimpleXMLDoc(out);
    doc.addNamespace("X", "https://xmen.org")
    .addNamespace("", "https://whyOhWhy.com/xml")
    .setXmlStyleSheet("somestle.xslt")
    .openElement("Endpoints")
    .openElement(doc.element("X:Endpoint")
          .addAttribute("name", "A Name")
          .addAttribute("url", "http://anywhere/")
          .addAttribute("meta", "meta not metta"))
     .closeElement(1)
     .addSimpleElement("description", "Something useful")
     .closeDocument();
    System.out.println(out.toString());

Key methods

  • addNamespace: adds one name space and establishes the alias. To keep it simple, namespaces are defined only at the beginning fo the document
  • setXmlStyleSheet: Same here, needs to be defined at the beginning - after all this class streams the result and stylesheets only start at the beginning
  • OpenElement starts a new XML Element. When provided with a string, it is an attribute free element, that can include the namespace abbreviation. When using a doc.element, we can add attributes
  • addSimpleElement: add an element, its String content and close it
  • closeElement: write out a number of closing tags. It deliberately uses number of tags and not tag names, so you don't need to track the names you have opened. Ensures that XML stays valid
  • closeDocument: closes all remaining Elements in the correct sequence and closes the document. Can be called once only

Check the full source code for details

As usual YMMV


Posted by on 13 April 2020 | Comments (0) | categories: Java XML

vert.x and CORS


One of the security mechanism for AJAX calls is CORS (Cross-Origin Resource sharing), where a server advice a browser if it can request resources from it, coming from a different domain.

It is then up to the browser to heed that advice. To complicate matters: when the browser wants to POST data (or other similar operations), it will go through a preflight request adding to site latency.

I have to admit, I never fully understood the rationale, since only browsers adhere to CORS, any webserver, Postman or CURL ignore CORS happily.

None, One or All, but not Some

There's another trouble with CORS: The specification only allows for no-access, all-access (using * as value for Access-Control-Allow-Origin, with restrictions) or one specific domain, but not a list of domains.

Mozilla writes

Limiting the possible Access-Control-Allow-Origin values to a set of allowed origins requires code on the server side to check the value of the Origin request header, compare that to a list of allowed origins, and then if the Origin value is in the list, to set the Access-Control-Allow-Origin value to the same value as the Origin value.


Read more

Posted by on 07 April 2020 | Comments (3) | categories: Salesforce Singapore

My Maven starter template


Maven is to Java what npm is to JavaScript. It can be a harsh mistress or your best companion. It depends

Beyond dependencies and builds

Maven removes the need to download and manages your dependencies. Unfortunately it doesn't come with mvn install <packagename> like npm (or I haven't learned that yet), so keeping that pom.xml current is a little PITA. However once we make peace with it, the power of plugins makes development in auto-pilot a breeze. Some of the things you can do:

  • Generate a project site
  • Generate various reports: code quality, code coverage
  • Run unit tests

Check out the complete list to get an idea. I'm specifically fond of the site generation capability. It allows us to keep your documentation in the same repository as the project, so we have one place less to worry about.

We simply add /src/site/ to our project and content can be created in multiple formats. My favorite one is Markdown. Besides my handcrafted pages, I generate reports:

  • Issue management
  • Licenses
  • Plugins
  • Source code location
  • Team
  • JavaDoc
  • PMD and CPD
  • Surefire (Test results) and JaCoCo (Test coverage)

All this involved a bit of boilerplate in the pom.xml so I keep a template around

that I copy into any new pom.xml file. On special fancy I use: I extracted all version numbers from plugin and dependencies and keep them in an alphabetical sorted property section. This way I avoid to have multiple versions of related dependencies around. Enjoy!

<properties>
  <!-- Dependency Versions -->
  <darvino.version>2.5.0</darvino.version>
  <domino.jna.version>0.9.26</domino.jna.version>
  <domino.version>10.0.1</domino.version>
  <expiringmap.version>0.5.9</expiringmap.version>
  <flexmark.version>0.60.2</flexmark.version>
  <grpc.version>1.24.0</grpc.version>
  <gson.version>2.8.5</gson.version>
  <guava.version>28.2-jre</guava.version>
  <ibm.commons.version>9.0.0</ibm.commons.version>
  <icu4j.version>65.1</icu4j.version>
  <javasimon.version>4.2.0</javasimon.version>
  <java.version>1.8</java.version>
  <joda.version>2.10</joda.version>
  <junit.platform.version>1.5.2</junit.platform.version>
  <junit.jupiter.version>5.6.0</junit.jupiter.version>
  <log4j.version>2.12.1</log4j.version>
  <lorem.version>2.1</lorem.version>
  <micrometer.version>1.3.5</micrometer.version>
  <mustache.version>0.9.5</mustache.version>
  <mockito.version>3.3.3</mockito.version>
  <netty.ssl.version>2.0.30.Final</netty.ssl.version>
  <pmd.version>6.22.0</pmd.version>
  <saxon.version>10.0</saxon.version>
  <slf4j.version>1.7.28</slf4j.version>
  <yaml.version>1.25</yaml.version>
  <vertx.version>4.0.0-milestone4</vertx.version>

  <!-- Maven Versions -->
  <maven.version>[3.6,)</maven.version>

  <!-- Plugin Versions -->
  <eclipse.plugin.version>2.10</eclipse.plugin.version>
  <maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
  <maven.enforcer.plugin.version>3.0.0-M3</maven.enforcer.plugin.version>
  <maven.jacoco.plugin.version>0.8.5</maven.jacoco.plugin.version>
  <maven.jar.plugin.version>3.2.0</maven.jar.plugin.version>
  <maven.javadoc.plugin.version>3.1.1</maven.javadoc.plugin.version>
  <maven.jxr.plugin.version>3.0.0</maven.jxr.plugin.version>
  <maven.project.info.reports.plugin.version>3.0.0</maven.project.info.reports.plugin.version>
  <maven.resources.plugin.version>3.1.0</maven.resources.plugin.version>
  <maven.site.plugin.version>3.8.2</maven.site.plugin.version>
  <maven.source.plugin.version>3.2.0</maven.source.plugin.version>
  <maven.surefire.plugin.version>3.0.0-M4</maven.surefire.plugin.version>
  <os.maven.plugin.version>1.6.2</os.maven.plugin.version>
  <pegdown.doclet.version>1.3</pegdown.doclet.version>
  <pmd.plugin.version>3.12.0</pmd.plugin.version>
  <protobuf.maven.plugin.version>0.6.1</protobuf.maven.plugin.version>
  <shade.version>3.2.1</shade.version>
  <versions.maven.plugin.version>2.7</versions.maven.plugin.version>

  <!-- Miscellaneous settings -->
  <project.autorelease>true</project.autorelease>
  <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <finalName>${project.artifactId}-${project.version}</finalName>

 </properties>

 <prerequisites>
  <maven>${maven.version}</maven>
 </prerequisites>

 <organization>
  <name>HCL Labs</name>
  <url>[FIXME: URL HERE]</url>
 </organization>

 <ciManagement>
  <system>CircleCI</system>
  <url>[FIXME: Link to CI]</url>
 </ciManagement>
 <issueManagement>
  <system>JIRA</system>
  <url>[FIXME: URL to Issue tracker]</url>
 </issueManagement>
 <developers>
  </developer>
  <developer>
   <name>Stephan H. Wissel</name>
   <roles>
    <role>Architect</role>
    <role>Developer</role>
   </roles>
   <url>https://github.com/stwissel</url>
  </developer>
 </developers>
 <licenses>
  <license>
   <name>The Apache Software License, Version 2.0</name>
   <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
   <distribution>manual</distribution>
  </license>
 </licenses>
 <scm>
  <developerConnection>scm:git:[FIXME: GIT URL]</developerConnection>
 </scm>

 <build>

  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>${maven.enforcer.plugin.version}</version>
    <executions>
     <execution>
      <id>enforce-maven</id>
      <goals>
       <goal>enforce</goal>
      </goals>
      <configuration>
       <rules>
        <requireMavenVersion>
         <version>${maven.version}</version>
        </requireMavenVersion>
       </rules>
      </configuration>
     </execution>
    </executions>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven.compiler.plugin.version}</version>
    <configuration>
     <source>${java.version}</source>
     <target>${java.version}</target>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>${maven.source.plugin.version}</version>
    <executions>
     <execution>
      <id>attach-sources</id>
      <goals>
       <goal>jar</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-eclipse-plugin</artifactId>
    <version>${eclipse.plugin.version}</version>
    <configuration>
     <downloadSources>true</downloadSources>
     <downloadJavadocs>true</downloadJavadocs>
    </configuration>
   </plugin>

   <plugin>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>${maven.javadoc.plugin.version}</version>
    <configuration>
     <doclet>ch.raffael.doclets.pegdown.PegdownDoclet</doclet>
     <docletArtifact>
      <groupId>ch.raffael.pegdown-doclet</groupId>
      <artifactId>pegdown-doclet</artifactId>
      <version>1.3</version>
     </docletArtifact>
     <useStandardDocletOptions>false</useStandardDocletOptions>
     <failOnError>false</failOnError>
    </configuration>
    <executions>
     <execution>
      <id>attach-javadocs</id>
      <goals>
       <goal>jar</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

   <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>${maven.jacoco.plugin.version}</version>
    <configuration>
     <excludes>
      <exclude>[FIXME: Do we need to exclude files from tests?]</exclude>
     </excludes>
    </configuration>
    <executions>
     <execution>
      <goals>
       <goal>prepare-agent</goal>
      </goals>
     </execution>
     <execution>
      <id>report</id>
      <phase>prepare-package</phase>
      <goals>
       <goal>report</goal>
      </goals>
     </execution>
    </executions>
   </plugin>

   <plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${maven.surefire.plugin.version}</version>
    <configuration>
     <includes>
      <include>**/*Test.java</include>
      <include>**/*Tests.java</include>
      <include>**/*TestCase.java</include>
     </includes>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>versions-maven-plugin</artifactId>
    <version>${versions.maven.plugin.version}</version>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-project-info-reports-plugin</artifactId>
    <version>${maven.project.info.reports.plugin.version}</version>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-site-plugin</artifactId>
    <version>${maven.site.plugin.version}</version>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>${pmd.plugin.version}</version>
    <configuration>
     <linkXRef>true</linkXRef>
     <targetJdk>${java.version}</targetJdk>
    </configuration>
    <dependencies>
     <dependency>
      <groupId>net.sourceforge.pmd</groupId>
      <artifactId>pmd-core</artifactId>
      <version>${pmd.version}</version>
     </dependency>
     <dependency>
      <groupId>net.sourceforge.pmd</groupId>
      <artifactId>pmd-java</artifactId>
      <version>${pmd.version}</version>
     </dependency>
     <dependency>
      <groupId>net.sourceforge.pmd</groupId>
      <artifactId>pmd-javascript</artifactId>
      <version>${pmd.version}</version>
     </dependency>
    </dependencies>
   </plugin>

  </plugins>

 </build>

 <reporting>
  <plugins>

   <plugin>
    <!-- This allows to use markdown in JavaDoc -->
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>${maven.javadoc.plugin.version}</version>
    <configuration>
     <doclet>ch.raffael.doclets.pegdown.PegdownDoclet</doclet>
     <docletArtifact>
      <groupId>ch.raffael.pegdown-doclet</groupId>
      <artifactId>pegdown-doclet</artifactId>
      <version>${pegdown.doclet.version}</version>
     </docletArtifact>
     <useStandardDocletOptions>false</useStandardDocletOptions>
     <failOnError>false</failOnError>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>${pmd.plugin.version}</version>
    <configuration>
     <linkXRef>true</linkXRef>
     <targetJdk>${java.version}</targetJdk>
    </configuration>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-report-plugin</artifactId>
    <version>${maven.surefire.plugin.version}</version>
   </plugin>

   <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>${maven.jacoco.plugin.version}</version>
    <reportSets>
     <reportSet>
      <reports>
       <!-- select non-aggregate reports -->
       <report>report</report>
      </reports>
     </reportSet>
    </reportSets>
   </plugin>

   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jxr-plugin</artifactId>
    <version>${maven.jxr.plugin.version}</version>
   </plugin>

  </plugins>
 </reporting>

 <dependencies>

  <!-- Test dependencies -->

  <dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-core</artifactId>
   <version>${mockito.version}</version>
   <scope>test</scope>
  </dependency>

  <dependency>
   <groupId>org.junit.platform</groupId>
   <artifactId>junit-platform-runner</artifactId>
   <version>${junit.platform.version}</version>
   <scope>test</scope>
  </dependency>

 </dependencies>

Check for FIXME: entries to find the spots that need updating. Maven has a task to check from time to time which of the depdendencies have newer version. You can run mvn versions:display-dependency-updates to find out what can be updated
As usual YMMV!


Posted by on 06 April 2020 | Comments (0) | categories: Java Maven WebDevelopment XML