An Alternative for the Google App Postman….

Until today I worked with the Rest-API Testing Tool Postman from Google. But this tool was making me more and more suspicious in the last time. For example, you are recently asked to sign in with a Google account. So it was time to lookout for an alternative. And finally I found Insomnia. It is open source and hosted on Github.

https://insomnia.rest/

To install the tool on Linux/Debian run:

# Add to sources
echo "deb https://dl.bintray.com/getinsomnia/Insomnia /" \
| sudo tee -a /etc/apt/sources.list.d/insomnia.list

# Add public key used to verify code signature
wget --quiet -O - https://insomnia.rest/keys/debian-public.key.asc \
| sudo apt-key add -

# Refresh repository sources and install Insomnia
sudo apt-get update
sudo apt-get install insomnia

Maven on Debian failed with JDK 1.9 – ClassFormatError

Today I ran into a problem with Maven under Debian GNU/Linux 9 (stretch). My Debian has OpenJDK 8 as also OpenJDK 9 installed. OpenJDK 9 is my default java version. My Maven version is 3.3.9.

mvn -version
Apache Maven 3.3.9
Maven home: /usr/share/maven
Java version: 9-Debian, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-9-openjdk-amd64
Default locale: de_DE, platform encoding: UTF-8
OS name: "linux", version: "4.9.0-6-amd64", arch: "amd64", family: "unix"

The problem is, that building one of my projects results in the following ClassFormat Error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.17:test (default-test) on project imixs-workflow-core: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.17:test failed: There was an error in the forked process
[ERROR] java.lang.ClassFormatError: Absent Code attribute in method that is not native or abstract in class file javax/xml/bind/JAXBException
[ERROR] at java.base/java.lang.ClassLoader.defineClass1(Native Method)
[ERROR] at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
[ERROR] at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:801)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:699)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:622)
[ERROR] at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
[ERROR] at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
[ERROR] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
[ERROR] at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
[ERROR] at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3139)
[ERROR] at java.base/java.lang.Class.getMethodsRecursive(Class.java:3280)
[ERROR] at java.base/java.lang.Class.getMethod0(Class.java:3266)
[ERROR] at java.base/java.lang.Class.getMethod(Class.java:2063)
[ERROR] at org.apache.maven.surefire.util.ReflectionUtils.tryGetMethod(ReflectionUtils.java:57)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isSuiteOnly(JUnit3TestChecker.java:64)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.isValidJUnit3Test(JUnit3TestChecker.java:59)
[ERROR] at org.apache.maven.surefire.common.junit3.JUnit3TestChecker.accept(JUnit3TestChecker.java:54)
[ERROR] at org.apache.maven.surefire.common.junit4.JUnit4TestChecker.accept(JUnit4TestChecker.java:52)
[ERROR] at org.apache.maven.surefire.util.DefaultScanResult.applyFilter(DefaultScanResult.java:97)
[ERROR] at org.apache.maven.surefire.junit4.JUnit4Provider.scanClassPath(JUnit4Provider.java:206)
[ERROR] at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:103)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
[ERROR] at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
[ERROR] -> [Help 1]

The problem is a incompatibility of maven 3.3.9 with JDK 1.9. To solve this problem I switch to my OpenJDK 8 by setting the JAVA_HOME variable explicitly to JDK8 :

export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/

After this change maven install works fine again in my projects.

To make the JAVA_HOME setting permanent follow this stepts.

1. find your preferred java version

ls -la /usr/lib/jvm/

2. edit the file /etc/profile and add the following line with the path to the JDK 8 you find before:

export JAVA_HOME="path to jdk8 that you found"

3. verify you maven installation

mvn -version

You maven should now be set to JDK8.

I hope this post will become obsolete in near future.

Cassandra – How to Handle Large Media Files

Using Apache Cassandra as an highly available  Big Data Platform is in my eyes a good choice as Cassandra Cluster is easy to handle. We are using Apache Cassandra as an archive platform for our human centric worklfow engine Imixs-Workflow. But how does Cassandra perform with large files?

If you start with Cassandra you have to change the way how you use databases, especially when you come from the SQL direction.  Although Cassandra can handle very large amounts of data easily, you have to consider the concept of the partition size. This means in short that the data within a partition (defined by the Partitionkey) should not exceed 100 MB. If you plan to store large files (e.g media files) you need to split up your data into smaller chunks. In the following I will explain in short how this can be done. Continue reading “Cassandra – How to Handle Large Media Files”

MVC 1.0 – Binding Input Values

MVC 1.0 is the new action based web framework for Jakarta EE. One advantage of the new technology is that you can work with plain html. With the expression language (EL) provided by JSP and Facelets you can easily bind values form a CDI controler to an input field:

<dl>
  <dt>Name:</dt>
  <dd>
    <input type="text" value="#{dataController.name}" name="name" />
   </dd>
</dl>

This works also for Textareas:

<dl>
  <dt>Description:</dt>
  <dd>
    <textarea name="descripton">#{dataController.description}</textarea>
  </dd>
</dl>

A little bit more tricky in this szeanrio is the handling of select options (Combobox). As the selected Item is defined by an attribute within the option tag a combination with EL is clumsy. But with the help of jQuery this can also be archived easily. See my following example:

<dl>
  <dt>Sort Order:</dt>
  <dd>
      <select name="sortOrder" id="sortOrder">
        <option value="DESC">Descanding</option>
        <option value="ASC">Ascanding</option>
      </select>
  </dd>
</dl>

<script type="text/javascript">
$(document).ready(function() {
  // update the select option....
  $("#sortOrder").val("#{dataController.sortOrder}");
});
</script>

See also the tutorial “MVC 1.0 in Java EE 8 – Handling Form Submits” to learn how you can submit you form inputs with MVC 1.0.

javax.ws.rs.client.Client and Form Based Authentication

Today I implemented a javax.ws.rs.client.ClientRequestFilter for a form based authentication. The FormAuthenticator class can be used in combination with a javax.ws.rs.client.Client  to interact, for example, with a rest api secured by a login form. Such a login form in Java EE typically uses the request URI ‘/j_security_check‘ with the form input fields ‘j_username’ and ‘j_password‘. As a result of a successful login the browser stores a cookie named “JSESSIONID” which need to be send with every request.

The request filter can be added to a javax.ws.rs.Client like this:

....
// create a javax.ws.rs.client
client = ClientBuilder.newClient();
// create new formAuthenticator
FormAuthenticator formAuthFilter = new FormAuthenticator(rest_api_url, 
     userid, password);
// register the filter...
client.register(formAuthFilter);
// now you can GET, POST, ....
....

You cam find the source code of this filter class on GitHub.

If you have any ideas for improvements your comments are welcome!

Do We Need an Open Protocol for Facebook?

These days we have again the discussion, about what is going on with Facebook. Mark Zuckerberg must explain his business model before a public committee.  Many people are puzzled and wondering what exactly is being done with their personal data. Again and again it is argued that one could not really leave Facebook as long there is no alternative platform. Mark Zuckerberg himself explains to the US Congress that he only want to bring people together. He want to open a way to allow people sharing there thoughts and ideas. OK, this is an honorable goal. But what in basic did we need to achieve such a goal? Continue reading “Do We Need an Open Protocol for Facebook?”

How to use Traefik.io as Static Proxy

Traefik.io is a very cool open source project, providing a powerful reverse proxy. The project is focusing mainly on container based architectures like Docker Swarm. In such an environment Traefik.io is able to recognize new containers in a network and dynamically computes the route from the frontend to the corresponding backend service. I wrote about this functionality in combination with docker swarm already in my blog: Lightweight Docker Swarm Environment. This concept is also part of the Imixs-Workflow project.

But what if you just want to add a kind of static route, which has nothing to do with container based services. I had this situation as I wanted to redirect incoming requests for a specific host name to an external server – outside of my docker swarm.

To realize this, you can add a front-end rule under the section [file] at the end of your traefik.toml file. This is an example how such a rule can looks like:

...
[file]

[backends]
 [backends.backend1]

 [backends.backend1.servers]
   [backends.backend1.servers.server0]
   url = "http://some.host.de:12345"
   # note that you cannot add path in 'url' field
 
[frontends]
  [frontends.frontend1]
  entryPoints = ["http"]
  backend = "backend1"
  passHostHeader = true
  [frontends.frontend1.routes]
    [frontends.frontend1.routes.route0]
    rule = "Host:www.myweb.com"

This rule proxies requests for “www.myweb.com” to the host “some.host.de:12345”. See also the discussion here.

Imixs-Workflow 4.2.6 released

Today I released version 4.2.6 of Imixs-Workflow. The new release is prepared for the Imixs-Archive feature which is the next big thing in Imixs-Workflow. The new version also includes some improvements of the Rest API and several bug fixes. The release notes can be seen on GitHub.