User Tools

Site Tools


wildfly

WildFly

Installation

Download from http://www.wildfly.org

Untar to /opt and create a symlink to /opt/wildfly.

# separate user for running WildFly
sudo adduser --system wildfly
sudo addgroup --system wildfly
sudo usermod -g wildfly wildfly # set primary group of user wildfly to group wildfly
 
# set owner of symlink & all WildFly files to wildfly
sudo chown --no-dereference wildfly:wildfly /opt/wildfly
sudo chown -HR wildfly:wildfly /opt/wildfly

Create a management user

sudo -u wildfly /opt/wildfly/bin/add-user.sh 

Start WildFly (optionally with command line parameters)

sudo -u wildfly /opt/wildfly/bin/standalone.sh

Visit the managment console: https://localhost:9990

Configuration

standalone.conf

/opt/wildfly/bin/standalone.conf:

Configure JVM arguments (e.g. -Xss, -Xmx) for standalone/server deployment. Note that when starting WildFly from Eclipse you need to configure these parameters in Eclipse!

It's also a good idea to explicitly set UTF-8 as default:

JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8"
JAVA_OPTS="$JAVA_OPTS -Dsun.jnu.encoding=UTF-8"

systemd service

Create the file /etc/systemd/system/wildfly.service and adapt the IP to the IP the service is publicly accessible with:

[Unit]
Description=WildFly
After=network.target

[Service]
Type=simple
User=wildfly
Group=wildfly
ExecStart=/opt/wildfly/bin/standalone.sh -b 127.0.0.1 -bmanagement 127.0.0.1

[Install]
WantedBy=multi-user.target

With WantedBy=multi-user.target we specify that we want to start WildFly after boot. For autostart to work we also have to enable the service:

sudo systemctl enable wildfly

Manually use / manage the service with:

sudo systemctl start wildfly
sudo systemctl stop wildfly
systemctl status wildfly
journalctl -f -u wildfly      # view log and follow it live

Timeouts

In case your deployments have a long setup time you must extend the default limit of 300 seconds.

Add these system properties to your /opt/wildfly/standalone/configuration/standalone.xml. The system-properties are a child element of server and must come after the extensions section. The timeout value is in seconds:

<server..>
    <extensions>
        ...
    </extensions>
    <system-properties>
        <property name="jboss.as.management.blocking.timeout" value="900"/>
    </system-properties>
    ...

Also add the timeout to the deployment-scanner:

<profile>
    <subsystem xmlns="urn:jboss:domain:deployment-scanner:2.0">
        <deployment-scanner path="deployments" relative-to="jboss.server.base.dir" 
          scan-interval="5000" deployment-timeout="900" 
          runtime-failure-causes-rollback=
            "${jboss.deployment.scanner.rollback.on.failure:false}"/>
    </subsystem>
    ...
</profile>

And to allow long transactions (if your logs contain tasks cancelled by the TransactionReaper) configure the default-timeout of the transaction subsystem:

<profile>
    <subsystem xmlns="urn:jboss:domain:transactions:5.0">
        <core-environment node-identifier="${jboss.tx.node.id:1}">
            <process-id>
                <uuid/>
            </process-id>
        </core-environment>
        <recovery-environment socket-binding="txn-recovery-environment" status-socket-binding="txn-status-manager"/>
        <coordinator-environment default-timeout="900" statistics-enabled="${wildfly.transactions.statistics-enabled:${wildfly.statistics-enabled:false}}"/>
        <object-store path="tx-object-store" relative-to="jboss.server.data.dir"/>
    </subsystem>
    ...
</profile>

Enabling GZIP Compression

Go to the undertow subsystem configuration in /opt/wildfly/standalone/configuration/standalone.xml.

Then add the gzip filter to the filter section and a filter-ref to host section under server, e.g.:

<subsystem xmlns="urn:jboss:domain:undertow:6.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/>
        <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content"/>
            <http-invoker security-realm="ApplicationRealm"/>
            <filter-ref name="gzipfilter" predicate="regex[pattern='text/html|text/css|application/javascript|application/json',value=%{o,Content-Type}] and max-content-size[value=1024]"/>
        </host>
    </server>
    <servlet-container name="default">
        <jsp-config/>
        <websockets/>
    </servlet-container>
    <handlers>
        <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
    </handlers>
    <filters>
        <gzip name="gzipfilter"/>
    </filters>
</subsystem>

Source: http://mcaikovski.blogspot.com/2018/01/how-to-activate-gzip-compression-of.html

This will then work e.g. for welcome-content, which is static. For e.g. REST services look into http://docs.jboss.org/resteasy/docs/3.5.1.Final/userguide/html/gzip.html

Serving on Port 80/443

Changing the default ports is easy. Look out for socket-binding in /opt/wildfly/standalone/configuration/standalone.xml:

<socket-binding name="http" port="${jboss.http.port:80}"/>
<socket-binding name="https" port="${jboss.https.port:443}"/>

Note that serving on ports below 1024 requires root privileges. This means when manually starting WildFly you can start it with sudo, but for a systemd service we need a different approach:

The safe way is to use setcap to allow java to bind ports but don't give it any more privileges. This must be done after every update of java!

sudo setcap cap_net_bind_service=+epi $JAVA_HOME/bin/java
sudo setcap cap_net_bind_service=+epi $JAVA_HOME/jre/bin/java

It is not recommended to simply use User=root in wildfly.service.

Redirect HTTP to HTTPS

In /opt/wildfly/standalone/configuration/standalone.xml add the following configuration to automatically redirect e.g. from port 80 to https on port 443.

In subsystem (undertow) > filters add a redirect including your full domain name. The %U retains the rest of the URL.

<rewrite name="http-to-https" redirect="true" target="https://example.com:443%U"/>

..or if you do not need to retain the domain name you can replace it with the host ip (%h)

<rewrite name="http-to-https" redirect="true" target="https://%h:443%U"/>

In subsystem (undertow) > server > host add a reference to the filter. Adapt the predicate to your needs, the example only activates the filter when port 80 is accessed.

<filter-ref name="http-to-https" predicate="equals(%p,80)"/>

See the undertow documentation for more variables.

HTTPS & TLS Certificate

When using HTTPS you should most probably also provide a valid TLS (aka SSL) certificate. Otherwise browsers tend to block access to your page or at least give a big warning that the page is not secure.

FIXME explore: there seems to be a new way to configure Letsencrypt directly via the WildFly CLI since WildFly 14: https://developer.jboss.org/people/fjuma/blog/2018/08/31/obtaining-certificates-from-lets-encrypt-using-the-wildfly-cli

The certificate must be present in a Java Keystore file. Copy com.example.jks to /opt/wildfly/standalone/configuration.

Then add the security-realm under management > security realms in /opt/wildfly/standalone/configuration/standalone.xml:

<security-realm name="SslRealm">
    <server-identities>
        <ssl>
            <keystore path="com.example.jks" relative-to="jboss.server.config.dir" keystore-password="YOUR_PASSWORD"/>
        </ssl>
    </server-identities>
</security-realm>

And add this in subsystem (undertow) > server:

<https-listener name="default-ssl" socket-binding="https" security-realm="SslRealm" enable-http2="true"/>

See SSL/TSL Certificates for more details.

Sources: http://reallifejava.com/configuring-ssl-in-wildfly-8, https://stackoverflow.com/questions/32008182/wildfly-9-http-to-https

Deployment / Management Website

By default port 9990 is used for deployment via the wildfly maven plugin and to access the web-based management interface.

For deployments to servers except localhost and to enter the management interface a 'Management User' in the 'ManagementRealm' is required:

sudo -u wildfly /opt/wildfly/bin/add-user.sh

This script creates an entry for each user in /opt/wildfly/standalone/configuration/mgmt-users.properties.

Using Maven to deploy to WildFly/Jboss: deploy_to_jboss

Maven Projects Using WildFly

Database Connectivity (PostgreSQL)

To access a database, e.g. PostgreSQL, the driver dependency must not be included into the deployment itself but a data source must be configured within WildFly. Simply including the database dependency into your deployment opens a memory leak since they corresponding classes can not be removed by WildFly during un/redeploys of your project.

Configure a Datasource

An easy way configure the data source is to use the WildFly Managment web frontend (http://your-server:9990) to upload the driver .jar and create a data source:

  1. Deployments → Add → Upload a new deployment
  2. Configuration → Subsystems → Datasources → Non-XA

Then configure the data source:

  • make sure to use the full connection URL including the database name & that the user/password are correct
  • enable “validate-on-match” in “validation”, which ensures the connection pool checks each connection and creates a new one if it is broken. This way we do not even notice restarts of the database server in our Java code. (see also http://stackoverflow.com/questions/28707650/wildfly-and-auto-reconnect-to-the-database)
  • limit the connection pool
  • test the connection in the “connection” tab

The data source configuration can also be found in /opt/wildfly/standalone/configuration/standalone.xml.

More info in the official docs.

Configure your Maven Build

Put the following configuration of the maven-war-plugin into the build/plugins section of your pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <configuration>
        <archive>
            <manifestEntries>
                <!-- "The Dependencies manifest header is used to specify dependencies 
                    that a jar file has." (https://docs.jboss.org/author/display/MODULES/Manifest+module+information) 
                    Note that sql drivers must NOT be put in the war file (this is a source of 
                    memory leaks), so they are deployed directly to Wildfly, and they needed 
                    to be listed as application dependency here. -->
                <Dependencies>deployment.postgresql-9.4.1208.jar</Dependencies>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Access the Datasource in Java

@ApplicationScoped
public class DB {
    @Resource(mappedName = "java:/PostgresDS")
    private DataSource ds;
 
    boolean connectToDb(String userId) {
        try (Connection conn = ds.getConnection();
                Statement statement = conn.createStatement();
                ResultSet rs = statement.executeQuery("SELECT id FROM um_user WHERE id=" + userId)) {
            //...
        } catch (SQLException e) {
            //...
        }
    }
}

Logging

In jboss-cli you add new loggers and configure existing loggers using these commands

# create logger
/subsystem=logging/logger=at.ac.ait:add(level=DEBUG)

# set loglevel
/subsystem=logging/logger=at.ac.ait:write-attribute(name=level,value=ALL) 
# note that the "FINEST" level of java.util.logging maps only to level ALL (and not to TRACE)

To remove a logger:

/subsystem=logging/logger=at.ac.ait:remove

CDI

Alternatives

To specify an Alternative Implementation for a Bean and have it override the default implementation use:

import javax.annotation.Priority;
import javax.ejb.Stateless;
import javax.enterprise.inject.Alternative;
 
 
@Alternative
@Priority(1)
@Stateless
public class BetterMyBean  implements MyBean {
   ...
}

EventBus

CDI brings its own EventBus implementation. See https://docs.oracle.com/javaee/6/tutorial/doc/gkhic.html

Simple Example

1. Define Dummy Event

public class DummyEvent{}

2. Define Listener

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
 
@ApplicationScoped
public class DummyEventListener{
  public void myObserverMethod(@Observes DummyEvent e) { doSomethingWith(e);}
}

3. Fire Event

import javax.inject.Inject;
import javax.enterprise.event.Event;
import javax.enterprise.context.ApplicationScoped;
 
@ApplicationScoped
public class Something {
  @Inject    
  private Event<DummyEvent> dummyEvent;
 
  public void someMethod() {
      dummyEvent.fire(new DummyEvent());
  }
}

Events seem to be processed syncronously. Asyncronous event processing can easily be enabled by defining an EventListener like this:

import javax.ejb.Asynchronous;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Singleton;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
 
@ApplicationScoped
@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class AsynchronousEventListener {
 
	@Asynchronous
	public void onEvent(@Observes DummyEvent e) {
		System.out.println("Got event and starting reeeeeally expensive computation ;) " );
		try {			
			Thread.sleep(10000);
			System.out.println("     DONE!" );
		} catch (InterruptedException e) {}	
	}
}

Gotchas

Managed Executor Service

The behaviour of executor services can be configured in (e.g.) /opt/wildfly/standalone/configuration/standalone.xml.

The queue-length must be set explicitly:

<managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" hung-task-threshold="60000" core-threads="2" max-threads="2" queue-length="1000" keepalive-time="5000"/>

Otherwise you will run into problems when submitting many tasks at once:

Caused by: javax.ejb.EJBException: java.util.concurrent.RejectedExecutionException: Task org.glassfish.enterprise.concurrent.internal.ManagedFutureTask@6e36d5b6 rejected from org.glassfish.enterprise.concurrent.internal.ManagedThreadPoolExecutor@6409b656[Running, pool size = 25, active threads = 25, queued tasks = 0, completed tasks = 12]
wildfly.txt · Last modified: 2020/10/29 14:13 by mstraub