OpenLiberty: Error on Injection, works on TomEE and Wildfly

SOLUTION:

I found the reason of the error, and it is NOT the problem with OpenLiberty. I did not specify any beans.xml, and with that, the bean-discovery-mode defaults to annotated.

Please refer to the following link:

By default, if you specify nothing and there is no beans.xml, the bean discovery mode of ‘annotated’ and not ‘all’ is assumed. (Oracle 2013)


While I was working on this blog, I encountered this error:

[INFO    ] DSRA8203I: Database product name : MySQL
[INFO    ] DSRA8204I: Database product version : 8.0.11
[INFO    ] DSRA8205I: JDBC driver name  : MySQL Connector/J
[INFO    ] DSRA8206I: JDBC driver version  : mysql-connector-java-8.0.11 (Revision: 6d4eaa273bc181b4cf1c8ad0821a2227f116fedf)
[INFO    ] CWWJP9990I: test/wsjpa:wsjar:file:/home/dwuysan/dev/appservers/wlp/usr/servers/test/apps/expanded/test.war/WEB-INF/lib/d9f2b261-b3c6-4001-8a61-0aaebe46aa99.jar!/_testPU login successful
[INFO    ] WELD-000900: 2.4.5 (Final)
[INFO    ] FFDC1015I: An FFDC Incident has been created: "org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)
 com.ibm.ws.container.service.state.internal.ApplicationStateManager 31" at ffdc_18.06.21_14.11.27.0.log
[INFO    ] FFDC1015I: An FFDC Incident has been created: "com.ibm.ws.container.service.state.StateChangeException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)
 com.ibm.ws.app.manager.module.internal.DeployedAppInfoBase 384" at ffdc_18.06.21_14.11.27.1.log
[INFO    ] CWWJP9990I: test/wsjpa:wsjar:file:/home/dwuysan/dev/appservers/wlp/usr/servers/test/apps/expanded/test.war/WEB-INF/lib/d9f2b261-b3c6-4001-8a61-0aaebe46aa99.jar!/_testPU logout successful
[ERROR   ] CWWKZ0002E: An exception occurred while starting the application test. The exception message was: com.ibm.ws.container.service.state.StateChangeException: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private id.co.lucyana.test.services.LogService.em
  at id.co.lucyana.test.services.LogService.em(LogService.java:0)

The two classes we need to focus on are:

package id.co.lucyana.test.util;

import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public class EntityManagerProducer {
    
    @PersistenceContext(unitName = "testPU")
    @Produces
    private EntityManager em;
}

AND

package id.co.lucyana.test.services;

import id.co.lucyana.test.entity.Log;
import java.util.Collection;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;

@Stateless
@LocalBean
public class LogService {

    @Inject
    private EntityManager em;
       
    public Collection<Log> getLogs() {
        return this.em.createNamedQuery(Log.FIND_ALL, Log.class).getResultList();
    }
}

The thing is, this approach is working on both TomEE and Wildfly.

Any thought?

P.S. I was following someone’s recommendation on the net, of using this approach previously, with the argument that if one should ever change the name of ‘unitName’, it can be done on one single spot. I couldn’t find the reference anymore. I am not sure if this is still a ‘good’ approach. I welcome any comment.

References

Oracle, 2013, ‘Default CDI Enablement in Java EE 7’, Oracle, accessed on 24 June 2018

Advertisements

Testing OpenLiberty with Arquillian (Remote)

Having heard many great reviews, I thought I’ll give Open Liberty a try.

In this post, I shall discuss the following:

  • Setup of Open Liberty
  • Setup JDBC connection
  • Setup Arquillian
  • Testing REST endpoint

Installing Open Liberty

At the time of writing, I am using Open Liberty 18.0.0.1, and I am using Java SE 1.8.0_172 (P.S. Keen to move on to Java 9 and Java 10, but I thought better wait for LTS Java 11).

Installation is very easy. Let’s assume we are going to create a running server name test.

First, unpack your Open Liberty download. It will create a directory structure wlp.

Navigate to bin directory and run the following command:

./server create test

Now a server name test has been created. To start:

./server start test

with the argument test being the name of the server.

Navigate to http://localhost:9080/test to see the context root.

To stop,

./server stop test

– Configure server.xml

Once you have start test server, a directory will be created under the /usr/servers/test, and inside that directory there is file named server.xml. Let’s check it out.

<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>jsp-2.3</feature>
    </featureManager>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint id="defaultHttpEndpoint"
                  httpPort="9080"
                  httpsPort="9443" />

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>
</server>

In this article we are using Java EE 7 Web Profile, to enable that, it is very simple to do that (and it is not even necessary to restart the server). Simply change the featureManager.

<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>webProfile-7.0</feature>
    </featureManager>

    <!-- the rest of the configuration omitted -->

You can check what features being loaded dynamically by looking at console.log.

Configuring JDBC Datasource

– Configure Datasource in server.xml

For this exercise, I am using MySQL 8.0. Setting up MySQL and its configuration is out-of-scope of this article.

Let’s assume we have created a new database, also named test.

To set up your datasource, make the following modification to your server.xml and restart (or not, not too sure on this one, but no harm in restarting).

Comments interleaved.

<?xml version="3.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>webProfile-7.0</feature>
    </featureManager>

    <!-- Declare the jar files for MySQL access through JDBC. -->
    <dataSource id="testDS" jndiName="jdbc/testDS">
        <jdbcDriver libraryRef="MySQLLib"/>
        <properties databaseName="test"
                  serverName="localhost" portNumber="3306"
                  user="root" password="P4sswordGoesH3r3"/>
    </dataSource>
    <library id="MySQLLib">
        <file name="/home/dwuysan/dev/appservers/wlp/usr/shared/resources/mysql/mysql-connector-java-8.0.11.jar"/>
    </library>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>
</server>

– persistence.xml

OpenLiberty comes with EclipseLink bundled as JPA Provider. In this example I have not configured any EclipseLink’s properties.

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="testPU">
        <jta-data-source>jdbc/testDS</jta-data-source>        
        <properties>
        </properties>
    </persistence-unit>
</persistence>

And you can then call it in your Java EE application via:

@Stateless
@LocalBean
public class LogService {

    @PersistenceContext
    private EntityManager em;

    public Collection<Log> getLogs() {
        return this.em.createNamedQuery(Log.FIND_ALL, Log.class).getResultList();
    }
}

Setting up arquillian

In this article, we are going to implement Arquillian remote testing against a running OpenLiberty server.

Firstly, add arquillian to your pom.xml.

– Configure pom.xml

This is the pom.xml that have been modified:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>id.co.lucyana</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>test</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jboss.arquillian</groupId>
                <artifactId>arquillian-bom</artifactId>
                <version>1.4.0.Final</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>        
        <dependency>
            <groupId>org.jboss.arquillian.graphene</groupId>
            <artifactId>graphene-webdriver</artifactId>
            <version>2.3.2</version>
            <type>pom</type>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <scope>test</scope>
            <version>3.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.arquillian.junit</groupId>
            <artifactId>arquillian-junit-container</artifactId>
            <scope>test</scope>
        </dependency>        
        <dependency>
            <!-- Arquillian WebSphere Liberty Profile support -->
            <groupId>io.openliberty.arquillian</groupId>
            <artifactId>arquillian-liberty-remote</artifactId>
            <version>1.0.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArguments>
                        <endorseddirs>${endorsed.dir}</endorseddirs>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.1</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <phase>validate</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${endorsed.dir}</outputDirectory>
                            <silent>true</silent>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>javax</groupId>
                                    <artifactId>javaee-endorsed-api</artifactId>
                                    <version>7.0</version>
                                    <type>jar</type>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

– Make modification to server.xml

The documentation provided here is quite self-explanatory. Please consult this documentation for more up-to-date information on how to enable remote-testing.

<?xml version="1.0" encoding="UTF-8"?>
<server description="new server">

    <!-- Enable features -->
    <featureManager>
        <feature>webProfile-7.0</feature>
        <feature>restConnector-2.0</feature>
    </featureManager>
    
    <!-- Declare the jar files for MySQL access through JDBC. -->
    <dataSource id="testDS" jndiName="jdbc/testDS">
        <jdbcDriver libraryRef="MySQLLib"/>
        <properties databaseName="test" 
                  serverName="localhost" portNumber="3306" 
                  user="root" password="P4sswordGoesH3r3"/>
    </dataSource>
    <library id="MySQLLib">
        <file name="/home/dwuysan/dev/appservers/wlp/usr/shared/resources/mysql/mysql-connector-java-8.0.11.jar"/>
    </library>

    <httpEndpoint httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint" host="*" />

    <!-- userName and password should also be set in arquillian.xml to these values -->
    <quickStartSecurity userName="admin" userPassword="admin" />

    <!-- Enable the keystore -->
    <keyStore id="defaultKeyStore" password="password" />

    <applicationMonitor updateTrigger="mbean" />
    <logging consoleLogLevel="INFO" />

    <!-- This section is needed to allow upload of files to the dropins directory, the remote container adapter relies on this configuration -->
    <remoteFileAccess>
        <writeDir>${server.config.dir}/dropins</writeDir>
    </remoteFileAccess>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>
</server>

– Trust the server (i.e. certificate)

You need to have those keys trusted by your client as well, otherwise you’ll see SSL certificate trust errors, and you need to give permissions for the container adapter to write to the dropins directory” (Liberty-Arquillian 2018)

Once you have made all the necessary modification above, (and re-start the server), notice that there is a new directory created under <location of your OpenLiberty server>/usr/servers/test/resources/security with test being the name of the server we have initially created.

Notice there are two files being created, keys.jks and ltpa.keys. Now, we are interested in the keys.jks.

So that we can run our test from Netbeans (Maven), the JDK must trust the running OpenLiberty.

Check the certificate

keytool -list -v -keystore key.jks
Enter keystore password: 

The password here is basically what we created in our server.xml, particularly this line:

<!-- Enable the keystore -->
<keyStore id="defaultKeyStore" password="password" />

so, enter the password, and the output should be as follows:

*****************  WARNING WARNING WARNING  *****************
* The integrity of the information stored in your keystore  *
* has NOT been verified!  In order to verify its integrity, *
* you must provide your keystore password.                  *
*****************  WARNING WARNING WARNING  *****************

Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: default
Creation date: May 26, 2018
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=localhost, OU=test, O=ibm, C=us
Issuer: CN=localhost, OU=test, O=ibm, C=us
Serial number: 2a6c5b27
Valid from: Sat May 26 12:24:30 WITA 2018 until: Sun May 26 12:24:30 WITA 2019
Certificate fingerprints:
	 MD5:  63:92:B2:4A:25:E3:BB:3B:96:37:11:C1:A7:25:38:B5
	 SHA1: B6:38:95:88:FC:50:EC:A0:8E:41:4E:DE:B5:D4:8B:85:2E:61:A2:5F
	 SHA256: 9C:7B:6A:FA:46:8C:50:F2:7D:7B:C4:24:4B:15:78:5A:34:25:C8:43:D1:AB:4D:EE:C7:00:4C:AF:30:F5:5C:92
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 88 F2 C2 32 73 73 B6 66   8F FA 42 85 1F 43 A5 AF  ...2ss.f..B..C..
0010: 84 33 62 D5                                        .3b.
]
]



*******************************************
*******************************************

Next, export the certificate

We now need to create a .cer. Use the following command:

keytool -export -alias default -file testwlp.crt -keystore key.jks
Enter keystore password:

Basically we are exporting the certificate of alias into a file named testwlp.crt. Now, a file named testwlp.crt should be created.

Lastly, let’s trust that certificate by importing that certificate into the JDK cacert

keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias testwlp -import -file testwlp.crt

P.S. Please note that, as pointed out by many experts (via Twitter), apparently there are many ways to ‘trust’ the server. I am sure there are better ways, and as much as possible I’d prefer not to touch any of the JDK’s files.

– Create arquillian.xml

Now all those plumbing works done, let’s add arquillian.xml accordingly.

<?xml version="1.0" encoding="UTF-8"?>
<arquillian xmlns="http://jboss.org/schema/arquillian" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://jboss.org/schema/arquillian http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
    <engine>
        <property name="deploymentExportPath">target</property>
    </engine>
    <container qualifier="liberty-remote" default="true">
        <configuration>
            <property name="hostName">localhost</property>
            <property name="serverName">test</property>

            <!-- check the 'quickStartSecurity' on 'server.xml' -->
            <property name="username">admin</property>
            <property name="password">admin</property>

            <!-- check the 'server.xml' -->
            <property name="httpPort">9080</property>
            <property name="httpsPort">9443</property> 
        </configuration>
    </container>    
    <extension qualifier="webdriver">
        <!--<property name="browser">firefox</property>-->
        <property name="remoteReusable">false</property>
    </extension>
</arquillian>

Write a REST Test case

With all those setups done, you can now write an Arquillian Test case. Below is an example of a test case against a JAX-RS end point (Please excuse the simplicity of the test case, the point is to show how we can test using Arquillian-remote against OpenLiberty):

package id.co.lucyana.test.resource;

import id.co.lucyana.test.entity.Log;
import id.co.lucyana.test.services.LogService;
import id.co.lucyana.test.util.ApplicationConfig;
import java.net.URL;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.ArchivePaths;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.openqa.selenium.WebDriver;

@RunWith(Arquillian.class)
public class LogResourceTest {
    
    @Drone
    private WebDriver webDriver;

    @Deployment
    public static JavaArchive createTestArchive() {
        return ShrinkWrap.create(JavaArchive.class)
                .addClass(Log.class)
                .addClass(LogResource.class)
                .addClass(LogService.class)
                .addClass(ApplicationConfig.class)
                .addAsManifestResource("test-persistence.xml",
                        ArchivePaths.create("persistence.xml"));
    }

    @Test
    @RunAsClient
    public void testLogResource(@ArquillianResource URL url) {        
        this.webDriver.get(url.toString() + "resources/log");
        String pageSource = this.webDriver.getPageSource();
        System.out.println("RESULT: " + pageSource);
        Assert.assertTrue(true);
    }
}

References

DigiCert, 2018, ‘How to install the trusted root into Java cacerts Keystore’, DigiCert, accessed on 20 June 2018

Liberty-Arquillian, 2018, ‘Arquillian Liberty Remote Documentation’, GitHub. Inc, accessed on 20 June 2018

SSLShopper, 2008, ‘The Most Common Java Keytool Keystore Commands’, SSLShopper, accessed on 20 June 2018