Red Hat

WildFly 20 S2I images have been released on quay.io

WildFly 20 S2I Docker images

The WildFly S2I (Source-to-Image) builder and runtime Docker images for WildFly 20 have been released on quay.io/wildfly.

Changes since the last release:

  • Upgraded Keycloak client adapters to version 10.0.2.

  • Reduced the size of the image generated during s2i chained build template (image named <app>-build-artifacts).

For a complete documentation on how to use these images using S2I, OpenShift and Docker, refer to the WildFly S2I README.

Adding the imagestreams and template to OpenShift

At some point the new images will be made available from the OpenShift catalog and image repository. But you can already use these images by adding them yourselves to your OpenShift cluster.

  • WildFly S2I builder image stream:

oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/imagestreams/wildfly-centos7.json
  • WildFly runtime image stream:

oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/imagestreams/wildfly-runtime-centos7.json
  • Chained build template:

oc create -n myproject -f https://raw.githubusercontent.com/wildfly/wildfly-s2i/wf-20.0/templates/wildfly-s2i-chained-build-template.yml

NB: If you import the image streams into your project, be sure to set the ImageStreams Namespace (IMAGE_STREAM_NAMESPACE argument) to your project namespace in the template. openshift being the default namespace.

Eclipse Microprofile OpenAPI example

Since version 19, WildFly implements a support for the Microprofile OpenAPI specification.

We are here deploying the WildFly microprofile-openapi quickstart inside OpenShift.

In order to tailor WildFly to our use-case (jaxrs service) we are using WildFly Galleon Layers during s2i build to construct a WildFly server composed of jaxrs and Microprofile OpenAPI (plus their required dependencies).

Build and run the application

The quickstart is a jaxrs service that exposes a set of operations to manage a store inventory. We are retrieving the service interface (HTTP operations, URL paths and data types) through the openapi endpoint that WildFly exposes in the root context (eg: http://127.0.0.1:8080/openapi).

  • Build the application image:

oc new-app wildfly-s2i-chained-build-template -p APPLICATION_NAME=openapi-app \
      -p GIT_REPO=https://github.com/wildfly/quickstart \
      -p GIT_CONTEXT_DIR=microprofile-openapi \
      -p GIT_BRANCH=20.0.0.Final \
      -p GALLEON_PROVISION_LAYERS=jaxrs,microprofile-openapi \
      -p IMAGE_STREAM_NAMESPACE=myproject \
      --build-env=MAVEN_ARGS_APPEND="-Dcom.redhat.xpaas.repo.jbossorg"
  • Create an application from the application image:

oc new-app myproject/openapi-app
  • Expose the service:

oc expose svc/openapi-app
  • The OpenAPI service definition is exposed at the following well known location: <application route>/openapi

  • From the service definition we can retrieve the HTTP operations and URL paths that the service supports. For example, the HTTP GET sent to <application route>/fruit returns a JSON array containing the fruits present in the inventory.

Enjoy the Apples and Pineapples!

WildFly 20 is released!

I’m pleased to announce that the WildFly 20 Final zip is now available for download.

After the big push on Eclipse MicroProfile 3.3 for WildFly 19, the focus for WildFly 20 was more on bug fixing and component updates. Between WildFly Core and full WildFly we resolved well over 100 bugs and did over 90 component upgrades, most of which also brought bug fixes. These are challenging times for all of us, with a lot of disruption in our lives, and I’m very proud of how much the many people contributing to WildFly have gotten done over these last couple of months.

But, of course, it wasn’t all bug fixing! So, what else is new?

Enhancements

Security

As always, the folks working on security have been busy:

EJB

  • The standard way to configure stateful bean session timeout for each ejb is via a @StatefulTimeout annotation, or a stateful-timeout setting in ejb-jar.xml. But if these are not provided WildFly now provides the ability to configure a default global stateful bean session timeout for all deployed stateful beans. This feature is useful for deploying and configuring multiple stateful beans consistently in a server instance or a cluster.

  • In a clustered environment where EJB timers are persisting to a shared database, applications may not want to rely solely on a periodic refresh of their timers before performing certain tasks. With WildFly 20 it is now possible to programmatically refresh EJB timers that use a database-data-store for persistence.

  • A large amount of information about the EJBs in a deployment is now available via the server management API.

MicroProfile Integration

  • RESTEasy (integrated in WildFly via the jaxrs subsystem) can now be configured using MicroProfile Config. In addition, the jaxrs subsystem now exposes servlet init parameters, filter init parameters and servlet context parameters to applications as MicroProfile Config config sources.

  • An example CLI script has been added to the server’s docs/examples directory to help users migrate a standalone configuration to one more like the standalone-microprofile.xml configuration WildFly provides.

Standards Support

WildFly 20.0.0 is a Jakarta EE 8 compatible implementation, with both the Full Platform and the Web Profile. Evidence supporting our certification is available for the Full Platform and for the Web Profile.

WildFly 20 is also a compatible implementation of Java EE 8.

WildFly 20 is also a compliant implementation of the Eclipse MicroProfile 3.3 platform specification.

JDK Support

For the last couple of years we’ve worked to ensure our releases run well for most developer use cases on the most recent GA JDK version available on the WildFly final release date. Unfortunately, that came to an end with WildFly 19 and JDK 14. We haven’t had time to digest some of the package removals in JDK 14, particularly in the security area.

However, I do believe WildFly runs well on JDK 13. By run well, I mean the main WildFly testsuite runs with no more than a few failures in areas not expected to be commonly used. We want developers who are trying to evaluate what the latest JVM means for their applications to be able to look to WildFly as a useful development platform. We do see a couple of test failures with JDK 13 when using the deprecated Picketlink subsystem and WS Trust

While we do want to run well on the most recent JDK, our recommendation is that you run WildFly on the most recent long-term support release, i.e. on JDK 11 for WildFly 20. We do considerably more testing of WildFly itself on the LTS JDKs, and we make no attempt to ensure the projects producing the various libraries we integrate are testing their libraries on anything other than JDK 8 or 11.

WildFly 20 also is heavily tested and runs well on Java 8. We plan to continue to support Java 8 at least through WildFly 22, and probably beyond.

Please note that WildFly runs on Java 11 and later in classpath mode.

At this point it is uncertain when we’ll be able to say that a release of WildFly runs well on JDK 14 or later. We’ll have to see how well the work for that, both in WildFly itself and in the projects we integrate, aligns with our other goals. I don’t expect it to be a priority before WildFly 22.

Documentation

The WildFly 20 documentation is available at the docs.wildfly.org site.

Just a reminder, starting with WildFly 19 we shifted the location of the auto-generated documentation of the appserver management API from the wildscribe.github.io site to a make it part of the general documentation for a release. The WildFly 20 management API documentation is in the wildscribe section of the WildFly 20 docs.

Jira Release Notes

The full list of issues resolved is available here. Issues resolved in the WildFly Core 12 releases included with WildFly 20 are available here.

Enjoy!

I hope this post finds you and your loved ones all safe and well. Please give WildFly 20 a spin and give us your feedback!

Pluging Apache Qpid into WildFly

Using JBoss Generic JMS Resource Adapter you can use a JMS compatible client to connect WildFly to any broker. This article will describe how to do this with Apache Qpid and thus use JMS over AMQP.

Installing Apache Qpid

You need to download and untar Apache Qpid Broker-J 8.0.0 from https://qpid.apache.org/download.html. You need to allow for anonymous access. Please use the initial-config.json configuration file. Note that we will start Apache Qpid HTTP server on 9080 to avoid port conflict with WildFly.

cd $INSTALL_DIR
tar xvzf qpid-broker-8.0.0-bin.tgz
export QPID_WORK=$INSTALL_DIR/qpid-broker/8.0.0/work
cd pid-broker/8.0.0/bin
./qpid-server -icp initial-config.json -prop "qpid.http_port=9080"

Now you can connect to the Qpid web interface using guest/guest. You can see that we have created 2 queues: outQueue and testQueue.

Configuring WildFly

We are going to use the JBoss Generic JMS Resource Adapter. For this we need to deploy a module for the JMS provider to connect to Apache Qpid. Download the archive qpid-provider.tar.gz which provides the module to connect to Apache Qpid. Then we start WildFly with the full profile.

cd $WILDFLY_HOME
tar xvzf qpid-provider.tar.gz
cd $WILDFLY_HOME/bin
./standalone.sh -c standalone-full.xml

To configure WildFly you need to execute the following operations using the jboss-cli. You can use the following script qpid.cli.

First we will enable the use of property replacement in our deployment for easier configurability:

/subsystem=ee:write-attribute(name=spec-descriptor-property-replacement, value=true)
/subsystem=ee:write-attribute(name=annotation-property-replacement, value=true)
/subsystem=ee:write-attribute(name=jboss-descriptor-property-replacement, value=true)

Then we need to configure the JNDI provider for Apache Qpid:

/subsystem=naming/binding=java\:global\/qpid:add(binding-type=external-context, class=javax.naming.InitialContext, module=org.jboss.genericjms.provider, environment={java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory, queue.testQueue=testQueue, queue.outQueue=outQueue, connectionfactory.QpidBroker="amqp://localhost:5672?jms.username=guest&amp;jms.password=guest"})
/subsystem=naming/binding=java\:\/jms\/qpid\/queue\/testQueue:add(binding-type=lookup, value=java\:global\/qpid\/testQueue)
/subsystem=naming/binding=java\:\/jms\/qpid\/queue\/outQueue:add(binding-type=lookup, lookup=java\:global\/qpid\/outQueue)

Last we need to configure the resource adapter to connect to our Apache Qpid broker:

/subsystem=resource-adapters/resource-adapter=apache-qpid:add(module=org.jboss.genericjms, transaction-support=NoTransaction)
/subsystem=resource-adapters/resource-adapter=apache-qpid/connection-definitions=QPIDCF:add(jndi-name=java\:\/jms\/qpid\/cf\/QpidBroker, class-name=org.jboss.resource.adapter.jms.JmsManagedConnectionFactory)
/subsystem=resource-adapters/resource-adapter=apache-qpid/connection-definitions=QPIDCF/config-properties=JndiParameters:add(value="java.naming.factory.initial=org.apache.qpid.jms.jndi.JmsInitialContextFactory;connectionfactory.QpidBroker=amqp://localhost:5672?jms.username=guest&jms.password=guest")

Running the example

You can download the example code from this GitHub repository.

The example consists of two parts : a client that will send a message to the testQueue to be processed by the Message Driven Bean which will send a message on the outQueue to be consumed by the client.

This is the client code that sends a message:

try (Connection connection = factory.createConnection("guest", "guest")) {
    connection.start();
    Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    MessageProducer messageProducer = session.createProducer(queue);

    TextMessage message = session.createTextMessage("Hello world!");
    messageProducer.send(message, DeliveryMode.NON_PERSISTENT, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
}

The MDB code is in RemoteQueueMDB.java and will send back a message to be consumed by the client.

@Override
public void onMessage(Message message) {
    try (QueueConnection queueConnection = qcf.createQueueConnection("guest", "guest");
    QueueSession queueSession = queueConnection.createQueueSession(true, Session.SESSION_TRANSACTED);
    QueueSender queueSender = queueSession.createSender(outQueue)) {
    if (message instanceof TextMessage) {
        txtMsg = (TextMessage) message;
        msgCnt++;
        queueSender.send(message);
        queueSession.commit();
    } else {
        LOG.warnf("MDB[%d] Message of wrong type: %s", mdbID, message.getClass().getName());
    }
}

Build using Apache Maven, then deploy the MDB by copying remote-mdb-ejb-1.0.0.jar into the deployments folder and run the client:

cd client
mvn "-Dexec.args=-classpath %classpath org.wildfly.jms.demo.qpid.client.HelloWorld" -Dexec.executable=/usr/lib/jvm/java-11/bin/java -Dexec.classpathScope=runtime org.codehaus.mojo:exec-maven-plugin:1.5.0:exec

You should see the following message in the traces showing that all went nicely and that the client has received the message :

Message received 419a7c4d-afe0-4dc2-9cf0-f17f531eb1ba:1:1:1-1 with text Hello world!

back to top