====== 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 [[https://docs.jboss.org/author/display/WFLY8/Command+line+parameters|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 [[https://community.jboss.org/message/552982|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: ... ... Also add the timeout to the deployment-scanner: ... And to allow long transactions (if your logs contain tasks cancelled by the TransactionReaper) configure the default-timeout of the transaction subsystem: ... ==== 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.: 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'': 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. ..or if you do not need to retain the domain name you can replace it with the host ip (''%h'') 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. See the [[http://undertow.io/undertow-docs/undertow-docs-1.4.0/predicates-attributes-handlers.html|undertow documentation]] for more variables. ==== HTTPS & TLS Certificate ==== When using HTTPS you should most probably also provide a valid [[https://de.wikipedia.org/wiki/Transport_Layer_Security|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'': And add this in subsystem (undertow) > server: 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 [[https://docs.jboss.org/wildfly/plugins/maven/latest|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: [[maven#deploy_to_jboss]] ===== Maven Projects Using WildFly ===== Check the [[https://github.com/wildfly/quickstart|official quickstart tutorials]] and the [[https://github.com/wildfly/boms|BOMs]] ===== 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 [[https://mvnrepository.com/artifact/org.postgresql/postgresql|driver .jar]] and create a data source: - Deployments -> Add -> Upload a new deployment - 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 [[https://docs.jboss.org/author/display/WFLY10/DataSource+configuration|official docs]]. ==== Configure your Maven Build ==== Put the following configuration of the maven-war-plugin into the build/plugins section of your pom.xml: org.apache.maven.plugins maven-war-plugin deployment.postgresql-9.4.1208.jar ==== 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; 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: 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]